@heygaia/cli 0.7.0-beta.1 → 0.7.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +113 -107
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,94 +1,98 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{Command as
|
|
3
|
-
`)
|
|
4
|
-
`)
|
|
5
|
-
`)}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
${t.fix}`)}import*as H from"fs";import*as Ft from"path";import*as ur from"node:fs";import*as yn from"node:path";var Rs=[{name:"MongoDB Connection",description:"MongoDB database connection",affectedFeatures:"All database operations, user data, and application state",requiredInProd:!0,allRequired:!0,docsUrl:"https://www.mongodb.com/docs/manual/reference/connection-string/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"MONGO_DB",required:!0,category:"MongoDB Connection",description:"MongoDB database connection",affectedFeatures:"All database operations, user data, and application state",docsUrl:"https://www.mongodb.com/docs/manual/reference/connection-string/"}]},{name:"Redis Connection",description:"Redis cache and queue service",affectedFeatures:"Caching, rate limiting, and task scheduling",requiredInProd:!0,allRequired:!0,docsUrl:"https://redis.io/docs/connect/clients/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"REDIS_URL",required:!0,category:"Redis Connection",description:"Redis cache and queue service",affectedFeatures:"Caching, rate limiting, and task scheduling",docsUrl:"https://redis.io/docs/connect/clients/"}]},{name:"PostgreSQL Connection",description:"PostgreSQL database connection",affectedFeatures:"Relational data storage and queries",requiredInProd:!0,allRequired:!0,docsUrl:"https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"POSTGRES_URL",required:!1,category:"PostgreSQL Connection",description:"PostgreSQL database connection",affectedFeatures:"Relational data storage and queries",docsUrl:"https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING"}]},{name:"ChromaDB Connection",description:"ChromaDB vector database connection",affectedFeatures:"Vector storage and semantic search capabilities",requiredInProd:!0,allRequired:!0,docsUrl:"https://docs.trychroma.com/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"CHROMADB_HOST",required:!1,category:"ChromaDB Connection",description:"ChromaDB vector database connection",affectedFeatures:"Vector storage and semantic search capabilities",docsUrl:"https://docs.trychroma.com/"},{name:"CHROMADB_PORT",required:!1,category:"ChromaDB Connection",description:"ChromaDB vector database connection",affectedFeatures:"Vector storage and semantic search capabilities",docsUrl:"https://docs.trychroma.com/"}]},{name:"RabbitMQ Connection",description:"RabbitMQ message queue connection",affectedFeatures:"Asynchronous task processing and job queue",requiredInProd:!0,allRequired:!0,docsUrl:"https://www.rabbitmq.com/uri-spec.html",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"RABBITMQ_URL",required:!1,category:"RabbitMQ Connection",description:"RabbitMQ message queue connection",affectedFeatures:"Asynchronous task processing and job queue",docsUrl:"https://www.rabbitmq.com/uri-spec.html"}]},{name:"WorkOS Authentication",description:"WorkOS authentication service",affectedFeatures:"User authentication, login, and session management",requiredInProd:!0,allRequired:!0,docsUrl:"https://workos.com/docs/reference/api-keys",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"WORKOS_API_KEY",required:!1,category:"WorkOS Authentication",description:"WorkOS authentication service",affectedFeatures:"User authentication, login, and session management",docsUrl:"https://workos.com/docs/reference/api-keys"},{name:"WORKOS_CLIENT_ID",required:!1,category:"WorkOS Authentication",description:"WorkOS authentication service",affectedFeatures:"User authentication, login, and session management",docsUrl:"https://workos.com/docs/reference/api-keys"},{name:"WORKOS_COOKIE_PASSWORD",required:!1,category:"WorkOS Authentication",description:"WorkOS authentication service",affectedFeatures:"User authentication, login, and session management",docsUrl:"https://workos.com/docs/reference/api-keys"}]},{name:"Cloudinary Media Storage",description:"Cloudinary media storage service",affectedFeatures:"File uploads, image storage, and support ticket attachments when BLOB_STORE is cloudinary (hosted, or a self-host that chose it)",requiredInProd:!0,allRequired:!0,docsUrl:"https://cloudinary.com/documentation/cloudinary_credentials",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"CLOUDINARY_CLOUD_NAME",required:!1,category:"Cloudinary Media Storage",description:"Cloudinary media storage service",affectedFeatures:"File uploads, image storage, and support ticket attachments when BLOB_STORE is cloudinary (hosted, or a self-host that chose it)",docsUrl:"https://cloudinary.com/documentation/cloudinary_credentials"},{name:"CLOUDINARY_API_KEY",required:!1,category:"Cloudinary Media Storage",description:"Cloudinary media storage service",affectedFeatures:"File uploads, image storage, and support ticket attachments when BLOB_STORE is cloudinary (hosted, or a self-host that chose it)",docsUrl:"https://cloudinary.com/documentation/cloudinary_credentials"},{name:"CLOUDINARY_API_SECRET",required:!1,category:"Cloudinary Media Storage",description:"Cloudinary media storage service",affectedFeatures:"File uploads, image storage, and support ticket attachments when BLOB_STORE is cloudinary (hosted, or a self-host that chose it)",docsUrl:"https://cloudinary.com/documentation/cloudinary_credentials"}]},{name:"File Sharing",description:"HMAC signing secret for single-purpose file-share grants",affectedFeatures:"File attachments fetched by Composio during tool execution",requiredInProd:!0,allRequired:!0,docsUrl:null,alternativeGroup:null,selfhostSetup:!1,variables:[{name:"SHARE_GRANT_SECRET",required:!1,category:"File Sharing",description:"HMAC signing secret for single-purpose file-share grants",affectedFeatures:"File attachments fetched by Composio during tool execution",docsUrl:null}]},{name:"Speech Processing",description:"Speech-to-text transcription service",affectedFeatures:"Audio transcription and voice interaction",requiredInProd:!0,allRequired:!1,docsUrl:"https://deepgram.com/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"DEEPGRAM_API_KEY",required:!1,category:"Speech Processing",description:"Speech-to-text transcription service",affectedFeatures:"Audio transcription and voice interaction",docsUrl:"https://deepgram.com/"}]},{name:"OpenAI Integration",description:"OpenAI API integration (alternative to Google AI)",affectedFeatures:"AI chat, text generation, and language processing",requiredInProd:!0,allRequired:!0,docsUrl:"https://platform.openai.com/api-keys",alternativeGroup:"Google AI",selfhostSetup:!0,variables:[{name:"OPENAI_API_KEY",required:!1,category:"OpenAI Integration",description:"OpenAI API integration (alternative to Google AI)",affectedFeatures:"AI chat, text generation, and language processing",docsUrl:"https://platform.openai.com/api-keys"}]},{name:"Google AI",description:"Google AI services (alternative to OpenAI)",affectedFeatures:"Google AI and ML capabilities",requiredInProd:!0,allRequired:!0,docsUrl:"https://console.cloud.google.com/apis/credentials",alternativeGroup:"OpenAI Integration",selfhostSetup:!0,variables:[{name:"GOOGLE_API_KEY",required:!1,category:"Google AI",description:"Google AI services (alternative to OpenAI)",affectedFeatures:"Google AI and ML capabilities",docsUrl:"https://console.cloud.google.com/apis/credentials"}]},{name:"Tavily Web Search",description:"Tavily AI-powered web search integration",affectedFeatures:"Web search capabilities, image search, news search, and content extraction",requiredInProd:!0,allRequired:!0,docsUrl:"https://tavily.com/#api",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"TAVILY_API_KEY",required:!1,category:"Tavily Web Search",description:"Tavily AI-powered web search integration",affectedFeatures:"Web search capabilities, image search, news search, and content extraction",docsUrl:"https://tavily.com/#api"}]},{name:"Firecrawl Web Scraping",description:"Firecrawl web scraping and content extraction service",affectedFeatures:"Advanced web content extraction, URL processing, and page scraping",requiredInProd:!0,allRequired:!0,docsUrl:"https://www.firecrawl.dev/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"FIRECRAWL_API_KEY",required:!1,category:"Firecrawl Web Scraping",description:"Firecrawl web scraping and content extraction service",affectedFeatures:"Advanced web content extraction, URL processing, and page scraping",docsUrl:"https://www.firecrawl.dev/"}]},{name:"Llama Index",description:"Llama Index for document processing and retrieval",affectedFeatures:"Advanced document indexing, RAG capabilities, and structured data retrieval",requiredInProd:!0,allRequired:!0,docsUrl:"https://docs.llamaindex.ai/",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"LLAMA_INDEX_KEY",required:!1,category:"Llama Index",description:"Llama Index for document processing and retrieval",affectedFeatures:"Advanced document indexing, RAG capabilities, and structured data retrieval",docsUrl:"https://docs.llamaindex.ai/"}]},{name:"Resend Email Service",description:"Resend email delivery service",affectedFeatures:"Email notifications and communication",requiredInProd:!0,allRequired:!0,docsUrl:"https://resend.com/docs/api-reference/api-keys",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"RESEND_API_KEY",required:!1,category:"Resend Email Service",description:"Resend email delivery service",affectedFeatures:"Email notifications and communication",docsUrl:"https://resend.com/docs/api-reference/api-keys"},{name:"RESEND_AUDIENCE_ID",required:!1,category:"Resend Email Service",description:"Resend email delivery service",affectedFeatures:"Email notifications and communication",docsUrl:"https://resend.com/docs/api-reference/api-keys"},{name:"EMAIL_UNSUBSCRIBE_SECRET",required:!1,category:"Resend Email Service",description:"Resend email delivery service",affectedFeatures:"Email notifications and communication",docsUrl:"https://resend.com/docs/api-reference/api-keys"}]},{name:"Weather Service",description:"OpenWeather API for weather data",affectedFeatures:"Weather forecasts and current conditions",requiredInProd:!0,allRequired:!0,docsUrl:"https://openweathermap.org/api",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"OPENWEATHER_API_KEY",required:!1,category:"Weather Service",description:"OpenWeather API for weather data",affectedFeatures:"Weather forecasts and current conditions",docsUrl:"https://openweathermap.org/api"}]},{name:"Composio Integration",description:"Composio integration service",affectedFeatures:"Composio platform integration and webhook processing",requiredInProd:!0,allRequired:!0,docsUrl:"https://docs.composio.dev/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"COMPOSIO_KEY",required:!1,category:"Composio Integration",description:"Composio integration service",affectedFeatures:"Composio platform integration and webhook processing",docsUrl:"https://docs.composio.dev/"},{name:"COMPOSIO_WEBHOOK_SECRET",required:!1,category:"Composio Integration",description:"Composio integration service",affectedFeatures:"Composio platform integration and webhook processing",docsUrl:"https://docs.composio.dev/"}]},{name:"E2B Code Execution",description:"E2B secure code execution environment",affectedFeatures:"Code execution and sandboxed environments",requiredInProd:!0,allRequired:!0,docsUrl:"https://e2b.dev/docs",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"E2B_API_KEY",required:!1,category:"E2B Code Execution",description:"E2B secure code execution environment",affectedFeatures:"Code execution and sandboxed environments",docsUrl:"https://e2b.dev/docs"}]},{name:"Browser Host",description:"gaia-browser-host: the BROWSER_ENGINE host + the Chromium host",affectedFeatures:"Autonomous browser automation (the browser_task tool)",requiredInProd:!1,allRequired:!0,docsUrl:null,alternativeGroup:null,selfhostSetup:!1,variables:[{name:"BROWSER_HOST_URL",required:!1,category:"Browser Host",description:"gaia-browser-host: the BROWSER_ENGINE host + the Chromium host",affectedFeatures:"Autonomous browser automation (the browser_task tool)",docsUrl:null},{name:"BROWSER_HOST_KEY",required:!1,category:"Browser Host",description:"gaia-browser-host: the BROWSER_ENGINE host + the Chromium host",affectedFeatures:"Autonomous browser automation (the browser_task tool)",docsUrl:null},{name:"BROWSER_FALLBACK_HOST_URL",required:!1,category:"Browser Host",description:"gaia-browser-host: the BROWSER_ENGINE host + the Chromium host",affectedFeatures:"Autonomous browser automation (the browser_task tool)",docsUrl:null}]},{name:"Dodo Payments",description:"Dodo payment processing service",affectedFeatures:"Payment processing and subscription management",requiredInProd:!0,allRequired:!0,docsUrl:"https://docs.dodopayments.com/",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"DODO_PAYMENTS_API_KEY",required:!1,category:"Dodo Payments",description:"Dodo payment processing service",affectedFeatures:"Payment processing and subscription management",docsUrl:"https://docs.dodopayments.com/"},{name:"DODO_WEBHOOK_PAYMENTS_SECRET",required:!1,category:"Dodo Payments",description:"Dodo payment processing service",affectedFeatures:"Payment processing and subscription management",docsUrl:"https://docs.dodopayments.com/"}]},{name:"Blog Management",description:"Blog content management",affectedFeatures:"Blog creation and management",requiredInProd:!0,allRequired:!0,docsUrl:null,alternativeGroup:null,selfhostSetup:!1,variables:[{name:"BLOG_BEARER_TOKEN",required:!1,category:"Blog Management",description:"Blog content management",affectedFeatures:"Blog creation and management",docsUrl:null}]},{name:"Sentry Monitoring",description:"Sentry error tracking and monitoring",affectedFeatures:"Error reporting and application monitoring",requiredInProd:!0,allRequired:!0,docsUrl:"https://docs.sentry.io/platforms/python/",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"SENTRY_DSN",required:!1,category:"Sentry Monitoring",description:"Sentry error tracking and monitoring",affectedFeatures:"Error reporting and application monitoring",docsUrl:"https://docs.sentry.io/platforms/python/"}]},{name:"Posthog Analytics",description:"Posthog analytics and event tracking",affectedFeatures:"User behavior analytics and event tracking",requiredInProd:!1,allRequired:!0,docsUrl:"https://posthog.com/docs/api",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"POSTHOG_PROJECT_TOKEN",required:!1,category:"Posthog Analytics",description:"Posthog analytics and event tracking",affectedFeatures:"User behavior analytics and event tracking",docsUrl:"https://posthog.com/docs/api"},{name:"POSTHOG_HOST",required:!1,category:"Posthog Analytics",description:"Posthog analytics and event tracking",affectedFeatures:"User behavior analytics and event tracking",docsUrl:"https://posthog.com/docs/api"}]}];var wn={selfhost:{MONGO_DB:"mongodb://mongo:27017/gaia",REDIS_URL:"redis://redis:6379",POSTGRES_URL:"postgresql://postgres:postgres@postgres:5432/langgraph",CHROMADB_HOST:"chromadb",CHROMADB_PORT:"8000",RABBITMQ_URL:"amqp://guest:guest@rabbitmq:5672/"},developer:{MONGO_DB:"mongodb://localhost:27017/gaia",REDIS_URL:"redis://localhost:6379",POSTGRES_URL:"postgresql://postgres:postgres@localhost:5432/postgres",CHROMADB_HOST:"localhost",CHROMADB_PORT:"8080",RABBITMQ_URL:"amqp://guest:guest@localhost:5672/"}},Ts={selfhost:{HOST:"http://localhost:3000",FRONTEND_URL:"http://localhost:3000",GAIA_BACKEND_URL:"http://gaia-backend:8000"},developer:{HOST:"http://localhost:8000",FRONTEND_URL:"http://localhost:3000",GAIA_BACKEND_URL:"http://host.docker.internal:8000"}};function dr(e,t){return wn[t][e]??Ts[t][e]}function Wr(){return structuredClone(Rs)}function Ps(e){let t=yn.join(e,"apps","web",".env.local"),r=ur.existsSync(t)?t:yn.join(e,"apps","web",".env");if(!ur.existsSync(r))return[];let o=ur.readFileSync(r,"utf-8"),n=[],i="General";for(let s of o.split(`
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
`))}function Ls(e,t,r){let o=Ft.join(e,"apps","web",".env.local");Kr(o);let n=Ps(e),i=As(t,r),s=["# GAIA Web App Environment Configuration","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""],a=new Map;for(let c of n){a.has(c.category)||a.set(c.category,[]);let l=i[c.name]??c.value;a.get(c.category).push({name:c.name,value:l})}if(n.length===0){s.push("# Core URLs");for(let[c,l]of Object.entries(i))s.push(`${c}=${l}`);s.push("")}else for(let[c,l]of a.entries()){s.push(`# ${c}`);for(let{name:d,value:p}of l)s.push(`${d}=${p}`);s.push("")}Yr(o,s.join(`
|
|
13
|
-
`))
|
|
14
|
-
`))
|
|
15
|
-
`))
|
|
16
|
-
|
|
17
|
-
`);for(let
|
|
18
|
-
`))
|
|
19
|
-
|
|
20
|
-
`)
|
|
21
|
-
`).
|
|
2
|
+
import{Command as ry,Option as oy}from"commander";var U={up:"Install GAIA and start it (or resume an earlier run)",status:"Show whether GAIA is running and healthy",stop:"Stop GAIA (your data is kept)",start:"Start GAIA again after 'gaia stop'",update:"Move GAIA to a newer release (keeps your data and settings)",doctor:"Find problems with your install and how to fix them",logs:"Show GAIA's logs as they happen",bots:"Connect GAIA to Telegram, Discord or Slack",connect:"Import browser logins so GAIA's browser stays signed in",bridge:"Let GAIA use tools and files on this computer",backup:"Save GAIA's data and settings to a folder",restore:"Bring back GAIA's data and settings from a backup",init:"Set up a development copy of GAIA from scratch",setup:"Configure an existing development copy",dev:"Run GAIA from source with live reload"};import*as Ba from"node:path";import _d from"is-unicode-supported";var w="cyan",gr=30,I="round",Ut=_d(),y={ok:Ut?"\u2713":"\u221A",fail:Ut?"\u2717":"x",warn:"!",skip:Ut?"\u2013":"-",pending:Ut?"\u25CB":"o",active:Ut?"\u25CF":"*",cancelled:Ut?"\u25A0":"#"},ms={ok:"green",fail:"red",warn:"yellow",skip:"gray",pending:"gray",active:w,cancelled:"yellow"};function le(e){let[t="",...r]=e.split(`
|
|
3
|
+
`),o=[`${y.fail} ${t}`,...r.map(n=>` ${n}`)];process.stderr.write(`${o.join(`
|
|
4
|
+
`)}
|
|
5
|
+
`)}var yt=[{volume:"gaia-selfhost_chroma_data",fileSuffix:"chroma_data",label:"Chroma",userData:!1},{volume:"gaia-selfhost_workspace",fileSuffix:"workspace",label:"Workspace",userData:!0},{volume:"gaia-selfhost_files",fileSuffix:"files",label:"Uploaded files",userData:!0}];function hr(e){return`mkdir -p /tmp/restore && tar xzf /backups/${e} -C /tmp/restore && { rm -rf /data/* 2>/dev/null; rm -rf /data/.[!.]* 2>/dev/null || true; } && cp -a /tmp/restore/. /data/ && rm -rf /tmp/restore`}import*as Y from"node:fs";import*as be from"node:path";import{execa as Fa}from"execa";import*as Kr from"node:fs";import*as gn from"node:path";var Dd=/^\d{4}-\d{2}-\d{2}(T\d{2}-\d{2}-\d{2}Z)?$/,Od=".partial",fs={prefix:"mongo-",suffix:".gz"},gs={prefix:"postgres-",suffix:".sql"},hs={prefix:"api-env-",suffix:".env"},Ss=".tar.gz",$d=[fs,gs,hs,...yt.map(e=>({prefix:`${e.fileSuffix}-`,suffix:Ss}))];function hn(e=new Date){return`${e.toISOString().slice(0,19).replaceAll(":","-")}Z`}function jt(e,t){let r=o=>gn.join(e,`${o.prefix}${t}${o.suffix}`);return{mongoFile:r(fs),postgresFile:r(gs),apiEnvFile:r(hs),volumeFiles:yt.map(o=>Sn(e,t,o))}}function Sn(e,t,r){return{volume:r.volume,label:r.label,file:gn.join(e,`${r.fileSuffix}-${t}${Ss}`)}}function wt(e){return`${e}${Od}`}function vs(e){return Kr.existsSync(e)?Kr.readdirSync(e).flatMap(r=>$d.flatMap(({prefix:o,suffix:n})=>{if(!r.startsWith(o)||!r.endsWith(n))return[];let i=r.slice(o.length,r.length-n.length);return Dd.test(i)?[i]:[]})).sort().at(-1):void 0}import*as Yr from"node:fs";import*as bs from"node:os";import{execa as qt}from"execa";var ys="/var/run/docker.sock",pe={selfhost:"gaia-selfhost",developer:"gaia-dev"},Ld=/\((healthy|unhealthy|health: starting)\)/;async function Es(e){return(await bt(e)).map(r=>({name:r.service,status:r.state==="running"?"running":"stopped",health:r.health}))}async function xs(e){let{stdout:t}=await qt("docker",["ps","--filter",`label=com.docker.compose.project=${e}`,"--format","{{.Ports}}"]),r=new Set;for(let o of t.matchAll(/:(\d+)->/g))r.add(Number(o[1]));return r}function Cs(){return bs.platform()!=="linux"||!Yr.existsSync(ys)?0:Yr.statSync(ys).gid}async function bt(e){let{stdout:t}=await qt("docker",["ps","-a","--filter",`label=com.docker.compose.project=${e}`,"--format",'{{.Label "com.docker.compose.service"}}|{{.State}}|{{.Status}}']);return Md(t)}function Md(e){let t=[];for(let r of e.trim().split(`
|
|
6
|
+
`)){if(!r)continue;let[o,n,i]=r.split("|");if(!o||!n)continue;let s=i?.match(Ld)?.[1];t.push(s?{service:o,state:n,health:s}:{service:o,state:n})}return t}async function Is(){let{stdout:e}=await qt("docker",["info","--format","{{.DockerRootDir}}"]),t=e.trim();if(!t)throw new Error("docker info returned an empty DockerRootDir");return t}async function ks(e){let{stdout:t}=await qt("df",["-k",e]);return t}var ws=26;async function Nd(){let{stdout:e}=await qt("docker",["version","--format","{{.Server.Version}}"]);return e.trim()}async function Rs(){let e=await Nd(),t=Number.parseInt(e,10);if(Number.isNaN(t)||t<ws)throw new Error(`The code sandbox needs Docker Engine ${ws} or newer (this daemon is ${e||"unknown"}): it mounts only each user's own files into their sandbox. Upgrade Docker, or run \`gaia up --no-code-sandbox\` and save an E2B key instead.`)}async function zr(e){let{stdout:t}=await qt("docker",["volume","ls","--quiet","--filter",`name=^${e}$`]);return t.trim().split(`
|
|
7
|
+
`).includes(e)}import*as Bs from"node:os";import{execa as Kd}from"execa";import{spawn as Ud}from"node:child_process";import*as En from"node:os";import{execa as xn}from"execa";import*as Ps from"node:fs";import*as wn from"node:path";import*as Ge from"fs";import*as As from"os";import*as yn from"path";var Ts={name:"@heygaia/cli",description:"CLI tool for setting up and managing GAIA",version:"0.7.0-beta.3",type:"module",files:["dist","README.md"],scripts:{"bake:logo":"node scripts/bake-logo.mjs",build:"node esbuild.config.mjs && chmod +x dist/index.js",check:"biome check src",dev:"tsx watch src/index.ts",fix:"biome check --write src",format:"biome format --write src",lint:"pnpm run check","lint:fix":"pnpm run fix",prepublishOnly:"pnpm run build",start:"NODE_ENV=production node dist/index.js","type-check":"tsc --noEmit"},dependencies:{"@inkjs/ui":"^2.0.0","@modelcontextprotocol/sdk":"^1.32.0",chalk:"^5.6.2",commander:"^14.0.3",execa:"^9.6.1",ink:"^6.8.0","ink-text-input":"^6.0.0","is-unicode-supported":"^2.1.0",react:"19.1.0","react-dom":"19.1.0",semver:"^7.8.5","simple-git":"^3.36.0","supports-hyperlinks":"^3.2.0","wrap-ansi":"^9.0.2",ws:"^8.21.0",zod:"^4.3.6"},devDependencies:{"@biomejs/biome":"^2.5.7","@gaia/shared":"workspace:*","@resvg/resvg-js":"^2.6.2","@types/node":"^24.13.3","@types/react":"^19.2.17","@types/react-dom":"^19.2.3","@types/semver":"^7.8.0","@types/ws":"^8.18.1",esbuild:"^0.25.12",tsx:"^4.23.11",typescript:"^7.0.2",vite:"^7.3.6",vitest:"^4.1.10"},bin:{gaia:"./dist/index.js"},engines:{node:">=20"},keywords:["ai-assistant","cli","gaia","setup"],license:"MIT",publishConfig:{access:"public"},repository:{type:"git",url:"git+https://github.com/theexperiencecompany/gaia.git",directory:"packages/cli"}};var $=Ts.version,Ke=`v${$}`;var Ye=yn.join(As.homedir(),".gaia"),vn=yn.join(Ye,"config.json");function Bd(){Ge.existsSync(Ye)||Ge.mkdirSync(Ye,{recursive:!0})}function L(){try{if(!Ge.existsSync(vn))return null;let e=Ge.readFileSync(vn,"utf-8");return JSON.parse(e)}catch{return null}}function Xr(e){Bd(),Ge.writeFileSync(vn,`${JSON.stringify(e,null,2)}
|
|
8
|
+
`)}function ye(e){let r={...L()??{version:$,setupComplete:!1,setupMethod:"manual",repoPath:"",createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()},...e,updatedAt:new Date().toISOString()};Xr(r)}var Sr=wn.join(Ye,"logs");function Et(e,t=new Date){Ps.mkdirSync(Sr,{recursive:!0});let r=t.toISOString().slice(0,19).replaceAll(":","-");return wn.join(Sr,`${e}-${r}.log`)}function Jr(e){let t="";return r=>{let o=(t+r).split(/\r?\n|\r/);t=o.pop()??"";for(let n of o)n.trim()&&e(n)}}import*as _s from"node:fs";import{execa as bn}from"execa";function Ds(){return typeof process.getuid=="function"&&process.getuid()===0}async function Gd(){Ds()||!(await bn("sudo",["-n","true"],{reject:!1})).failed||await bn("sudo",["-v","-p","[sudo] password for %u: "],{stdio:"inherit"})}async function Ht(e,t,r,o){await Gd();let[n,i]=Ds()?[e,[...t]]:["sudo",["-n",e,...t]],s=_s.createWriteStream(r,{flags:"a"}),a=Jr(d=>o?.(d)),c=bn(n,i,{all:!0,reject:!1});c.all?.on("data",d=>{s.write(d),a(d.toString())});let l=await c;if(await new Promise(d=>s.end(d)),l.failed)throw new Error(`'${[e,...t].join(" ")}' failed (exit ${l.exitCode??"unknown"}). Its output is in ${r}`)}var re="docker",Cn="GAIA_DOCKER_GROUP_RELAUNCHED",Os="GAIA_RESUMED_STEP",$s="GAIA_RESUMED_STEP_STARTS";function Qr(){return process.env[Os]||void 0}function Zr(){let e=process.env[$s];return e?JSON.parse(e):{}}function Ls(){return process.env[Cn]==="1"}async function In(){let{stdout:e}=await xn("id",["-nG",En.userInfo().username]);return e.split(/\s+/).includes(re)}function Ms(e){let t=e.stderr;return typeof t=="string"&&t.toLowerCase().includes("permission denied")}async function Ns(){if(process.env[Cn]==="1")throw new Error(`Still no access to the Docker socket after joining the '${re}' group.
|
|
9
|
+
Check the socket's group with 'ls -l /var/run/docker.sock', then log out and back in and rerun.`);if(await In())return;let e=En.userInfo().username;try{await Ht("usermod",["-aG",re,e],Et("docker-group"))}catch(t){throw new Error(`Could not add ${e} to the '${re}' group: ${t.message}
|
|
10
|
+
Run 'sudo usermod -aG ${re} ${e}', log out and back in, then rerun.`)}}var jd=/^[A-Za-z_][A-Za-z0-9_]*$/;async function qd(e){try{return await xn("sh",["-c",'command -v "$1"',"sh",e]),!0}catch{return!1}}async function Hd(){try{return await xn("sudo",["-l","-g",re,"--",process.execPath]),!0}catch{return!1}}async function Fs(){if(await qd("sg"))return"sg";if(await Hd())return"sudo";throw new Error(`Docker access was granted, but this login session predates it and cannot pick it up ('sg' is missing and sudo cannot switch to the '${re}' group).
|
|
11
|
+
Log out and back in (or run 'newgrp ${re}'), then rerun this command.`)}function Vd(e){return`'${e.replaceAll("'","'\\''")}'`}function Wd(e,t,r){return e==="sg"?["sg",[re,"-c",t.map(Vd).join(" ")]]:["sudo",[`--preserve-env=${Object.keys(r).filter(n=>jd.test(n)).join(",")}`,"-g",re,"--",...t]]}function kn(e,t,r){let o={...process.env,[Cn]:"1",[Os]:e,[$s]:JSON.stringify(r)},[n,i]=Wd(t,[process.execPath,...process.argv.slice(1)],o),s=Ud(n,i,{stdio:"inherit",env:o});return new Promise((a,c)=>{s.on("error",c),s.on("exit",(l,d)=>{process.exit(l??(d?1:0))})})}var Yd=5e3,zd="https://orbstack.dev",Rn="Run 'gaia up': it installs everything GAIA needs.";async function J(){try{return await Kd("docker",["info"],{timeout:Yd}),"ready"}catch(e){return e.code==="ENOENT"?"not-installed":Ms(e)?"no-permission":"not-running"}}async function Ue(e){let t=Bs.platform()==="darwin";switch(e){case"not-installed":return{summary:"Docker isn't installed",state:"isn't installed",fix:t?`Install OrbStack (${zd}) or Docker Desktop, open it, then try again.`:Rn};case"not-running":return{summary:"Docker isn't running",state:"isn't running",fix:t?"Open OrbStack or Docker Desktop, then try again.":"Start it with 'sudo systemctl start docker', then try again."};case"no-permission":return{summary:"Docker is running, but your user can't use it yet",state:"is running, but your user can't use it yet",fix:await In()?`Your user just joined the '${re}' group. Log out and back in (or run 'newgrp ${re}' in this terminal), then try again.`:`Run 'sudo usermod -aG ${re} $USER', log out and back in, then try again.`}}}async function xt(e){let t=await Ue(e);return new Error(`${t.summary}.
|
|
12
|
+
${t.fix}`)}import*as V from"fs";import*as Vt from"path";import*as vr from"node:fs";import*as Tn from"node:path";var Gs=[{name:"MongoDB Connection",description:"MongoDB database connection",affectedFeatures:"All database operations, user data, and application state",requiredInProd:!0,allRequired:!0,docsUrl:"https://www.mongodb.com/docs/manual/reference/connection-string/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"MONGO_DB",required:!0,category:"MongoDB Connection",description:"MongoDB database connection",affectedFeatures:"All database operations, user data, and application state",docsUrl:"https://www.mongodb.com/docs/manual/reference/connection-string/"}]},{name:"Redis Connection",description:"Redis cache and queue service",affectedFeatures:"Caching, rate limiting, and task scheduling",requiredInProd:!0,allRequired:!0,docsUrl:"https://redis.io/docs/connect/clients/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"REDIS_URL",required:!0,category:"Redis Connection",description:"Redis cache and queue service",affectedFeatures:"Caching, rate limiting, and task scheduling",docsUrl:"https://redis.io/docs/connect/clients/"}]},{name:"PostgreSQL Connection",description:"PostgreSQL database connection",affectedFeatures:"Relational data storage and queries",requiredInProd:!0,allRequired:!0,docsUrl:"https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"POSTGRES_URL",required:!1,category:"PostgreSQL Connection",description:"PostgreSQL database connection",affectedFeatures:"Relational data storage and queries",docsUrl:"https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING"}]},{name:"ChromaDB Connection",description:"ChromaDB vector database connection",affectedFeatures:"Vector storage and semantic search capabilities",requiredInProd:!0,allRequired:!0,docsUrl:"https://docs.trychroma.com/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"CHROMADB_HOST",required:!1,category:"ChromaDB Connection",description:"ChromaDB vector database connection",affectedFeatures:"Vector storage and semantic search capabilities",docsUrl:"https://docs.trychroma.com/"},{name:"CHROMADB_PORT",required:!1,category:"ChromaDB Connection",description:"ChromaDB vector database connection",affectedFeatures:"Vector storage and semantic search capabilities",docsUrl:"https://docs.trychroma.com/"}]},{name:"RabbitMQ Connection",description:"RabbitMQ message queue connection",affectedFeatures:"Asynchronous task processing and job queue",requiredInProd:!0,allRequired:!0,docsUrl:"https://www.rabbitmq.com/uri-spec.html",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"RABBITMQ_URL",required:!1,category:"RabbitMQ Connection",description:"RabbitMQ message queue connection",affectedFeatures:"Asynchronous task processing and job queue",docsUrl:"https://www.rabbitmq.com/uri-spec.html"}]},{name:"WorkOS Authentication",description:"WorkOS authentication service",affectedFeatures:"User authentication, login, and session management",requiredInProd:!0,allRequired:!0,docsUrl:"https://workos.com/docs/reference/api-keys",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"WORKOS_API_KEY",required:!1,category:"WorkOS Authentication",description:"WorkOS authentication service",affectedFeatures:"User authentication, login, and session management",docsUrl:"https://workos.com/docs/reference/api-keys"},{name:"WORKOS_CLIENT_ID",required:!1,category:"WorkOS Authentication",description:"WorkOS authentication service",affectedFeatures:"User authentication, login, and session management",docsUrl:"https://workos.com/docs/reference/api-keys"},{name:"WORKOS_COOKIE_PASSWORD",required:!1,category:"WorkOS Authentication",description:"WorkOS authentication service",affectedFeatures:"User authentication, login, and session management",docsUrl:"https://workos.com/docs/reference/api-keys"}]},{name:"Cloudinary Media Storage",description:"Cloudinary media storage service",affectedFeatures:"File uploads, image storage, and support ticket attachments when BLOB_STORE is cloudinary (hosted, or a self-host that chose it)",requiredInProd:!0,allRequired:!0,docsUrl:"https://cloudinary.com/documentation/cloudinary_credentials",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"CLOUDINARY_CLOUD_NAME",required:!1,category:"Cloudinary Media Storage",description:"Cloudinary media storage service",affectedFeatures:"File uploads, image storage, and support ticket attachments when BLOB_STORE is cloudinary (hosted, or a self-host that chose it)",docsUrl:"https://cloudinary.com/documentation/cloudinary_credentials"},{name:"CLOUDINARY_API_KEY",required:!1,category:"Cloudinary Media Storage",description:"Cloudinary media storage service",affectedFeatures:"File uploads, image storage, and support ticket attachments when BLOB_STORE is cloudinary (hosted, or a self-host that chose it)",docsUrl:"https://cloudinary.com/documentation/cloudinary_credentials"},{name:"CLOUDINARY_API_SECRET",required:!1,category:"Cloudinary Media Storage",description:"Cloudinary media storage service",affectedFeatures:"File uploads, image storage, and support ticket attachments when BLOB_STORE is cloudinary (hosted, or a self-host that chose it)",docsUrl:"https://cloudinary.com/documentation/cloudinary_credentials"}]},{name:"File Sharing",description:"HMAC signing secret for single-purpose file-share grants",affectedFeatures:"File attachments fetched by Composio during tool execution",requiredInProd:!0,allRequired:!0,docsUrl:null,alternativeGroup:null,selfhostSetup:!1,variables:[{name:"SHARE_GRANT_SECRET",required:!1,category:"File Sharing",description:"HMAC signing secret for single-purpose file-share grants",affectedFeatures:"File attachments fetched by Composio during tool execution",docsUrl:null}]},{name:"Speech Processing",description:"Speech-to-text transcription service",affectedFeatures:"Audio transcription and voice interaction",requiredInProd:!0,allRequired:!1,docsUrl:"https://deepgram.com/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"DEEPGRAM_API_KEY",required:!1,category:"Speech Processing",description:"Speech-to-text transcription service",affectedFeatures:"Audio transcription and voice interaction",docsUrl:"https://deepgram.com/"}]},{name:"OpenAI Integration",description:"OpenAI API integration (alternative to Google AI)",affectedFeatures:"AI chat, text generation, and language processing",requiredInProd:!0,allRequired:!0,docsUrl:"https://platform.openai.com/api-keys",alternativeGroup:"Google AI",selfhostSetup:!0,variables:[{name:"OPENAI_API_KEY",required:!1,category:"OpenAI Integration",description:"OpenAI API integration (alternative to Google AI)",affectedFeatures:"AI chat, text generation, and language processing",docsUrl:"https://platform.openai.com/api-keys"}]},{name:"Google AI",description:"Google AI services (alternative to OpenAI)",affectedFeatures:"Google AI and ML capabilities",requiredInProd:!0,allRequired:!0,docsUrl:"https://console.cloud.google.com/apis/credentials",alternativeGroup:"OpenAI Integration",selfhostSetup:!0,variables:[{name:"GOOGLE_API_KEY",required:!1,category:"Google AI",description:"Google AI services (alternative to OpenAI)",affectedFeatures:"Google AI and ML capabilities",docsUrl:"https://console.cloud.google.com/apis/credentials"}]},{name:"Tavily Web Search",description:"Tavily AI-powered web search integration",affectedFeatures:"Web search capabilities, image search, news search, and content extraction",requiredInProd:!0,allRequired:!0,docsUrl:"https://tavily.com/#api",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"TAVILY_API_KEY",required:!1,category:"Tavily Web Search",description:"Tavily AI-powered web search integration",affectedFeatures:"Web search capabilities, image search, news search, and content extraction",docsUrl:"https://tavily.com/#api"}]},{name:"Firecrawl Web Scraping",description:"Firecrawl web scraping and content extraction service",affectedFeatures:"Advanced web content extraction, URL processing, and page scraping",requiredInProd:!0,allRequired:!0,docsUrl:"https://www.firecrawl.dev/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"FIRECRAWL_API_KEY",required:!1,category:"Firecrawl Web Scraping",description:"Firecrawl web scraping and content extraction service",affectedFeatures:"Advanced web content extraction, URL processing, and page scraping",docsUrl:"https://www.firecrawl.dev/"}]},{name:"Llama Index",description:"Llama Index for document processing and retrieval",affectedFeatures:"Advanced document indexing, RAG capabilities, and structured data retrieval",requiredInProd:!0,allRequired:!0,docsUrl:"https://docs.llamaindex.ai/",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"LLAMA_INDEX_KEY",required:!1,category:"Llama Index",description:"Llama Index for document processing and retrieval",affectedFeatures:"Advanced document indexing, RAG capabilities, and structured data retrieval",docsUrl:"https://docs.llamaindex.ai/"}]},{name:"Resend Email Service",description:"Resend email delivery service",affectedFeatures:"Email notifications and communication",requiredInProd:!0,allRequired:!0,docsUrl:"https://resend.com/docs/api-reference/api-keys",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"RESEND_API_KEY",required:!1,category:"Resend Email Service",description:"Resend email delivery service",affectedFeatures:"Email notifications and communication",docsUrl:"https://resend.com/docs/api-reference/api-keys"},{name:"RESEND_AUDIENCE_ID",required:!1,category:"Resend Email Service",description:"Resend email delivery service",affectedFeatures:"Email notifications and communication",docsUrl:"https://resend.com/docs/api-reference/api-keys"},{name:"EMAIL_UNSUBSCRIBE_SECRET",required:!1,category:"Resend Email Service",description:"Resend email delivery service",affectedFeatures:"Email notifications and communication",docsUrl:"https://resend.com/docs/api-reference/api-keys"}]},{name:"Weather Service",description:"OpenWeather API for weather data",affectedFeatures:"Weather forecasts and current conditions",requiredInProd:!0,allRequired:!0,docsUrl:"https://openweathermap.org/api",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"OPENWEATHER_API_KEY",required:!1,category:"Weather Service",description:"OpenWeather API for weather data",affectedFeatures:"Weather forecasts and current conditions",docsUrl:"https://openweathermap.org/api"}]},{name:"Composio Integration",description:"Composio integration service",affectedFeatures:"Composio platform integration and webhook processing",requiredInProd:!0,allRequired:!0,docsUrl:"https://docs.composio.dev/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"COMPOSIO_KEY",required:!1,category:"Composio Integration",description:"Composio integration service",affectedFeatures:"Composio platform integration and webhook processing",docsUrl:"https://docs.composio.dev/"},{name:"COMPOSIO_WEBHOOK_SECRET",required:!1,category:"Composio Integration",description:"Composio integration service",affectedFeatures:"Composio platform integration and webhook processing",docsUrl:"https://docs.composio.dev/"}]},{name:"E2B Code Execution",description:"E2B secure code execution environment",affectedFeatures:"Code execution and sandboxed environments",requiredInProd:!0,allRequired:!0,docsUrl:"https://e2b.dev/docs",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"E2B_API_KEY",required:!1,category:"E2B Code Execution",description:"E2B secure code execution environment",affectedFeatures:"Code execution and sandboxed environments",docsUrl:"https://e2b.dev/docs"}]},{name:"Browser Host",description:"gaia-browser-host: the BROWSER_ENGINE host + the Chromium host",affectedFeatures:"Autonomous browser automation (the browser_task tool)",requiredInProd:!1,allRequired:!0,docsUrl:null,alternativeGroup:null,selfhostSetup:!1,variables:[{name:"BROWSER_HOST_URL",required:!1,category:"Browser Host",description:"gaia-browser-host: the BROWSER_ENGINE host + the Chromium host",affectedFeatures:"Autonomous browser automation (the browser_task tool)",docsUrl:null},{name:"BROWSER_HOST_KEY",required:!1,category:"Browser Host",description:"gaia-browser-host: the BROWSER_ENGINE host + the Chromium host",affectedFeatures:"Autonomous browser automation (the browser_task tool)",docsUrl:null},{name:"BROWSER_FALLBACK_HOST_URL",required:!1,category:"Browser Host",description:"gaia-browser-host: the BROWSER_ENGINE host + the Chromium host",affectedFeatures:"Autonomous browser automation (the browser_task tool)",docsUrl:null}]},{name:"Dodo Payments",description:"Dodo payment processing service",affectedFeatures:"Payment processing and subscription management",requiredInProd:!0,allRequired:!0,docsUrl:"https://docs.dodopayments.com/",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"DODO_PAYMENTS_API_KEY",required:!1,category:"Dodo Payments",description:"Dodo payment processing service",affectedFeatures:"Payment processing and subscription management",docsUrl:"https://docs.dodopayments.com/"},{name:"DODO_WEBHOOK_PAYMENTS_SECRET",required:!1,category:"Dodo Payments",description:"Dodo payment processing service",affectedFeatures:"Payment processing and subscription management",docsUrl:"https://docs.dodopayments.com/"}]},{name:"Blog Management",description:"Blog content management",affectedFeatures:"Blog creation and management",requiredInProd:!0,allRequired:!0,docsUrl:null,alternativeGroup:null,selfhostSetup:!1,variables:[{name:"BLOG_BEARER_TOKEN",required:!1,category:"Blog Management",description:"Blog content management",affectedFeatures:"Blog creation and management",docsUrl:null}]},{name:"Sentry Monitoring",description:"Sentry error tracking and monitoring",affectedFeatures:"Error reporting and application monitoring",requiredInProd:!0,allRequired:!0,docsUrl:"https://docs.sentry.io/platforms/python/",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"SENTRY_DSN",required:!1,category:"Sentry Monitoring",description:"Sentry error tracking and monitoring",affectedFeatures:"Error reporting and application monitoring",docsUrl:"https://docs.sentry.io/platforms/python/"}]},{name:"Posthog Analytics",description:"Posthog analytics and event tracking",affectedFeatures:"User behavior analytics and event tracking",requiredInProd:!1,allRequired:!0,docsUrl:"https://posthog.com/docs/api",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"POSTHOG_PROJECT_TOKEN",required:!1,category:"Posthog Analytics",description:"Posthog analytics and event tracking",affectedFeatures:"User behavior analytics and event tracking",docsUrl:"https://posthog.com/docs/api"},{name:"POSTHOG_HOST",required:!1,category:"Posthog Analytics",description:"Posthog analytics and event tracking",affectedFeatures:"User behavior analytics and event tracking",docsUrl:"https://posthog.com/docs/api"}]}];var An={selfhost:{MONGO_DB:"mongodb://mongo:27017/gaia",REDIS_URL:"redis://redis:6379",POSTGRES_URL:"postgresql://postgres:postgres@postgres:5432/langgraph",CHROMADB_HOST:"chromadb",CHROMADB_PORT:"8000",RABBITMQ_URL:"amqp://guest:guest@rabbitmq:5672/"},developer:{MONGO_DB:"mongodb://localhost:27017/gaia",REDIS_URL:"redis://localhost:6379",POSTGRES_URL:"postgresql://postgres:postgres@localhost:5432/postgres",CHROMADB_HOST:"localhost",CHROMADB_PORT:"8080",RABBITMQ_URL:"amqp://guest:guest@localhost:5672/"}},Us={selfhost:{HOST:"http://localhost:3000",FRONTEND_URL:"http://localhost:3000",GAIA_BACKEND_URL:"http://gaia-backend:8000"},developer:{HOST:"http://localhost:8000",FRONTEND_URL:"http://localhost:3000",GAIA_BACKEND_URL:"http://host.docker.internal:8000"}};function yr(e,t){return An[t][e]??Us[t][e]}function eo(){return structuredClone(Gs)}function js(e){let t=Tn.join(e,"apps","web",".env.local"),r=vr.existsSync(t)?t:Tn.join(e,"apps","web",".env");if(!vr.existsSync(r))return[];let o=vr.readFileSync(r,"utf-8"),n=[],i="General";for(let s of o.split(`
|
|
13
|
+
`)){let a=s.trim();if(a.startsWith("#")&&!a.startsWith("#=")){let p=a.replace(/^#+\s*/,"").trim();p&&!p.startsWith("These are")&&(i=p);continue}if(!a||a.startsWith("#"))continue;let c=a.indexOf("=");if(c===-1)continue;let l=a.substring(0,c).trim(),d=a.substring(c+1).trim();n.push({name:l,value:d,category:i})}return n}function qs(e,t){return{NEXT_PUBLIC_API_BASE_URL:`http://localhost:${t?.[8e3]??8e3}/api/v1/`}}function Hs(e,t,r){let o=r==="selfhost"?new Set(Object.keys(An.selfhost)):new Set;for(let[n,i]of Object.entries(t)){let s=Number(n),a=Number(i);for(let[c,l]of Object.entries(e)){if(o.has(c))continue;if(l===String(s)){e[c]=String(a);continue}let d=new RegExp(`:${s}(?=[/\\s]|$)`,"g");e[c]=l.replaceAll(d,`:${a}`)}}}function Vs(e,t){return e.map(r=>({...r,variables:r.variables.map(o=>{let n=yr(o.name,t);return{...o,defaultValue:n||o.defaultValue}})}))}function wr(){return Object.keys(An.selfhost)}function Ws(e){return{...Us[e]}}function Ct(e){let t={};if(!e)return t;for(let r of e.split(`
|
|
14
|
+
`)){let o=r.trim();if(!o||o.startsWith("#"))continue;let n=o.indexOf("=");if(n<=0)continue;let i=o.substring(0,n).trim(),s=o.substring(n+1).trim().replace(/^["']|["']$/g,"");i&&s&&(t[i]=s)}return t}var Pn=384;function to(e){if(V.existsSync(e)){let t=`${e}.bak`;V.copyFileSync(e,t),V.chmodSync(t,Pn)}}function ro(e,t){V.writeFileSync(e,t,{encoding:"utf-8",mode:Pn}),V.chmodSync(e,Pn)}function oo(e,t){to(t),ro(t,V.readFileSync(e,"utf-8"))}function br(e,t){let r=Vt.join(e,".env");to(r);let o=["# GAIA Environment Configuration","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""],n=["MONGO","REDIS","POSTGRES","CHROMADB","RABBITMQ","WORKOS","GOOGLE","OPENAI","INFISICAL","LANGSMITH","DISCORD","SLACK","TELEGRAM","CLOUDINARY","COMPOSIO","FIRECRAWL","LIVEKIT","DEEPGRAM","ELEVENLABS","RESEND","SENTRY","POSTHOG","E2B","DODO","NEXT_PUBLIC","GAIA"];function i(a){for(let l of n)if(a===l||a.startsWith(`${l}_`))return l;let c=a.split("_");return c.length===1?"Core":c[0]||"Core"}let s=new Map;for(let[a,c]of Object.entries(t)){let l=i(a);s.has(l)||s.set(l,[]);let p=/[\s#"'\\]/.test(c)||c===""?`"${c.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`:c;s.get(l).push(`${a}=${p}`)}for(let[a,c]of s.entries())o.push(`# ${a} Configuration`),o.push(...c),o.push("");ro(r,o.join(`
|
|
15
|
+
`))}function Ys(e,t,r){let o=Vt.join(e,"apps","web",".env.local");to(o);let n=js(e),i=qs(t,r),s=["# GAIA Web App Environment Configuration","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""],a=new Map;for(let c of n){a.has(c.category)||a.set(c.category,[]);let l=i[c.name]??c.value;a.get(c.category).push({name:c.name,value:l})}if(n.length===0){s.push("# Core URLs");for(let[c,l]of Object.entries(i))s.push(`${c}=${l}`);s.push("")}else for(let[c,l]of a.entries()){s.push(`# ${c}`);for(let{name:d,value:p}of l)s.push(`${d}=${p}`);s.push("")}ro(o,s.join(`
|
|
16
|
+
`))}var _n={8e3:"API_HOST_PORT",5432:"POSTGRES_HOST_PORT",6379:"REDIS_HOST_PORT",27017:"MONGO_HOST_PORT",5672:"RABBITMQ_HOST_PORT",15672:"RABBITMQ_MGMT_PORT",8080:"CHROMADB_HOST_PORT",8083:"MONGO_EXPRESS_HOST_PORT",3e3:"WEB_HOST_PORT",3443:"HTTPS_HOST_PORT"},Ks=Object.fromEntries(Object.entries(_n).map(([e,t])=>[t,Number(e)])),Qd="proxy";function zs(e){return Vt.join(e,"infra","docker",".env")}function no(e){let t=zs(e);return V.existsSync(t)?Ct(V.readFileSync(t,"utf-8")):{}}var Dn="GAIA_VERSION",Zd="latest",Xs="GAIA_DOMAIN";function Js(e){return no(e)[Xs]||void 0}function Te(e){return no(e)[Dn]??Zd}function Qs(e,t){let r=zs(e);to(r);let o=["# Docker Compose environment overrides","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""];for(let[n,i]of Object.entries(t))o.push(`${n}=${i}`);o.push(""),ro(r,o.join(`
|
|
17
|
+
`))}function Zs(e,t,r){Qs(e,{...no(e),[t]:r})}function On(e,t,r,o){let{NEXT_PUBLIC_APP_URL:n,...i}=no(e);for(let[s,a]of Object.entries(t)){let c=Number(s),l=_n[c];l&&(i[l]=String(a))}r==="selfhost"&&o&&(i.COMPOSE_PROFILES??=Qd,i.DOCKER_SOCKET_GID=String(o.dockerSocketGid),o.domain&&(i[Xs]=o.domain)),Qs(e,i)}function ze(e){let t={};for(let[r,o]of Object.entries(e)){let n=Number(r),i=_n[n];i&&(t[i]=String(o))}return t}function ea(e){let t=Vt.join(e,"infra","docker","docker-compose.yml");if(!V.existsSync(t))return;let r=V.readFileSync(t,"utf-8"),o=[{varName:"API_HOST_PORT",hostPort:8e3,containerPort:80},{varName:"CHROMADB_HOST_PORT",hostPort:8080,containerPort:8e3},{varName:"POSTGRES_HOST_PORT",hostPort:5432,containerPort:5432},{varName:"REDIS_HOST_PORT",hostPort:6379,containerPort:6379},{varName:"MONGO_HOST_PORT",hostPort:27017,containerPort:27017},{varName:"RABBITMQ_HOST_PORT",hostPort:5672,containerPort:5672},{varName:"MONGO_EXPRESS_HOST_PORT",hostPort:8083,containerPort:8081},{varName:"WEB_HOST_PORT",hostPort:3e3,containerPort:3e3}],n=!1;for(let{varName:i,hostPort:s,containerPort:a}of o){let c=`"${s}:${a}"`,l=`"\${${i}:-${s}}:${a}"`;r.includes(c)&&(r=r.replaceAll(c,l),n=!0)}{let i='"15672:15672"';r.includes(i)&&(r=r.replaceAll(i,'"${RABBITMQ_MGMT_PORT:-15672}:15672"'),n=!0)}n&&V.writeFileSync(t,r,"utf-8")}function N(e){let t=Vt.join(e,"infra","docker",".env"),r={};if(!V.existsSync(t))return r;let o=V.readFileSync(t,"utf-8");for(let n of o.split(`
|
|
18
|
+
`)){let i=n.trim();if(i&&!i.startsWith("#")){let[s,...a]=i.split("=");if(s&&Ks[s]){let c=a.join("=").trim().replace(/^["']|["']$/g,""),l=Number(c);!Number.isNaN(l)&&l>0&&l<=65535&&(r[Ks[s]]=l)}}}return r}import{execa as Vp}from"execa";import*as we from"fs";import*as ue from"path";import*as Wt from"node:fs";import*as Er from"node:path";import*as ra from"node:crypto";var ta=["AGENT_SECRET","BOT_SESSION_TOKEN_SECRET","EMAIL_UNSUBSCRIBE_SECRET","SHARE_GRANT_SECRET","GAIA_BOT_API_KEY"],tp=["INSTANCE_SECRET"];function $n(){return ra.randomBytes(32).toString("hex")}function rp(e){return new Set(Object.keys(Ct(e)))}function io(e){let t=rp(e),r={},o=e===null?[...ta,...tp]:ta;for(let n of o)t.has(n)||(r[n]=$n());return r}var oa=["telegram","discord","slack"],na={telegram:["TELEGRAM_BOT_TOKEN"],discord:["DISCORD_BOT_TOKEN","DISCORD_CLIENT_ID"],slack:["SLACK_BOT_TOKEN","SLACK_APP_TOKEN","SLACK_SIGNING_SECRET"]},Nn={telegram:"TELEGRAM_BOT_USERNAME",discord:"DISCORD_CLIENT_ID",slack:"SLACK_WORKSPACE_URL"},op={GAIA_BOT_API_KEY:"GAIA_BOT_API_KEY",GAIA_FRONTEND_URL:"FRONTEND_URL",RABBITMQ_URL:"RABBITMQ_URL"},np="BOT_LOG_HASH_SECRET";function me(e){return`bot-${e}`}function xr(e,t){let r=t.find(i=>i.service===me(e));if(!r)return{health:"failing",detail:"not created"};let o=[r.state,r.health].filter(Boolean).join(", ");return r.state!=="running"||r.health==="unhealthy"?{health:"failing",detail:o}:{health:r.health===void 0||r.health==="healthy"?"healthy":"starting",detail:o}}function ia(e){return`docker-compose.${me(e)}.yml`}function Ln(e){return Er.join(e,"apps","api")}function ip(e){return Er.join(e,"apps","bots")}function Mn(e){let t=Er.join(e,".env");return Wt.existsSync(t)?Ct(Wt.readFileSync(t,"utf-8")):{}}function sa(e,t){let r={...e,...t.set};for(let o of t.unset??[])delete r[o];return r}function so(e,t){let r=Ln(e),o=Mn(r),n=sa(o,t);JSON.stringify(n)!==JSON.stringify(o)&&br(r,n)}function Cr(e,t={}){let r=Er.join(Ln(e),".env");if(!Wt.existsSync(r))throw new Error(`${r} does not exist; run 'gaia up' to configure the install first.`);let o=io(Wt.readFileSync(r,"utf-8"));Object.keys(o).length>0&&so(e,{set:o});let n=Mn(Ln(e)),i={};for(let[c,l]of Object.entries(op)){let d=n[l];if(!d)throw new Error(`${l} is not set in apps/api/.env; run 'gaia up' to configure the install first.`);i[c]=d}let s=ip(e),a=sa(Mn(s),t);a[np]??=$n(),br(s,{...a,...i})}var sp={proxy:"proxy","gaia-web":"web app","gaia-backend":"server",arq_worker:"background jobs",mongo:"MongoDB",postgres:"PostgreSQL",redis:"Redis",rabbitmq:"RabbitMQ",chromadb:"ChromaDB","bot-telegram":"Telegram bot","bot-discord":"Discord bot","bot-slack":"Slack bot"},ap={mongodb:"MongoDB",postgres:"PostgreSQL",redis:"Redis",rabbitmq:"RabbitMQ",chromadb:"ChromaDB"};function Ae(e){return sp[e]??e}function ao(e){return ap[e]??e}import*as aa from"node:os";function Pe(e,t=aa.homedir()){return e===t?"~":e.startsWith(`${t}/`)?`~${e.slice(t.length)}`:e}import{execa as hp}from"execa";import{execa as lp}from"execa";import co from"fs";import up from"simple-git";var cp={KiB:1024,MiB:1048576,GiB:1073741824};function It(e){return e>=1e9?`${(e/1e9).toFixed(1)} GB`:`${Math.round(e/1e6)} MB`}function ca(e){let t=/^([\d.]+)\s*(KiB|MiB|GiB)$/.exec(e.trim());return!t?.[1]||!t[2]?null:Number(t[1])*cp[t[2]]}var Fn=.85,dp=/Receiving objects:\s+(\d+)%[^,\r\n]*(?:,\s*([\d.]+\s*[KMG]iB))?/g,pp=/Resolving deltas:\s+(\d+)%/g,mp=/remote: (?:Enumerating|Counting|Compressing) objects:/;function fp(e){let t=[...e.matchAll(pp)].at(-1);if(t?.[1]){let o=Number(t[1]);return{percent:Math.floor(Fn*100+o*(1-Fn)),label:"Unpacking the files"}}let r=[...e.matchAll(dp)].at(-1);if(r?.[1]){let o=Number(r[1]),n=r[2]?ca(r[2]):null;return{percent:Math.floor(o*Fn),label:n===null?"Downloading":`${It(n)} so far`}}return mp.test(e)?{percent:0,label:"GitHub is preparing the download"}:null}async function lo(e,t,r,o){if(co.existsSync(e)){let n=`${e}/.git`;if(!co.existsSync(n))throw new Error(`Directory ${e} exists but is not a git repository`);await up().cwd(e).pull(),r(100,"Already exists, pulled latest")}else try{let n=["clone","--progress"];o&&n.push("--branch",o),n.push(t,e);let i=lp("git",n);i.stderr?.on("data",s=>{let a=fp(s.toString());a&&r(a.percent,a.label)}),await i,r(100,"Clone complete")}catch(n){throw co.existsSync(e)&&co.rmSync(e,{recursive:!0,force:!0}),n}}var ua="https://github.com/theexperiencecompany/gaia.git",la="https://heygaia.io/install.sh",Sp=/^\d+\.\d+\.\d+-beta\.\d+$/;function Bn(e){return Sp.test(e)?"beta":"latest"}function Ir(e){return e==="beta"?`curl -fsSL ${la} | GAIA_CHANNEL=beta sh`:`curl -fsSL ${la} | sh`}function da(e){let t=Bn(e),r=[`For a newer release, update the CLI first (${Ir(t)}), then rerun 'gaia update'.`];return t==="beta"&&r.push(`This is a beta CLI. To move to the stable channel once a stable release newer than ${e} is out, install it with ${Ir("latest")} and rerun 'gaia update'.`),r}var vp=2,yp=/^v\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/;function Kt(e){if(!yp.test(e))throw new Error(`${e} is not a GAIA release tag (v<major>.<minor>.<patch>, e.g. v0.7.0): only a release has compose files that match its images.`);return`cli-${e}`}async function Gn(e,t,r){let o=Kt(t),n=await hp("git",["ls-remote","--exit-code","--tags",e,`refs/tags/${o}`],{cwd:r,reject:!1});if(n.exitCode!==0)throw n.exitCode===vp?new Error(`GAIA ${t} has no published release: ${e} has no tag ${o}.
|
|
19
|
+
Install a released CLI (${Ir("latest")}) and rerun.`):new Error(`Could not read ${o} from ${e}: ${n.stderr.trim()}`)}function Un(e,t){Zs(e,Dn,t)}async function pa(e,t,r){await Gn(t,Ke),await lo(e,t,r,Kt(Ke)),Un(e,Ke)}var wp=/ghcr\.io\/theexperiencecompany\/(gaia[\w-]*):([\w.-]+)/,bp={gaia:"API","gaia-web":"web app"};function fa(e){let t=wp.exec(e);return t?.[1]&&t[2]?{name:t[1],tag:t[2]}:null}function ma(e){let t=bp[e];return t?`GAIA's ${t} image (${e})`:`the ${e} image`}function Yt(e,t){let[r=e.image,o=""]=e.image.split(":");return e.kind==="wrong-cpu"?{cause:`${ma(r)} at ${o} has no build for this computer's processor (${e.arch}).`,next:`Build it on this machine instead: ${t} (15-30 minutes).`}:{cause:`GAIA ${o} isn't published: ${ma(r)} doesn't exist in the registry.`,next:`Update the CLI (${Ir(Bn($))}) and run it again, or build from source: ${t}.`}}var Ep=(e,t)=>{let r=/no matching manifest for linux\/([\w]+)/.exec(e)?.[1];if(!r)return null;let o=fa(e);return o?Yt({kind:"wrong-cpu",image:`${o.name}:${o.tag}`,arch:r},t.rebuildCommand):{cause:`One of GAIA's images has no build for this computer's processor (${r}).`,next:`Build it on this machine instead: ${t.rebuildCommand} (15-30 minutes).`}},xp=(e,t)=>{if(!/manifest unknown|: not found|failed to resolve reference|No such image/.test(e))return null;let r=fa(e);if(r)return Yt({kind:"not-published",image:`${r.name}:${r.tag}`},t.rebuildCommand);let o=/No such image: ([\w./-]+:[\w.-]+)/.exec(e)?.[1];return{cause:o?`The image ${o} was never built on this machine.`:"An image GAIA needs could not be found.",next:`Build the images here: ${t.rebuildCommand}.`}},Cp=e=>{let t=/Bind for [\d.:[\]]*:(\d+) failed/.exec(e)?.[1]??/listen tcp[46]? [\d.:[\]]*:(\d+): bind: address already in use/.exec(e)?.[1];return!t&&!/port is already allocated|address already in use/.test(e)?null:{cause:`Port ${t??"GAIA needs"} is already used by another program.`,next:"Stop that program, or pick another port: gaia up --web-port <port>."}},Ip=[[/permission denied while trying to connect/i,{cause:"Docker refused your user.",next:"Log out and back in (or run 'newgrp docker'), then try again."}],[/Cannot connect to the Docker daemon|Is the docker daemon running/i,{cause:"Docker stopped running.",next:"Start Docker (sudo systemctl start docker, or open OrbStack / Docker Desktop), then try again."}],[/no space left on device/i,{cause:"The disk is full.",next:"Free some space ('docker system prune' removes unused images), then try again."}],[/toomanyrequests|rate limit/i,{cause:"The image registry is limiting downloads from this network.",next:"Wait a few minutes, then try again."}],[/i\/o timeout|TLS handshake timeout|no such host|network is unreachable|connection reset by peer|dial tcp/i,{cause:"GAIA's images could not be downloaded (network error).",next:"Check this machine's internet connection, then try again."}]],kp=e=>{let t=/container ([\w-]+?)(?:-\d+)? is unhealthy/.exec(e)?.[1];if(!t)return null;let r=t.replace(/^gaia-(selfhost|dev)-/,"");return{cause:`GAIA's ${Ae(r)} didn't start.`,next:"Try: gaia doctor",service:r}};function Rp(e){return([...e].reverse().find(r=>/error|failed|denied/i.test(r))??e.at(-1)??"docker compose failed").trim()}function ga(e,t,r){let o=[...e,...t].join(`
|
|
20
|
+
`);for(let n of[Ep,xp,Cp,kp]){let i=n(o,r);if(i)return i}for(let[n,i]of Ip)if(n.test(o))return i;return{cause:`Docker Compose failed: ${e.at(-1)??Rp(t)}`,next:""}}var Xe=class extends Error{failure;logPath;constructor(t,r){let o=t.logTail?.length?["Its last log lines:",...t.logTail.map(n=>` ${n}`)]:[];super([t.cause,...o,`Full log: ${Pe(r)}`,t.next].filter(Boolean).join(`
|
|
21
|
+
`)),this.name="ComposeError",this.failure=t,this.logPath=r}};import*as Ca from"node:fs";import{execa as Ia}from"execa";import ba from"semver";function Sa(){return{images:new Map,layers:new Map,steps:new Map,containers:new Map,started:new Set,awaitingHealth:new Set,stopping:new Map,finished:[],errors:[],downloadPercent:0}}var uo="Image ",va="Container ",Tp=/^\[[^\]]*\d+\/\d+\]/,Ap=/^gaia-(?:selfhost|dev)-(.+)-\d+$/,Pp=new Set(["Stopping","Removing"]),ha=new Set(["Stopped","Removed"]),_p=2;function Dp(e){return e.slice(e.lastIndexOf("/")+1)}function Op(e){let t=e.slice(va.length);return Ap.exec(t)?.[1]??t}function $p(e,t){let r=(t.id??"").slice(uo.length);if(t.status==="Error"){e.errors.push(`${r}: ${t.details??t.text??"error"}`);return}e.images.get(r)!=="ready"&&(t.text==="Pulled"||t.text==="Built"?(e.finished.push(`${t.text==="Built"?"Built":"Downloaded"} ${Dp(r)}`),e.images.set(r,"ready")):e.images.set(r,t.text==="Building"?"building":"downloading"))}function Lp(e,t){let r=t.id??"",o=e.layers.get(r)??{image:(t.parent_id??"").slice(uo.length),current:0,total:0,done:!1};t.text==="Downloading"&&t.total&&(o.total=t.total,o.current=t.current??o.current),(t.text==="Download complete"||t.text==="Pull complete"||t.text==="Already exists")&&(o.done=!0,o.current=o.total),e.layers.set(r,o)}function Mp(e,t){let r=Op(t.id??""),o=t.text??"";if(Pp.has(o)||ha.has(o)){e.stopping.set(r,e.stopping.get(r)===!0||ha.has(o));return}let n=["Started","Running","Healthy"].includes(t.text??"");t.status==="Error"&&e.errors.push(`${r}: ${t.details??t.text??"error"}`),t.text==="Waiting"&&e.awaitingHealth.add(r),t.text==="Healthy"&&e.awaitingHealth.delete(r),t.text==="Started"&&!e.started.has(r)&&(e.started.add(r),e.finished.push(`Started ${Ae(r)}`)),e.containers.set(r,e.containers.get(r)===!0||n)}function ya(e,t){t.error&&t.message&&e.errors.push(t.message);for(let o of t.vertexes??[]){let n=e.steps.get(o.digest),i=o.name??n?.name;!i||!Tp.test(i)||e.steps.set(o.digest,{name:i,done:n?.done===!0||!!o.completed})}let r=t.id??"";return r.startsWith(uo)?$p(e,t):r.startsWith(va)?Mp(e,t):t.parent_id?.startsWith(uo)&&Lp(e,t),e}var Np=99;function Fp(e){let t=[...e.layers.values()],r=t.filter(c=>c.total>0),o=r.reduce((c,l)=>c+l.current,0);if(r.length===0)return{downloaded:o,percent:0};let n=r.reduce((c,l)=>c+l.total,0)/r.length,i=t.filter(c=>c.total===0),s=r.reduce((c,l)=>c+l.total,0)+i.length*n,a=o+i.filter(c=>c.done).length*n;return{downloaded:o,percent:Math.min(Np,Math.floor(a/s*100))}}function jn(e){let t=e.slice(0,_p).map(Ae),r=e.length-t.length;return r>0?`${t.join(", ")} and ${r} more`:t.join(" and ")}function Bp(e){let t=[...e].filter(([,i])=>!i).map(([i])=>i),r=e.size-t.length,o=`${r} of ${e.size} stopped`,n=Math.floor(r/e.size*100);return t.length===0?{stage:"stopping",label:`Stopping GAIA: ${o}`,percent:n}:{stage:"stopping",label:`Stopping GAIA: waiting on ${jn(t)} (${o})`,percent:n}}function Gp(e){let t=[...e.containers],r=t.filter(([,s])=>s).length,o=`${r} of ${t.length} up`,n=Math.floor(r/t.length*100),i=t.filter(([,s])=>!s).map(([s])=>s);return e.awaitingHealth.size>0?{stage:"starting",label:`Starting GAIA: waiting for ${jn([...e.awaitingHealth])} to be ready (${o})`,percent:n}:i.length>0?{stage:"starting",label:`Starting GAIA: starting ${jn(i)} (${o})`,percent:n}:{stage:"starting",label:`Starting GAIA: ${r} of ${t.length} services up`,percent:n}}function Up(e){let t=[...e.layers.values()];return[...e.images].filter(([,o])=>o==="downloading").map(([o])=>o).every(o=>t.some(n=>n.image===o)&&t.every(n=>n.image!==o||n.done))}function wa(e){if(e.stopping.size>0)return Bp(e.stopping);let t=[...e.steps.values()],r=t.filter(n=>n.done).length;if(t.length>0&&r<t.length)return{stage:"building",label:`Building GAIA from source: step ${r+1} of ${t.length}`,percent:Math.floor(r/t.length*100)};let o=[...e.images.values()];if(o.includes("building")&&!o.includes("downloading"))return{stage:"building",label:"Building GAIA from source: saving the images",percent:99};if(o.includes("downloading")){let n=o.filter(l=>l==="ready").length,{downloaded:i,percent:s}=Fp(e);e.downloadPercent=Math.max(e.downloadPercent,s);let a=`${n} of ${o.length} ready`;return Up(e)?{stage:"unpacking",label:`Unpacking GAIA's images: ${It(i)} downloaded (${a})`,percent:e.downloadPercent}:{stage:"downloading",label:`Downloading GAIA's images: ${i>0?`${It(i)} so far`:"starting"} (${a})`,percent:e.downloadPercent}}return e.containers.size>0?Gp(e):null}var Ea="2.29.1",jp=40,xa;function qp(){return xa??=(async()=>{let{stdout:e}=await Ia("docker",["compose","version","--short"]),t=ba.coerce(e.trim());if(!t||ba.lt(t,Ea))throw new Error(`GAIA needs Docker Compose ${Ea} or newer; this machine has ${e.trim()||"an unknown version"}.
|
|
22
|
+
Update Docker (https://docs.docker.com/engine/install/), then try again.`)})(),xa}function Hp(e){if(!e.startsWith("{"))return null;try{return JSON.parse(e)}catch{return null}}async function po(e,t){await qp();let r=Et(t.logName),o=Ca.createWriteStream(r);t.onLogFile?.(r);let n=Sa(),i=[],s=Jr(l=>{let d=Hp(l);if(!d){i.push(l),i.length>jp&&i.shift();return}ya(n,d);let p=wa(n);p&&t.onProgress?.(p,n.finished)}),a=Ia("docker",["compose","--progress","json",...e],{cwd:t.cwd,env:t.env,all:!0,reject:!1,timeout:t.timeoutMs});a.all?.on("data",l=>{o.write(l),s(l.toString())});let c=await a;if(s(`
|
|
23
|
+
`),await new Promise(l=>o.end(l)),c.timedOut)throw new Xe({cause:`Docker Compose was still running after ${Math.round((t.timeoutMs??0)/6e4)} minutes, so it was stopped.`,next:"Run it again; set GAIA_START_TIMEOUT_MIN to allow longer (0 = no limit)."},r);if(c.failed)throw new Xe(ga(n.errors,i,{rebuildCommand:t.rebuildCommand}),r);return{startedServices:n.started.size}}var Wp=e=>new Promise(t=>setTimeout(t,e)),Ta="dev-start.log",fo=".gaia-dev.pid",Aa="gaia start --build";function go(e){let t=ue.join(e,".env");return we.existsSync(t)?["--env-file",".env"]:[]}var Kp=60;function Yp(){let e=process.env.GAIA_START_TIMEOUT_MIN?.trim(),t=e?Number(e):Number.NaN,r=Number.isFinite(t)&&t>=0?t:Kp;return r===0?void 0:r*60*1e3}function zt(e={}){let t=L(),r=["docker-compose.selfhost.yml"];return e.build&&r.push("docker-compose.build.yml"),t?.codeSandbox===!0&&r.push("docker-compose.sandbox.yml"),r.push(...(t?.bots??[]).map(ia)),r}function Je(e){return e.flatMap(t=>["-f",t])}var Pa="gaia-sandbox-workspace",ka="/legacy-sandbox-workspace";function zp(e,t){return["compose",...Je(e),...t,"run","--rm","--no-deps","-v",`${Pa}:${ka}:ro`,"gaia-backend","python","-m","app.scripts.migrate_legacy_sandbox_workspace","--legacy-root",ka]}function Xp(e,t,r){let o=[...Je(e),...t,"up","-d","--remove-orphans"];return o.push(r?.build?"--build":"--no-build"),r?.pull&&o.push("--pull",r.pull),o}function qn(e){let t=ue.join(e,fo);if(!we.existsSync(t))return null;try{let r=Number.parseInt(we.readFileSync(t,"utf-8").trim(),10);return Number.isNaN(r)||r<=0?null:r}catch{return null}}function mo(e){try{return process.kill(e,0),!0}catch(t){return t.code==="EPERM"}}async function oe(e,t,r,o,n,i){if(t!=="selfhost")throw r?.("Developer mode must run in foreground."),new Error("Developer mode runs in foreground. Use 'gaia dev' or 'gaia dev full' instead of 'gaia start'.");r?.(i?.build?"Building GAIA from source\u2026":"Starting GAIA\u2026");let s=ue.join(e,"infra/docker"),a=o&&Object.keys(o).length>0?ze(o):void 0,c=L();c?.codeSandbox===!0&&await Rs(),c?.bots?.length&&Cr(e);let l=zt({build:i?.build}),d=go(s),p=[...Je(l),...d],m=await po(Xp(l,d,i),{cwd:s,env:a,timeoutMs:Yp(),logName:i?.build?"compose-build":"compose-up",rebuildCommand:i?.rebuildCommand??Aa,onLogFile:i?.onLogFile,onProgress:n}).catch(async g=>{throw await Qp(g,p,s)});return await zr(Pa)&&(r?.("Moving code-sandbox files into per-user workspaces\u2026"),await ne("docker",zp(l,d),s,void 0,void 0,a)),r?.("GAIA's services are running."),m}var Jp=8;async function Qp(e,t,r){if(!(e instanceof Xe)||!e.failure.service)return e;let{stdout:o}=await Vp("docker",["compose",...t,"logs","--no-color","--no-log-prefix","--tail",String(Jp),e.failure.service],{cwd:r}),n=o.split(`
|
|
24
|
+
`).filter(i=>i.trim());return new Xe({...e.failure,logTail:n},e.logPath)}function Hn(e){return["compose",...Je(zt()),...go(e)]}async function _a(e,t,r,o){let n=ue.join(e,"infra/docker");await ne("docker",[...Hn(n),"run","--rm","--no-deps",t,...r],n,void 0,o)}var Zp=["gaia-backend","arq_worker","gaia-web"];async function Da(e,t,r){let o=ue.join(e,"infra/docker");await po([...Je(zt()),...go(o),"pull",...Zp,...(L()?.bots??[]).map(me)],{cwd:o,env:{GAIA_VERSION:t},logName:"compose-pull",rebuildCommand:"gaia up --build",onProgress:r})}async function Oa(e,t,r,o){let n=ue.join(e,"infra/docker"),i=await F(e),s=await J();if(s==="ready"){t?.("Stopping GAIA's containers\u2026");let a=go(n),c=i==="selfhost"?Je(zt()):[];await po([...c,...a,"down"],{cwd:n,logName:"compose-down",rebuildCommand:Aa,onProgress:l=>t?.(l.label)})}else{if(i==="selfhost")throw await xt(s);if(s==="no-permission")throw await xt(s)}i!=="selfhost"&&await em(e,t,r,o),t?.("All services stopped.")}async function em(e,t,r,o){t?.("Stopping GAIA-managed local processes (safe mode)\u2026");let n=qn(e),i=n!==null&&await tm(e,n);try{we.unlinkSync(ue.join(e,fo))}catch{}if(!i){if(o?.forcePorts){t?.("No GAIA PID found. Force-stopping listeners on app ports\u2026"),await rm(e,[r?.[8e3]??8e3,r?.[3e3]??3e3]);return}t?.(n!==null?"Stored GAIA PID is stale. Skipping port cleanup in safe mode. Use `gaia stop --force-ports` for aggressive cleanup.":"No GAIA-managed PID found. Skipping port cleanup in safe mode. Use `gaia stop --force-ports` for aggressive cleanup.")}}async function tm(e,t){if(!mo(t))return!1;try{return process.platform==="win32"?(await ne("taskkill",["/PID",String(t),"/T","/F"],e),!0):(Ra(t,"SIGTERM"),await Wp(800),mo(t)&&Ra(t,"SIGKILL"),!0)}catch{return!1}}function Ra(e,t){try{process.kill(-e,t)}catch{process.kill(e,t)}}async function rm(e,t){for(let r of t){let[o,n]=process.platform==="win32"?["powershell",["-Command",`Get-NetTCPConnection -LocalPort ${r} -ErrorAction SilentlyContinue | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force -ErrorAction SilentlyContinue }`]]:["sh",["-c",`lsof -ti :${r} -sTCP:LISTEN | xargs kill 2>/dev/null || true`]];await ne(o,n,e)}}async function F(e){let t=je(e);if(!we.existsSync(t))return null;let r=we.readFileSync(t,"utf-8"),o=r.match(/^SETUP_MODE=(.+)$/m);if(o?.[1]){let n=o[1].trim().replace(/^["']|["']$/g,"");if(n==="selfhost"||n==="developer")return n}return r.includes("mongodb://mongo:")?"selfhost":(r.includes("mongodb://localhost:"),"developer")}var om=8;function nm(e,t){return e.trimEnd().split(`
|
|
22
25
|
`).slice(-t).join(`
|
|
23
|
-
`)}async function
|
|
24
|
-
${
|
|
25
|
-
`))}await Y.promises.mkdir(n,{recursive:!0,mode:448});try{Y.chmodSync(n,448)}catch{}let l=[s.mongoFile,s.postgresFile,s.apiEnvFile,...s.volumeFiles.map(p=>p.file)],d;try{d=await
|
|
26
|
-
Manual command: ${n[1]}`)}try{await
|
|
27
|
-
Manual command: ${n[2]}`)}let s=[],a=[];for(let c of
|
|
28
|
-
`)}function
|
|
29
|
-
`)
|
|
30
|
-
`)}
|
|
26
|
+
`)}async function ne(e,t,r,o,n,i,s){let{spawn:a}=await import("child_process");return new Promise((c,l)=>{let d=a(e,t,{cwd:r,stdio:["ignore","pipe","pipe"],env:i?{...process.env,...i}:void 0}),p="",m=0,g=!1,v;s&&(v=setTimeout(()=>{g=!0,d.kill("SIGTERM"),l(new Error(`Command timed out after ${Math.round(s/6e4)}m. Check \`docker compose logs\` to debug.`))},s)),d.stdout?.on("data",E=>{let b=E.toString();p+=b,n?.(b),m=Math.min(m+5,95),o?.(m)}),d.stderr?.on("data",E=>{let b=E.toString();p+=b,n?.(b),m=Math.min(m+5,95),o?.(m)}),d.on("close",E=>{v&&clearTimeout(v),!g&&(E===0?(o?.(100),c()):l(new Error(`Command failed with code ${E}:
|
|
27
|
+
${nm(p,om)}`)))}),d.on("error",E=>{v&&clearTimeout(v),!g&&l(E)})})}var im="apps/api/app/config/settings_validator.py";function je(e){return ue.join(e,"apps","api",".env")}function Qe(e){return we.existsSync(ue.join(e,im))}function $a(e){let t=e;for(;t!==ue.dirname(t);){if(Qe(t))return t;t=ue.dirname(t)}return null}function La(){let e=L();return e?.repoPath?Qe(e.repoPath)?e.repoPath:(console.warn(`Warning: Saved repo path "${e.repoPath}" is no longer a valid GAIA installation. Resetting config.`),ye({repoPath:"",setupComplete:!1}),null):null}function Xt(e){return $a(e??process.cwd())??La()}function _(e){let t=$a(e??process.cwd());return t&&we.existsSync(je(t))?t:La()??t}function kr(e,t){if(!e)return"GAIA isn't installed yet";let r=Pe(e);return t?`${r} (${t==="selfhost"?"self-host":"developer"})`:`${r} (not set up yet: no apps/api/.env)`}function sm(e,t=hn()){let r=jt(e,t);return[`mkdir -p ${e}`,`docker compose -f docker-compose.selfhost.yml exec -T mongo mongodump --archive --gzip > ${r.mongoFile}`,`docker compose -f docker-compose.selfhost.yml exec -T postgres pg_dump -U postgres -d langgraph > ${r.postgresFile}`,`install -m 600 ../../apps/api/.env ${r.apiEnvFile}`,...r.volumeFiles.map(({volume:o,file:n})=>`docker run --rm -v ${o}:/data -v ${e}:/backups alpine tar czf /backups/${be.basename(n)} -C /data .`)]}function am(e){return be.join(e,"infra","docker")}function cm(e,t){return t?be.resolve(t):be.join(e,"backups")}async function Vn(e={}){let t=_();if(!t)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo or set the recorded install path.");let r=am(t),o=be.join(r,"docker-compose.selfhost.yml");if(!Y.existsSync(o))throw new Error(`Compose file not found: ${o}`);let n=cm(t,e.outputDir),i=hn(),s=jt(n,i),a=sm(n,i);if(e.dryRun)return{...s,commands:a,warnings:[]};let c=await J();if(c!=="ready"){let p=await Ue(c);throw new Error([`${p.summary}, so the databases cannot be backed up.`,p.fix,"Or run the backup commands yourself:",...a.map(m=>` ${m}`)].join(`
|
|
28
|
+
`))}await Y.promises.mkdir(n,{recursive:!0,mode:448});try{Y.chmodSync(n,448)}catch{}let l=[s.mongoFile,s.postgresFile,s.apiEnvFile,...s.volumeFiles.map(p=>p.file)],d;try{d=await lm(t,r,n,i,a)}catch(p){for(let m of l)Y.rmSync(wt(m),{force:!0});throw p}for(let p of[s.mongoFile,s.postgresFile,s.apiEnvFile,...d.volumeFiles.map(m=>m.file)])Y.renameSync(wt(p),p);return{...s,...d,commands:a}}async function lm(e,t,r,o,n){let i=jt(r,o);um(e,wt(i.apiEnvFile));try{await Na("docker",Ma("mongo",["mongodump","--archive","--gzip"]),t,wt(i.mongoFile))}catch(c){throw new Error(`MongoDB backup failed: ${c.message}
|
|
29
|
+
Manual command: ${n[1]}`)}try{await Na("docker",Ma("postgres",["pg_dump","-U","postgres","-d","langgraph"]),t,wt(i.postgresFile))}catch(c){throw new Error(`PostgreSQL backup failed: ${c.message}
|
|
30
|
+
Manual command: ${n[2]}`)}let s=[],a=[];for(let c of yt){let l=Sn(r,o,c),d=wt(l.file);if(!await zr(c.volume)){a.push(`${c.label} volume ${c.volume} not found \u2014 nothing to back up`);continue}try{await Fa("docker",["run","--rm","-v",`${c.volume}:/data`,"-v",`${be.dirname(d)}:/backups`,"alpine","tar","czf",`/backups/${be.basename(d)}`,"-C","/data","."],{cwd:t});try{Y.chmodSync(d,384)}catch{}s.push(l)}catch(p){Y.rmSync(d,{force:!0});let m=`${c.label} backup failed: ${p.message}`;if(c.userData)throw new Error(m);a.push(m)}}return{volumeFiles:s,warnings:a}}function um(e,t){let r=je(e);if(!Y.existsSync(r))throw new Error(`${r} not found \u2014 it holds INSTANCE_SECRET, without which the backup's stored credentials cannot be decrypted. Run gaia up to configure this install.`);oo(r,t)}function Ma(e,t){return["compose","-f","docker-compose.selfhost.yml","exec","-T",e,...t]}async function Na(e,t,r,o){Y.writeFileSync(o,"",{mode:384,flag:"wx"});try{await Fa(e,t,{cwd:r,stdout:{file:o},buffer:{stdout:!1}})}catch(n){throw Y.rmSync(o,{force:!0}),n}}function T(e=""){process.stdout.write(`${e}
|
|
31
|
+
`)}async function Ga(e={}){if(e.dryRun){let t=await Vn({outputDir:e.output,dryRun:!0});T("Backup commands (dry run \u2014 not executed):");for(let r of t.commands)T(` ${r}`);T(""),T(`Volumes (${yt.map(r=>r.volume).join(", ")}) are backed up via`),T(" docker run --rm -v <volume>:/data -v <output>:/backups alpine tar ..."),T(" and are skipped if the volume does not exist yet."),T(""),T("Run without --dry-run to execute inside the running containers,"),T("or copy-paste the commands from the directory containing infra/docker/");return}try{T("Starting GAIA backup\u2026");let t=await Vn({outputDir:e.output});T(`MongoDB dump: ${t.mongoFile}`),T(`PostgreSQL dump: ${t.postgresFile}`),T(`API settings (apps/api/.env): ${t.apiEnvFile}`);for(let{label:r,file:o}of t.volumeFiles)T(`${r} archive: ${o}`);if(t.warnings.length)for(let r of t.warnings)T(`Note: ${r}`);T(""),T("Backups complete. Store them off-host and access-controlled \u2014"),T(`${t.apiEnvFile} holds INSTANCE_SECRET, which decrypts the stored provider credentials.`),T(""),T("Restore with gaia restore --from <dir>, or manually from the repo root:"),T(` install -m 600 ${t.apiEnvFile} apps/api/.env`),T(` cat ${t.postgresFile} | docker compose -f infra/docker/docker-compose.selfhost.yml exec -T postgres psql -U postgres -d langgraph`),T(` docker compose -f infra/docker/docker-compose.selfhost.yml exec -T mongo mongorestore --archive --gzip --drop < ${t.mongoFile}`);for(let{volume:r,file:o}of t.volumeFiles)T(` docker run --rm -v ${r}:/data -v $(dirname ${o}):/backups alpine sh -c "${hr(Ba.basename(o))}"`)}catch(t){le(t.message),process.exitCode=1}}import{Argument as Df,Command as Of}from"commander";async function ie(e){try{await e()}catch(t){le(t instanceof Error?t.message:String(t)),process.exit(1)}}import{supportsColor as pc}from"chalk";import{supportsHyperlink as Hm}from"supports-hyperlinks";import dm from"wrap-ansi";var pm=40,mm=80,fm=24;function Rr(e){return{columns:e.columns||mm,rows:e.rows||fm}}function Jt(e,t){return dm(e,t,{hard:!0})}function Ze(e,t=0){let r=process.stdout.isTTY?process.stdout.columns:void 0;return!r||r-t<pm?e:Jt(e,r-t).split(`
|
|
32
|
+
`).join(`
|
|
33
|
+
${" ".repeat(t)}`)}import{networkInterfaces as Ua}from"node:os";var A=3e3,ho=8e3,Tr=3443;function kt(e,t){return`http://localhost:${e==="selfhost"?t[A]??A:t[ho]??ho}`}function se(e,t){return`${kt(e,t)}/api/v1`}var gm=/^(docker\d+|br-[0-9a-f]+)$/;function ja(e,t){return Object.entries(t).filter(([r])=>!gm.test(r)).flatMap(([,r])=>r??[]).filter(r=>r.family==="IPv4"&&!r.internal).map(r=>`http://${r.address}:${e}`)}function qa(e,t,r=Ua()){return[...t?[`https://${t}`]:[],`http://localhost:${e}`,...ja(e,r)]}function hm(e=process.env,t=process.platform){return e.SSH_CONNECTION||e.SSH_TTY?!0:t==="linux"&&!e.DISPLAY&&!e.WAYLAND_DISPLAY}function Wn(e,t,r=Ua(),o=hm()){if(t)return`https://${t}`;let n=`http://localhost:${e}`;return o?ja(e,r)[0]??n:n}function et(e,t){return Wn(t,Js(e))}async function So(e,t,r=5e3){return fetch(e,{...t,signal:AbortSignal.timeout(r)})}async function _e(e,t,r=5e3){try{let o=await So(`${e}/setup/${t}`,void 0,r);return o.ok?{data:await o.json()}:{detail:`HTTP ${o.status} from /api/v1/setup/${t}`}}catch{return{detail:`Could not read setup ${t}`}}}import*as Ee from"node:fs";import*as Yn from"node:path";import za from"semver";import*as Va from"node:os";var Wa="https://ghcr.io",Ka="theexperiencecompany",Ya=8e3,Sm=["gaia","gaia-web"],vm=["application/vnd.oci.image.index.v1+json","application/vnd.docker.distribution.manifest.list.v2+json","application/vnd.oci.image.manifest.v1+json","application/vnd.docker.distribution.manifest.v2+json"].join(",");function vo(e=Va.arch()){return e==="x64"?"amd64":e}async function ym(e){let t=await fetch(`${Wa}/token?scope=repository:${Ka}/${e}:pull`,{signal:AbortSignal.timeout(Ya)});if(!t.ok)throw new Error(`GHCR token request answered HTTP ${t.status}`);return(await t.json()).token}async function Ha(e,t,r){return fetch(`${Wa}/v2/${Ka}/${e}/${t}`,{headers:{Authorization:`Bearer ${r}`,Accept:vm},signal:AbortSignal.timeout(Ya)})}async function wm(e,t){let r=await ym(e),o=await Ha(e,`manifests/${t}`,r);if(o.status===404)return[];if(!o.ok)throw new Error(`GHCR answered HTTP ${o.status} for ${e}:${t}`);let n=await o.json();if(n.manifests)return n.manifests.map(a=>a.platform?.architecture).filter(a=>!!a&&a!=="unknown");if(!n.config)return[];let i=await Ha(e,`blobs/${n.config.digest}`,r);if(!i.ok)throw new Error(`GHCR answered HTTP ${i.status} for ${e}:${t}'s config`);let{architecture:s}=await i.json();return s?[s]:[]}async function Qt(e,t=[],r=vo()){let o=[...Sm,...t.map(n=>`gaia-bot-${n}`)];for(let n of o){let i=await wm(n,e);if(i.length===0)return{kind:"not-published",image:`${n}:${e}`};if(!i.includes(r))return{kind:"wrong-cpu",image:`${n}:${e}`,arch:r}}return null}var bm="https://registry.npmjs.org/@heygaia/cli/latest",Kn=Yn.join(Ye,"update-check.json"),Em=Yn.join(Sr,"update-check.log"),xm=1440*60*1e3,Cm=5e3;function tt(e){return/^v\d/.test(e)?za.parse(e.slice(1)):null}var Im=/^[0-9a-f]{40}$/,km=12;function yo(e){return Im.test(e)?e.slice(0,km):e}function qe(e,t){let r=tt(e),o=tt(t);return r!==null&&o!==null&&za.gt(r,o)}function Xa(){if(!Ee.existsSync(Kn))return null;let e=JSON.parse(Ee.readFileSync(Kn,"utf-8"));return e.arch===vo()?e:null}function Ja(){return Xa()?.latest??null}async function Rm(){let e=await fetch(bm,{signal:AbortSignal.timeout(Cm)});if(!e.ok)throw new Error(`npm answered HTTP ${e.status}`);let{version:t}=await e.json(),r=`v${t}`;return await Qt(r)===null?r:null}function Tm(e){Ee.mkdirSync(Sr,{recursive:!0}),Ee.appendFileSync(Em,`${new Date().toISOString()} update check failed: ${e.message}
|
|
34
|
+
`)}async function wo(){let e=Xa();if(e&&Date.now()-Date.parse(e.checkedAt)<xm)return e.latest;try{let t=await Rm();Ee.mkdirSync(Ye,{recursive:!0});let r={checkedAt:new Date().toISOString(),arch:vo(),latest:t};return Ee.writeFileSync(Kn,JSON.stringify(r)),t}catch(t){return Tm(t),e?.latest??null}}var Qa=300,Am="ai_models";function Pm(e,t){let r=e.features[Am]?.in_use[0];return r?t?.providers[r]?.label??r:null}async function bo(){let e=_(),t=e?await F(e):null;if(!e||!t)return{running:!1,installed:!1};let r=N(e),o=se(t,r),[n,i]=await Promise.all([_e(o,"status",Qa),_e(o,"catalog",Qa)]);if("detail"in n)return{running:!1,installed:!0};let s=r[A]??A;return{running:!0,webUrl:et(e,s),provider:Pm(n.data,"data"in i?i.data:null)}}function Eo(){wo();let e=_(),t=Ja();return!e||!t?null:qe(t,Te(e))?t:null}import{Chalk as Fm}from"chalk";import{Chalk as _m}from"chalk";var zn={large:[".........mmmmm.........","......mmmmmmmmmmm......",".....mmmmmmmmmmmmm.....","....ddddddmmmllllll....","...ddddddddmllllllll...","...ddddddd...lllllll...","....ddd.........lll....",".lll................dd.",".lll...............ddd.",".llll.............ddddm","mllll.............ddddm","mmlll.............ddddm","mmllll............dddmm",".mmlll...........dddmmm",".mmmml...........dmmmm.",".mmmmmd.........llmmmm.","..mmmmdd.......lllmmmm.","..mmmmddd.....llllmmm..","...mmmdddd...llllmmm...","....mmddddd.lllllmm....",".....mmdddd.llllmm.....","......mmddd.lllmm......"],small:["......mmmmmm......","....mmmmmmmmmm....","...ddddmmmmllll...","..dddddddlllllll..","..ddddd....lllll..","..................","lll............ddd","lll............ddd","llll..........dddd","mlll..........dddm","mlll..........dddm","mmml..........dmmm","mmmm..........mmmm",".mmmdd......llmmm.",".mmmddd....lllmmm.","..mmdddd..llllmm..","...mmddd..lllmm...","....mmdd..llmm...."]},Xn={d:"#0f537c",m:"#059cda",l:"#02bdff"},Jn={d:24,m:38,l:39};var Dm={d:"blue",m:"cyan",l:"cyanBright"},Om={d:"bgBlue",m:"bgCyan",l:"bgCyanBright"},tc="\u2580",rc="\u2584",$m="\u2588";function Za(e){return e==="d"||e==="m"||e==="l"?e:null}function Lm(e,t){return e===null&&t===null?{ch:" ",fg:null,bg:null}:e===t?{ch:" ",fg:null,bg:e}:e===null?{ch:rc,fg:t,bg:null}:{ch:tc,fg:e,bg:t}}function Mm(e,t){return{ch:e!==null&&t!==null?$m:e!==null?tc:t!==null?rc:" ",fg:null,bg:null}}function ec(e,{fg:t,bg:r}){let o=e;return t!==null&&(o=e.level===3?o.hex(Xn[t]):e.level===2?o.ansi256(Jn[t]):o[Dm[t]]),r!==null&&(o=e.level===3?o.bgHex(Xn[r]):e.level===2?o.bgAnsi256(Jn[r]):o[Om[r]]),o}function Nm(e,t){let r="",o="",n=null;for(let i of t)n&&(i.fg!==n.fg||i.bg!==n.bg)&&(r+=ec(e,n)(o),o=""),n=i,o+=i.ch;return n?r+ec(e,n)(o):r}function oc(e){return zn[e][0].length}function nc(e,t){let r=zn[e],o=new _m({level:t}),n=[];for(let i=0;i<r.length;i+=2){let s=r[i]??"",a=r[i+1]??"",c=[...s].map((l,d)=>{let p=Za(l),m=Za(a[d]);return t===0?Mm(p,m):Lm(p,m)});n.push(Nm(o,c))}return n}var ic=3,Bm=40,sc=" \xB7 ",ac="Your proactive personal assistant",cc={truecolor:"#af8700",ansi256:136};function Gm(e,t){return t?`\x1B]8;;${e}\x1B\\${e}\x1B]8;;\x1B\\`:e}function Um(e){return e.level===3?e.hex(cc.truecolor):e.level===2?e.ansi256(cc.ansi256):e.yellow}function lc(e,t){return{plain:`GAIA v${t}`,styled:`${e.bold("GAIA")} ${e.dim(`v${t}`)}`}}function jm(e,t,r){if(!t.running){let n=t.installed?`${y.pending} Not running \xB7 start it with gaia start`:`${y.pending} Not installed \xB7 set it up with gaia up`;return{plain:n,styled:e.dim(n)}}let o=t.provider?` \xB7 ${t.provider}`:"";return{plain:`\u25CF Running at ${t.webUrl}${o}`,styled:`${e.green("\u25CF")} Running at ${Gm(t.webUrl,r)}${e.dim(o)}`}}function uc(e,t){let r=[];if(e.status&&r.push(jm(t,e.status,e.hyperlinks)),e.update){let o=`Update available: ${e.update} \xB7 run gaia update`;r.push({plain:o,styled:Um(t)(o)})}return r}function dc(e){return[...e.plain].length}function qm(e,t){let r=lc(t,e.version);for(let o of uc(e,t)){let n={plain:`${r.plain}${sc}${o.plain}`,styled:`${r.styled}${t.dim(sc)}${o.styled}`};if(dc(n)>e.columns)break;r=n}return r.styled}function xo(e){let t=new Fm({level:e.level}),r=[lc(t,e.version),{plain:ac,styled:t.dim(ac)},...uc(e,t)],o=oc(e.size)+ic+Math.max(...r.map(dc));if(!e.isTTY||e.rows<Bm||o>e.columns)return[qm(e,t)];let n=nc(e.size,e.level),i=Math.floor((n.length-r.length)/2);return n.map((s,a)=>{let c=r[a-i];return c?`${s}${" ".repeat(ic)}${c.styled}`:s})}function Qn(){return process.env.NO_COLOR?0:pc?pc.level:0}function Zn(e){return{isTTY:e.isTTY===!0,hyperlinks:Hm(e)}}async function Vm({size:e="small",showStatus:t=!0,showUpdate:r=!0}={}){let o={...Rr(process.stdout),...Zn(process.stdout)},n=t&&o.isTTY?await bo():null;return["",...xo({size:e,level:Qn(),...o,version:$,status:n,update:r?Eo():null}),""]}async function Rt(e){process.stdout.write(`${(await Vm(e)).join(`
|
|
31
35
|
`)}
|
|
32
|
-
`)}async function
|
|
33
|
-
`);return}await
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
`)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
`)}async function mc(){if(!process.stdout.isTTY){process.stdout.write(`${$}
|
|
37
|
+
`);return}await Rt({size:"large"})}var Wm="2048";function fc(e){let t=new URL("https://discord.com/oauth2/authorize");return t.searchParams.set("client_id",e),t.searchParams.set("scope","bot applications.commands"),t.searchParams.set("permissions",Wm),t.toString()}function gc(e){return`https://t.me/${e}`}async function ei(e,t){let r=await fetch(e,{...t,signal:AbortSignal.timeout(1e4)}),o=r.headers.get("content-type")?.includes("application/json");if(r.ok||o)return await r.json();throw new Error(`${new URL(e).hostname} answered HTTP ${r.status}. Try again in a minute.`)}async function Sc(e){let t=await ei(`https://api.telegram.org/bot${e}/getMe`,{method:"GET"});if(!t.ok||!t.result)throw new Error(`Telegram rejected the bot token: ${t.description??"unknown error"}. Copy it again from @BotFather.`);return t.result.username}async function vc(e){let t=await ei("https://discord.com/api/v10/applications/@me",{method:"GET",headers:{Authorization:`Bot ${e}`}});if(!t.id)throw new Error(`Discord rejected the bot token: ${t.message??"unknown error"}. Reset and copy it from the Developer Portal's Bot page.`);if(((t.flags??0)&786432)===0)throw new Error("Turn on Message Content Intent in the Discord Developer Portal (Bot page, Privileged Gateway Intents), then rerun this command.");return t.id}async function hc(e,t){return await ei(`https://slack.com/api/${e}`,{method:"POST",headers:{Authorization:`Bearer ${t}`}})}async function yc(e,t){let r=await hc("auth.test",e);if(!r.ok||!r.team||!r.url)throw new Error(`Slack rejected the bot token (xoxb-): ${r.error??"unknown error"}.`);let o=await hc("apps.connections.open",t);if(!o.ok)throw new Error(`Slack rejected the app token (xapp-): ${o.error??"unknown error"}. Enable Socket Mode and create an app-level token with connections:write.`);return{name:r.team,url:r.url}}import*as ii from"node:fs";import*as _r from"node:os";import*as Pc from"node:path";import{execa as af}from"execa";import*as ae from"node:fs";import*as wc from"node:path";var ri="/var/log/dpkg.log",ti="/var/cache/apt/archives",Km=1e3,Ym=1e6,zm=/^\S+ \S+ (unpack|configure) ([^:\s]+)/,Xm={unpack:"unpacking",configure:"setting up"};function Jm(e){let t=zm.exec(e);return!t?.[1]||!t[2]?null:`${Xm[t[1]]} ${t[2]}`}function bc(e){return ae.existsSync(e)?ae.statSync(e).size:0}function Qm(e){return ae.existsSync(ti)?ae.readdirSync(ti).filter(t=>t.endsWith(".deb")).map(t=>ae.statSync(wc.join(ti,t))).filter(t=>t.ctimeMs>=e).reduce((t,r)=>t+r.size,0):0}function Zm(e){let t=bc(ri),r=t<e?0:e;if(t===r)return{activity:null,offset:r};let o=Buffer.alloc(t-r),n=ae.openSync(ri,"r");try{ae.readSync(n,o,0,o.length,r)}finally{ae.closeSync(n)}return{activity:o.toString().split(`
|
|
38
|
+
`).map(Jm).findLast(a=>a!==null)??null,offset:t}}function Ec(e){let t=Date.now(),r=bc(ri),o=0,n=setInterval(()=>{let i=Zm(r);if(r=i.offset,i.activity){e(i.activity);return}let s=Qm(t);s>=Ym&&s>o&&(o=s,e(`downloading packages: ${It(s)}`))},Km);return()=>clearInterval(n)}var Ar="steps";function Pr(e){return e.currentState.data[Ar]??[]}function xc(e,t){let r=Zr();e.updateData(Ar,t.map(o=>({...o,state:"pending",startedAt:r[o.id]})))}function oi(e){return Object.fromEntries(Pr(e).flatMap(t=>t.startedAt===void 0?[]:[[t.id,t.startedAt]]))}function He(e,t,r){e.updateData(Ar,Pr(e).map(o=>o.id===t?{...o,...r}:o))}function rt(e,t,r={}){let o=Date.now(),n=Pr(e).find(i=>i.id===t);He(e,t,{state:"active",startedAt:n?.startedAt??o,...r})}function Tt(e,t,r){let o=Pr(e).find(n=>n.id===t);He(e,t,{state:"done",endedAt:Date.now(),startedAt:o?.startedAt??Date.now(),detail:void 0,percent:void 0,hint:void 0,...r?{doneLabel:r}:{}})}function ot(e,t){let r=Pr(e).find(o=>o.state==="active"||o.state==="waiting");r&&He(e,r.id,{state:t,endedAt:Date.now()})}function nt(e){let t=Math.max(0,Math.floor(e/1e3));if(t<60)return`${t}s`;let r=Math.floor(t/60);return r<60?`${r}m ${String(t%60).padStart(2,"0")}s`:`${Math.floor(r/60)}h ${String(r%60).padStart(2,"0")}m`}function ef(e){let t=e.startedAt!==void 0&&e.endedAt!==void 0?` (${nt(e.endedAt-e.startedAt)})`:"";return e.state==="active"?` ${e.label}\u2026`:e.state==="done"?`${y.ok} ${e.doneLabel}${t}`:e.state==="failed"?`${y.fail} ${e.label}${t}`:e.state==="cancelled"?`${y.cancelled} ${e.label}${t}`:null}function fe(){return process.stdin.isTTY===!0&&process.stdout.isTTY===!0}function Cc(e){if(fe())return;let t=e?`'gaia ${e}'`:"this command";le(`${t} needs an interactive terminal to ask its questions.
|
|
39
|
+
Run it from a regular terminal, not a pipe or a script.`),process.exit(1)}function Ic(e,t=""){let r=t,o="",n="",i=new Map;e.on("change",s=>{let a=s.data[Ar]??[];for(let c of a){if(i.get(c.id)===c.state)continue;i.set(c.id,c.state);let l=ef(c);l&&console.info(l)}a.length===0&&s.step&&s.step!==r&&(r=s.step,console.info(`
|
|
40
|
+
[${s.step}]`)),s.status&&s.status!==o&&(o=s.status,console.info(` ${s.status}`)),s.error&&s.error.message!==n&&(n=s.error.message,le(s.error.message))})}import{execa as At}from"execa";var De={git:"https://git-scm.com/downloads",docker:"https://docs.docker.com/get-docker/",mise:"https://mise.jdx.dev/getting-started.html"},kc={8e3:"API Server",5432:"PostgreSQL",6379:"Redis",27017:"MongoDB",5672:"RabbitMQ",15672:"RabbitMQ Management",[A]:"Web Frontend",[Tr]:"Web Frontend (HTTPS)",8080:"ChromaDB",8083:"Mongo Express"},tf={selfhost:[A,Tr],developer:[ho,5432,6379,27017,5672,15672,A,8080,8083]};async function Co(e,t={}){let r=await xs(pe[e]),o=tf[e].map(a=>t[a]??a),n=o.filter(a=>!r.has(a)),i=await rf(n),s=new Map(i.map(a=>[a.port,a]));return o.map(a=>s.get(a)??{port:a,service:kc[a]||`Port ${a}`,available:!0})}async function ni(){try{return await At("git",["--version"]),"success"}catch{return"error"}}async function Rc(){try{return await At("mise",["--version"]),"success"}catch{return"missing"}}async function Tc(){if((await import("node:os")).platform()==="win32")try{return await At("powershell",["-Command","irm https://mise.jdx.dev/install.ps1 | iex"]),!0}catch{return!1}try{return await At("sh",["-c","curl https://mise.jdx.dev/install.sh | sh"]),!0}catch{return!1}}async function rf(e){let t=await import("node:net"),r=[],o=n=>new Promise(i=>{let s=t.createServer();s.once("error",()=>i(!1)),s.once("listening",()=>{s.close(()=>i(!0))}),s.listen(n)});for(let n of e){let i=kc[n]||`Port ${n}`;if(await o(n))r.push({port:n,service:i,available:!0});else{let a=await of(n),c=await nf(n+1,n+100,o);r.push({port:n,service:i,available:!1,usedBy:a,alternative:c||void 0})}}return r}async function of(e){if((await import("node:os")).platform()==="win32"){try{let{stdout:o}=await At("netstat",["-ano","-p","TCP"]),n=o.trim().split(`
|
|
41
|
+
`);for(let i of n)if(i.includes(`:${e}`)&&i.includes("LISTENING")){let s=i.trim().split(/\s+/),a=s[s.length-1];if(a)try{let{stdout:c}=await At("tasklist",["/FI",`PID eq ${a}`,"/FO","CSV","/NH"]);return c.trim().split(",")[0]?.replace(/"/g,"")||`PID ${a}`}catch{return`PID ${a}`}}}catch{}return}try{let{stdout:o}=await At("lsof",["-i",`:${e}`,"-sTCP:LISTEN","-P","-n"]),n=o.trim().split(`
|
|
42
|
+
`);if(n.length>1)return n[1]?.split(/\s+/)?.[0]||void 0}catch{}}async function nf(e,t,r){for(let o=e;o<=t;o++)if(await r(o))return o;return null}var cf="https://get.docker.com",lf="https://orbstack.dev",uf="https://docs.docker.com/desktop/install/mac-install/",df={git:"Git",docker:"Docker"},si="prerequisite_install_confirm",_t="missingPrerequisites";function pf(){return ii.existsSync("/usr/bin/apt-get")||ii.existsSync("/etc/debian_version")}function Pt(e,t,r){e.updateData("checks",{...e.currentState.data.checks,[t]:r})}function Zt(e){return e.map(t=>df[t]).join(" and ")}function mf(){throw _r.platform()==="darwin"?new Error(`GAIA runs in Docker, which isn't installed yet.
|
|
43
|
+
\u2022 OrbStack (lightweight): ${lf}
|
|
44
|
+
\u2022 Docker Desktop: ${uf}
|
|
45
|
+
Install either, open it, then run this command again.`):new Error(`GAIA runs in Docker, which isn't installed yet. Install it from ${De.docker}, then run this command again.`)}async function ff(e,t,r){if(r.assumeYes)return;let o=Zt(t);if(!fe())throw new Error(`GAIA needs ${o}, and there is no terminal to ask before installing.
|
|
40
46
|
Rerun with --yes to install them, or install them first:
|
|
41
|
-
`+t.map(i=>` ${
|
|
42
|
-
`));for(let i of t)
|
|
43
|
-
`+t.map(i=>` ${
|
|
44
|
-
`))}async function
|
|
45
|
-
Install it by hand following ${
|
|
46
|
-
Install it by hand following ${
|
|
47
|
-
`).filter(i=>i.trim()!=="");e.updateData(t,[...o,...n].slice(-
|
|
48
|
-
\u2022 Mise: ${
|
|
49
|
-
\u203A `),!process.stdin.isTTY){let t=
|
|
50
|
-
`),t(i)},n=i=>{let s=i.toString("utf-8").replace(
|
|
51
|
-
`),process.exit(130))
|
|
52
|
-
`){o(r.trim(),
|
|
47
|
+
`+t.map(i=>` ${De[i]}`).join(`
|
|
48
|
+
`));for(let i of t)Pt(e,i,"missing");if(e.updateData(_t,t),await e.waitForInput(si)!=="install")throw new Error(`GAIA needs ${o}. Install ${t.length>1?"them":"it"}, then run this command again:
|
|
49
|
+
`+t.map(i=>` ${De[i]}`).join(`
|
|
50
|
+
`))}async function _c(e,t,r){let o=Ec(n=>e.setStatus(`${t()} \xB7 ${n}`));try{await r()}finally{o()}}async function gf(e){let t="Installing Git: updating the package list";e.setStatus(`${t}\u2026`);let r=Et("git-install");try{await _c(e,()=>t,async()=>{await Ht("apt-get",["update"],r),t="Installing Git",e.setStatus(`${t}\u2026`),await Ht("apt-get",["install","-y","git"],r)})}catch(o){throw new Error(`Git installation failed: ${o.message}
|
|
51
|
+
Install it by hand following ${De.git}, then run this command again.`)}if(await ni()!=="success")throw new Error(`Git was installed but 'git --version' still fails. Install it by hand following ${De.git}, then run this command again.`)}function hf(e){return e.includes("Executing docker install script")?"Starting Docker's installer":e.startsWith("+ ")?e.includes("docker-ce")?"Installing Docker":e.includes("apt-get")&&e.includes("update")?"Updating the package list":e.includes("gpg")||e.includes("docker.asc")?"Adding Docker's package source":e.includes("apt-get")&&e.includes("install")?"Installing what Docker needs":e.includes("systemctl")?"Starting Docker":null:null}async function Sf(e){let t=Pc.join(_r.tmpdir(),"gaia-docker-install.sh"),r=Et("docker-install"),o="Downloading Docker's installer",n=i=>{o=i,e.setStatus(`${i}\u2026`)};n(o),await af("curl",["-fsSL",cf,"-o",t]);try{await _c(e,()=>o,()=>Ht("sh",[t],r,i=>{let s=hf(i);s&&n(s)}))}catch(i){throw new Error(`Docker installation failed: ${i.message}
|
|
52
|
+
Install it by hand following ${De.docker}, then run this command again.`)}}async function Ac(e,t,r){Pt(e,t,"pending");try{let o=await r();return Pt(e,t,"success"),o}catch(o){throw Pt(e,t,"error"),o}}async function vf(e,t){if(t==="no-permission")return e.setStatus("Giving your user access to Docker (the docker group)\u2026"),await Ns(),e.updateData("dockerGroupSwitch",await Fs()),e.setStatus("Docker access granted. Continuing with it\u2026"),"relaunch";if(t!=="ready")throw await xt(t);return"ready"}async function Io(e,t){let r=t.needGit&&await ni()!=="success",o=await J(),n=[];r&&n.push("git"),o==="not-installed"&&n.push("docker");let i=_r.platform()==="linux"&&pf();if(r&&!i)throw Pt(e,"git","error"),new Error(`GAIA needs Git, which isn't installed. Install it from ${De.git}, then run this command again.`);if(o==="not-installed"&&!i&&(Pt(e,"docker","error"),mf()),n.length>0){try{await ff(e,n,t)}catch(s){for(let a of n)Pt(e,a,"error");throw s}t.onInstallStart?.(n)}return t.needGit&&await Ac(e,"git",async()=>{r&&await gf(e)}),Ac(e,"docker",async()=>(o==="not-installed"&&(await Sf(e),e.setStatus("Docker installed. Checking that it runs\u2026"),o=await J()),vf(e,o)))}var z=e=>new Promise(t=>setTimeout(t,e)),ko=(e,t="dependencyLogs")=>r=>{let o=e.currentState.data[t]||[],n=r.split(`
|
|
53
|
+
`).filter(i=>i.trim()!=="");e.updateData(t,[...o,...n].slice(-gr))};function Dc(e){return(t,r)=>{e.updateData("dependencyPhase",t.label),e.updateData("dependencyProgress",t.percent),e.updateData("dependencyLogs",r.slice(-gr))}}async function Ro(e){e.updateData("checks",{git:"pending"}),await z(500);try{return await Io(e,{needGit:!0})==="ready"}catch(t){return e.setError(t),!1}}async function To(e){e.updateData("checks",{...e.currentState.data.checks,mise:"pending"});let t=await Rc();return e.updateData("checks",{...e.currentState.data.checks,mise:t}),t==="missing"&&(e.setStatus("Installing Mise\u2026"),t=await Tc()?"success":"error",e.updateData("checks",{...e.currentState.data.checks,mise:t})),t==="error"?(e.setError(new Error(`Developer mode requires Mise but it failed to install.
|
|
54
|
+
\u2022 Mise: ${De.mise}`)),null):"success"}async function er(e,t){e.setStatus("Checking Ports\u2026");let r=await Co(t),o={},n=r.filter(i=>!i.available);if(n.length>0){let i=n.filter(a=>!a.alternative);if(i.length>0)return e.setError(new Error(`Cannot find free alternative ports for: ${i.map(a=>`${a.port} (${a.service})`).join(", ")}. Free these ports and try again.`)),null;if(e.updateData("portConflicts",r),await e.waitForInput("port_conflicts")==="abort")return e.setError(new Error("Port conflicts not resolved. Please free the ports and try again.")),null;for(let a of r)!a.available&&a.alternative&&(o[a.port]=a.alternative)}return e.updateData("portOverrides",o),e.setStatus("Git and Docker are ready"),await z(1e3),o}async function Oc(e,t,r,o){e.setStep("Project Setup"),e.updateData("dependencyPhase","Setting up project\u2026"),e.updateData("dependencyProgress",0),e.updateData("dependencyComplete",!1),e.updateData("dependencyLogs",[]);try{e.updateData("dependencyPhase","Trusting mise configuration\u2026"),await ne("mise",["trust"],t,void 0,o),e.updateData("dependencyProgress",20),e.updateData("dependencyPhase","Installing tools\u2026"),await ne("mise",["install"],t,i=>{e.updateData("dependencyProgress",20+i*.3)},o),e.updateData("dependencyPhase","Running mise setup\u2026");let n=Object.keys(r).length>0?ze(r):void 0;return await ne("mise",["setup"],t,i=>{e.updateData("dependencyProgress",50+i*.5)},o,n),e.updateData("dependencyProgress",100),e.updateData("dependencyPhase","Set up"),e.updateData("dependencyComplete",!0),!0}catch(n){return e.setError(new Error(`Failed to setup project: ${n.message}`)),!1}}import{createInterface as Lc}from"node:readline/promises";import{Writable as yf}from"node:stream";async function it(e,t){let r=Lc({input:process.stdin,output:process.stdout});try{let o=t?` [${t}]`:"";return(await r.question(`${e}${o}: `)).trim()||t||""}finally{r.close()}}var $c=4,Ao="\x1B",wf="",bf=new Set(["\x7F","\b"]),Ef=new RegExp(`${Ao}\\[[0-9;]*[A-Za-z~]`,"g");function xf(e){let t=e.length>$c*2?$c:0;return"\u2022".repeat(e.length-t)+e.slice(e.length-t)}async function Po(e){if(process.stdout.write(`${e}
|
|
55
|
+
\u203A `),!process.stdin.isTTY){let t=Lc({input:process.stdin,output:new yf({write:(r,o,n)=>n()})});try{return(await t.question("")).trim()}finally{t.close()}}return new Promise(t=>{let r="",o=(i,s)=>{process.stdin.off("data",n),process.stdin.setRawMode(!1),process.stdin.pause(),process.stdout.write(`\r\u203A ${s}${Ao}[K
|
|
56
|
+
`),t(i)},n=i=>{let s=i.toString("utf-8").replace(Ef,"");(s===wf||s===Ao)&&(o("",""),process.stdout.write(`${y.cancelled} Cancelled \xB7 nothing changed.
|
|
57
|
+
`),process.exit(130));for(let a of s){if(a==="\r"||a===`
|
|
58
|
+
`){o(r.trim(),xf(r.trim()));return}bf.has(a)?r=r.slice(0,-1):a>=" "&&(r+=a)}process.stdout.write(`\r\u203A ${"\u2022".repeat(r.length)}${Ao}[K`)};process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.on("data",n)})}async function st(e,t=!0){let r=await it(`${e} (${t?"Y/n":"y/N"})`);return r?/^y(es)?$/i.test(r):t}async function _o(e,t){for(process.stdout.write(`
|
|
53
59
|
${e}
|
|
54
60
|
`),t.forEach((r,o)=>{process.stdout.write(` ${o+1}. ${r}
|
|
55
|
-
`)});;){let r=await
|
|
56
|
-
`)}}
|
|
57
|
-
`).
|
|
58
|
-
${" ".repeat(t)}`)}var Nm={discord:["node","dist/deploy-commands.js"],telegram:["node","dist/set-commands.js"]},Bm=12e4,Gm=3e3,mc={telegram:[{key:"token",flag:"--token",label:"Telegram bot token",hint:"In Telegram, message @BotFather, send /newbot and copy the token it replies with."}],discord:[{key:"token",flag:"--token",label:"Discord bot token",hint:"At https://discord.com/developers/applications open your app > Bot > Reset Token. Turn on Message Content Intent on the same page."}],slack:[{key:"token",flag:"--token",label:"Slack bot token (xoxb-)",hint:"At https://api.slack.com/apps open your app > OAuth & Permissions > Bot User OAuth Token."},{key:"appToken",flag:"--app-token",label:"Slack app-level token (xapp-)",hint:"Turn on Socket Mode, then Basic Information > App-Level Tokens: create one with the connections:write scope."},{key:"signingSecret",flag:"--signing-secret",label:"Slack signing secret",hint:"Basic Information > App Credentials > Signing Secret."}]};function me(e=""){process.stdout.write(`${e}
|
|
59
|
-
`)}function zn(e,t){if(!e)throw new Error(`Missing ${t}.`);return e}var Rt={telegram:"Telegram",discord:"Discord",slack:"Slack"},Um=3;async function jm(e,t){let r={...t};for(let o of mc[e]){if(r[o.key])continue;if(!pe())throw new Error(`Missing ${o.flag}. ${o.hint}`);me(),me(kt(o.hint));let n=await Eo(o.label);if(!n)throw new Error(`No ${o.label} entered. Nothing changed.`);r[o.key]=n}return r}async function qm(e,t){for(let r=1;;r++){let o=await jm(e,t);me(`Checking your ${Rt[e]} credentials\u2026`);try{return await Hm(e,o)}catch(n){let i=mc[e].some(a=>!t[a.key]),s=Um-r;if(!i||!pe()||s===0)throw n;me(`${b.fail} ${n.message} Paste ${s===1?"it":"them"} again (${s} ${s===1?"try":"tries"} left), or press Esc to stop.`)}}}async function Qn(){let e=_();if(!e||await N(e)!=="selfhost")throw new Error("No self-host GAIA install found. Run 'gaia up' first; chat bots run alongside it.");return e}async function Hm(e,t){let r=zn(t.token,"--token");if(e==="telegram"){let s=await Ja(r);return{botsEnv:{TELEGRAM_BOT_TOKEN:r},handle:s,nextSteps:[`Open ${za(s)} and send /auth to link your GAIA account.`]}}if(e==="discord"){let s=await Za(r);return{botsEnv:{DISCORD_BOT_TOKEN:r,DISCORD_CLIENT_ID:s},handle:s,nextSteps:[`Add the bot to a server: ${Xa(s)}`,"Then run /auth in Discord to link your GAIA account."]}}let o=zn(t.appToken,"--app-token"),n=zn(t.signingSecret,"--signing-secret"),i=await ec(r,o);return{botsEnv:{SLACK_BOT_TOKEN:r,SLACK_APP_TOKEN:o,SLACK_SIGNING_SECRET:n},handle:i.url,nextSteps:[`Running in the ${i.name} workspace. Run /auth in Slack to link your GAIA account.`]}}async function Vm(e){let t=le.selfhost,r=Date.now()+Bm;for(;;){let o=gr(e,await gt(t));if(o.health==="healthy")return;if(Date.now()>=r)throw new Error(`The ${Rt[e]} bot did not come up (${o.detail}). See why with 'docker compose -p ${t} logs ${ue(e)}'; 'gaia bots remove ${e}' undoes the setup.`);await X(Gm)}}async function fc(e){await oe(e,"selfhost",t=>me(t),F(e),void 0,{pull:"missing"})}async function gc(e,t){let r=await Qn(),o=await qm(e,t);hr(r,{set:o.botsEnv}),Jr(r,{set:{[Tn[e]]:o.handle}});let n=$()?.bots??[];n.includes(e)||Se({bots:[...n,e]}),await fc(r);let i=Nm[e];i&&(me(`Registering the ${Rt[e]} bot's commands\u2026`),await fa(r,ue(e),i)),me(`Waiting for the ${Rt[e]} bot to connect\u2026`),await Vm(e),me(`${b.ok} The ${Rt[e]} bot is running`);for(let s of o.nextSteps)me(s)}async function hc(e){let t=await Qn(),r=$()?.bots??[];if(!r.includes(e))throw new Error(`The ${Rt[e]} bot is not enabled. See 'gaia bots list'.`);Se({bots:r.filter(o=>o!==e)}),hr(t,{unset:Hs[e]}),Jr(t,{unset:[Tn[e]]}),await fc(t),me(`${b.ok} The ${Rt[e]} bot is stopped and its credentials are deleted`)}async function Sc(){await Qn();let e=$()?.bots??[];if(e.length===0){me("No chat bots enabled. Add one with: gaia bots add <telegram|discord|slack>");return}let t=await gt(le.selfhost);for(let r of e)me(` ${r.padEnd(10)}${gr(r,t).detail}`)}function vc(){return new Wm("<platform>","chat platform").choices(qs)}var Cr=new Km("bots").description(G.bots).hook("preAction",()=>wt()).addHelpText("after",`
|
|
61
|
+
`)});;){let r=await it(`Choose 1-${t.length}`),o=Number.parseInt(r,10)-1;if(o>=0&&o<t.length)return o;process.stdout.write(`Invalid choice, try again.
|
|
62
|
+
`)}}var Cf={discord:["node","dist/deploy-commands.js"],telegram:["node","dist/set-commands.js"]},If=12e4,kf=3e3,Mc={telegram:[{key:"token",flag:"--token",label:"Telegram bot token",hint:"In Telegram, message @BotFather, send /newbot and copy the token it replies with."}],discord:[{key:"token",flag:"--token",label:"Discord bot token",hint:"At https://discord.com/developers/applications open your app > Bot > Reset Token. Turn on Message Content Intent on the same page."}],slack:[{key:"token",flag:"--token",label:"Slack bot token (xoxb-)",hint:"At https://api.slack.com/apps open your app > OAuth & Permissions > Bot User OAuth Token."},{key:"appToken",flag:"--app-token",label:"Slack app-level token (xapp-)",hint:"Turn on Socket Mode, then Basic Information > App-Level Tokens: create one with the connections:write scope."},{key:"signingSecret",flag:"--signing-secret",label:"Slack signing secret",hint:"Basic Information > App Credentials > Signing Secret."}]};function ge(e=""){process.stdout.write(`${e}
|
|
63
|
+
`)}function ai(e,t){if(!e)throw new Error(`Missing ${t}.`);return e}var Dt={telegram:"Telegram",discord:"Discord",slack:"Slack"},Rf=3;async function Tf(e,t,r){let o={...t},n=0;for(let i of Mc[e]){if(o[i.key])continue;if(!fe())throw new Error(`Missing ${i.flag}. ${i.hint}`);r&&(n>0&&ge(),ge(Ze(i.hint))),n++;let s=await Po(i.label);if(!s)throw new Error(`No ${i.label} entered. Nothing changed.`);o[i.key]=s}return o}async function Af(e,t){for(let r=1;;r++){let o=await Tf(e,t,r===1);ge(`Checking your ${Dt[e]} credentials\u2026`);try{return await Pf(e,o)}catch(n){let i=Mc[e].filter(a=>!t[a.key]),s=Rf-r;if(i.length===0||!fe()||s===0)throw n;ge(Ze(`${y.fail} ${n.message} Paste ${i.length===1?"it":"them"} again (${s} ${s===1?"try":"tries"} left), or press Esc to stop.`,2))}}}async function ci(){let e=_();if(!e||await F(e)!=="selfhost")throw new Error("No self-host GAIA install found. Run 'gaia up' first; chat bots run alongside it.");return e}async function Pf(e,t){let r=ai(t.token,"--token");if(e==="telegram"){let s=await Sc(r);return{botsEnv:{TELEGRAM_BOT_TOKEN:r},handle:s,nextSteps:[`Open ${gc(s)} and send /auth to link your GAIA account.`]}}if(e==="discord"){let s=await vc(r);return{botsEnv:{DISCORD_BOT_TOKEN:r,DISCORD_CLIENT_ID:s},handle:s,nextSteps:[`Add the bot to a server: ${fc(s)}`,"Then run /auth in Discord to link your GAIA account."]}}let o=ai(t.appToken,"--app-token"),n=ai(t.signingSecret,"--signing-secret"),i=await yc(r,o);return{botsEnv:{SLACK_BOT_TOKEN:r,SLACK_APP_TOKEN:o,SLACK_SIGNING_SECRET:n},handle:i.url,nextSteps:[`Running in the ${i.name} workspace. Run /auth in Slack to link your GAIA account.`]}}async function _f(e){let t=pe.selfhost,r=Date.now()+If;for(;;){let o=xr(e,await bt(t));if(o.health==="healthy")return;if(Date.now()>=r)throw new Error(`The ${Dt[e]} bot did not come up (${o.detail}). See why with 'docker compose -p ${t} logs ${me(e)}'; 'gaia bots remove ${e}' undoes the setup.`);await z(kf)}}async function Nc(e){await oe(e,"selfhost",t=>ge(t),N(e),void 0,{pull:"missing"})}async function Fc(e,t){let r=await ci(),o=await Af(e,t);Cr(r,{set:o.botsEnv}),so(r,{set:{[Nn[e]]:o.handle}});let n=L()?.bots??[];n.includes(e)||ye({bots:[...n,e]}),await Nc(r);let i=Cf[e];i&&(ge(`Registering the ${Dt[e]} bot's commands\u2026`),await _a(r,me(e),i)),ge(`Waiting for the ${Dt[e]} bot to connect\u2026`),await _f(e),ge(`${y.ok} The ${Dt[e]} bot is running`);for(let s of o.nextSteps)ge(s)}async function Bc(e){let t=await ci(),r=L()?.bots??[];if(!r.includes(e))throw new Error(`The ${Dt[e]} bot is not enabled. See 'gaia bots list'.`);ye({bots:r.filter(o=>o!==e)}),Cr(t,{unset:na[e]}),so(t,{unset:[Nn[e]]}),await Nc(t),ge(`${y.ok} The ${Dt[e]} bot is stopped and its credentials are deleted`)}async function Gc(){await ci();let e=L()?.bots??[];if(e.length===0){ge("No chat bots enabled. Add one with: gaia bots add <telegram|discord|slack>");return}let t=await bt(pe.selfhost);for(let r of e)ge(` ${r.padEnd(10)}${xr(r,t).detail}`)}function Uc(){return new Df("<platform>","chat platform").choices(oa)}var Or=new Of("bots").description(U.bots).hook("preAction",()=>Rt()).addHelpText("after",`
|
|
60
64
|
Examples:
|
|
61
65
|
gaia bots add telegram (asks for the token from @BotFather)
|
|
62
66
|
gaia bots add telegram --token <token from @BotFather>
|
|
63
67
|
gaia bots add discord --token <bot token>
|
|
64
68
|
gaia bots add slack --token xoxb-... --app-token xapp-... --signing-secret <secret>
|
|
65
|
-
`);
|
|
66
|
-
`)||"(empty)"}]}}catch(s){return n(s instanceof Error?s.message:String(s))}}),t.registerTool("read_file",{description:"Read the contents of a text or image file on the user's machine.",inputSchema:{path:
|
|
67
|
-
`)||"(no matches)"}]}}catch(a){return n(a instanceof Error?a.message:String(a))}}),e.allowWrite&&t.registerTool("write_file",{description:"Write text to a file on the user's machine (overwrites if it exists).",inputSchema:{path:
|
|
69
|
+
`);Or.command("add").description("Check the bot's credentials (asked for when not passed), save them and start the bot").addArgument(Uc()).option("--token <token>","Bot token (Slack: the xoxb- bot user token)").option("--app-token <token>","Slack: app-level token (xapp-)").option("--signing-secret <secret>","Slack: the app's signing secret").action(async(e,t)=>{await ie(()=>Fc(e,t))});Or.command("list").alias("ls").description("Show the enabled bots and whether each is running").action(async()=>{await ie(Gc)});Or.command("remove").alias("rm").description("Stop a bot and delete its saved credentials").addArgument(Uc()).action(async e=>{await ie(()=>Bc(e))});import{Command as Ug}from"commander";import{existsSync as Fo,mkdirSync as tg,readFileSync as Qc,writeFileSync as vi}from"node:fs";import{homedir as Jc}from"node:os";import{join as yi}from"node:path";import{sep as $f}from"node:path";var j={PING:"ping",MCP_OPEN:"mcp.open",MCP_CLOSE:"mcp.close",MCP_MSG:"mcp.msg",REVOKE:"revoke",SERVER_REMOVE:"server.remove",PONG:"pong",HELLO:"hello",MCP_OPENED:"mcp.opened",MCP_ERROR:"mcp.error",EXEC_OPEN:"exec.open",EXEC_STDOUT:"exec.stdout",EXEC_STDERR:"exec.stderr",EXEC_EXIT:"exec.exit"},li="https://api.heygaia.io",Ot="filesystem",Do=$f,ui=500,di=6e4,pi=5e3,mi=1e6,fi=5e6,Oo=9e4,$o=1e6;import{homedir as Lf}from"node:os";import{join as Mf}from"node:path";var Nf={info:e=>console.error(e),error:e=>console.error(e)},gi={},Ff=null;function X(){return Ff??Nf}function Oe(){return{stateDir:gi.stateDir??Mf(Lf(),".gaia","bridge"),env:gi.env??process.env,shell:gi.shell??process.env.SHELL??"/bin/sh"}}import{Client as Yf}from"@modelcontextprotocol/sdk/client/index.js";import{getDefaultEnvironment as zf,StdioClientTransport as Xf}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as Jf}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{InMemoryTransport as Qf}from"@modelcontextprotocol/sdk/inMemory.js";import{lstat as Bf,readdir as Vc,readFile as jc,realpath as Gf,stat as Uf,writeFile as jf}from"node:fs/promises";import{dirname as qc,extname as qf,join as Wc,resolve as Hf,sep as hi}from"node:path";import{McpServer as Vf}from"@modelcontextprotocol/sdk/server/mcp.js";import{z as tr}from"zod";var Wf={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".gif":"image/gif"},rr=class extends Error{};async function Si(e){try{return await Gf(e)}catch{return null}}async function Kf(e){try{return(await Bf(e)).isSymbolicLink()}catch{return!1}}function Hc(e,t){return t===hi?e.startsWith(hi):e===t||e.startsWith(t+hi)}async function Lo(e,t,r){let o=Hf(e),n=await Si(o);if(n){if(t.some(s=>Hc(n,s)))return n;throw new rr(`Path is outside your approved folders: ${e}`)}if(r)throw new rr(`No such file or directory: ${e}`);let i=await Si(qc(o));if(!i||!t.some(s=>Hc(i,s)))throw new rr(`Path is outside your approved folders: ${e}`);if(await Kf(o))throw new rr(`Refusing to write through a symlink: ${e}`);return Wc(i,o.slice(qc(o).length+1))}async function Kc(e,t,r,o){if(o.length>=r)return;let n;try{n=await Vc(e,{withFileTypes:!0})}catch{return}for(let i of n){if(o.length>=r)return;let s=Wc(e,i.name);i.name.toLowerCase().includes(t.toLowerCase())&&o.push(s),i.isDirectory()&&!i.isSymbolicLink()&&await Kc(s,t,r,o)}}function Yc(e){let t=new Vf({name:"gaia-filesystem",version:"0.1.0"}),r=null,o=()=>(r||(r=Promise.all(e.allow.map(Si)).then(i=>i.filter(s=>s!==null))),r),n=i=>({isError:!0,content:[{type:"text",text:i}]});return t.registerTool("list_directory",{description:"List the entries (files and folders) in a directory on the user's machine.",inputSchema:{path:tr.string().describe("Absolute path to a directory")}},async({path:i})=>{try{let s=await Lo(i,await o(),!0);return{content:[{type:"text",text:(await Vc(s,{withFileTypes:!0})).map(l=>`${l.isDirectory()?"dir ":"file"} ${l.name}`).join(`
|
|
70
|
+
`)||"(empty)"}]}}catch(s){return n(s instanceof Error?s.message:String(s))}}),t.registerTool("read_file",{description:"Read the contents of a text or image file on the user's machine.",inputSchema:{path:tr.string().describe("Absolute path to a file")}},async({path:i})=>{try{let s=await Lo(i,await o(),!0),a=await Uf(s);if(!a.isFile())return n(`Not a file: ${i}`);let c=Wf[qf(s).toLowerCase()];if(c){if(a.size>fi)return n(`Image is too large to read (${a.size} bytes).`);let d=await jc(s);return{content:[{type:"text",text:`Image file ${s} (${c}, ${a.size} bytes) \u2014 shown below.`},{type:"image",data:d.toString("base64"),mimeType:c}]}}return a.size>mi?n(`File is too large to read (${a.size} bytes).`):{content:[{type:"text",text:await jc(s,"utf-8")}]}}catch(s){return n(s instanceof Error?s.message:String(s))}}),t.registerTool("search_files",{description:"Recursively find files/folders whose name contains a query, under a directory.",inputSchema:{path:tr.string().describe("Absolute path to the directory to search under"),query:tr.string().describe("Substring to match against names")}},async({path:i,query:s})=>{try{let a=await Lo(i,await o(),!0),c=[];return await Kc(a,s,200,c),{content:[{type:"text",text:c.join(`
|
|
71
|
+
`)||"(no matches)"}]}}catch(a){return n(a instanceof Error?a.message:String(a))}}),e.allowWrite&&t.registerTool("write_file",{description:"Write text to a file on the user's machine (overwrites if it exists).",inputSchema:{path:tr.string().describe("Absolute path to the file to write"),content:tr.string().describe("Text content to write")}},async({path:i,content:s})=>{try{let a=await Lo(i,await o(),!1);return await jf(a,s,"utf-8"),{content:[{type:"text",text:`Wrote ${s.length} bytes to ${i}`}]}}catch(a){return n(a instanceof Error?a.message:String(a))}}),t}var Zf=new Set(["localhost","127.0.0.1","::1"]),zc=5;function at(e){let t=new URL(e);if(t.protocol!=="http:"&&t.protocol!=="https:")throw new Error(`url servers must be http(s), got ${t.protocol}`);let r=t.hostname.replace(/^\[|\]$/g,"");if(!Zf.has(r))throw new Error("url servers must point at this machine (localhost / 127.0.0.1 / ::1)");return t}function eg(e){return new URL(typeof e=="string"?e:e instanceof URL?e.href:e.url)}async function Xc(e,t){let r=eg(e),o={...t,redirect:"manual"};for(let n=0;;n++){let i=await fetch(r,o);if(i.status<300||i.status>=400)return i;let s=i.headers.get("location"),a=s?new URL(s,r.href):null;if(await i.body?.cancel(),!a||a.origin!==r.origin)throw new Error(`refusing ${i.status} redirect to ${s??"(no location)"} \u2014 an MCP server must be addressed directly, not via a redirect`);if(n>=zc)throw new Error(`too many redirects (>${zc}) \u2014 refusing to follow`);r=a,o={...t,redirect:"manual"}}}async function Mo(e){if(e.type==="url"){let n=at(e.url),i=new Jf(n,{requestInit:{...e.headers?{headers:e.headers}:{}},fetch:Xc});return{transport:i,close:()=>i.close()}}if(e.type==="stdio"){let n=Oe().env,i=new Xf({command:e.command,args:e.args,env:{...zf(),...n.PATH!==void 0?{PATH:n.PATH}:{},...n.HOME!==void 0?{HOME:n.HOME}:{},...e.env}});return{transport:i,close:()=>i.close()}}let[t,r]=Qf.createLinkedPair(),o=Yc(e);return await o.connect(r),{transport:t,close:async()=>{await o.close(),await t.close()}}}async function No(e){let t=await Mo(e),r=new Yf({name:"gaia-bridge-test",version:"0.1.0"});try{await r.connect(t.transport);let{tools:o}=await r.listTools();return o.map(n=>n.name)}finally{try{await r.close(),await t.close()}catch{}}}function wi(){return Oe().stateDir}function bi(){return yi(wi(),"credentials.json")}function Zc(){return yi(wi(),"config.json")}function el(){let e=wi();Fo(e)||tg(e,{recursive:!0,mode:448})}function $e(){let e=bi();if(!Fo(e))return null;try{return JSON.parse(Qc(e,"utf-8"))}catch{return null}}function $r(e){el(),vi(bi(),JSON.stringify(e,null,2),{mode:384})}function Lr(){let e=bi();Fo(e)&&vi(e,"{}",{mode:384})}function Q(){let e=Zc();if(!Fo(e))return{servers:[]};try{return{servers:JSON.parse(Qc(e,"utf-8")).servers??[]}}catch{return{servers:[]}}}function tl(e){el(),vi(Zc(),JSON.stringify(e,null,2),{mode:384})}function Bo(e){e.type==="url"&&at(e.url);let t=Q(),r=t.servers.findIndex(o=>o.key===e.key);r>=0?t.servers[r]=e:t.servers.push(e),tl(t)}function Mr(e){let t=Q(),r=t.servers.length;return t.servers=t.servers.filter(o=>o.key!==e),tl(t),t.servers.length<r}function Ei(e){return e==="~"?Jc():e.startsWith("~/")?yi(Jc(),e.slice(2)):e}function xi(e,t){return{type:"filesystem",key:Ot,name:"Local Files",allow:e,allowWrite:t}}function Nr(e){if(e)return e.replace(/\/$/,"");let t=$e();return t?.apiUrl?t.apiUrl.replace(/\/$/,""):(process.env.GAIA_API_URL??li).replace(/\/$/,"")}import{hostname as ng,platform as ig}from"node:os";var rl="x-request-id";function rg(e){if(!e||typeof e!="object")return;let{message:t,code:r}=e;if(!(typeof t!="string"&&typeof r!="string"))return e}var xe=class e extends Error{status;envelope;body;requestId;constructor(t,r,o={}){super(t,o.cause===void 0?void 0:{cause:o.cause}),this.name="ApiError",this.status=r,this.envelope=o.envelope,this.body=o.body??"",this.requestId=o.requestId}get code(){let t=this.envelope?.code;return typeof t=="string"?t:void 0}static fromBody(t,r,o={}){let n=rg(r),i=n?.message??o.fallbackMessage??`API request failed: ${t}`;return new e(i,t,{envelope:n,body:typeof r=="string"?r:JSON.stringify(r??""),requestId:o.requestId,cause:o.cause})}};async function ol(e){if(!e.ok){let t=await e.text(),r=t;try{r=JSON.parse(t)}catch{}throw xe.fromBody(e.status,r,{fallbackMessage:`${e.status} ${e.statusText}`,requestId:e.headers.get(rl)??void 0})}return await e.json()}async function Go(e,t,r,o){let n=await fetch(`${e}/api/v1${t}`,{method:"POST",headers:{"content-type":"application/json",...o?{authorization:`Bearer ${o}`}:{}},body:JSON.stringify(r)});return ol(n)}async function og(e,t,r){let o=await fetch(`${e}/api/v1${t}`,{method:"DELETE",headers:{authorization:`Bearer ${r}`}});return ol(o)}function Ci(e,t,r,o){return Go(e,"/device/pair/start",{name:t,platform:r,daemon_version:o})}function Ii(e,t){return Go(e,"/device/pair/poll",{device_code:t})}function ki(e,t){return Go(e,"/device/token",{refresh_token:t})}function Ri(e,t,r,o,n){return Go(e,"/device/servers",{server_key:r,display_name:o,kind:n},t)}function nl(e,t,r){return og(e,`/device/servers/${encodeURIComponent(r)}`,t)}async function sg(e){await new Promise(t=>setTimeout(t,e))}function Ti(){return!!$e()?.refreshToken}async function il(e,t){let r=Nr(t.api),o=t.name||ng(),n=await Ci(r,o,ig(),t.daemonVersion);e.onPrompt(n.verification_url,n.user_code),e.onStatus?.("Waiting for approval\u2026");let i=Date.now()+n.expires_in*1e3;for(;Date.now()<i;){await sg(n.interval*1e3);let s;try{s=await Ii(r,n.device_code)}catch(a){X().error(`[gaia bridge] poll failed, retrying: ${a instanceof Error?a.message:a}`);continue}if(s.status==="approved"&&s.device_id&&s.refresh_token){$r({apiUrl:r,deviceId:s.device_id,refreshToken:s.refresh_token}),e.onStatus?.(`
|
|
68
72
|
Paired as "${o}".
|
|
69
|
-
`);return}if(s.status==="expired")throw new Error(`pairing ${s.status}`)}throw new Error("pairing timed out")}var
|
|
73
|
+
`);return}if(s.status==="expired")throw new Error(`pairing ${s.status}`)}throw new Error("pairing timed out")}var ag={onPrompt(e,t){console.info(`
|
|
70
74
|
To pair this device, open:
|
|
71
75
|
`),console.info(` ${e}`),console.info(`
|
|
72
76
|
and enter this code: ${t}
|
|
73
|
-
`)},onStatus(e){console.info(e)}};async function
|
|
74
|
-
`)}catch{}}async function
|
|
77
|
+
`)},onStatus(e){console.info(e)}};async function cg(){let e=_();if(!(!e||await F(e)!=="selfhost"))return kt("selfhost",N(e))}async function or(e={}){let t=e.api??(process.env.GAIA_API_URL?void 0:await cg());await il(ag,{...e,...t!==void 0?{api:t}:{},daemonVersion:$})}import{spawn as Ig}from"node:child_process";import{existsSync as Pi,mkdirSync as kg,openSync as Rg,readFileSync as Tg,unlinkSync as pl,writeFileSync as Ag}from"node:fs";import{homedir as Pg}from"node:os";import{join as _i}from"node:path";import{mkdirSync as sl,readFileSync as lg,rmSync as al,writeFileSync as ug}from"node:fs";import{dirname as dg,join as cl}from"node:path";var pg=3e4,mg=3e4,fg=50,gg=e=>new Promise(t=>setTimeout(t,e));function ll(){return cl(Oe().stateDir,"credentials.lock")}function hg(){return cl(ll(),"stamp")}async function Sg(e){let t=ll(),r=hg();sl(dg(t),{recursive:!0});let o=Date.now()+mg;for(;;){try{sl(t);break}catch(i){if(i?.code!=="EEXIST")throw i}let n=null;try{let i=Number(lg(r,"utf-8"));n=Number.isFinite(i)?Date.now()-i:Number.POSITIVE_INFINITY}catch(i){i?.code!=="ENOENT"&&(n=Number.POSITIVE_INFINITY)}if(n===null||n<pg){if(Date.now()>o)throw new Error("another gaia process is rotating the device credential \u2014 try again");await gg(fg);continue}try{al(t,{recursive:!0,force:!0})}catch{}}try{return ug(r,String(Date.now()),{mode:384}),await e()}finally{try{al(t,{recursive:!0,force:!0})}catch{}}}async function Fr(){return Sg(async()=>{let e=$e();if(!e?.refreshToken)throw new xe("not paired \u2014 run: gaia bridge login",401);let t=await ki(e.apiUrl,e.refreshToken),r={...e,refreshToken:t.refresh_token};return $r(r),{creds:r,accessToken:t.access_token}})}async function nr(){let e=Q().servers;if(e.length===0)throw new Error("no servers configured \u2014 run: gaia bridge add");let{creds:t,accessToken:r}=await Fr();await Promise.all(e.map(o=>Ri(t.apiUrl,r,o.key,o.name,o.type)))}async function Ai(e){let t=Mr(e);try{let{creds:r,accessToken:o}=await Fr();await nl(r.apiUrl,o,e)}catch(r){X().info(`[gaia bridge] removed '${e}' locally; the cloud will reconcile on next connect (${r instanceof Error?r.message:String(r)})`)}return t}import{randomInt as Cg}from"node:crypto";import dl from"ws";import{spawn as vg}from"node:child_process";import{appendFileSync as yg,mkdirSync as wg}from"node:fs";import{homedir as bg}from"node:os";import{join as Eg}from"node:path";function xg(e,t){try{let r=Oe().stateDir;wg(r,{recursive:!0,mode:448});let o=t?` (cwd: ${t})`:"";yg(Eg(r,"exec-audit.log"),`${new Date().toISOString()}${o} $ ${e}
|
|
78
|
+
`)}catch{}}async function ul(e,t,r){xg(e,t);let o=vg(Oe().shell,["-c",e],{cwd:t||bg(),env:Oe().env,stdio:["ignore","pipe","pipe"]}),n=0,i=!1,s=c=>l=>{if(i)return;let d=$o-n,p=l.length>d?l.subarray(0,d):l;p.length>0&&(n+=p.length,r[c](p.toString("utf-8"))),n>=$o&&(i=!0,r.stderr(`
|
|
75
79
|
[gaia bridge] output truncated \u2014 cap reached
|
|
76
80
|
`),o.kill("SIGKILL"))};o.stdout.on("data",s("stdout")),o.stderr.on("data",s("stderr"));let a=setTimeout(()=>{r.stderr(`
|
|
77
|
-
[gaia bridge] killed \u2014 exceeded ${
|
|
78
|
-
`),o.kill("SIGKILL")},
|
|
79
|
-
`),r.exit(127),c()}),o.on("close",l=>{clearTimeout(a),r.exit(l??-1),c()})})}var
|
|
80
|
-
`),
|
|
81
|
+
[gaia bridge] killed \u2014 exceeded ${Oo/1e3}s timeout
|
|
82
|
+
`),o.kill("SIGKILL")},Oo);await new Promise(c=>{o.on("error",l=>{clearTimeout(a),r.stderr(`[gaia bridge] could not start command: ${l.message}
|
|
83
|
+
`),r.exit(127),c()}),o.on("close",l=>{clearTimeout(a),r.exit(l??-1),c()})})}var Br=class{constructor(t){this.creds=t}ws=null;sessions=new Map;reconnectDelay=ui;stopped=!1;async run(){for(;!this.stopped;){try{await this.connectOnce()}catch(t){t instanceof xe&&t.status===401?(X().error("[gaia bridge] this device is no longer authorized (revoked or unpaired). Re-pair with: gaia bridge login"),this.stopped=!0):X().error(`[gaia bridge] connection error: ${t instanceof Error?t.message:t}`)}if(this.stopped)break;await this.backoff()}}async stop(){this.stopped=!0,await this.closeAllSessions(),this.ws?.close()}async connectOnce(){let{creds:t,accessToken:r}=await Fr();this.creds=t;let o=`${this.creds.apiUrl.replace(/^http/,"ws")}/api/v1/ws/device`,n=new dl(o,{headers:{authorization:`Bearer ${r}`}});this.ws=n,await new Promise((i,s)=>{let a=!1,c=!1,l=d=>{c||(c=!0,d())};n.on("open",()=>{a=!0,this.reconnectDelay=pi;let d=Q().servers.map(p=>p.key);this.send({t:j.HELLO,servers:d}),X().info(`[gaia bridge] connected \u2014 exposing: ${d.join(", ")||"(nothing configured)"}`)}),n.on("message",d=>{this.guardRejection(this.onFrame(d.toString()),"frame handler error")}),n.on("close",()=>{this.guardRejection(this.closeAllSessions(),"session cleanup error"),this.ws=null,l(()=>a?i():s(new Error("socket closed before open")))}),n.on("error",d=>{a||l(()=>s(d))})})}async onFrame(t){let r;try{r=JSON.parse(t)}catch{return}switch(r.t){case j.PING:this.send({t:j.PONG});return;case j.MCP_OPEN:await this.openSession(r);return;case j.MCP_MSG:await this.forwardToServer(r);return;case j.MCP_CLOSE:await this.closeSession(r.sid);return;case j.EXEC_OPEN:await this.runExec(r);return;case j.REVOKE:X().error("[gaia bridge] this device was revoked \u2014 exiting."),await this.stop();return;case j.SERVER_REMOVE:r.key&&Mr(r.key)&&X().info(`[gaia bridge] removed server '${r.key}' (deleted in GAIA).`);return;default:return}}async openSession(t){let r=t.sid,o=t.server,n=t.pod;if(!r||!o)return;let i=Q().servers.find(a=>a.key===o);if(!i){this.send({t:j.MCP_ERROR,sid:r,pod:n,error:`Unknown server '${o}'`});return}let s=Date.now();X().info(`[gaia bridge] opening MCP session for '${o}'\u2026`);try{let a=await Mo(i);a.transport.onmessage=c=>{this.send({t:j.MCP_MSG,sid:r,pod:n,data:JSON.stringify(c)})},a.transport.onclose=()=>{this.sessions.has(r)&&this.send({t:j.MCP_ERROR,sid:r,pod:n,error:`Local server '${o}' exited`}),this.guardRejection(this.closeSession(r),"session close error")},await a.transport.start(),this.sessions.set(r,a),this.send({t:j.MCP_OPENED,sid:r,pod:n}),X().info(`[gaia bridge] MCP session for '${o}' ready in ${Date.now()-s}ms`)}catch(a){let c=a instanceof Error?a.message:String(a);X().error(`[gaia bridge] MCP session for '${o}' failed after ${Date.now()-s}ms: ${c}`),this.send({t:j.MCP_ERROR,sid:r,pod:n,error:c})}}async forwardToServer(t){let r=t.sid?this.sessions.get(t.sid):void 0;if(!(!r||!t.data))try{let o=JSON.parse(t.data);await r.transport.send(o)}catch(o){X().error(`[gaia bridge] forward error: ${o instanceof Error?o.message:o}`)}}async runExec(t){let r=t.sid,o=t.pod,n=t.command;!r||!n||await ul(n,t.cwd,{stdout:i=>this.send({t:j.EXEC_STDOUT,sid:r,pod:o,data:i}),stderr:i=>this.send({t:j.EXEC_STDERR,sid:r,pod:o,data:i}),exit:i=>this.send({t:j.EXEC_EXIT,sid:r,pod:o,code:i})})}async closeSession(t){if(!t)return;let r=this.sessions.get(t);if(r){this.sessions.delete(t);try{await r.close()}catch{}}}async closeAllSessions(){let t=[...this.sessions.keys()];await Promise.all(t.map(r=>this.closeSession(r)))}send(t){this.ws?.readyState===dl.OPEN&&this.ws.send(JSON.stringify(t))}guardRejection(t,r){t.catch(o=>{X().error(`[gaia bridge] ${r}: ${o instanceof Error?o.message:o}`)})}async backoff(){let t=Cg(this.reconnectDelay);X().info(`[gaia bridge] reconnecting in ${t}ms\u2026`),await new Promise(r=>setTimeout(r,t)),this.reconnectDelay=Math.min(this.reconnectDelay*2,di)}};var Di=_i(Pg(),".gaia","bridge"),$t=_i(Di,"daemon.pid"),ml=_i(Di,"daemon.log");function Oi(){if(!Pi($t))return null;let e=Number(Tg($t,"utf-8").trim());if(!e)return null;try{return process.kill(e,0),e}catch{return null}}function fl(){let e=Oi();return e?`Tunnel: running in the background (pid ${e}) \u2014 stop with: gaia bridge down`:"Tunnel: not running \u2014 start with: gaia bridge up"}function gl(){let e=Oi();if(!e){Pi($t)&&pl($t),console.info("No bridge tunnel is running.");return}try{process.kill(e,"SIGTERM")}catch{}Pi($t)&&pl($t),console.info(`Stopped the bridge tunnel (pid ${e}).`)}async function Uo(){let e=Oi();if(e){console.info(`Bridge tunnel is already running (pid ${e}) \u2014 it already serves your configured servers, including any you just added. Nothing else to do.`);return}console.error("[gaia bridge] connected: GAIA can run commands and access files on this machine.");let t=Q().servers.filter(s=>s.type==="url"&&s.headers&&Object.keys(s.headers).length>0);t.length>0&&console.error(`[gaia bridge] forwarding request headers (credentials) to ${t.length} local url server(s).`);try{await nr()}catch(s){if(s instanceof xe&&s.status===401)console.error(`[gaia bridge] this device is no longer authorized (revoked or unpaired). Let's re-pair.
|
|
84
|
+
`),Lr(),await or(),await nr();else throw s}let r=process.argv[1];if(!r)throw new Error("cannot locate the gaia CLI entrypoint to start the daemon");kg(Di,{recursive:!0,mode:448});let o=Rg(ml,"a"),n={detached:!0,stdio:["ignore",o,o]},i=Ig(process.execPath,[...process.execArgv,r,"bridge","up","--serve"],n);i.unref(),Ag($t,String(i.pid??""),{mode:384}),console.info(`
|
|
81
85
|
Bridge tunnel started in the background (pid ${i.pid}).
|
|
82
|
-
Logs: ${
|
|
83
|
-
Stop: gaia bridge down`)}async function
|
|
84
|
-
The command needs ${n}.`),r[n]=await
|
|
85
|
-
Examples: npx -y my-mcp-server \xB7 uvx my-server \xB7 docker run -i --rm my/image`);let e=await
|
|
86
|
-
Heads up: these headers travel unencrypted over local HTTP. Anyone else on this machine (or the receiving server's logs) can read them.`),!await
|
|
87
|
-
Testing the connection (this may download/start the server)\u2026`);try{let t=await
|
|
88
|
-
Saved '${r.key}'.`);try{await
|
|
89
|
-
Configured servers:`);for(let r of t)if(r.type==="filesystem")console.info(` [${r.key}] filesystem${r.allowWrite?" (rw)":" (ro)"}: ${r.allow.join(", ")}`);else if(r.type==="stdio"){let o=Object.keys(r.env);console.info(` [${r.key}] ${r.name}: ${r.command} ${r.args.join(" ")}`),o.length&&console.info(` env: ${o.join(", ")}`)}else{console.info(` [${r.key}] ${r.name}: ${r.url}`);let o=r.headers?Object.keys(r.headers):[];o.length&&console.info(` headers: ${o.join(", ")}`)}}var
|
|
90
|
-
Revoke a device anytime from GAIA \u2192 Settings \u2192 Devices.`);
|
|
91
|
-
`)){let[o,...n]=r.trim().split(/\s+/);if(n.join(" ").replace(/^\*/,"")===t&&o!==void 0)return o.toLowerCase()}throw new Error(`${
|
|
86
|
+
Logs: ${ml}
|
|
87
|
+
Stop: gaia bridge down`)}async function hl(){let e=$e();if(!e?.refreshToken)throw new Error("not paired \u2014 run: gaia bridge login");let t=new Br(e),r=async()=>{await t.stop(),process.exit(0)};process.on("SIGINT",()=>void r()),process.on("SIGTERM",()=>void r()),await t.run()}import{basename as wl}from"node:path";import{resolve as _g}from"node:path";function $i(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)}function Li(e){let t=[],r="",o=null;for(let s of e.trim())o?s===o?o=null:r+=s:s==='"'||s==="'"?o=s:/\s/.test(s)?r&&(t.push(r),r=""):r+=s;r&&t.push(r);let[n,...i]=t;if(!n)throw new Error("Empty command");return{command:n,args:i}}function Sl(e,t,r){let o={};for(let n of e??[]){let i=n.indexOf(t);if(i<=0)throw new Error(`invalid ${r} '${n}', expected KEY${t}VALUE`);o[n.slice(0,i).trim()]=n.slice(i+1)}return o}function vl(e){let t=$i(e??"");if(!e||!t||t===Ot)throw new Error("--name is required and must contain letters or digits");return t}function yl(e){if(e.type==="stdio"){if(!e.command)throw new Error("--command is required for --type stdio");let{command:t,args:r}=Li(e.command);return{type:"stdio",key:vl(e.name),name:e.name,command:t,args:r,env:Sl(e.env,"=","--env")}}if(e.type==="url"){if(!e.url)throw new Error("--url is required for --type url");at(e.url);let t=Sl(e.header,":","--header");return Object.keys(t).length>0&&new URL(e.url).protocol==="http:"&&console.warn("warning: --header values travel unencrypted over local HTTP \u2014 prefer an https: URL for credential headers"),{type:"url",key:vl(e.name),name:e.name,url:e.url,...Object.keys(t).length?{headers:t}:{}}}if(e.type==="filesystem"){let t=e.path??[];if(t.length===0)throw new Error("--path is required for --type filesystem");let r=t.includes(Do)?[Do]:t.map(o=>_g(Ei(o)));return xi(r,!!e.write)}throw new Error("--type must be one of: stdio, url, filesystem")}function Dg(e,t){let o=[...t].reverse().filter(n=>!n.startsWith("-"))[0]??e;return wl(o).replace(/@[^@]*$/,"")}function Og(e){try{let t=new URL(e);return t.port?`local-${t.port}`:t.hostname}catch{return""}}async function bl(e){for(;;){let t=await it("Name for this server",e),r=$i(t);if(!t||!r||r===Ot){console.info("Pick a different name.");continue}if(!(Q().servers.some(o=>o.key===r)&&!await st(`'${r}' already exists \u2014 overwrite?`,!1)))return{name:t,key:r}}}function $g(e,t){if(wl(e)!=="docker")return[];let r=[];for(let o=0;o<t.length;o++){let n=t[o];if(n!==void 0)if(n==="-e"||n==="--env"){let i=t[o+1];i&&!i.includes("=")&&r.push(i)}else n.startsWith("-e")&&n.length>2&&!n.includes("=")&&r.push(n.slice(2))}return[...new Set(r)]}async function Mi(e){let t=process.env[e];if(t!==void 0&&t!==""&&await st(` Found ${e} in your environment \u2014 use that value?`,!0))return t;for(;;){let r=await Po(` Paste ${e}`);if(r)return console.info(` Got it (${r.length} characters).`),r;console.info(" Empty \u2014 paste the value, or Ctrl+C to abort.")}}async function El(e,t){let r={};for(let n of $g(e,t))console.info(`
|
|
88
|
+
The command needs ${n}.`),r[n]=await Mi(n);let o=Object.keys(r).length?"Any other environment variables to add?":"Does the server need environment variables (API keys, tokens\u2026)?";if(!await st(o,!1))return r;for(console.info("Enter each variable's name; leave blank when done.");;){let n=(await it(" Variable name")).trim();if(!n)break;if(n in r){console.info(" Already added.");continue}r[n]=await Mi(n)}return r}async function Lg(){console.info(`
|
|
89
|
+
Examples: npx -y my-mcp-server \xB7 uvx my-server \xB7 docker run -i --rm my/image`);let e=await it("Command that starts your MCP server");if(!e)throw new Error("a command is required");let{command:t,args:r}=Li(e),o=await El(t,r),{name:n,key:i}=await bl(Dg(t,r));return{type:"stdio",key:i,name:n,command:t,args:r,env:o}}async function Mg(){let e={};if(!await st("Does the server need request headers (e.g. Authorization)?",!1))return e;for(console.info("Enter each header's name; leave blank when done.");;){let t=(await it(" Header name")).trim();if(!t)break;if(t in e){console.info(" Already added.");continue}e[t]=await Mi(t)}return e}async function Ng(){let e=await it("Server URL (e.g. http://localhost:3000/mcp)");if(!e)throw new Error("a URL is required");at(e);let t=await Mg();if(Object.keys(t).length>0&&new URL(e).protocol==="http:"&&(console.info(`
|
|
90
|
+
Heads up: these headers travel unencrypted over local HTTP. Anyone else on this machine (or the receiving server's logs) can read them.`),!await st("Send these headers over unencrypted HTTP anyway?",!1)))throw new Error("aborted \u2014 use an https: URL or drop the headers");let{name:r,key:o}=await bl(Og(e));return{type:"url",key:o,name:r,url:e,...Object.keys(t).length?{headers:t}:{}}}async function Fg(e){for(;;){console.info(`
|
|
91
|
+
Testing the connection (this may download/start the server)\u2026`);try{let t=await No(e),r=t.slice(0,5).join(", ");return console.info(`Connected \u2014 ${t.length} tools found${r?` (${r}${t.length>5?", \u2026":""})`:""}.`),!0}catch(t){console.error(`Connection failed: ${t instanceof Error?t.message:t}`);let r=["Retry the test"];e.type==="stdio"&&r.push("Re-enter environment variables"),r.push("Save anyway (fix it later)","Abort");let o=r[await _o("What now?",r)];if(o==="Re-enter environment variables"&&e.type==="stdio")e.env=await El(e.command,e.args);else{if(o==="Save anyway (fix it later)")return!0;if(o==="Abort")return!1}}}}async function Bg(e){let t=yl(e),r;try{r=await No(t)}catch(o){throw new Error(`Could not start '${t.key}': ${o instanceof Error?o.message:o}`)}Bo(t),await nr(),console.info(`Saved '${t.key}' (${r.length} tools) and registered with GAIA. A running 'gaia bridge up' daemon serves it automatically; otherwise start one.`)}async function xl(e={}){if(!Ti()){if(e.type)throw new Error("This device isn't paired yet. Run `gaia bridge login` on it first.");console.info("This device isn't paired with GAIA yet, let's do that first."),await or()}if(e.type){await Bg(e);return}let r=await _o("What do you want to connect?",["A command starts an MCP server (stdio) \u2014 npx / uvx / docker / python \u2026","An MCP server already running at a local URL \u2014 e.g. http://localhost:3000/mcp"])===0?await Lg():await Ng();if(!await Fg(r))throw new Error("aborted");Bo(r),console.info(`
|
|
92
|
+
Saved '${r.key}'.`);try{await nr(),console.info("Registered with GAIA.")}catch(o){console.error(`Could not register with GAIA (will retry on \`gaia bridge up\`): ${o instanceof Error?o.message:o}`)}await st("Keep this device connected in the background now?")?await Uo():console.info("Run `gaia bridge up` whenever you're ready.")}function Gg(e){let t=e.type==="url"?e.url:e.type==="stdio"?e.command:e.allow.join(", ");return`${e.name} \u2014 ${e.type} (${t})`}async function Cl(e){if(e){let n=await Ai(e);console.info(n?`Removed '${e}' from this device and GAIA.`:`No server '${e}'.`);return}let t=Q().servers;if(t.length===0){console.info("No servers configured \u2014 nothing to remove.");return}let r=await _o("Which server do you want to remove?",t.map(Gg)),o=t[r];if(o){if(!await st(`Remove '${o.key}'?`,!1)){console.info("Left it in place.");return}await Ai(o.key),console.info(`Removed '${o.key}'. The tunnel stops serving it right away, and GAIA drops it too.`)}}function jg(){let e=$e();console.info(e?.deviceId?`Paired (device ${e.deviceId}, ${Nr()})`:"Not paired \u2014 run: gaia bridge login"),console.info(fl());let t=Q().servers;if(t.length===0){console.info("No servers configured \u2014 run: gaia bridge add");return}console.info(`
|
|
93
|
+
Configured servers:`);for(let r of t)if(r.type==="filesystem")console.info(` [${r.key}] filesystem${r.allowWrite?" (rw)":" (ro)"}: ${r.allow.join(", ")}`);else if(r.type==="stdio"){let o=Object.keys(r.env);console.info(` [${r.key}] ${r.name}: ${r.command} ${r.args.join(" ")}`),o.length&&console.info(` env: ${o.join(", ")}`)}else{console.info(` [${r.key}] ${r.name}: ${r.url}`);let o=r.headers?Object.keys(r.headers):[];o.length&&console.info(` headers: ${o.join(", ")}`)}}var Ve=new Ug("bridge").description(U.bridge).addHelpText("after",`
|
|
94
|
+
Revoke a device anytime from GAIA \u2192 Settings \u2192 Devices.`);Ve.command("add").description("Connect a local MCP server (guided; or non-interactive with --type)").option("--type <type>","stdio | url \u2014 enables non-interactive mode (no prompts)").option("--name <name>","display name").option("--command <command>","stdio: the command that starts the server").option("--url <url>","url: the local MCP server URL").option("--env <pair...>","stdio: KEY=VALUE env var (repeatable)").option("--header <pair...>","url: Header:Value request header (repeatable)").action(async e=>{await ie(()=>xl(e))});Ve.command("login").description("Pair this machine with your GAIA account").option("--api <url>","GAIA API base URL (default: this machine's self-host install, else GAIA Cloud)").option("--name <name>","Name to show for this device in Settings").action(async e=>{await ie(async()=>{await or({...e.api!==void 0?{api:e.api}:{},...e.name!==void 0?{name:e.name}:{}}),console.info("Next: gaia bridge add")})});Ve.command("ls").alias("list").description("Show pairing status and configured servers").action(async()=>{await ie(jg)});Ve.command("remove").alias("rm").description("Remove a configured server (interactive picker if no key given)").argument("[key]","Server key from `gaia bridge ls` (optional)").action(async e=>{await ie(()=>Cl(e))});Ve.command("up").alias("start").description("Connect with full file access + serve in the background (stop with: gaia bridge down)").option("--serve","(internal) hold the tunnel in the foreground; used by the background daemon").action(async e=>{await ie(e.serve?hl:Uo)});Ve.command("down").alias("stop").description("Stop the background tunnel started by `gaia bridge up`").action(async()=>{await ie(gl)});Ve.command("logout").description("Forget local credentials").action(async()=>{await ie(()=>{Lr(),console.info("Logged out. Your device record remains until you revoke it in GAIA settings.")})});import{Command as zg}from"commander";import{createHash as Hg}from"node:crypto";import*as he from"node:fs/promises";import*as _l from"node:path";import*as kl from"node:os";import*as Rl from"node:path";var qg="https://github.com/theexperiencecompany/gaia/releases/download",jo=`cli-v${$}`,Ni="gaia-connect-SHA256SUMS",Il={"darwin-arm64":"gaia-connect-darwin-arm64","darwin-x64":"gaia-connect-darwin-amd64","linux-x64":"gaia-connect-linux-amd64","linux-arm64":"gaia-connect-linux-arm64","win32-x64":"gaia-connect-windows-amd64.exe"};function Tl(e,t){let r=Il[`${e}-${t}`];if(r===void 0)throw new Error(`gaia connect is not available for ${e}/${t}. Supported: ${Object.keys(Il).join(", ")}.`);return r}function Fi(e){return`${qg}/${jo}/${e}`}function Al(e){let t=e==="win32"?".exe":"";return Rl.join(kl.homedir(),".gaia","bin",`gaia-connect-${$}${t}`)}async function Pl(e){let t=await fetch(e);if(!t.ok)throw new Error(`Download failed (${t.status} ${t.statusText}): ${e}`);return Buffer.from(await t.arrayBuffer())}function Vg(e,t){for(let r of e.split(`
|
|
95
|
+
`)){let[o,...n]=r.trim().split(/\s+/);if(n.join(" ").replace(/^\*/,"")===t&&o!==void 0)return o.toLowerCase()}throw new Error(`${Ni} on release ${jo} has no entry for ${t}.`)}function Wg(e){return Hg("sha256").update(e).digest("hex")}async function Kg(e){try{return await he.access(e),!0}catch{return!1}}async function Dl(e,t){let r=Al(e);if(await Kg(r))return r;let o=Tl(e,t);console.info(`Downloading gaia-connect (${jo})\u2026`);let[n,i]=await Promise.all([Pl(Fi(o)),Pl(Fi(Ni)).then(l=>l.toString("utf-8"))]),s=Vg(i,o),a=Wg(n);if(a!==s)throw new Error(`Checksum mismatch for ${o}: expected ${s}, got ${a}. Refusing to run the download.`);await he.mkdir(_l.dirname(r),{recursive:!0});let c=`${r}.${process.pid}.tmp`;try{await he.writeFile(c,n),e!=="win32"&&await he.chmod(c,448),await he.rename(c,r)}catch(l){throw await he.rm(c,{force:!0}),l}return r}import{spawn as Yg}from"node:child_process";async function Ol(e,t){return await new Promise((r,o)=>{let n=Yg(e,t,{stdio:"inherit",shell:!1}),i=s=>{n.kill(s)};process.on("SIGINT",i),process.on("SIGTERM",i),n.on("error",s=>{process.off("SIGINT",i),process.off("SIGTERM",i),o(s)}),n.on("close",(s,a)=>{if(process.off("SIGINT",i),process.off("SIGTERM",i),a==="SIGINT"||a==="SIGTERM"){r(0);return}r(s??1)})})}async function Xg(e){let t=await Dl(process.platform,process.arch);return await Ol(t,e)}var $l=new zg("connect").description(U.connect).allowUnknownOption().allowExcessArguments().argument("[args...]","flags forwarded to gaia-connect").addHelpText("after",`
|
|
92
96
|
Get an import code from GAIA -> Settings -> Browser -> Import, then run:
|
|
93
97
|
npx @heygaia/cli connect --token <code>
|
|
94
98
|
|
|
@@ -100,40 +104,42 @@ Flags forwarded to gaia-connect:
|
|
|
100
104
|
--sites <domains> comma-separated domains to sync (default: all)
|
|
101
105
|
--json robot mode: no TUI, structured JSON on stdout
|
|
102
106
|
--list with --json: list browsers, or sessions with --browser
|
|
103
|
-
`).action(
|
|
104
|
-
`)},process.platform!=="win32")}finally{try{
|
|
105
|
-
`).filter(i=>i.trim().length>0).at(-1);if(!r)return null;let o=r.trim().split(/\s+/),n=Number(o[3]);return!Number.isFinite(n)||n<0?null:n}async function
|
|
106
|
-
`)}var
|
|
107
|
-
`)})})};import{Spinner as
|
|
108
|
-
`),o=Bo();return q(j,{flexDirection:"column",borderStyle:I,borderColor:"red",paddingX:1,marginTop:1,width:o,children:[q(j,{children:[x(ie,{kind:"fail"}),x(P,{bold:!0,children:t})]}),x(j,{flexDirection:"column",marginLeft:2,children:r.map(n=>x(P,{color:n.startsWith("Full log:")?"gray":void 0,children:n},n))})]})},nh={success:"ok",error:"fail",missing:"warn"},$i=({label:e,status:t})=>q(j,{children:[t==="pending"?x(j,{marginRight:1,children:x(Gl,{type:"dots"})}):x(ie,{kind:nh[t]}),x(P,{children:e})]}),tr=({portResults:e,onAccept:t,onAbort:r})=>{Ul((n,i)=>{i.return?t():i.escape&&r()});let o=e.filter(n=>!n.available);return q(j,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:"yellow",children:[x(j,{marginBottom:1,children:x(P,{bold:!0,color:"yellow",children:"Port Conflicts Detected"})}),e.map(n=>q(j,{children:[q(P,{color:n.available?"green":n.alternative?"yellow":"red",children:[n.available?b.ok:n.alternative?b.warn:b.fail," "]}),q(P,{children:[n.service," (:",n.port,")"]}),!n.available&&q(P,{color:n.alternative?"gray":"red",children:[" ","- in use",n.usedBy?` by ${n.usedBy}`:"",n.alternative?` \u2192 will use :${n.alternative}`:" \u2014 NO ALTERNATIVE FOUND"]})]},n.port)),o.some(n=>!n.alternative)&&x(j,{marginTop:1,children:x(P,{color:"red",children:"Some ports have no available alternative. Free them and retry."})}),!o.some(n=>!n.alternative)&&o.some(n=>n.alternative)&&x(j,{marginTop:1,children:x(P,{color:"gray",children:"Alternative ports will be used for conflicting services."})}),x(j,{marginTop:1,children:q(P,{dimColor:!0,children:[x(P,{bold:!0,children:"Enter"})," continue \xB7 ",x(P,{bold:!0,children:"Esc"})," cancel"]})})]})},ih=({missing:e,onConfirm:t,onDecline:r})=>{Ul((i,s)=>{s.return&&t(),s.escape&&r()});let o=e.length>1?"them":"it",n=e.length>1?"aren't":"isn't";return q(j,{flexDirection:"column",marginTop:1,marginLeft:2,children:[q(P,{children:["GAIA needs ",x(P,{bold:!0,children:Xn(e)}),", which ",n," ","installed yet."]}),q(P,{children:["Install ",o," now? This uses sudo and takes a few minutes."]}),q(j,{marginTop:1,children:[x(P,{color:y,bold:!0,children:"Enter"}),q(P,{children:[" install ",o]}),x(P,{color:"gray",children:" \xB7 "}),x(P,{bold:!0,children:"Esc"}),x(P,{children:" I'll do it myself"})]})]})},rr=({inputId:e,missing:t,onConfirm:r,onDecline:o})=>e!==Yn||!t?.length?null:x(ih,{missing:t,onConfirm:r,onDecline:o});import{useEffect as sh,useState as ah}from"react";function _e(e){let[t,r]=ah(e.currentState);return sh(()=>{let o=()=>r({...e.currentState});return e.on("change",o),()=>{e.off("change",o)}},[e]),t}import*as Hl from"node:path";var Mi=["openrouter","gemini","openai","ollama","custom"],ch={openrouter:{key:"required",baseUrl:"unused",model:"unused"},gemini:{key:"required",baseUrl:"unused",model:"unused"},openai:{key:"required",baseUrl:"unused",model:"unused"},ollama:{key:"unused",baseUrl:"optional",model:"optional"},custom:{key:"required",baseUrl:"required",model:"required"}},jo={key:"--llm-key",baseUrl:"--llm-base-url",model:"--llm-model"};function Li(e,t){let r={key:e.llmKey,baseUrl:e.llmBaseUrl,model:e.llmModel}[t];return r!==void 0&&r!==""}function Vl(e){let t=Object.keys(jo);if(!e.llmProvider){let o=t.find(n=>Li(e,n));if(o)throw new Error(`${jo[o]} requires --llm-provider <${Mi.join("|")}>.`);return}let r=e.llmProvider;for(let o of t){let n=ch[r][o];if(n==="required"&&!Li(e,o))throw new Error(`--llm-provider ${r} requires ${jo[o]}.`);if(n==="unused"&&Li(e,o))throw new Error(`${jo[o]} is not used with --llm-provider ${r}.`)}if(e.noStart)throw new Error("--llm-provider saves the provider into the running instance, so it cannot be combined with --no-start. Drop --no-start, or configure the provider in the web setup wizard later.")}function lh(e){let t=["--provider",e.llmProvider];return e.llmBaseUrl&&t.push("--base-url",e.llmBaseUrl),e.llmModel&&t.push("--model",e.llmModel),t}var ql="GAIA_PROVIDER_API_KEY",_r={openrouter:"OpenRouter",gemini:"Gemini",openai:"OpenAI",ollama:"Ollama",custom:"custom provider"},uh=/Could not save \w+: (.+)/;async function Wl(e,t){let r=Hl.join(e,"infra/docker");try{await J("docker",[...Mn(r),"exec","-T","-e",ql,"gaia-backend","python","-m","app.scripts.save_provider",...lh(t)],r,void 0,void 0,{[ql]:t.llmKey??""})}catch(o){let n=uh.exec(o.message)?.[1];throw n?new Error(n,{cause:o}):o}}var qo=[["gaia status","check health"],["gaia stop","stop GAIA"],["gaia doctor","find problems"],["gaia --help","all commands"]],dh="Your user was added to the 'docker' group. Other terminals get it after you log out and back in (or run 'newgrp docker'); until then, 'gaia status' there can't reach Docker.";function ph(e){return e.noStart?"GAIA is set up \xB7 nothing was started":e.stillStarting?"GAIA is still starting":e.startedServices===0?"GAIA is already running \xB7 nothing to do":`GAIA is running \xB7 ready in ${Kt(e.elapsedMs)}`}function mh(e){return e?"on, in local containers on this machine":"off \xB7 turn on: gaia up --code-sandbox, or add an E2B key in Settings"}function Ho(e){let t=[];if(e.noStart)t.push({label:"Next",text:"Start it with gaia start",tone:"primary"});else{e.stillStarting&&t.push({label:"Status",text:"It is still starting in the background. Check again with gaia status.",tone:"warn"});let r=`${e.webUrl}/setup`;t.push(e.setupComplete?{label:"Next",text:`Open ${e.webUrl}`,url:e.webUrl,tone:"primary"}:{label:"Next",text:`Open ${r} to create your admin account and pick an AI model.`,url:r,tone:"primary"});let o=e.reachableUrls.filter(n=>n!==e.webUrl);o.length>0&&t.push({label:"Also at",text:o.join(", "),tone:"dim"})}return e.savedProvider&&t.push({label:"AI",text:`${_r[e.savedProvider]} key saved \xB7 change it in Settings`}),t.push({label:"Code execution",text:mh(e.codeSandbox),tone:"dim"}),e.joinedDockerGroup&&t.push({label:"Docker",text:dh,tone:"warn"}),{tone:e.noStart||e.stillStarting?"pending":"success",headline:ph(e),rows:t}}import{jsx as V,jsxs as nt}from"react/jsx-runtime";var fh=16,gh=14,Kl=30,hh={primary:void 0,warn:"yellow",dim:"gray"},Sh=({row:e})=>{let t=e.tone?hh[e.tone]:void 0;if(!e.url)return V(it,{color:t,children:e.text});let[r,o]=e.text.split(e.url);return nt(it,{color:t,children:[r,V(it,{color:"cyan",bold:!0,underline:!0,children:e.url}),o]})},vh=({outcome:e})=>{let t=Ho(e),r=t.tone==="success"?"green":y,o=Bo();return nt(De,{flexDirection:"column",marginTop:1,children:[nt(De,{flexDirection:"column",borderStyle:I,borderColor:r,paddingX:2,paddingY:1,width:o,children:[nt(it,{bold:!0,color:r,children:[t.tone==="success"?`${b.ok} `:"",t.headline]}),V(De,{flexDirection:"column",marginTop:1,children:t.rows.map(n=>nt(De,{marginBottom:n.tone==="primary"?1:0,children:[V(De,{width:fh,flexShrink:0,children:V(it,{bold:n.tone==="primary",children:n.label})}),V(Sh,{row:n})]},n.label))})]}),V(De,{flexDirection:"row",flexWrap:"wrap",marginTop:1,paddingX:2,width:Kl*2+4,children:qo.map(([n,i])=>nt(De,{width:Kl,children:[V(De,{width:gh,children:V(it,{color:y,children:n})}),V(it,{color:"gray",children:i})]},n))})]})},yh=({state:e,store:t})=>e.inputRequest?.id==="port_conflicts"?e.data.portConflicts?V(tr,{portResults:e.data.portConflicts,onAccept:()=>t.submitInput("accept"),onAbort:()=>t.submitInput("abort")}):null:V(rr,{inputId:e.inputRequest?.id,missing:e.data[It],onConfirm:()=>t.submitInput("install"),onDecline:()=>t.submitInput("decline")}),Yl=({store:e})=>{let t=_e(e),r=t.data.steps??[],o=t.data.upOutcome,n=t.data.logPath,i=t.data.finished===!0&&o!==void 0;return nt(De,{flexDirection:"column",width:"100%",children:[V(rt,{size:"large",showStatus:!1}),V(Bl,{steps:r,waiting:t.inputRequest!==null,status:t.status}),V(yh,{state:t,store:e}),n&&!i&&V(De,{marginTop:1,marginLeft:2,children:nt(it,{color:"gray",children:["Full log: ",n]})}),i&&V(vh,{outcome:o}),t.error&&V(Ae,{message:t.error.message})]})};import{Select as Bi,Spinner as _h}from"@inkjs/ui";import{Box as h,Text as f,useInput as or}from"ink";import Or from"ink-text-input";import{useEffect as Gi,useState as ce}from"react";import{Box as wh,Text as Fi,useInput as bh}from"ink";import{useEffect as Eh,useRef as xh,useState as Ch}from"react";import{jsx as Ih,jsxs as Ni}from"react/jsx-runtime";var Xl=8;function zl(e,t){return`${e} ${t}${e===1?"":"s"}`}var Vo=({logs:e})=>{let[t,r]=Ch(0),o=Math.min(e.length,Xl),n=e.length>Xl,i=xh(e.length);Eh(()=>{e.length!==i.current&&(i.current=e.length,r(0))},[e.length]),bh((c,l)=>{n&&(l.upArrow?r(d=>Math.min(d+1,e.length-o)):l.downArrow&&r(d=>Math.max(0,d-1)))});let s=Math.max(0,e.length-o-t),a=e.slice(s,s+o);return Ni(wh,{flexDirection:"column",marginTop:1,marginLeft:1,children:[s>0&&Ni(Fi,{color:"gray",children:[zl(s,"earlier line")," (\u2191 to scroll)"]}),a.map((c,l)=>Ih(Fi,{color:"gray",wrap:"truncate",children:c},s+l)),t>0&&Ni(Fi,{color:"gray",children:[zl(t,"newer line")," (\u2193)"]})]})};import{Box as Dr,Text as Wo}from"ink";import{Box as kh,Text as Rh}from"ink";import{jsx as Ql}from"react/jsx-runtime";var Th=new Set(["Welcome","Finished"]),Jl=({status:e,step:t})=>Th.has(t)?null:Ql(kh,{width:"100%",paddingX:1,marginTop:1,children:Ql(Rh,{color:"gray",dimColor:!0,children:e})});import{jsx as st,jsxs as Ko}from"react/jsx-runtime";var Ph=[{id:"Welcome",label:"Welcome"},{id:"Prerequisites",label:"Prereqs"},{id:"Setup Mode",label:"Mode"},{id:"Repository Setup",label:"Repo"},{id:"Environment Setup",label:"Env"},{id:"Install Tools",label:"Tools"},{id:"Project Setup",label:"Setup"},{id:"Finished",label:"Done"}],Zl=[{id:"Detect Repo",label:"Detect"},{id:"Prerequisites",label:"Prereqs"},{id:"Environment Setup",label:"Env"},{id:"Project Setup",label:"Setup"},{id:"Finished",label:"Done"}],Ah=({currentStep:e,steps:t})=>{let r=t.findIndex(n=>n.id===e),o=r===t.length-1;return st(Dr,{marginBottom:1,flexWrap:"wrap",children:t.map(({id:n,label:i},s)=>{let a=s<r||o,c=s===r&&!o;return Ko(Dr,{flexShrink:0,children:[s>0&&st(Wo,{color:"gray",children:" \xB7 "}),a&&Ko(Wo,{color:"green",children:[b.ok," ",i]}),c&&st(Wo,{color:y,bold:!0,children:i}),!a&&!c&&st(Wo,{color:"gray",children:i})]},n)})})},Yo=({children:e,status:t,step:r,steps:o=Ph,header:n})=>Ko(Dr,{flexDirection:"column",height:"100%",width:"100%",children:[Ko(Dr,{flexGrow:1,flexDirection:"column",children:[st(rt,{...n}),st(Ah,{currentStep:r,steps:o}),st(Dr,{flexDirection:"column",flexGrow:1,children:e})]}),st(Jl,{status:t,step:r})]});import{jsx as u,jsxs as S}from"react/jsx-runtime";var Dh=({onConfirm:e})=>(or((t,r)=>{r.return&&e()}),S(h,{flexDirection:"column",paddingX:2,borderStyle:I,borderColor:y,children:[u(f,{bold:!0,children:"Welcome to GAIA Setup"}),S(h,{flexDirection:"column",marginTop:1,marginBottom:1,children:[u(f,{children:"This wizard will guide you through the setup process:"}),u(f,{children:" 1. Check prerequisites and choose setup mode"}),u(f,{children:" 2. Clone repository"}),u(f,{children:" 3. Configure environment variables"}),u(f,{children:" 4. Install tools and dependencies"})]}),u(f,{dimColor:!0,children:"~5-15 min depending on network speed"}),u(h,{marginTop:1,children:S(f,{color:y,children:[u(f,{bold:!0,children:"Enter"})," to start"]})})]})),Oh=({defaultValue:e,onSubmit:t})=>{let[r,o]=ce(e);return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:y,children:[u(f,{children:"Clone repository to:"}),u(f,{color:"gray",dimColor:!0,children:"Press Enter for default, or type a custom path"}),S(h,{marginTop:1,children:[u(f,{color:y,children:"\u2192 "}),u(Or,{value:r,onChange:o,onSubmit:t})]})]})},$h=({repoPath:e,onAction:t})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:"yellow",children:[u(h,{marginBottom:1,children:u(f,{bold:!0,color:"yellow",children:"Existing Installation Found"})}),S(f,{children:["Found a GAIA installation at"," ",u(f,{color:"cyan",bold:!0,children:e})]}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"What would you like to do?"})}),u(h,{marginTop:1,children:u(Bi,{options:[{label:"Use existing installation",value:"use_existing"},{label:"Delete and re-clone",value:"delete_reclone"},{label:"Choose a different path",value:"different_path"},{label:"Exit setup",value:"exit"}],onChange:o=>t(o)})})]}),Lh=({setupMode:e,portOverrides:t,stillStarting:r,onConfirm:o})=>{or((s,a)=>{a.return&&o()});let n=t?.[3e3]??3e3,i=ne(e??"developer",t??{});return e==="selfhost"?S(h,{flexDirection:"column",marginTop:2,borderStyle:I,borderColor:"green",padding:1,children:[u(f,{bold:!0,color:"green",children:r?"GAIA is starting\u2026":"GAIA is running"}),u(h,{marginTop:1,children:u(f,{color:"green",children:r?"Containers are up but not answering yet":"\u2713 All services started"})}),S(h,{marginTop:1,flexDirection:"column",children:[S(f,{children:["Finish setup in your browser:"," ",S(f,{color:"cyan",bold:!0,children:["http://localhost:",n,"/setup"]})]}),S(f,{children:["Web:"," ",S(f,{color:"cyan",bold:!0,children:["http://localhost:",n]})]}),S(f,{children:["API:"," ",u(f,{color:"cyan",bold:!0,children:i})]})]}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia doctor"})}),u(h,{marginTop:1,children:S(f,{dimColor:!0,children:[u(f,{bold:!0,children:"Enter"})," to exit"]})})]}):S(h,{flexDirection:"column",marginTop:2,borderStyle:I,borderColor:y,padding:1,children:[u(f,{color:y,bold:!0,children:"You're all set!"}),S(h,{marginTop:1,children:[u(f,{bold:!0,children:"Run: "}),u(f,{color:"cyan",children:"$ gaia dev"})]}),S(h,{marginTop:1,flexDirection:"column",children:[S(f,{children:["Web:"," ",S(f,{color:"cyan",bold:!0,children:["http://localhost:",n]})]}),S(f,{children:["API:"," ",u(f,{color:"cyan",bold:!0,children:i})]})]}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"gaia dev full \xB7 gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup"})}),u(h,{marginTop:1,children:S(f,{dimColor:!0,children:[u(f,{bold:!0,children:"Enter"})," to exit"]})})]})},Ui=({phase:e,progress:t,isComplete:r,logs:o,title:n,hint:i})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:y,children:[u(h,{marginBottom:1,children:u(f,{bold:!0,color:y,children:n||"Installing Dependencies"})}),S(h,{flexDirection:"column",gap:1,children:[u(h,{children:r?S(f,{color:"green",children:[b.ok," ",e]}):u(_h,{label:e||"Preparing\u2026"})}),!r&&t>0&&u(er,{percent:t}),!r&&o&&o.length>0&&u(Vo,{logs:o}),!r&&u(h,{marginTop:1,children:u(f,{color:"gray",dimColor:!0,children:i||"This may take a few minutes\u2026"})})]})]}),ji=({onSelect:e})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:y,children:[u(f,{bold:!0,children:"Setup Mode"}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"How do you want to run GAIA?"})}),u(h,{marginTop:1,children:u(Bi,{options:[{label:"Self-Host \u2014 run everything in Docker",value:"selfhost"},{label:"Developer \u2014 local dev with hot reload",value:"developer"}],onChange:r=>e(r)})})]}),qi=({onSelect:e})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:y,children:[u(f,{bold:!0,children:"Environment Variables Setup"}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"Choose how you want to configure environment variables:"})}),u(h,{marginTop:1,children:u(Bi,{options:[{label:"Manual Setup (Recommended)",value:"manual"},{label:"Infisical (Advanced)",value:"infisical"}],onChange:r=>e(r)})}),S(h,{marginTop:1,flexDirection:"column",children:[u(f,{color:"gray",dimColor:!0,children:"Manual Setup: Configure variables interactively (recommended for most users)"}),u(f,{color:"gray",dimColor:!0,children:"Infisical: All secrets managed in Infisical dashboard (requires pre-configuration)"})]})]}),Hi=({onSubmit:e})=>{let[t,r]=ce({INFISICAL_PROJECT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET:""}),[o,n]=ce(0),[i,s]=ce(null),a=[{key:"INFISICAL_PROJECT_ID",description:"Found in your Infisical project settings"},{key:"INFISICAL_MACHINE_IDENTITY_CLIENT_ID",description:"From Access Control \u2192 Machine Identities"},{key:"INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET",description:"Generated when creating the machine identity"}];or((l,d)=>{if(d.tab||d.downArrow)n(p=>p<a.length-1?p+1:p);else if(d.upArrow)n(p=>p>0?p-1:p);else if(d.return){if(o<a.length-1){n(m=>m+1);return}let p=a.filter(m=>!t[m.key].trim());if(p.length>0){s(`Required: ${p.map(g=>g.key).join(", ")}`);let m=a.findIndex(g=>!t[g.key].trim());m>=0&&n(m);return}e(t)}});let c=a[o];return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:y,children:[u(h,{marginBottom:1,children:u(f,{bold:!0,color:y,children:"Infisical Configuration"})}),u(h,{marginBottom:1,children:u(f,{color:"gray",children:"All secrets managed in your Infisical project. Only credentials stored locally."})}),S(h,{marginBottom:1,flexDirection:"column",children:[u(f,{color:"gray",children:"Configure your Infisical credentials."}),S(f,{color:"gray",dimColor:!0,children:["Visit"," ",u(f,{color:"cyan",underline:!0,children:"app.infisical.com"})," ","to get these values."]})]}),a.map((l,d)=>{let p=l.key.includes("SECRET")||l.key.includes("TOKEN");return S(h,{flexDirection:"column",marginBottom:1,children:[u(h,{children:S(f,{color:d===o?y:"white",children:[d===o?"\u25B8 ":" ",l.key,":"]})}),u(h,{marginLeft:2,children:u(f,{color:"gray",dimColor:!0,children:l.description})}),d===o?u(h,{marginLeft:2,children:u(Or,{value:t[l.key],onChange:m=>{r(g=>({...g,[l.key]:m})),s(null)},placeholder:"Enter value\u2026",mask:p?"*":void 0})}):u(h,{marginLeft:2,children:u(f,{color:t[l.key]?"green":"gray",children:t[l.key]?p?`\u2713 ${"*".repeat(8)}`:`\u2713 ${t[l.key]}`:"(not set)"})})]},l.key)}),i&&u(h,{marginTop:1,children:u(f,{color:"red",children:i})}),u(h,{marginTop:1,children:S(f,{dimColor:!0,children:[u(f,{bold:!0,children:"Enter"})," confirm \xB7 ",u(f,{bold:!0,children:"\u2191\u2193"})," navigate"]})})]})},Vi=({category:e,currentIndex:t,totalGroups:r,onSubmit:o})=>{let[n,i]=ce(()=>{let m={};for(let g of e.variables)m[g.name]=g.defaultValue||"";return m}),[s,a]=ce(0),[c,l]=ce(null);Gi(()=>{let m={};for(let g of e.variables)m[g.name]=g.defaultValue||"";i(m),a(0),l(null)},[e.name]),or((m,g)=>{if(g.tab||g.downArrow)a(v=>v<e.variables.length-1?v+1:v);else if(g.upArrow)a(v=>v>0?v-1:v);else if(g.escape){let v=e.variables.filter(E=>E.required&&!n[E.name]?.trim());if(v.length>0){l(`Required fields cannot be skipped: ${v.map(E=>E.name).join(", ")}`);return}o(n)}});let d=()=>{if(s<e.variables.length-1)a(s+1);else{let m=e.variables.filter(g=>g.required&&!n[g.name]?.trim());if(m.length>0){l(`Required fields are missing: ${m.map(g=>g.name).join(", ")}`);return}l(null),o(n)}},p=e.variables.some(m=>m.required);return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:c?"red":y,children:[S(h,{justifyContent:"space-between",children:[S(f,{bold:!0,children:["Configure ",e.name]}),S(f,{color:"gray",children:["Group ",t+1," / ",r]})]}),u(h,{marginTop:1,children:u(f,{color:"gray",children:e.description})}),u(h,{marginTop:1,flexDirection:"column",children:e.variables.map((m,g)=>{let v=g===s,E=!!m.defaultValue;return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[S(f,{color:v?y:"gray",bold:v,children:[v?"\u279C ":" ",m.name]}),m.required&&S(f,{color:"red",bold:!0,children:[" ","*"]}),E&&!v&&S(f,{color:"gray",dimColor:!0,children:[" ","(default: ",m.defaultValue,")"]})]}),v&&u(h,{marginLeft:2,children:u(Or,{value:n[m.name]||"",onChange:w=>{i(C=>({...C,[m.name]:w})),c&&l(null)},onSubmit:d,placeholder:E?`Default: ${m.defaultValue}`:m.required?"Enter a value (required)":"Press Enter to skip"})})]},m.name)})}),c&&u(h,{marginTop:1,children:S(f,{color:"red",bold:!0,children:[b.warn," ",c]})}),u(h,{marginTop:1,children:S(f,{dimColor:!0,children:[u(f,{bold:!0,children:"Enter"})," next \xB7 ",u(f,{bold:!0,children:"\u2191\u2193"})," navigate",!p&&S(f,{children:[" ","\xB7 ",u(f,{bold:!0,children:"ESC"})," skip"]})]})})]})},Wi=({alternatives:e,onSubmit:t})=>{let[r,o]=ce(new Set),[n,i]=ce({}),[s,a]=ce(0),[c,l]=ce(null);Gi(()=>{let w={};for(let C of e)for(let M of C.variables)w[M.name]=M.defaultValue||"";i(w)},[e]);let d=[];for(let w=0;w<e.length;w++)if(d.push({type:"provider",categoryIndex:w}),r.has(w)){let C=e[w];if(C)for(let M=0;M<C.variables.length;M++)d.push({type:"field",categoryIndex:w,fieldIndex:M})}d.push({type:"submit"});let p=d[s],m=p?.type==="field",g=p?.type==="submit";or((w,C)=>{let M=Math.min(s,d.length-1);if(M!==s){a(M);return}if(m)C.upArrow?a(D=>Math.max(0,D-1)):(C.downArrow||C.tab)&&a(D=>Math.min(d.length-1,D+1));else if(g)C.upArrow?a(D=>Math.max(0,D-1)):(C.return||w===" ")&&E();else if(C.upArrow)a(D=>Math.max(0,D-1));else if(C.downArrow||C.tab)a(D=>Math.min(d.length-1,D+1));else if((C.return||w===" ")&&p?.type==="provider"){let D=p.categoryIndex;o(pt=>{let B=new Set(pt);return B.has(D)?B.delete(D):B.add(D),B}),c&&l(null)}});let v=()=>{c&&l(null),a(w=>Math.min(d.length-1,w+1))},E=()=>{let w=[],C={};for(let M of r){let D=e[M];if(!D)continue;if(D.variables.some(B=>n[B.name]?.trim())){w.push(D.name);for(let B of D.variables){let Gr=n[B.name];Gr&&(C[B.name]=Gr)}}}if(w.length===0){r.size===0?l("Enable at least one provider (press Space or Enter)"):l("Enter a value for at least one field");return}t(w,C)};return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:c?"red":y,children:[S(h,{justifyContent:"space-between",children:[u(f,{bold:!0,children:"Configure AI Provider"}),u(f,{color:"yellow",children:"* At least one required"})]}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"Enable and configure at least one AI provider below:"})}),u(h,{marginTop:1,flexDirection:"column",children:e.map((w,C)=>{let M=r.has(C),D=d.findIndex(B=>B.type==="provider"&&B.categoryIndex===C),pt=s===D;return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[u(f,{color:pt?y:void 0,bold:pt,children:pt?"\u279C ":" "}),u(f,{color:M?"green":"gray",children:M?`[${b.ok}]`:"[ ]"}),S(f,{color:M?y:"gray",bold:M,children:[" ",w.name]}),w.description&&S(f,{color:"gray",dimColor:!0,children:[" ","- ",w.description]})]}),pt&&w.docsUrl&&S(h,{marginLeft:6,children:[u(f,{color:"yellow",children:"\u{1F4D6} "}),u(f,{color:"blue",underline:!0,children:w.docsUrl})]}),M&&u(h,{marginLeft:4,flexDirection:"column",marginTop:1,children:w.variables.map((B,Gr)=>{let nd=d.findIndex(ar=>ar.type==="field"&&ar.categoryIndex===C&&ar.fieldIndex===Gr),Ot=s===nd,es=!!B.defaultValue,nn=n[B.name]||"";return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[S(f,{color:Ot?y:"gray",bold:Ot,children:[Ot?" \u279C ":" ",B.name]}),!Ot&&nn&&u(f,{color:"green",children:" \u2713"}),!Ot&&!nn&&es&&S(f,{color:"gray",dimColor:!0,children:[" ","(default: ",B.defaultValue,")"]})]}),Ot&&u(h,{marginLeft:4,children:u(Or,{value:nn,onChange:ar=>{i(id=>({...id,[B.name]:ar})),c&&l(null)},onSubmit:v,placeholder:es?`Default: ${B.defaultValue}`:"Enter value\u2026"})})]},B.name)})})]},w.name)})}),c&&u(h,{marginTop:1,children:S(f,{color:"red",bold:!0,children:[b.warn," ",c]})}),S(h,{marginTop:1,children:[u(f,{color:g?y:void 0,bold:g,children:g?"\u279C ":" "}),u(h,{borderStyle:I,borderColor:g?y:"gray",paddingX:2,children:u(f,{color:g?y:"gray",bold:g,children:"Continue \u2192"})})]}),u(h,{marginTop:1,children:u(f,{color:"gray",dimColor:!0,children:"\u2191/\u2193 navigate \u2022 Space/Enter toggle/select \u2022 Tab skip field"})})]})},Ki=({currentVar:e,currentIndex:t,totalCount:r,onSubmit:o,onSkip:n})=>{let[i,s]=ce(e.defaultValue||""),[a,c]=ce(null);Gi(()=>{s(e.defaultValue||""),c(null)},[e.name]),or((p,m)=>{if(m.escape){if(e.required&&!i.trim()){c("This field is required and cannot be skipped");return}n()}});let l=p=>{if(e.required&&!p.trim()){c("This field is required");return}c(null),o(p)},d=!!e.defaultValue;return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:a?"red":y,children:[S(h,{justifyContent:"space-between",children:[S(h,{children:[u(f,{color:y,bold:!0,children:e.name}),e.required?u(f,{color:"red",children:" *"}):S(f,{color:"gray",dimColor:!0,children:[" ","optional"]})]}),S(f,{color:"gray",children:[t+1,"/",r]})]}),u(h,{marginLeft:1,children:u(f,{color:"gray",children:e.description})}),S(h,{marginTop:1,children:[u(f,{color:y,children:"\u2192 "}),u(Or,{value:i,onChange:p=>{s(p),a&&c(null)},onSubmit:l,placeholder:d?`Default: ${e.defaultValue}`:e.required?"required":"skip with Enter"})]}),a&&u(h,{marginTop:1,children:u(f,{color:"red",children:a})}),u(h,{marginTop:1,children:S(f,{dimColor:!0,children:[u(f,{bold:!0,children:"Enter"})," confirm",!e.required&&S(f,{children:[" ","\xB7 ",u(f,{bold:!0,children:"ESC"})," skip"]})]})})]})},eu=({store:e})=>{let t=_e(e);return S(Yo,{status:t.status,step:t.step,children:[t.step==="Welcome"&&t.inputRequest?.id==="welcome"&&u(Dh,{onConfirm:()=>e.submitInput(!0)}),t.step==="Prerequisites"&&t.data.checks&&u(Go,{checks:t.data.checks}),u(rr,{inputId:t.inputRequest?.id,missing:t.data[It],onConfirm:()=>e.submitInput("install"),onDecline:()=>e.submitInput("decline")}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&u(tr,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="repo_path"&&u(Oh,{defaultValue:t.inputRequest.meta.default,onSubmit:r=>e.submitInput(r)}),t.inputRequest?.id==="existing_repo"&&t.data.existingRepoPath&&u($h,{repoPath:t.data.existingRepoPath,onAction:r=>e.submitInput(r)}),t.step==="Repository Setup"&&!t.inputRequest&&u(jl,{title:"Cloning Repository",progress:t.data.repoProgress,phase:t.data.repoPhase}),t.inputRequest?.id==="setup_mode"&&u(ji,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_method"&&u(qi,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_infisical"&&u(Hi,{onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&u(Ki,{categories:t.data.envCategories||[],currentVar:t.data.currentEnvVar,currentIndex:t.data.envVarIndex||0,totalCount:t.data.envVarTotal||0,onSubmit:r=>e.submitInput(r),onSkip:()=>e.submitInput("")}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_group"&&t.data.currentEnvGroup&&u(Vi,{category:t.data.currentEnvGroup,currentIndex:t.data.envGroupIndex||0,totalGroups:t.data.envGroupTotal||0,onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_alternatives"&&t.data.alternativeGroups&&u(Wi,{alternatives:t.data.alternativeGroups,onSubmit:(r,o)=>e.submitInput({selectedGroups:r,values:o})}),t.step==="Environment Setup"&&!t.inputRequest&&u(Uo,{status:t.status}),t.step==="Finished"&&u(Lh,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,stillStarting:t.data.stillStarting===!0,onConfirm:()=>e.submitInput("exit")}),(t.step==="Install Tools"||t.step==="Project Setup")&&u(Ui,{title:t.step==="Install Tools"?"Installing Tools":"Project Setup",phase:t.data.dependencyPhase||"",progress:t.data.dependencyProgress||0,isComplete:t.step==="Install Tools"?t.data.toolComplete||!1:t.data.dependencyComplete||!1,logs:t.data.dependencyLogs||[]}),t.error&&u(Ae,{message:t.error.message})]})};import{Spinner as Mh}from"@inkjs/ui";import{Box as nr,Text as $r}from"ink";import{jsx as at,jsxs as je}from"react/jsx-runtime";var tu=({store:e})=>{let t=_e(e),r=t.step==="Starting"||t.step==="Stopping",o=t.step==="Running"||t.step==="Stopped",n=t.data.dockerLogs??[];return je(nr,{flexDirection:"column",width:"100%",children:[at(rt,{showStatus:o}),r&&!t.error&&je(nr,{flexDirection:"column",marginTop:1,children:[at(Mh,{label:t.status||"Working\u2026"}),n.length>0&&at(Vo,{logs:n})]}),t.step==="Running"&&t.data.started&&je(nr,{flexDirection:"column",marginTop:1,children:[je(nr,{children:[at(ie,{kind:"ok"}),je($r,{children:["GAIA is running at"," ",at($r,{color:"cyan",bold:!0,children:t.data.webUrl})]})]}),je($r,{color:"gray",children:[" ","gaia status shows its health \xB7 gaia stop shuts it down"]})]}),t.step==="Stopped"&&t.data.stopped&&je(nr,{flexDirection:"column",marginTop:1,children:[je(nr,{children:[at(ie,{kind:"ok"}),at($r,{children:t.status})]}),t.data.stopMode==="force-ports"&&je($r,{color:"yellow",children:[" ","--force-ports also stopped whatever else listened on GAIA's ports."]})]}),t.error&&at(Ae,{message:t.error.message})]})};import{Spinner as Fh}from"@inkjs/ui";import{Box as ct,Text as ge,useInput as Nh}from"ink";import{jsx as k,jsxs as Oe}from"react/jsx-runtime";var ru=({store:e})=>{let t=_e(e);return Oe(Yo,{status:t.status,step:t.step,steps:Zl,children:[t.step==="Detect Repo"&&Oe(ct,{flexDirection:"column",paddingX:2,borderStyle:I,borderColor:y,children:[k(ge,{bold:!0,children:"Detecting GAIA Repository"}),k(ct,{marginTop:1,children:k(Fh,{label:"Searching for repository\u2026"})}),t.data.repoPath&&k(ct,{marginTop:1,children:Oe(ge,{color:"green",children:["Found: ",t.data.repoPath]})})]}),t.step==="Prerequisites"&&t.data.checks&&k(Go,{checks:t.data.checks}),k(rr,{inputId:t.inputRequest?.id,missing:t.data[It],onConfirm:()=>e.submitInput("install"),onDecline:()=>e.submitInput("decline")}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&k(tr,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="setup_mode"&&k(ji,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_method"&&k(qi,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_infisical"&&k(Hi,{onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&k(Ki,{categories:t.data.envCategories||[],currentVar:t.data.currentEnvVar,currentIndex:t.data.envVarIndex||0,totalCount:t.data.envVarTotal||0,onSubmit:r=>e.submitInput(r),onSkip:()=>e.submitInput("")}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_group"&&t.data.currentEnvGroup&&k(Vi,{category:t.data.currentEnvGroup,currentIndex:t.data.envGroupIndex||0,totalGroups:t.data.envGroupTotal||0,onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_alternatives"&&t.data.alternativeGroups&&k(Wi,{alternatives:t.data.alternativeGroups,onSubmit:(r,o)=>e.submitInput({selectedGroups:r,values:o})}),t.step==="Environment Setup"&&!t.inputRequest&&k(Uo,{status:t.status}),t.step==="Project Setup"&&k(Ui,{title:"Project Setup",phase:t.data.dependencyPhase||"",progress:t.data.dependencyProgress||0,isComplete:t.data.dependencyComplete||!1,logs:t.data.dependencyLogs||[]}),t.step==="Finished"&&k(Bh,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,onConfirm:()=>e.submitInput("exit")}),t.error&&k(Ae,{message:t.error.message})]})},Bh=({setupMode:e,portOverrides:t,onConfirm:r})=>{Nh((s,a)=>{a.return&&r()});let o=t?.[3e3]??3e3,n=ne(e??"developer",t??{}),i=e==="selfhost";return Oe(ct,{flexDirection:"column",marginTop:2,borderStyle:I,borderColor:y,padding:1,children:[k(ge,{color:y,bold:!0,children:"Setup Complete!"}),Oe(ct,{marginTop:1,children:[k(ge,{bold:!0,children:"Run: "}),k(ge,{color:"cyan",children:i?"$ gaia start":"$ gaia dev"})]}),Oe(ct,{marginTop:1,flexDirection:"column",children:[Oe(ge,{children:["Web:"," ",Oe(ge,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),Oe(ge,{children:["API:"," ",k(ge,{color:"cyan",bold:!0,children:n})]})]}),k(ct,{marginTop:1,children:k(ge,{color:"gray",children:i?"gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup":"gaia dev full \xB7 gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup"})}),k(ct,{marginTop:1,children:Oe(ge,{dimColor:!0,children:[k(ge,{bold:!0,children:"Enter"})," to exit"]})})]})};import{Spinner as Qh}from"@inkjs/ui";import{Box as te,Text as Ee,useInput as Jh}from"ink";var Gh=[{name:"API",port:8e3,type:"http",path:"/health"},{name:"Web",port:3e3,type:"http",path:"/"},{name:"PostgreSQL",port:5432,type:"tcp"},{name:"Redis",port:6379,type:"tcp"},{name:"MongoDB",port:27017,type:"tcp"},{name:"RabbitMQ",port:5672,type:"tcp"},{name:"ChromaDB",port:8080,type:"tcp"}];async function ou(e){return Promise.all(Gh.map(t=>{let r=e[t.port]??t.port;return t.type==="http"?Uh(t.name,r,t.path):jh(t.name,r)}))}async function Uh(e,t,r){let o=Date.now();try{let n=await fetch(`http://localhost:${t}${r}`,{signal:AbortSignal.timeout(5e3)}),i=Date.now()-o;return{name:e,port:t,status:n.ok?"up":"down",latency:i,details:n.ok?`HTTP ${n.status}`:`HTTP ${n.status} (error)`}}catch{return{name:e,port:t,status:"down",details:"Connection failed"}}}async function jh(e,t){let r=await import("node:net"),o=Date.now();return new Promise(n=>{let i=new r.Socket;i.setTimeout(3e3),i.on("connect",()=>{let s=Date.now()-o;i.destroy(),n({name:e,port:t,status:"up",latency:s})}),i.on("timeout",()=>{i.destroy(),n({name:e,port:t,status:"down"})}),i.on("error",()=>{i.destroy(),n({name:e,port:t,status:"down"})}),i.connect(t,"localhost")})}async function nu(e){let t=await Q();if(t!=="ready")return{access:t,problem:await Me(t),containers:[]};let r=await ls(le[e]);return{access:t,containers:r}}var Lr="statusFacts";async function qh(){let e=_(),t=e?await N(e):null,r=vr(e,t);if(!e||!t)return{install:r,installed:!1,services:[],setupComplete:null};let o=F(e),n=o[T]??T,[i,s,a]=await Promise.all([t==="developer"?ou(o):[],nu(t),Fo(yt(t,o),le[t])]),c=a.reachable?await ke(ne(t,o),"status"):null;return{install:r,installed:!0,docker:t==="selfhost"&&s.access==="ready"?{...s,containers:Hh(s.containers)}:s,readiness:a,services:i,webUrl:ze(n,Nt(e)),setupComplete:c&&"data"in c?!c.data.needs_setup:null}}function Hh(e){let t=($()?.bots??[]).map(ue).filter(r=>!e.some(o=>o.name===r));return[...e,...t.map(r=>({name:r,status:"not_found"}))]}async function Vh(e){e.setStep("Checking"),e.setStatus("Checking GAIA's services\u2026");let t=await qh();e.updateData(Lr,t),e.updateData("checkedAt",new Date().toLocaleTimeString()),e.setStep("Results")}async function iu(e,t={}){for(e.updateData("watch",t.watch===!0);;)if(await Vh(e),!t.watch||await e.waitForInput("exit_or_refresh")!=="refresh")return}var Wh=["gaia-web","gaia-backend","arq_worker","proxy"],Kh=["mongo","postgres","redis","rabbitmq","chromadb"];function Xo(e,t,r){return t.some(n=>!n.ok)?{label:e,items:t,note:r,tone:"fail"}:{label:e,items:t,tone:"ok"}}function su(e,t){return t.map(r=>e.find(o=>o.name===r)).filter(r=>r!==void 0).map(r=>({ok:r.status==="running",name:Fe(r.name)}))}function au(e,t){let r=e.readiness,o=r?.reachable===!0?r.dependencies.map(i=>({ok:i.ok,name:Zr(i.name)})):su(t,Kh),n=r?.reachable===!0?r.dependencies.find(i=>!i.ok)?.fix:void 0;return Xo("Data",o,n??"See why with: gaia doctor")}function Yh(e){let t=e.filter(r=>r.name.startsWith("bot-"));return t.length===0?{label:"Bots",items:[],note:"none \xB7 add one: gaia bots add telegram",tone:"dim"}:Xo("Bots",t.map(r=>({ok:r.status==="running",name:Fe(r.name)})),"See why with: gaia doctor")}function cu(e){return e.setupComplete===null?null:e.setupComplete?{label:"Setup",items:[],note:"finished",tone:"ok"}:{label:"Setup",items:[],note:`not finished \xB7 open ${e.webUrl}/setup`,tone:"warn"}}function Xh(e,t){let r=t.containers,n=[Xo("App",su(r,Wh),"Start it: gaia start"),au(e,r),Yh(r)],i=cu(e);i&&n.push(i);let s=r.some(c=>c.status==="running"),a=n.some(c=>c.tone==="fail");return s?{headline:a?{kind:"fail",text:"GAIA is running, but part of it is down"}:{kind:"ok",text:"GAIA is running",url:e.webUrl},rows:n,unhealthy:a}:{headline:{kind:"fail",text:"GAIA isn't running \xB7 start it: gaia start"},rows:[],unhealthy:!0}}function zh(e){let t=e.services.map(o=>({ok:o.status==="up",name:`${o.name} :${o.port}`})),r=Xo("Local",t,"Start them: gaia dev");return{headline:r.tone==="fail"?{kind:"fail",text:"Part of the dev stack is down"}:{kind:"ok",text:"The dev stack is running",url:e.webUrl},rows:[r],unhealthy:r.tone==="fail"}}function zo(e){if(!e.installed)return{headline:{kind:"warn",text:`${e.install} \xB7 run: gaia up`},rows:[],unhealthy:!0};let t=e.docker;if(t?.problem){let r=e.readiness?.reachable===!0,o={label:"Docker",items:[],note:t.problem.state,tone:"warn"},n=cu(e);return{headline:r?{kind:"ok",text:"GAIA is running",url:e.webUrl}:{kind:"fail",text:t.problem.summary},hint:t.problem.fix,rows:r?[au(e,[]),...n?[n]:[],o]:[],unhealthy:!0}}return e.services.length>0?zh(e):Xh(e,t??{access:"ready",containers:[]})}import{jsx as A,jsxs as qe}from"react/jsx-runtime";var lu=8,uu={ok:void 0,warn:"yellow",fail:"red",dim:"gray"},Zh=({row:e})=>qe(te,{flexDirection:"column",children:[qe(te,{flexWrap:"wrap",children:[A(te,{width:lu,flexShrink:0,children:A(Ee,{bold:!0,children:e.label})}),e.items.map(t=>qe(te,{marginRight:2,children:[A(ie,{kind:t.ok?"ok":"fail"}),A(Ee,{children:t.name})]},t.name)),e.items.length===0&&e.note&&qe(te,{children:[e.tone!=="dim"&&A(ie,{kind:e.tone==="warn"?"warn":"ok"}),A(Ee,{color:uu[e.tone],children:e.note})]})]}),e.items.length>0&&e.note&&A(te,{marginLeft:lu,children:A(Ee,{color:uu[e.tone],children:e.note})})]}),du=({store:e})=>{let t=_e(e),r=t.data[Lr],o=t.data.watch===!0,n=t.step==="Results"&&r!==void 0;Jh((a,c)=>{a==="q"||c.return||c.escape?e.submitInput("exit"):a==="r"&&e.submitInput("refresh")},{isActive:o&&t.inputRequest!==null});let i=r?zo(r):null,s=i?.headline.kind??"ok";return qe(te,{flexDirection:"column",width:"100%",children:[A(rt,{showStatus:!1}),t.step==="Checking"&&A(te,{marginTop:1,marginLeft:2,children:A(Qh,{label:t.status})}),n&&i&&qe(te,{flexDirection:"column",marginTop:1,marginLeft:2,children:[qe(te,{children:[A(ie,{kind:s==="ok"?"active":s}),A(Ee,{bold:!0,children:i.headline.text})]}),i.headline.url&&A(te,{marginLeft:2,children:A(Ee,{color:y,children:i.headline.url})}),i.hint&&A(te,{marginLeft:2,children:A(Ee,{children:i.hint})}),i.rows.length>0&&A(te,{flexDirection:"column",marginTop:1,children:i.rows.map(a=>A(Zh,{row:a},a.label))}),r.installed&&A(te,{marginTop:1,children:qe(Ee,{color:"gray",children:["Installed at ",r.install]})}),o&&A(te,{marginTop:1,children:qe(Ee,{color:"gray",children:["checked ",t.data.checkedAt," \xB7 ",A(Ee,{bold:!0,children:"r"})," check again \xB7 ",A(Ee,{bold:!0,children:"q"})," quit"]})})]}),t.error&&A(Ae,{message:t.error.message})]})};import{defaultTheme as eS,extendTheme as tS}from"@inkjs/ui";var pu=tS(eS,{components:{Spinner:{styles:{frame:()=>({color:y})}},ProgressBar:{styles:{completed:()=>({color:y})}}}});import{jsx as se,jsxs as ir}from"react/jsx-runtime";var iS=["init","setup","status","start","stop","up"],Yi=class extends nS.Component{constructor(t){super(t),this.state={error:null}}static getDerivedStateFromError(t){return{error:t}}render(){return this.state.error?ir(Qo,{flexDirection:"column",padding:1,children:[se(_t,{color:"red",bold:!0,children:"An unexpected error occurred:"}),se(_t,{color:"red",children:this.state.error.message}),this.state.error.stack&&se(Qo,{marginTop:1,children:se(_t,{color:"gray",dimColor:!0,children:this.state.error.stack})})]}):this.props.children}},sS=({store:e,command:t})=>{switch(t){case"init":return se(eu,{store:e});case"setup":return se(ru,{store:e});case"status":return se(du,{store:e});case"start":case"stop":return se(tu,{store:e,command:t});case"up":return se(Yl,{store:e});default:return ir(Qo,{flexDirection:"column",padding:1,children:[ir(_t,{color:"red",children:["Unknown command: ",t]}),ir(Qo,{marginTop:1,flexDirection:"column",children:[se(_t,{bold:!0,children:"Available commands:"}),iS.map(r=>ir(_t,{children:[" ",se(_t,{color:"cyan",children:r})]},r))]})]})}},aS=({onCancel:e})=>(oS((t,r)=>{r.ctrl&&t==="c"&&e()}),null),mu=({store:e,command:t,onCancel:r})=>se(Yi,{children:ir(rS,{theme:pu,children:[se(aS,{onCancel:r}),se(sS,{store:e,command:t})]})});import{EventEmitter as cS}from"events";var lS=150,Xi=class extends cS{state={step:"init",status:"",error:null,data:{},inputRequest:null};inputResolver=null;emitTimer=null;emitPending=!1;autoResolveInputs=new Map;answerResolvers=[];setAutoResolve(t,r="exit"){this.autoResolveInputs.set(t,r)}pushAnswerResolver(t){this.answerResolvers.push(t)}get currentState(){return this.state}scheduleEmit(){this.emitPending=!0,this.emitTimer||(this.emitTimer=setTimeout(()=>{this.emitTimer=null,this.emitPending&&(this.emitPending=!1,this.emit("change",this.state))},lS))}flush(){this.emitPending&&this.emitNow()}emitNow(){this.emitTimer&&(clearTimeout(this.emitTimer),this.emitTimer=null),this.emitPending=!1,this.emit("change",this.state)}setStep(t){this.state.step=t,this.emitNow()}setStatus(t){this.state.status=t,this.scheduleEmit()}setError(t){this.state.error=t,t!==null&&this.inputResolver&&(this.inputResolver(null),this.inputResolver=null,this.state.inputRequest=null),this.emitNow()}updateData(t,r){this.state.data={...this.state.data,[t]:r},this.scheduleEmit()}ask(t,r,o){return this.answerResolvers.map(i=>i(t,o)).find(i=>i!==void 0)===void 0&&!this.autoResolveInputs.has(t)&&this.setStatus(r),this.waitForInput(t,o)}waitForInput(t,r,o){if(this.autoResolveInputs.has(t))return this.state.inputRequest=null,this.emitNow(),Promise.resolve(this.autoResolveInputs.get(t));for(let n of this.answerResolvers){let i=n(t,r);if(i!==void 0)return this.state.inputRequest=null,this.emitNow(),Promise.resolve(i)}return this.state.inputRequest={id:t,meta:r},this.emitNow(),new Promise(n=>{if(this.inputResolver=n,o!=null){let i=setTimeout(()=>{this.inputResolver&&(this.inputResolver=null,this.state.inputRequest=null,this.emitNow(),n(null))},o),s=this.inputResolver;this.inputResolver=a=>{clearTimeout(i),s(a)}}})}submitInput(t){this.inputResolver&&(this.inputResolver(t),this.inputResolver=null,this.state.inputRequest=null,this.emitNow())}},fu=()=>new Xi;async function he(e){let t=fu();if(e.whenNonInteractive==="fail"){rc(e.command),await gu(t,e);return}pe()?await gu(t,e):await pS(t,e)}async function pS(e,t){oc(e,bs());for(let[r,o]of t.autoResolve??[])e.setAutoResolve(r,o);try{await t.runFlow(e);let r=hu(e);r&&await Sn(e.currentState.step,r),t.onPlainComplete?.(e)}catch(r){e.setError(r)}Su(e)}async function gu(e,t){let r=()=>{},{unmount:o,clear:n}=uS(dS.createElement(mu,{store:e,command:t.command,onCancel:()=>r()}),{exitOnCtrlC:!1}),i=()=>{o();let a=t.cancelHint?` ${t.cancelHint}`:"";process.stdout.write(`
|
|
109
|
-
${
|
|
110
|
-
`),process.exit(130)};r=i,process.once("SIGINT",i),process.once("SIGTERM",i);try{await t.runFlow(e)}catch(a){e.setError(a)}finally{process.off("SIGINT",i),process.off("SIGTERM",i)}
|
|
111
|
-
`),
|
|
112
|
-
Try removing it manually: rm -rf "${i}"`));return}break}else{if(p==="different_path")continue;e.setError(new Error("Setup cancelled by user."));return}}if(
|
|
113
|
-
`)[0]??"unknown error";e.setStatus(`Registry pull failed (${m}) \u2014 building images locally (this takes a few minutes)\u2026`)}if(!c)try{await oe(i,"selfhost",p=>e.setStatus(p),n,a,{build:!0})}catch(p){e.setError(new Error(`Failed to start services: ${p.message}`));return}e.updateData("dependencyProgress",100),e.updateData("dependencyComplete",!0);let l=e.currentState.data.envMethod||"manual";
|
|
114
|
-
`));if(c&&!
|
|
115
|
-
`))}if(c&&
|
|
116
|
-
`)}function
|
|
117
|
-
`)}async function
|
|
118
|
-
`)}function
|
|
119
|
-
Run it with --force-dev-tree to go ahead anyway.`));return}if(
|
|
120
|
-
${s}`)),!1}async function
|
|
121
|
-
Once 'gaia status' shows it running, run 'gaia up' again with the same flags.`);try{await
|
|
122
|
-
Check the key and run 'gaia up --llm-provider ${n} --llm-key <key>' again, or add it on the setup page above.`)}return
|
|
123
|
-
`)}function
|
|
124
|
-
`)
|
|
107
|
+
`).action(e=>ie(async()=>process.exit(await Xg(e))));import*as Ho from"fs";import*as Ll from"path";import{spawn as Jg}from"child_process";async function ir(e,t,r,o,n,i=!1){await qo([{cmd:e,args:t,cwd:r,env:o,onSpawn:n,detached:i}])}async function qo(e){e.length!==0&&await new Promise((t,r)=>{let o=e.map(p=>Jg(p.cmd,p.args,{cwd:p.cwd,stdio:"inherit",shell:!1,detached:p.detached??!1,env:p.env?{...process.env,...p.env}:process.env}));o.forEach((p,m)=>{e[m]?.onSpawn?.(p.pid)});let n=!1,i=0,s=!1,a,c=()=>{process.off("SIGINT",d),process.off("SIGTERM",d)},l=()=>{if(!s){s=!0;for(let[p,m]of o.entries()){let g=e[p];try{process.platform!=="win32"&&g?.detached&&typeof m.pid=="number"?process.kill(-m.pid,"SIGTERM"):m.kill("SIGTERM")}catch{}}a=setTimeout(()=>{for(let[p,m]of o.entries()){let g=e[p];try{process.platform!=="win32"&&g?.detached&&typeof m.pid=="number"?process.kill(-m.pid,"SIGKILL"):m.kill("SIGKILL")}catch{}}},1e3)}},d=()=>{l()};process.on("SIGINT",d),process.on("SIGTERM",d),o.forEach((p,m)=>{let g=e[m];p.on("error",v=>{n||(n=!0,c(),l(),r(v))}),p.on("close",(v,E)=>{if(i+=1,!(v===0||(E==="SIGINT"||E==="SIGTERM"||v===130||v===143||s))&&!n){n=!0,c(),l(),r(new Error(`Command failed with code ${String(v)}: ${g?.cmd??"unknown"} ${g?.args.join(" ")??""}`));return}i>=o.length&&!n&&(n=!0,c(),a&&clearTimeout(a),t())})})})}async function Ml(e){if(e&&e!=="full")throw new Error(`Invalid developer profile: '${e}'. Use 'gaia dev' or 'gaia dev full'.`);let t=Xt();if(!t)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let r=await F(t);if(!r)throw new Error("No .env file found. Run 'gaia init' for fresh setup, or 'gaia setup' to configure an existing repo.");if(r!=="developer")throw new Error("Developer mode is not enabled for this repo. Use 'gaia start' for self-host mode.");let o=Ll.join(t,fo);try{await ir("mise",[e==="full"?"dev:full":"dev"],t,void 0,n=>{typeof n=="number"&&n>0&&Ho.writeFileSync(o,`${n}
|
|
108
|
+
`)},process.platform!=="win32")}finally{try{Ho.unlinkSync(o)}catch{}}}import fh,{Chalk as gh}from"chalk";import*as Fl from"node:fs";import*as Lt from"node:os";import{execa as Nl}from"execa";var Qg={mongodb:{service:"mongo",cause:"a full disk is the usual cause; users, chats and settings live here"},postgres:{service:"postgres",cause:"a full disk is the usual cause; agent state lives here"},redis:{service:"redis",cause:"background jobs and reminders queue here and wait until it is back"},rabbitmq:{service:"rabbitmq",cause:"it takes up to a minute to boot after a restart, so rerun first"},chromadb:{service:"chromadb",cause:"memory and file search stay unavailable until it answers"}};function Zg(e,t){let r=Qg[e];return r?`Check its logs: docker compose -p ${t} logs ${r.service} (${r.cause}).`:`Check the API logs: docker compose -p ${t} logs gaia-backend`}async function Vo(e,t){let r;try{r=await fetch(`${e}/health/ready`,{signal:AbortSignal.timeout(5e3)})}catch(n){return{reachable:!1,detail:`Could not reach ${e}/health/ready: ${n.message}`}}if(!r.ok&&r.status!==503)return{reachable:!1,detail:`HTTP ${r.status} from ${e}/health/ready`};let o=await r.json();return{reachable:!0,ready:o.status==="ready",dependencies:o.dependencies.map(n=>n.ok?n:{...n,fix:Zg(n.name,t)})}}var eh=2*1024*1024*1024,th=4*1024*1024*1024,rh=2*1024*1024*1024,Bl={"gaia-selfhost":["chromadb","postgres","redis","mongo","rabbitmq","gaia-backend","gaia-web","arq_worker","proxy"],"gaia-dev":["chromadb","postgres","redis","mongo","rabbitmq"]};function Bi(e){return e==="running"?"running":e==="restarting"?"restarting":"stopped"}function oh(e,t){return t.every(r=>e.some(o=>o.service===r&&Bi(o.state)==="running"))}function nh(e,t){return t.map(r=>({service:r,info:e.find(o=>o.service===r)})).filter(({info:r})=>!r||Bi(r.state)!=="running").map(({service:r,info:o})=>o?`${r} ${Bi(o.state)}`:`${r} missing`).join(", ")}function Gl(e,t){return e[t]??t}async function Ul(e,t={}){let r={id:"port-conflict",label:"Ports",severity:"blocker"},o;try{o=await Co(e,t)}catch{return{...r,state:"skipped",detail:"Could not check ports"}}let n=o.filter(s=>!s.available);if(n.length===0)return{...r,state:"ok",detail:"no conflicts"};let i=n.map(s=>`:${s.port} in use by ${s.usedBy??"unknown"}`).join(", ");return{...r,state:"fail",detail:i,fix:e==="selfhost"?"Free the port or re-run 'gaia up' with --web-port (or set WEB_HOST_PORT in infra/docker/.env).":"Free the port or set its *_HOST_PORT override in infra/docker/.env."}}function ih(e){return`Open ${e}/setup in your browser to finish setting GAIA up.`}function sh(e,t,r){let n=[{label:"LLM provider configured",configured:t.some(i=>e.providers?.[i]?.configured===!0),missing:"no AI provider yet"},{label:"admin account created",configured:e.has_admin_account===!0,missing:"no admin account yet"}];return e.deployment.bills&&n.push({label:"plans seeded",configured:e.plans_seeded,missing:"billing plans not set up yet"}),n.map(i=>({...i,fix:i.configured?"":ih(r)}))}function ah(e){let r=e.trim().split(`
|
|
109
|
+
`).filter(i=>i.trim().length>0).at(-1);if(!r)return null;let o=r.trim().split(/\s+/),n=Number(o[3]);return!Number.isFinite(n)||n<0?null:n}async function jl(e){let t={id:"docker-daemon",label:"Docker",severity:"blocker"};if(e==="ready")return{...t,state:"ok",detail:"running"};let r=await Ue(e);return{...t,state:"fail",detail:r.state,fix:r.fix}}async function ql(e){let t={id:"compose-containers",label:"Containers",severity:"blocker"},r;try{r=await bt(e.project)}catch{return{...t,state:"skipped",detail:"they need Docker"}}return oh(r,e.expected)?{...t,state:"ok",detail:`${e.expected.length} services running`}:{...t,state:"fail",detail:nh(r,e.expected),fix:`Run 'gaia start' to bring the stack up, or check 'docker compose -p ${e.project} logs'.`}}function Hl(e){let t={id:"compose-containers",label:"GAIA",severity:"blocker",state:"fail"};return e?{...t,detail:`${e} isn't set up yet (no apps/api/.env)`,fix:"Run 'gaia up' to finish setting it up, or 'gaia setup' for a development checkout."}:{...t,detail:"isn't installed yet",fix:Rn}}async function Vl(e,t="gaia start"){let r={id:"api-health",label:"API",severity:"blocker"};try{let o=await So(`${e}/ping`);return o.ok?{...r,state:"ok",detail:`answering at ${e}`}:{...r,state:"fail",detail:`answered HTTP ${o.status} at ${e}/ping`,fix:`See why with 'gaia logs', then restart it with '${t}'.`}}catch{return{...r,state:"fail",detail:`not answering at ${e}`,fix:`Start GAIA with '${t}'.`}}}async function Wl(e){let t={id:"dependencies",label:"Dependencies",severity:"blocker"};if(!e.apiHealthy)return[{...t,state:"skipped",detail:"they need GAIA's API"}];let r=await Vo(e.origin,e.project);return r.reachable?r.dependencies.map(o=>({id:`dependency-${o.name}`,label:ao(o.name),severity:"blocker",state:o.ok?"ok":"fail",detail:o.ok?`${Math.round(o.latency_ms)} ms`:`${o.error_type??"failed"} after ${Math.round(o.latency_ms)} ms`,fix:o.fix})):[{...t,state:"fail",detail:r.detail,fix:"Run 'gaia update': an API or proxy older than this CLI does not serve /health/ready."}]}async function Kl(e,t="gaia start"){let r={id:"web-reachable",label:"Web app",severity:"blocker"};try{let o=await So(`http://localhost:${e}`,{method:"HEAD"});return o.ok?{...r,state:"ok",detail:`answering at http://localhost:${e}`}:{...r,state:"fail",detail:`answered HTTP ${o.status} at http://localhost:${e}`,fix:`See why with 'gaia logs', then restart it with '${t}'.`}}catch{return{...r,state:"fail",detail:`not answering at http://localhost:${e}`,fix:`Start GAIA with '${t}'.`}}}async function Yl(e){let t={id:"setup-readiness",label:"Setup",severity:"warning"};if(!e.apiHealthy)return[{...t,state:"skipped",detail:"they need GAIA's API"}];let[r,o]=await Promise.all([_e(e.apiUrl,"status"),_e(e.apiUrl,"catalog")]);if("detail"in r)return[{...t,state:"skipped",detail:r.detail}];if("detail"in o)return[{...t,state:"skipped",detail:o.detail}];let n=sh(r.data,o.data.llm_provider_keys,e.webUrl);if(n.every(s=>s.configured))return[{...t,state:"ok",detail:"finished"}];let i=n.filter(s=>!s.configured);return[{...t,state:"fail",detail:`not finished: ${i.map(s=>s.missing).join(", ")}`,fix:i[0]?.fix}]}async function Gi(e=eh){let t={id:"disk-headroom",label:"Disk space",severity:"blocker"},r;try{r=await Is()}catch{return{...t,state:"skipped",detail:"they need Docker"}}let o;try{let i=await ks(r),s=ah(i);o=s===null?null:s*1024}catch{o=null}if(o===null)return{...t,state:"skipped",detail:`Could not read disk usage for ${r}`};let n=i=>`${(i/1024**3).toFixed(1)} GB`;return o>=e?{...t,state:"ok",detail:`${n(o)} free at ${r}`}:{...t,state:"fail",detail:`${n(o)} free at ${r}, need \u2265 ${n(e)}`,fix:"Free up disk space (e.g. 'docker system prune') before pulling/building images."}}function ch(e){let t=e.match(/^MemAvailable:\s+(\d+)\s+kB/m);if(t?.[1]){let o=Number(t[1]);if(Number.isFinite(o)&&o>=0)return o*1024}let r=e.match(/^MemTotal:\s+(\d+)\s+kB/m);if(r?.[1]){let o=Number(r[1]);if(Number.isFinite(o)&&o>=0)return o*1024}return null}function lh(e){let t=e.match(/page size of (\d+) bytes/),r=t?.[1]?Number(t[1]):4096,o=e.match(/Pages free:\s+(\d+)/),n=e.match(/Pages inactive:\s+(\d+)/),i=e.match(/Pages speculative:\s+(\d+)/);if(!(o||n||i))return null;let s=l=>l?Number(l[1]):0,a=s(o),c=s(n);return!Number.isFinite(a)||!Number.isFinite(c)||!Number.isFinite(r)||r<=0?null:(a+c+s(i))*r}function Ui(e){try{return e()}catch{return null}}function uh(){try{let e=Fl.readFileSync("/proc/meminfo","utf-8"),t=ch(e);if(t!==null)return t}catch{}return Ui(()=>Lt.freemem())}async function dh(){try{let{stdout:e}=await Nl("vm_stat",[]),t=lh(e);if(t!==null)return t}catch{}try{let{stdout:e}=await Nl("sysctl",["-n","hw.memsize"]),t=Number(e.trim());if(Number.isFinite(t)&&t>0)return t}catch{}return Ui(()=>Lt.totalmem())}async function ph(){let e=Lt.platform();return e==="linux"?uh():e==="darwin"?dh():Ui(()=>Lt.freemem())}async function ji(){let e=await ph().catch(()=>null);if(e===null)return{id:"memory-headroom",label:"Memory",severity:"blocker",state:"skipped",detail:"Could not read available memory"};let t=r=>`${(r/1024**3).toFixed(1)} GB`;return e<rh?{id:"memory-headroom",label:"Memory",severity:"blocker",state:"fail",detail:`${t(e)} free; GAIA needs at least 2 GB to start`,fix:"Close other apps or add RAM before starting GAIA."}:e<th?{id:"memory-headroom",label:"Memory",severity:"warning",state:"fail",detail:`${t(e)} free; GAIA's API uses about 2.5 GB and may run out during chats`,fix:"Close other apps or add RAM."}:{id:"memory-headroom",label:"Memory",severity:"blocker",state:"ok",detail:`${t(e)} free`}}async function zl(e,t,r=wo){let o={id:"gaia-version",label:"GAIA version",severity:"warning"};if(!e)return{...o,state:"skipped",detail:"GAIA isn't installed"};if(t!=="selfhost")return{...o,state:"skipped",detail:"Developer checkout: update it with 'gaia update --git'"};let n=Te(e);if(tt(n)===null)return{...o,state:"ok",detail:`development build (${yo(n)})`};let i=await r();return i&&qe(i,n)?{...o,state:"fail",detail:`${i} is available (this install runs ${n})`,fix:"Run 'gaia update'. Your data and settings are kept."}:{...o,state:"ok",detail:n}}async function Xl(e,t){if(e.length===0)return[];let r;try{r=await bt(t)}catch{r=null}return e.map(o=>{let n={id:`bot-${o}`,label:Ae(me(o)),severity:"warning"};if(!r)return{...n,state:"skipped",detail:"they need Docker"};let{health:i,detail:s}=xr(o,r);return i!=="failing"?{...n,state:"ok",detail:s}:{...n,state:"fail",detail:s,fix:`A rejected or revoked token keeps the bot restarting: check 'docker compose -p ${t} logs ${me(o)}', then rerun 'gaia bots add ${o}' with a fresh token.`}})}function Jl(e){return e.results.some(t=>t.severity==="blocker"&&t.state==="fail")}async function mh(){let e=_(),t=e?N(e):{},r=e?await F(e):null;return{repoPath:e,origin:kt(r??"selfhost",t),apiUrl:se(r??"selfhost",t),webPort:Gl(t,3e3),overrides:t,mode:r,project:r?pe[r]:null}}async function Ql(){let e=[],t=await mh(),r=await J();if(e.push(await jl(r)),e.push(r==="ready"?await Ul(t.mode??"selfhost",t.overrides):{id:"port-conflict",label:"Ports",severity:"blocker",state:"skipped",detail:"they need Docker"}),!t.repoPath||!t.project||!t.mode){e.push(Hl(t.repoPath));for(let i of["API","Setup","Web app"])e.push({label:i,severity:"blocker",state:"skipped",detail:"GAIA isn't installed"});return e.push(await Gi()),e.push(await ji()),{install:kr(t.repoPath,t.mode),installed:!1,results:e}}let o=t.mode==="developer"?"gaia dev":"gaia start";e.push(await ql({project:t.project,expected:Bl[t.project]})),t.project===pe.selfhost&&e.push(...await Xl(L()?.bots??[],t.project));let n=await Vl(t.apiUrl,o);return e.push(n),e.push(...await Wl({apiHealthy:n.state==="ok",origin:t.origin,project:t.project})),e.push(...await Yl({apiHealthy:n.state==="ok",apiUrl:t.apiUrl,webUrl:et(t.repoPath,t.webPort)})),e.push(await Kl(t.webPort,o)),e.push(await Gi()),e.push(await ji()),e.push(await zl(t.repoPath,t.mode)),{install:kr(t.repoPath,t.mode),installed:!0,results:e}}function Mt(e=""){process.stdout.write(`${e}
|
|
110
|
+
`)}var Zl=16,Hi=" ",Z=process.env.NO_COLOR!==void 0?new gh({level:0}):fh,hh={ok:Z.green,fail:Z.red,warn:Z.yellow,skip:Z.gray,pending:Z.gray,active:Z.cyan,cancelled:Z.yellow};function Sh(e){return e.state==="ok"?"ok":e.state==="skipped"?"skip":e.severity==="warning"?"warn":"fail"}var qi=Hi.length+2+Zl;function vh(e,t){let r=Sh(e),o=e.detail?Z.gray(Ze(e.detail,qi)):"";Mt(`${Hi}${hh[r](y[r])} ${e.label.padEnd(Zl)}${o}`),e.state==="fail"&&e.fix&&t?.fix!==e.fix&&Mt(`${" ".repeat(qi)}${Ze(e.fix,qi)}`)}function yh(e){let t=new Map;for(let r of e){let o=r.detail??"skipped";t.set(o,[...t.get(o)??[],r.label])}for(let[r,o]of t)Mt(`${Hi}${Z.gray(y.skip)} ${Z.gray(`Not checked: ${o.join(", ")} (${r})`)}`)}function wh(e){let t=e.results.filter(n=>n.severity==="blocker"&&n.state==="fail").length,r=e.results.filter(n=>n.severity==="warning"&&n.state==="fail").length;if(t===0&&r===0)return Z.green(`${y.ok} Everything checked out`);let o=[];return t>0&&o.push(Z.red(`${t} problem${t===1?"":"s"}`)),r>0&&o.push(Z.yellow(`${r} warning${r===1?"":"s"}`)),o.join(" \xB7 ")}function bh(e){Mt(e.installed?`${Z.bold("Checking")} ${e.install}`:Z.bold("Checking this computer")),Mt();let t=e.results.filter(r=>r.state!=="skipped");t.forEach((r,o)=>{vh(r,t[o+1])}),yh(e.results.filter(r=>r.state==="skipped")),Mt(),Mt(wh(e))}async function eu(){await Rt();let e=await Ql();bh(e),Jl(e)&&(process.exitCode=1)}import{render as ev}from"ink";import tv from"react";import{ThemeProvider as WS}from"@inkjs/ui";import{Box as an,Text as Ft,useInput as KS}from"ink";import YS from"react";import{Box as Ce,Static as Zh,Text as dt}from"ink";import{Box as Ih,Text as kh,useStdout as Rh}from"ink";import{useEffect as Th,useState as tu}from"react";import{useStdout as Eh}from"ink";import{useEffect as xh,useState as Ch}from"react";function Wo(){let{stdout:e}=Eh(),[t,r]=Ch(()=>Rr(e));return xh(()=>{let o=()=>r(Rr(e));return e.on("resize",o),()=>{e.off("resize",o)}},[e]),t}import{jsx as ru}from"react/jsx-runtime";var ct=({size:e="small",showStatus:t=!0,showUpdate:r=!0})=>{let{stdout:o}=Rh(),n=Wo(),[i,s]=tu(null),[a]=tu(()=>r?Eo():null);Th(()=>{if(!t){s(null);return}let l=!0;return bo().then(d=>{l&&s(d)}),()=>{l=!1}},[t]);let c=xo({size:e,level:Qn(),...n,...Zn(o),version:$,status:t?i:null,update:a});return ru(Ih,{marginTop:1,children:ru(kh,{children:c.join(`
|
|
111
|
+
`)})})};import{Spinner as $h}from"@inkjs/ui";import{Box as lt,Text as Ko}from"ink";import{useEffect as Lh,useState as Mh}from"react";import{Box as Ah,Text as Ph}from"ink";import{jsx as ou}from"react/jsx-runtime";var ee=({kind:e})=>ou(Ah,{marginRight:1,children:ou(Ph,{color:ms[e],children:y[e]})});import{ProgressBar as _h}from"@inkjs/ui";import{Box as nu,Text as Dh}from"ink";import{jsx as iu,jsxs as su}from"react/jsx-runtime";var Oh=40,sr=({percent:e})=>su(nu,{children:[iu(nu,{width:Oh,children:iu(_h,{value:e})}),su(Dh,{color:"gray",children:[" ",e,"%"]})]});import{jsx as W,jsxs as au}from"react/jsx-runtime";var Nh=40,Fh=1e3;function Vi(e){let[t,r]=Mh(Date.now());return Lh(()=>{if(!e)return;let o=setInterval(()=>r(Date.now()),Fh);return()=>clearInterval(o)},[e]),t}function Bh(e,t){return e.startedAt===void 0?"":nt((e.endedAt??t)-e.startedAt)}var Gh=({step:e,waiting:t})=>e.state==="done"?W(ee,{kind:"ok"}):e.state==="failed"?W(ee,{kind:"fail"}):e.state==="cancelled"?W(ee,{kind:"cancelled"}):e.state==="active"&&!t?W(lt,{marginRight:1,children:W($h,{})}):W(ee,{kind:"pending"}),Wi=({step:e,now:t,waiting:r,status:o})=>{let n=e.state==="active",i=e.state==="done"?e.doneLabel:e.label,s=e.detail??(n?o:void 0);return au(lt,{flexDirection:"column",children:[au(lt,{children:[W(Gh,{step:e,waiting:r}),W(lt,{width:Nh,children:W(Ko,{color:e.state==="pending"?"gray":void 0,bold:n,children:i})}),!(n&&r)&&W(Ko,{color:"gray",children:Bh(e,t)})]}),n&&e.percent!==void 0&&W(lt,{marginLeft:2,children:W(sr,{percent:e.percent})}),n&&s&&W(lt,{marginLeft:2,children:W(Ko,{color:"gray",wrap:"truncate",children:s})}),n&&e.hint&&W(lt,{marginLeft:2,children:W(Ko,{color:"gray",dimColor:!0,children:e.hint})})]})};function cu(e){let t=e.findIndex(o=>o.state!=="done"),r=t===-1?e.length:t;return{finished:e.slice(0,r),live:e.slice(r)}}var lu=({steps:e,waiting:t,status:r})=>{let o=Vi(e.some(n=>n.state==="active"));return W(lt,{flexDirection:"column",children:e.map(n=>W(Wi,{step:n,now:o,waiting:t,status:r},n.id))})};import{Spinner as uu}from"@inkjs/ui";import{Box as q,Text as P,useInput as du}from"ink";var Uh=100;function Yo(){return Math.min(Wo().columns,Uh)}import{jsx as x,jsxs as H}from"react/jsx-runtime";var zo=({checks:e})=>H(q,{flexDirection:"column",borderStyle:I,paddingX:1,borderColor:w,children:[x(P,{bold:!0,children:"System Checks"}),H(q,{flexDirection:"column",marginTop:1,children:[x(Ki,{label:"Git",status:e.git}),e.docker&&x(Ki,{label:"Docker",status:e.docker}),e.mise&&x(Ki,{label:"Mise",status:e.mise})]})]}),Xo=({status:e})=>H(q,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:w,children:[x(P,{bold:!0,children:"Environment Setup"}),x(q,{marginTop:1,children:x(uu,{label:e||"Configuring environment\u2026"})})]}),pu=({title:e,progress:t,phase:r})=>H(q,{flexDirection:"column",borderStyle:I,padding:1,borderColor:w,children:[x(P,{bold:!0,children:e}),H(q,{marginTop:1,flexDirection:"column",children:[x(sr,{percent:t||0}),r&&x(P,{color:"gray",children:r})]})]}),jh=6,Le=({message:e})=>{let[t="",...r]=e.split(`
|
|
112
|
+
`),o=Yo(),n=o-jh;return H(q,{flexDirection:"column",borderStyle:I,borderColor:"red",paddingX:1,marginTop:1,width:o,children:[H(q,{children:[x(ee,{kind:"fail"}),x(P,{bold:!0,children:Jt(t,n)})]}),x(q,{flexDirection:"column",marginLeft:2,children:r.map(i=>x(P,{color:i.startsWith("Full log:")?"gray":void 0,children:Jt(i,n)},i))})]})},qh={success:"ok",error:"fail",missing:"warn"},Ki=({label:e,status:t})=>H(q,{children:[t==="pending"?x(q,{marginRight:1,children:x(uu,{type:"dots"})}):x(ee,{kind:qh[t]}),x(P,{children:e})]}),ar=({portResults:e,onAccept:t,onAbort:r})=>{du((n,i)=>{i.return?t():i.escape&&r()});let o=e.filter(n=>!n.available);return H(q,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:"yellow",children:[x(q,{marginBottom:1,children:x(P,{bold:!0,color:"yellow",children:"Port Conflicts Detected"})}),e.map(n=>H(q,{children:[H(P,{color:n.available?"green":n.alternative?"yellow":"red",children:[n.available?y.ok:n.alternative?y.warn:y.fail," "]}),H(P,{children:[n.service," (:",n.port,")"]}),!n.available&&H(P,{color:n.alternative?"gray":"red",children:[" ","- in use",n.usedBy?` by ${n.usedBy}`:"",n.alternative?` \u2192 will use :${n.alternative}`:" \u2014 NO ALTERNATIVE FOUND"]})]},n.port)),o.some(n=>!n.alternative)&&x(q,{marginTop:1,children:x(P,{color:"red",children:"Some ports have no available alternative. Free them and retry."})}),!o.some(n=>!n.alternative)&&o.some(n=>n.alternative)&&x(q,{marginTop:1,children:x(P,{color:"gray",children:"Alternative ports will be used for conflicting services."})}),x(q,{marginTop:1,children:H(P,{dimColor:!0,children:[x(P,{bold:!0,children:"Enter"})," continue \xB7 ",x(P,{bold:!0,children:"Esc"})," cancel"]})})]})},Hh=({missing:e,onConfirm:t,onDecline:r})=>{du((i,s)=>{s.return&&t(),s.escape&&r()});let o=e.length>1?"them":"it",n=e.length>1?"aren't":"isn't";return H(q,{flexDirection:"column",marginTop:1,marginLeft:2,children:[H(P,{children:["GAIA needs ",x(P,{bold:!0,children:Zt(e)}),", which ",n," ","installed yet."]}),H(P,{children:["Install ",o," now? This uses sudo and takes a few minutes."]}),H(q,{marginTop:1,children:[x(P,{color:w,bold:!0,children:"Enter"}),H(P,{children:[" install ",o]}),x(P,{color:"gray",children:" \xB7 "}),x(P,{bold:!0,children:"Esc"}),x(P,{children:" I'll do it myself"})]})]})},cr=({inputId:e,missing:t,onConfirm:r,onDecline:o})=>e!==si||!t?.length?null:x(Hh,{missing:t,onConfirm:r,onDecline:o});import{useEffect as Vh,useState as Wh}from"react";function Me(e){let[t,r]=Wh(e.currentState);return Vh(()=>{let o=()=>r({...e.currentState});return e.on("change",o),()=>{e.off("change",o)}},[e]),t}import*as fu from"node:path";var zi=["openrouter","gemini","openai","ollama","custom"],Kh={openrouter:{key:"required",baseUrl:"unused",model:"unused"},gemini:{key:"required",baseUrl:"unused",model:"unused"},openai:{key:"required",baseUrl:"unused",model:"unused"},ollama:{key:"unused",baseUrl:"optional",model:"optional"},custom:{key:"required",baseUrl:"required",model:"required"}},Jo={key:"--llm-key",baseUrl:"--llm-base-url",model:"--llm-model"};function Yi(e,t){let r={key:e.llmKey,baseUrl:e.llmBaseUrl,model:e.llmModel}[t];return r!==void 0&&r!==""}function gu(e){let t=Object.keys(Jo);if(!e.llmProvider){let o=t.find(n=>Yi(e,n));if(o)throw new Error(`${Jo[o]} requires --llm-provider <${zi.join("|")}>.`);return}let r=e.llmProvider;for(let o of t){let n=Kh[r][o];if(n==="required"&&!Yi(e,o))throw new Error(`--llm-provider ${r} requires ${Jo[o]}.`);if(n==="unused"&&Yi(e,o))throw new Error(`${Jo[o]} is not used with --llm-provider ${r}.`)}if(e.noStart)throw new Error("--llm-provider saves the provider into the running instance, so it cannot be combined with --no-start. Drop --no-start, or configure the provider in the web setup wizard later.")}function Yh(e){let t=["--provider",e.llmProvider];return e.llmBaseUrl&&t.push("--base-url",e.llmBaseUrl),e.llmModel&&t.push("--model",e.llmModel),t}var mu="GAIA_PROVIDER_API_KEY",lr={openrouter:"OpenRouter",gemini:"Gemini",openai:"OpenAI",ollama:"Ollama",custom:"custom provider"},zh=/Could not save \w+: (.+)/;async function hu(e,t){let r=fu.join(e,"infra/docker");try{await ne("docker",[...Hn(r),"exec","-T","-e",mu,"gaia-backend","python","-m","app.scripts.save_provider",...Yh(t)],r,void 0,void 0,{[mu]:t.llmKey??""})}catch(o){let n=zh.exec(o.message)?.[1];throw n?new Error(n,{cause:o}):o}}var Qo=[["gaia status","check health"],["gaia stop","stop GAIA"],["gaia doctor","find problems"],["gaia --help","all commands"]],Xh="Your user was added to the 'docker' group. Other terminals get it after you log out and back in (or run 'newgrp docker'); until then, 'gaia status' there can't reach Docker.";function Jh(e){if(e.noStart)return"GAIA is set up \xB7 nothing was started";if(e.stillStarting)return"GAIA is still starting";let t=e.startedServices===0?"GAIA is already running":`GAIA is running \xB7 ready in ${nt(e.elapsedMs)}`;return e.unsavedProvider?`${t} \xB7 your ${lr[e.unsavedProvider]} key wasn't saved`:e.startedServices===0?`${t} \xB7 nothing to do`:t}function Qh(e){return e?"on, in local containers on this machine":"off \xB7 turn on: gaia up --code-sandbox, or add an E2B key in Settings"}function Zo(e){let t=[];if(e.noStart)t.push({label:"Next",text:"Start it with gaia start",tone:"primary"});else{e.stillStarting&&t.push({label:"Status",text:"It is still starting in the background. Check again with gaia status.",tone:"warn"});let r=`${e.webUrl}/setup`;t.push(e.setupComplete?{label:"Next",text:`Open ${e.webUrl}`,url:e.webUrl,tone:"primary"}:{label:"Next",text:`Open ${r} to create your admin account and pick an AI model.`,url:r,tone:"primary"});let o=e.reachableUrls.filter(n=>n!==e.webUrl);o.length>0&&t.push({label:"Also at",text:o.join(", "),tone:"dim"})}return e.savedProvider&&t.push({label:"AI",text:`${lr[e.savedProvider]} key saved \xB7 change it in Settings`}),t.push({label:"Code execution",text:Qh(e.codeSandbox),tone:"dim"}),e.joinedDockerGroup&&t.push({label:"Docker",text:Xh,tone:"warn"}),{tone:e.noStart||e.stillStarting?"pending":"success",headline:Jh(e),rows:t}}import{jsx as B,jsxs as ut}from"react/jsx-runtime";var eS={kind:"header"},Su=16,tS=6,rS=14,vu=30,oS={primary:void 0,warn:"yellow",dim:"gray"},nS=({row:e,width:t})=>{let r=e.tone?oS[e.tone]:void 0,o=Jt(e.text,t);if(!e.url)return B(dt,{color:r,children:o});let[n,i]=o.split(e.url);return ut(dt,{color:r,children:[n,B(dt,{color:"cyan",bold:!0,underline:!0,children:e.url}),i]})},iS=({outcome:e})=>{let t=Zo(e),r=t.tone==="success"?"green":w,o=Yo();return ut(Ce,{flexDirection:"column",marginTop:1,children:[ut(Ce,{flexDirection:"column",borderStyle:I,borderColor:r,paddingX:2,paddingY:1,width:o,children:[ut(dt,{bold:!0,color:r,children:[t.tone==="success"?`${y.ok} `:"",t.headline]}),B(Ce,{flexDirection:"column",marginTop:1,children:t.rows.map(n=>ut(Ce,{marginBottom:n.tone==="primary"?1:0,children:[B(Ce,{width:Su,flexShrink:0,children:B(dt,{bold:n.tone==="primary",children:n.label})}),B(nS,{row:n,width:o-tS-Su})]},n.label))})]}),B(Ce,{flexDirection:"row",flexWrap:"wrap",marginTop:1,paddingX:2,width:vu*2+4,children:Qo.map(([n,i])=>ut(Ce,{width:vu,children:[B(Ce,{width:rS,children:B(dt,{color:w,children:n})}),B(dt,{color:"gray",children:i})]},n))})]})},sS=({state:e,store:t})=>e.inputRequest?.id==="port_conflicts"?e.data.portConflicts?B(ar,{portResults:e.data.portConflicts,onAccept:()=>t.submitInput("accept"),onAbort:()=>t.submitInput("abort")}):null:B(cr,{inputId:e.inputRequest?.id,missing:e.data[_t],onConfirm:()=>t.submitInput("install"),onDecline:()=>t.submitInput("decline")}),yu=({store:e})=>{let t=Me(e),r=t.data.steps??[],o=t.data.upOutcome,n=t.data.logPath,i=t.data.finished===!0&&o!==void 0,{finished:s,live:a}=cu(r),c=[...Qr()?[]:[eS],...s.map(l=>({kind:"step",step:l}))];return ut(Ce,{flexDirection:"column",width:"100%",children:[B(Zh,{items:c,children:l=>l.kind==="header"?B(Ce,{marginBottom:1,children:B(ct,{size:"large",showStatus:!1})},"header"):B(Wi,{step:l.step,now:Date.now(),waiting:!1,status:""},l.step.id)}),B(lu,{steps:a,waiting:t.inputRequest!==null,status:t.status}),B(sS,{state:t,store:e}),n&&!i&&!t.error&&B(Ce,{marginTop:1,marginLeft:2,children:ut(dt,{color:"gray",children:["Full log: ",Pe(n)]})}),i&&B(iS,{outcome:o}),t.error&&B(Le,{message:t.error.message})]})};import{Select as Qi,Spinner as vS}from"@inkjs/ui";import{Box as h,Text as f,useInput as ur}from"ink";import Ur from"ink-text-input";import{useEffect as Zi,useState as de}from"react";import{Box as aS,Text as Xi,useInput as cS}from"ink";import{useEffect as lS,useRef as uS,useState as dS}from"react";import{jsx as pS,jsxs as Ji}from"react/jsx-runtime";var wu=8;function bu(e,t){return`${e} ${t}${e===1?"":"s"}`}var en=({logs:e})=>{let[t,r]=dS(0),o=Math.min(e.length,wu),n=e.length>wu,i=uS(e.length);lS(()=>{e.length!==i.current&&(i.current=e.length,r(0))},[e.length]),cS((c,l)=>{n&&(l.upArrow?r(d=>Math.min(d+1,e.length-o)):l.downArrow&&r(d=>Math.max(0,d-1)))});let s=Math.max(0,e.length-o-t),a=e.slice(s,s+o);return Ji(aS,{flexDirection:"column",marginTop:1,marginLeft:1,children:[s>0&&Ji(Xi,{color:"gray",children:[bu(s,"earlier line")," (\u2191 to scroll)"]}),a.map((c,l)=>pS(Xi,{color:"gray",wrap:"truncate",children:c},s+l)),t>0&&Ji(Xi,{color:"gray",children:[bu(t,"newer line")," (\u2193)"]})]})};import{Box as Gr,Text as tn}from"ink";import{Box as mS,Text as fS}from"ink";import{jsx as Eu}from"react/jsx-runtime";var gS=new Set(["Welcome","Finished"]),xu=({status:e,step:t})=>gS.has(t)?null:Eu(mS,{width:"100%",paddingX:1,marginTop:1,children:Eu(fS,{color:"gray",dimColor:!0,children:e})});import{jsx as pt,jsxs as rn}from"react/jsx-runtime";var hS=[{id:"Welcome",label:"Welcome"},{id:"Prerequisites",label:"Prereqs"},{id:"Setup Mode",label:"Mode"},{id:"Repository Setup",label:"Repo"},{id:"Environment Setup",label:"Env"},{id:"Install Tools",label:"Tools"},{id:"Project Setup",label:"Setup"},{id:"Finished",label:"Done"}],Cu=[{id:"Detect Repo",label:"Detect"},{id:"Prerequisites",label:"Prereqs"},{id:"Environment Setup",label:"Env"},{id:"Project Setup",label:"Setup"},{id:"Finished",label:"Done"}],SS=({currentStep:e,steps:t})=>{let r=t.findIndex(n=>n.id===e),o=r===t.length-1;return pt(Gr,{marginY:1,flexWrap:"wrap",children:t.map(({id:n,label:i},s)=>{let a=s<r||o,c=s===r&&!o;return rn(Gr,{flexShrink:0,children:[s>0&&pt(tn,{color:"gray",children:" \xB7 "}),a&&rn(tn,{color:"green",children:[y.ok," ",i]}),c&&pt(tn,{color:w,bold:!0,children:i}),!a&&!c&&pt(tn,{color:"gray",children:i})]},n)})})},on=({children:e,status:t,step:r,steps:o=hS,header:n})=>rn(Gr,{flexDirection:"column",height:"100%",width:"100%",children:[rn(Gr,{flexGrow:1,flexDirection:"column",children:[pt(ct,{...n}),pt(SS,{currentStep:r,steps:o}),pt(Gr,{flexDirection:"column",flexGrow:1,children:e})]}),pt(xu,{status:t,step:r})]});import{jsx as u,jsxs as S}from"react/jsx-runtime";var yS=({onConfirm:e})=>(ur((t,r)=>{r.return&&e()}),S(h,{flexDirection:"column",paddingX:2,borderStyle:I,borderColor:w,children:[u(f,{bold:!0,children:"Welcome to GAIA Setup"}),S(h,{flexDirection:"column",marginTop:1,marginBottom:1,children:[u(f,{children:"This wizard will guide you through the setup process:"}),u(f,{children:" 1. Check prerequisites and choose setup mode"}),u(f,{children:" 2. Clone repository"}),u(f,{children:" 3. Configure environment variables"}),u(f,{children:" 4. Install tools and dependencies"})]}),u(f,{dimColor:!0,children:"~5-15 min depending on network speed"}),u(h,{marginTop:1,children:S(f,{color:w,children:[u(f,{bold:!0,children:"Enter"})," to start"]})})]})),wS=({defaultValue:e,onSubmit:t})=>{let[r,o]=de(e);return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:w,children:[u(f,{children:"Clone repository to:"}),u(f,{color:"gray",dimColor:!0,children:"Press Enter for default, or type a custom path"}),S(h,{marginTop:1,children:[u(f,{color:w,children:"\u2192 "}),u(Ur,{value:r,onChange:o,onSubmit:t})]})]})},bS=({repoPath:e,onAction:t})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:"yellow",children:[u(h,{marginBottom:1,children:u(f,{bold:!0,color:"yellow",children:"Existing Installation Found"})}),S(f,{children:["Found a GAIA installation at"," ",u(f,{color:"cyan",bold:!0,children:e})]}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"What would you like to do?"})}),u(h,{marginTop:1,children:u(Qi,{options:[{label:"Use existing installation",value:"use_existing"},{label:"Delete and re-clone",value:"delete_reclone"},{label:"Choose a different path",value:"different_path"},{label:"Exit setup",value:"exit"}],onChange:o=>t(o)})})]}),ES=({setupMode:e,portOverrides:t,stillStarting:r,onConfirm:o})=>{ur((s,a)=>{a.return&&o()});let n=t?.[3e3]??3e3,i=se(e??"developer",t??{});return e==="selfhost"?S(h,{flexDirection:"column",marginTop:2,borderStyle:I,borderColor:"green",padding:1,children:[u(f,{bold:!0,color:"green",children:r?"GAIA is starting\u2026":"GAIA is running"}),u(h,{marginTop:1,children:u(f,{color:"green",children:r?"Containers are up but not answering yet":"\u2713 All services started"})}),S(h,{marginTop:1,flexDirection:"column",children:[S(f,{children:["Finish setup in your browser:"," ",S(f,{color:"cyan",bold:!0,children:["http://localhost:",n,"/setup"]})]}),S(f,{children:["Web:"," ",S(f,{color:"cyan",bold:!0,children:["http://localhost:",n]})]}),S(f,{children:["API:"," ",u(f,{color:"cyan",bold:!0,children:i})]})]}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia doctor"})}),u(h,{marginTop:1,children:S(f,{dimColor:!0,children:[u(f,{bold:!0,children:"Enter"})," to exit"]})})]}):S(h,{flexDirection:"column",marginTop:2,borderStyle:I,borderColor:w,padding:1,children:[u(f,{color:w,bold:!0,children:"You're all set!"}),S(h,{marginTop:1,children:[u(f,{bold:!0,children:"Run: "}),u(f,{color:"cyan",children:"$ gaia dev"})]}),S(h,{marginTop:1,flexDirection:"column",children:[S(f,{children:["Web:"," ",S(f,{color:"cyan",bold:!0,children:["http://localhost:",n]})]}),S(f,{children:["API:"," ",u(f,{color:"cyan",bold:!0,children:i})]})]}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"gaia dev full \xB7 gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup"})}),u(h,{marginTop:1,children:S(f,{dimColor:!0,children:[u(f,{bold:!0,children:"Enter"})," to exit"]})})]})},es=({phase:e,progress:t,isComplete:r,logs:o,title:n,hint:i})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:w,children:[u(h,{marginBottom:1,children:u(f,{bold:!0,color:w,children:n||"Installing Dependencies"})}),S(h,{flexDirection:"column",gap:1,children:[u(h,{children:r?S(f,{color:"green",children:[y.ok," ",e]}):u(vS,{label:e||"Preparing\u2026"})}),!r&&t>0&&u(sr,{percent:t}),!r&&o&&o.length>0&&u(en,{logs:o}),!r&&u(h,{marginTop:1,children:u(f,{color:"gray",dimColor:!0,children:i||"This may take a few minutes\u2026"})})]})]}),ts=({onSelect:e})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:w,children:[u(f,{bold:!0,children:"Setup Mode"}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"How do you want to run GAIA?"})}),u(h,{marginTop:1,children:u(Qi,{options:[{label:"Self-Host \u2014 run everything in Docker",value:"selfhost"},{label:"Developer \u2014 local dev with hot reload",value:"developer"}],onChange:r=>e(r)})})]}),rs=({onSelect:e})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:w,children:[u(f,{bold:!0,children:"Environment Variables Setup"}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"Choose how you want to configure environment variables:"})}),u(h,{marginTop:1,children:u(Qi,{options:[{label:"Manual Setup (Recommended)",value:"manual"},{label:"Infisical (Advanced)",value:"infisical"}],onChange:r=>e(r)})}),S(h,{marginTop:1,flexDirection:"column",children:[u(f,{color:"gray",dimColor:!0,children:"Manual Setup: Configure variables interactively (recommended for most users)"}),u(f,{color:"gray",dimColor:!0,children:"Infisical: All secrets managed in Infisical dashboard (requires pre-configuration)"})]})]}),os=({onSubmit:e})=>{let[t,r]=de({INFISICAL_PROJECT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET:""}),[o,n]=de(0),[i,s]=de(null),a=[{key:"INFISICAL_PROJECT_ID",description:"Found in your Infisical project settings"},{key:"INFISICAL_MACHINE_IDENTITY_CLIENT_ID",description:"From Access Control \u2192 Machine Identities"},{key:"INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET",description:"Generated when creating the machine identity"}];ur((l,d)=>{if(d.tab||d.downArrow)n(p=>p<a.length-1?p+1:p);else if(d.upArrow)n(p=>p>0?p-1:p);else if(d.return){if(o<a.length-1){n(m=>m+1);return}let p=a.filter(m=>!t[m.key].trim());if(p.length>0){s(`Required: ${p.map(g=>g.key).join(", ")}`);let m=a.findIndex(g=>!t[g.key].trim());m>=0&&n(m);return}e(t)}});let c=a[o];return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:w,children:[u(h,{marginBottom:1,children:u(f,{bold:!0,color:w,children:"Infisical Configuration"})}),u(h,{marginBottom:1,children:u(f,{color:"gray",children:"All secrets managed in your Infisical project. Only credentials stored locally."})}),S(h,{marginBottom:1,flexDirection:"column",children:[u(f,{color:"gray",children:"Configure your Infisical credentials."}),S(f,{color:"gray",dimColor:!0,children:["Visit"," ",u(f,{color:"cyan",underline:!0,children:"app.infisical.com"})," ","to get these values."]})]}),a.map((l,d)=>{let p=l.key.includes("SECRET")||l.key.includes("TOKEN");return S(h,{flexDirection:"column",marginBottom:1,children:[u(h,{children:S(f,{color:d===o?w:"white",children:[d===o?"\u25B8 ":" ",l.key,":"]})}),u(h,{marginLeft:2,children:u(f,{color:"gray",dimColor:!0,children:l.description})}),d===o?u(h,{marginLeft:2,children:u(Ur,{value:t[l.key],onChange:m=>{r(g=>({...g,[l.key]:m})),s(null)},placeholder:"Enter value\u2026",mask:p?"*":void 0})}):u(h,{marginLeft:2,children:u(f,{color:t[l.key]?"green":"gray",children:t[l.key]?p?`\u2713 ${"*".repeat(8)}`:`\u2713 ${t[l.key]}`:"(not set)"})})]},l.key)}),i&&u(h,{marginTop:1,children:u(f,{color:"red",children:i})}),u(h,{marginTop:1,children:S(f,{dimColor:!0,children:[u(f,{bold:!0,children:"Enter"})," confirm \xB7 ",u(f,{bold:!0,children:"\u2191\u2193"})," navigate"]})})]})},ns=({category:e,currentIndex:t,totalGroups:r,onSubmit:o})=>{let[n,i]=de(()=>{let m={};for(let g of e.variables)m[g.name]=g.defaultValue||"";return m}),[s,a]=de(0),[c,l]=de(null);Zi(()=>{let m={};for(let g of e.variables)m[g.name]=g.defaultValue||"";i(m),a(0),l(null)},[e.name]),ur((m,g)=>{if(g.tab||g.downArrow)a(v=>v<e.variables.length-1?v+1:v);else if(g.upArrow)a(v=>v>0?v-1:v);else if(g.escape){let v=e.variables.filter(E=>E.required&&!n[E.name]?.trim());if(v.length>0){l(`Required fields cannot be skipped: ${v.map(E=>E.name).join(", ")}`);return}o(n)}});let d=()=>{if(s<e.variables.length-1)a(s+1);else{let m=e.variables.filter(g=>g.required&&!n[g.name]?.trim());if(m.length>0){l(`Required fields are missing: ${m.map(g=>g.name).join(", ")}`);return}l(null),o(n)}},p=e.variables.some(m=>m.required);return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:c?"red":w,children:[S(h,{justifyContent:"space-between",children:[S(f,{bold:!0,children:["Configure ",e.name]}),S(f,{color:"gray",children:["Group ",t+1," / ",r]})]}),u(h,{marginTop:1,children:u(f,{color:"gray",children:e.description})}),u(h,{marginTop:1,flexDirection:"column",children:e.variables.map((m,g)=>{let v=g===s,E=!!m.defaultValue;return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[S(f,{color:v?w:"gray",bold:v,children:[v?"\u279C ":" ",m.name]}),m.required&&S(f,{color:"red",bold:!0,children:[" ","*"]}),E&&!v&&S(f,{color:"gray",dimColor:!0,children:[" ","(default: ",m.defaultValue,")"]})]}),v&&u(h,{marginLeft:2,children:u(Ur,{value:n[m.name]||"",onChange:b=>{i(C=>({...C,[m.name]:b})),c&&l(null)},onSubmit:d,placeholder:E?`Default: ${m.defaultValue}`:m.required?"Enter a value (required)":"Press Enter to skip"})})]},m.name)})}),c&&u(h,{marginTop:1,children:S(f,{color:"red",bold:!0,children:[y.warn," ",c]})}),u(h,{marginTop:1,children:S(f,{dimColor:!0,children:[u(f,{bold:!0,children:"Enter"})," next \xB7 ",u(f,{bold:!0,children:"\u2191\u2193"})," navigate",!p&&S(f,{children:[" ","\xB7 ",u(f,{bold:!0,children:"ESC"})," skip"]})]})})]})},is=({alternatives:e,onSubmit:t})=>{let[r,o]=de(new Set),[n,i]=de({}),[s,a]=de(0),[c,l]=de(null);Zi(()=>{let b={};for(let C of e)for(let M of C.variables)b[M.name]=M.defaultValue||"";i(b)},[e]);let d=[];for(let b=0;b<e.length;b++)if(d.push({type:"provider",categoryIndex:b}),r.has(b)){let C=e[b];if(C)for(let M=0;M<C.variables.length;M++)d.push({type:"field",categoryIndex:b,fieldIndex:M})}d.push({type:"submit"});let p=d[s],m=p?.type==="field",g=p?.type==="submit";ur((b,C)=>{let M=Math.min(s,d.length-1);if(M!==s){a(M);return}if(m)C.upArrow?a(O=>Math.max(0,O-1)):(C.downArrow||C.tab)&&a(O=>Math.min(d.length-1,O+1));else if(g)C.upArrow?a(O=>Math.max(0,O-1)):(C.return||b===" ")&&E();else if(C.upArrow)a(O=>Math.max(0,O-1));else if(C.downArrow||C.tab)a(O=>Math.min(d.length-1,O+1));else if((C.return||b===" ")&&p?.type==="provider"){let O=p.categoryIndex;o(vt=>{let G=new Set(vt);return G.has(O)?G.delete(O):G.add(O),G}),c&&l(null)}});let v=()=>{c&&l(null),a(b=>Math.min(d.length-1,b+1))},E=()=>{let b=[],C={};for(let M of r){let O=e[M];if(!O)continue;if(O.variables.some(G=>n[G.name]?.trim())){b.push(O.name);for(let G of O.variables){let Wr=n[G.name];Wr&&(C[G.name]=Wr)}}}if(b.length===0){r.size===0?l("Enable at least one provider (press Space or Enter)"):l("Enter a value for at least one field");return}t(b,C)};return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:c?"red":w,children:[S(h,{justifyContent:"space-between",children:[u(f,{bold:!0,children:"Configure AI Provider"}),u(f,{color:"yellow",children:"* At least one required"})]}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"Enable and configure at least one AI provider below:"})}),u(h,{marginTop:1,flexDirection:"column",children:e.map((b,C)=>{let M=r.has(C),O=d.findIndex(G=>G.type==="provider"&&G.categoryIndex===C),vt=s===O;return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[u(f,{color:vt?w:void 0,bold:vt,children:vt?"\u279C ":" "}),u(f,{color:M?"green":"gray",children:M?`[${y.ok}]`:"[ ]"}),S(f,{color:M?w:"gray",bold:M,children:[" ",b.name]}),b.description&&S(f,{color:"gray",dimColor:!0,children:[" ","- ",b.description]})]}),vt&&b.docsUrl&&S(h,{marginLeft:6,children:[u(f,{color:"yellow",children:"\u{1F4D6} "}),u(f,{color:"blue",underline:!0,children:b.docsUrl})]}),M&&u(h,{marginLeft:4,flexDirection:"column",marginTop:1,children:b.variables.map((G,Wr)=>{let Ad=d.findIndex(fr=>fr.type==="field"&&fr.categoryIndex===C&&fr.fieldIndex===Wr),Gt=s===Ad,ps=!!G.defaultValue,fn=n[G.name]||"";return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[S(f,{color:Gt?w:"gray",bold:Gt,children:[Gt?" \u279C ":" ",G.name]}),!Gt&&fn&&u(f,{color:"green",children:" \u2713"}),!Gt&&!fn&&ps&&S(f,{color:"gray",dimColor:!0,children:[" ","(default: ",G.defaultValue,")"]})]}),Gt&&u(h,{marginLeft:4,children:u(Ur,{value:fn,onChange:fr=>{i(Pd=>({...Pd,[G.name]:fr})),c&&l(null)},onSubmit:v,placeholder:ps?`Default: ${G.defaultValue}`:"Enter value\u2026"})})]},G.name)})})]},b.name)})}),c&&u(h,{marginTop:1,children:S(f,{color:"red",bold:!0,children:[y.warn," ",c]})}),S(h,{marginTop:1,children:[u(f,{color:g?w:void 0,bold:g,children:g?"\u279C ":" "}),u(h,{borderStyle:I,borderColor:g?w:"gray",paddingX:2,children:u(f,{color:g?w:"gray",bold:g,children:"Continue \u2192"})})]}),u(h,{marginTop:1,children:u(f,{color:"gray",dimColor:!0,children:"\u2191/\u2193 navigate \u2022 Space/Enter toggle/select \u2022 Tab skip field"})})]})},ss=({currentVar:e,currentIndex:t,totalCount:r,onSubmit:o,onSkip:n})=>{let[i,s]=de(e.defaultValue||""),[a,c]=de(null);Zi(()=>{s(e.defaultValue||""),c(null)},[e.name]),ur((p,m)=>{if(m.escape){if(e.required&&!i.trim()){c("This field is required and cannot be skipped");return}n()}});let l=p=>{if(e.required&&!p.trim()){c("This field is required");return}c(null),o(p)},d=!!e.defaultValue;return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:a?"red":w,children:[S(h,{justifyContent:"space-between",children:[S(h,{children:[u(f,{color:w,bold:!0,children:e.name}),e.required?u(f,{color:"red",children:" *"}):S(f,{color:"gray",dimColor:!0,children:[" ","optional"]})]}),S(f,{color:"gray",children:[t+1,"/",r]})]}),u(h,{marginLeft:1,children:u(f,{color:"gray",children:e.description})}),S(h,{marginTop:1,children:[u(f,{color:w,children:"\u2192 "}),u(Ur,{value:i,onChange:p=>{s(p),a&&c(null)},onSubmit:l,placeholder:d?`Default: ${e.defaultValue}`:e.required?"required":"skip with Enter"})]}),a&&u(h,{marginTop:1,children:u(f,{color:"red",children:a})}),u(h,{marginTop:1,children:S(f,{dimColor:!0,children:[u(f,{bold:!0,children:"Enter"})," confirm",!e.required&&S(f,{children:[" ","\xB7 ",u(f,{bold:!0,children:"ESC"})," skip"]})]})})]})},Iu=({store:e})=>{let t=Me(e);return S(on,{status:t.status,step:t.step,children:[t.step==="Welcome"&&t.inputRequest?.id==="welcome"&&u(yS,{onConfirm:()=>e.submitInput(!0)}),t.step==="Prerequisites"&&t.data.checks&&u(zo,{checks:t.data.checks}),u(cr,{inputId:t.inputRequest?.id,missing:t.data[_t],onConfirm:()=>e.submitInput("install"),onDecline:()=>e.submitInput("decline")}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&u(ar,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="repo_path"&&u(wS,{defaultValue:t.inputRequest.meta.default,onSubmit:r=>e.submitInput(r)}),t.inputRequest?.id==="existing_repo"&&t.data.existingRepoPath&&u(bS,{repoPath:t.data.existingRepoPath,onAction:r=>e.submitInput(r)}),t.step==="Repository Setup"&&!t.inputRequest&&u(pu,{title:"Cloning Repository",progress:t.data.repoProgress,phase:t.data.repoPhase}),t.inputRequest?.id==="setup_mode"&&u(ts,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_method"&&u(rs,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_infisical"&&u(os,{onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&u(ss,{categories:t.data.envCategories||[],currentVar:t.data.currentEnvVar,currentIndex:t.data.envVarIndex||0,totalCount:t.data.envVarTotal||0,onSubmit:r=>e.submitInput(r),onSkip:()=>e.submitInput("")}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_group"&&t.data.currentEnvGroup&&u(ns,{category:t.data.currentEnvGroup,currentIndex:t.data.envGroupIndex||0,totalGroups:t.data.envGroupTotal||0,onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_alternatives"&&t.data.alternativeGroups&&u(is,{alternatives:t.data.alternativeGroups,onSubmit:(r,o)=>e.submitInput({selectedGroups:r,values:o})}),t.step==="Environment Setup"&&!t.inputRequest&&u(Xo,{status:t.status}),t.step==="Finished"&&u(ES,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,stillStarting:t.data.stillStarting===!0,onConfirm:()=>e.submitInput("exit")}),(t.step==="Install Tools"||t.step==="Project Setup")&&u(es,{title:t.step==="Install Tools"?"Installing Tools":"Project Setup",phase:t.data.dependencyPhase||"",progress:t.data.dependencyProgress||0,isComplete:t.step==="Install Tools"?t.data.toolComplete||!1:t.data.dependencyComplete||!1,logs:t.data.dependencyLogs||[]}),t.error&&u(Le,{message:t.error.message})]})};import{Spinner as xS}from"@inkjs/ui";import{Box as Nt,Text as dr}from"ink";import{useState as CS}from"react";import{jsx as mt,jsxs as Ie}from"react/jsx-runtime";var ku=({store:e})=>{let t=Me(e),r=t.step==="Starting"||t.step==="Stopping",o=t.step==="Running"||t.step==="Stopped",n=t.data.dockerLogs??[],[i]=CS(Date.now),s=Vi(r);return Ie(Nt,{flexDirection:"column",width:"100%",children:[mt(ct,{showStatus:o}),r&&!t.error&&Ie(Nt,{flexDirection:"column",marginTop:1,children:[Ie(Nt,{children:[mt(xS,{label:t.status||"Working\u2026"}),Ie(dr,{color:"gray",children:[" ",nt(s-i)]})]}),n.length>0&&mt(en,{logs:n})]}),t.step==="Running"&&t.data.started&&Ie(Nt,{flexDirection:"column",marginTop:1,children:[Ie(Nt,{children:[mt(ee,{kind:"ok"}),Ie(dr,{children:["GAIA is running at"," ",mt(dr,{color:"cyan",bold:!0,children:t.data.webUrl})]})]}),Ie(dr,{color:"gray",children:[" ","gaia status shows its health \xB7 gaia stop shuts it down"]})]}),t.step==="Stopped"&&t.data.stopped&&Ie(Nt,{flexDirection:"column",marginTop:1,children:[Ie(Nt,{children:[mt(ee,{kind:"ok"}),mt(dr,{children:t.status})]}),t.data.stopMode==="force-ports"&&Ie(dr,{color:"yellow",children:[" ","--force-ports also stopped whatever else listened on GAIA's ports."]})]}),t.error&&mt(Le,{message:t.error.message})]})};import{Spinner as IS}from"@inkjs/ui";import{Box as ft,Text as Se,useInput as kS}from"ink";import{jsx as k,jsxs as Ne}from"react/jsx-runtime";var Ru=({store:e})=>{let t=Me(e);return Ne(on,{status:t.status,step:t.step,steps:Cu,children:[t.step==="Detect Repo"&&Ne(ft,{flexDirection:"column",paddingX:2,borderStyle:I,borderColor:w,children:[k(Se,{bold:!0,children:"Detecting GAIA Repository"}),k(ft,{marginTop:1,children:k(IS,{label:"Searching for repository\u2026"})}),t.data.repoPath&&k(ft,{marginTop:1,children:Ne(Se,{color:"green",children:["Found: ",t.data.repoPath]})})]}),t.step==="Prerequisites"&&t.data.checks&&k(zo,{checks:t.data.checks}),k(cr,{inputId:t.inputRequest?.id,missing:t.data[_t],onConfirm:()=>e.submitInput("install"),onDecline:()=>e.submitInput("decline")}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&k(ar,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="setup_mode"&&k(ts,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_method"&&k(rs,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_infisical"&&k(os,{onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&k(ss,{categories:t.data.envCategories||[],currentVar:t.data.currentEnvVar,currentIndex:t.data.envVarIndex||0,totalCount:t.data.envVarTotal||0,onSubmit:r=>e.submitInput(r),onSkip:()=>e.submitInput("")}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_group"&&t.data.currentEnvGroup&&k(ns,{category:t.data.currentEnvGroup,currentIndex:t.data.envGroupIndex||0,totalGroups:t.data.envGroupTotal||0,onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_alternatives"&&t.data.alternativeGroups&&k(is,{alternatives:t.data.alternativeGroups,onSubmit:(r,o)=>e.submitInput({selectedGroups:r,values:o})}),t.step==="Environment Setup"&&!t.inputRequest&&k(Xo,{status:t.status}),t.step==="Project Setup"&&k(es,{title:"Project Setup",phase:t.data.dependencyPhase||"",progress:t.data.dependencyProgress||0,isComplete:t.data.dependencyComplete||!1,logs:t.data.dependencyLogs||[]}),t.step==="Finished"&&k(RS,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,onConfirm:()=>e.submitInput("exit")}),t.error&&k(Le,{message:t.error.message})]})},RS=({setupMode:e,portOverrides:t,onConfirm:r})=>{kS((s,a)=>{a.return&&r()});let o=t?.[3e3]??3e3,n=se(e??"developer",t??{}),i=e==="selfhost";return Ne(ft,{flexDirection:"column",marginTop:2,borderStyle:I,borderColor:w,padding:1,children:[k(Se,{color:w,bold:!0,children:"Setup Complete!"}),Ne(ft,{marginTop:1,children:[k(Se,{bold:!0,children:"Run: "}),k(Se,{color:"cyan",children:i?"$ gaia start":"$ gaia dev"})]}),Ne(ft,{marginTop:1,flexDirection:"column",children:[Ne(Se,{children:["Web:"," ",Ne(Se,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),Ne(Se,{children:["API:"," ",k(Se,{color:"cyan",bold:!0,children:n})]})]}),k(ft,{marginTop:1,children:k(Se,{color:"gray",children:i?"gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup":"gaia dev full \xB7 gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup"})}),k(ft,{marginTop:1,children:Ne(Se,{dimColor:!0,children:[k(Se,{bold:!0,children:"Enter"})," to exit"]})})]})};import{Spinner as BS}from"@inkjs/ui";import{Box as te,Text as Fe,useInput as GS}from"ink";var TS=[{name:"API",port:8e3,type:"http",path:"/health"},{name:"Web",port:3e3,type:"http",path:"/"},{name:"PostgreSQL",port:5432,type:"tcp"},{name:"Redis",port:6379,type:"tcp"},{name:"MongoDB",port:27017,type:"tcp"},{name:"RabbitMQ",port:5672,type:"tcp"},{name:"ChromaDB",port:8080,type:"tcp"}];async function Tu(e){return Promise.all(TS.map(t=>{let r=e[t.port]??t.port;return t.type==="http"?AS(t.name,r,t.path):PS(t.name,r)}))}async function AS(e,t,r){let o=Date.now();try{let n=await fetch(`http://localhost:${t}${r}`,{signal:AbortSignal.timeout(5e3)}),i=Date.now()-o;return{name:e,port:t,status:n.ok?"up":"down",latency:i,details:n.ok?`HTTP ${n.status}`:`HTTP ${n.status} (error)`}}catch{return{name:e,port:t,status:"down",details:"Connection failed"}}}async function PS(e,t){let r=await import("node:net"),o=Date.now();return new Promise(n=>{let i=new r.Socket;i.setTimeout(3e3),i.on("connect",()=>{let s=Date.now()-o;i.destroy(),n({name:e,port:t,status:"up",latency:s})}),i.on("timeout",()=>{i.destroy(),n({name:e,port:t,status:"down"})}),i.on("error",()=>{i.destroy(),n({name:e,port:t,status:"down"})}),i.connect(t,"localhost")})}async function Au(e){let t=await J();if(t!=="ready")return{access:t,problem:await Ue(t),containers:[]};let r=await Es(pe[e]);return{access:t,containers:r}}var jr="statusFacts";async function _S(){let e=_(),t=e?await F(e):null,r=kr(e,t);if(!e||!t)return{install:r,installed:!1,services:[],setupComplete:null};let o=N(e),n=o[A]??A,[i,s,a]=await Promise.all([t==="developer"?Tu(o):[],Au(t),Vo(kt(t,o),pe[t])]),c=a.reachable?await _e(se(t,o),"status"):null;return{install:r,installed:!0,docker:t==="selfhost"&&s.access==="ready"?{...s,containers:DS(s.containers)}:s,readiness:a,services:i,webUrl:et(e,n),setupComplete:c&&"data"in c?!c.data.needs_setup:null}}function DS(e){let t=(L()?.bots??[]).map(me).filter(r=>!e.some(o=>o.name===r));return[...e,...t.map(r=>({name:r,status:"not_found"}))]}async function OS(e){e.setStep("Checking"),e.setStatus("Checking GAIA's services\u2026");let t=await _S();e.updateData(jr,t),e.updateData("checkedAt",new Date().toLocaleTimeString()),e.setStep("Results")}async function Pu(e,t={}){for(e.updateData("watch",t.watch===!0);;)if(await OS(e),!t.watch||await e.waitForInput("exit_or_refresh")!=="refresh")return}var $S=["gaia-web","gaia-backend","arq_worker","proxy"],LS=["mongo","postgres","redis","rabbitmq","chromadb"];function nn(e,t,r){return t.some(n=>!n.ok)?{label:e,items:t,note:r,tone:"fail"}:{label:e,items:t,tone:"ok"}}function _u(e,t){return t.map(r=>e.find(o=>o.name===r)).filter(r=>r!==void 0).map(r=>({ok:r.status==="running",name:Ae(r.name)}))}function Du(e,t){let r=e.readiness,o=r?.reachable===!0?r.dependencies.map(i=>({ok:i.ok,name:ao(i.name)})):_u(t,LS),n=r?.reachable===!0?r.dependencies.find(i=>!i.ok)?.fix:void 0;return nn("Data",o,n??"See why with: gaia doctor")}function MS(e){let t=e.filter(r=>r.name.startsWith("bot-"));return t.length===0?{label:"Bots",items:[],note:"none \xB7 add one: gaia bots add telegram",tone:"dim"}:nn("Bots",t.map(r=>({ok:r.status==="running",name:Ae(r.name)})),"See why with: gaia doctor")}function Ou(e){return e.setupComplete===null?null:e.setupComplete?{label:"Setup",items:[],note:"finished",tone:"ok"}:{label:"Setup",items:[],note:`not finished \xB7 open ${e.webUrl}/setup`,tone:"warn"}}function NS(e,t){let r=t.containers,n=[nn("App",_u(r,$S),"Start it: gaia start"),Du(e,r),MS(r)],i=Ou(e);i&&n.push(i);let s=r.some(c=>c.status==="running"),a=n.some(c=>c.tone==="fail");return s?{headline:a?{kind:"fail",text:"GAIA is running, but part of it is down"}:{kind:"ok",text:"GAIA is running",url:e.webUrl},rows:n,unhealthy:a}:{headline:{kind:"fail",text:"GAIA isn't running \xB7 start it: gaia start"},rows:[],unhealthy:!0}}function FS(e){let t=e.services.map(o=>({ok:o.status==="up",name:`${o.name} :${o.port}`})),r=nn("Local",t,"Start them: gaia dev");return{headline:r.tone==="fail"?{kind:"fail",text:"Part of the dev stack is down"}:{kind:"ok",text:"The dev stack is running",url:e.webUrl},rows:[r],unhealthy:r.tone==="fail"}}function sn(e){if(!e.installed)return{headline:{kind:"warn",text:`${e.install} \xB7 run: gaia up`},rows:[],unhealthy:!0};let t=e.docker;if(t?.problem){let r=e.readiness?.reachable===!0,o={label:"Docker",items:[],note:t.problem.state,tone:"warn"},n=Ou(e);return{headline:r?{kind:"ok",text:"GAIA is running",url:e.webUrl}:{kind:"fail",text:t.problem.summary},hint:t.problem.fix,rows:r?[Du(e,[]),...n?[n]:[],o]:[],unhealthy:!0}}return e.services.length>0?FS(e):NS(e,t??{access:"ready",containers:[]})}import{jsx as D,jsxs as We}from"react/jsx-runtime";var US=8,jS={ok:void 0,warn:"yellow",fail:"red",dim:"gray"},qS=({row:e})=>We(te,{children:[D(te,{width:US,flexShrink:0,children:D(Fe,{bold:!0,children:e.label})}),We(te,{flexDirection:"column",flexShrink:1,children:[e.items.length>0&&D(te,{flexWrap:"wrap",children:e.items.map(t=>We(te,{marginRight:2,flexShrink:0,children:[D(ee,{kind:t.ok?"ok":"fail"}),D(Fe,{children:t.name})]},t.name))}),e.note&&We(te,{children:[e.items.length===0&&e.tone!=="dim"&&D(ee,{kind:e.tone==="warn"?"warn":"ok"}),D(Fe,{color:jS[e.tone],children:e.note})]})]})]}),$u=({store:e})=>{let t=Me(e),r=t.data[jr],o=t.data.watch===!0,n=t.step==="Results"&&r!==void 0;GS((a,c)=>{a==="q"||c.return||c.escape?e.submitInput("exit"):a==="r"&&e.submitInput("refresh")},{isActive:o&&t.inputRequest!==null});let i=r?sn(r):null,s=i?.headline.kind??"ok";return We(te,{flexDirection:"column",width:"100%",children:[D(ct,{showStatus:!1}),t.step==="Checking"&&D(te,{marginTop:1,marginLeft:2,children:D(BS,{label:t.status})}),n&&i&&We(te,{flexDirection:"column",marginTop:1,marginLeft:2,children:[We(te,{children:[D(ee,{kind:s==="ok"?"active":s}),D(Fe,{bold:!0,children:i.headline.text})]}),i.headline.url&&D(te,{marginLeft:2,children:D(Fe,{color:w,children:i.headline.url})}),i.hint&&D(te,{marginLeft:2,children:D(Fe,{children:i.hint})}),i.rows.length>0&&D(te,{flexDirection:"column",marginTop:1,children:i.rows.map(a=>D(qS,{row:a},a.label))}),r.installed&&D(te,{marginTop:1,children:We(Fe,{color:"gray",children:["Installed at ",r.install]})}),o&&D(te,{marginTop:1,children:We(Fe,{color:"gray",children:["checked ",t.data.checkedAt," \xB7 ",D(Fe,{bold:!0,children:"r"})," check again \xB7 ",D(Fe,{bold:!0,children:"q"})," quit"]})})]}),t.error&&D(Le,{message:t.error.message})]})};import{defaultTheme as HS,extendTheme as VS}from"@inkjs/ui";var Lu=VS(HS,{components:{Spinner:{styles:{frame:()=>({color:w})}},ProgressBar:{styles:{completed:()=>({color:w})}}}});import{jsx as ce,jsxs as pr}from"react/jsx-runtime";var zS=["init","setup","status","start","stop","up"],as=class extends YS.Component{constructor(t){super(t),this.state={error:null}}static getDerivedStateFromError(t){return{error:t}}render(){return this.state.error?pr(an,{flexDirection:"column",padding:1,children:[ce(Ft,{color:"red",bold:!0,children:"An unexpected error occurred:"}),ce(Ft,{color:"red",children:this.state.error.message}),this.state.error.stack&&ce(an,{marginTop:1,children:ce(Ft,{color:"gray",dimColor:!0,children:this.state.error.stack})})]}):this.props.children}},XS=({store:e,command:t})=>{switch(t){case"init":return ce(Iu,{store:e});case"setup":return ce(Ru,{store:e});case"status":return ce($u,{store:e});case"start":case"stop":return ce(ku,{store:e,command:t});case"up":return ce(yu,{store:e});default:return pr(an,{flexDirection:"column",padding:1,children:[pr(Ft,{color:"red",children:["Unknown command: ",t]}),pr(an,{marginTop:1,flexDirection:"column",children:[ce(Ft,{bold:!0,children:"Available commands:"}),zS.map(r=>pr(Ft,{children:[" ",ce(Ft,{color:"cyan",children:r})]},r))]})]})}},JS=({onCancel:e})=>(KS((t,r)=>{r.ctrl&&t==="c"&&e()}),null),Mu=({store:e,command:t,onCancel:r})=>ce(as,{children:pr(WS,{theme:Lu,children:[ce(JS,{onCancel:r}),ce(XS,{store:e,command:t})]})});import{EventEmitter as QS}from"events";var ZS=150,cs=class extends QS{state={step:"init",status:"",error:null,data:{},inputRequest:null};inputResolver=null;emitTimer=null;emitPending=!1;autoResolveInputs=new Map;answerResolvers=[];setAutoResolve(t,r="exit"){this.autoResolveInputs.set(t,r)}pushAnswerResolver(t){this.answerResolvers.push(t)}get currentState(){return this.state}scheduleEmit(){this.emitPending=!0,this.emitTimer||(this.emitTimer=setTimeout(()=>{this.emitTimer=null,this.emitPending&&(this.emitPending=!1,this.emit("change",this.state))},ZS))}flush(){this.emitPending&&this.emitNow()}emitNow(){this.emitTimer&&(clearTimeout(this.emitTimer),this.emitTimer=null),this.emitPending=!1,this.emit("change",this.state)}setStep(t){this.state.step=t,this.emitNow()}setStatus(t){this.state.status=t,this.scheduleEmit()}setError(t){this.state.error=t,t!==null&&this.inputResolver&&(this.inputResolver(null),this.inputResolver=null,this.state.inputRequest=null),this.emitNow()}updateData(t,r){this.state.data={...this.state.data,[t]:r},this.scheduleEmit()}ask(t,r,o){return this.answerResolvers.map(i=>i(t,o)).find(i=>i!==void 0)===void 0&&!this.autoResolveInputs.has(t)&&this.setStatus(r),this.waitForInput(t,o)}waitForInput(t,r,o){if(this.autoResolveInputs.has(t))return this.state.inputRequest=null,this.emitNow(),Promise.resolve(this.autoResolveInputs.get(t));for(let n of this.answerResolvers){let i=n(t,r);if(i!==void 0)return this.state.inputRequest=null,this.emitNow(),Promise.resolve(i)}return this.state.inputRequest={id:t,meta:r},this.emitNow(),new Promise(n=>{if(this.inputResolver=n,o!=null){let i=setTimeout(()=>{this.inputResolver&&(this.inputResolver=null,this.state.inputRequest=null,this.emitNow(),n(null))},o),s=this.inputResolver;this.inputResolver=a=>{clearTimeout(i),s(a)}}})}submitInput(t){this.inputResolver&&(this.inputResolver(t),this.inputResolver=null,this.state.inputRequest=null,this.emitNow())}},Nu=()=>new cs;async function ve(e){let t=Nu();if(e.whenNonInteractive==="fail"){Cc(e.command),await Bu(t,e);return}fe()?await Bu(t,e):await rv(t,e)}async function rv(e,t){Ic(e,Qr());for(let[r,o]of t.autoResolve??[])e.setAutoResolve(r,o);try{await t.runFlow(e);let r=Uu(e);r&&await kn(e.currentState.step,r,oi(e)),t.onPlainComplete?.(e)}catch(r){e.setError(r)}ju(e)}var Gu=30,ov=Math.ceil(1e3/Gu);async function Fu(e){e.flush(),await new Promise(t=>setTimeout(t,2*ov))}async function Bu(e,t){let r=async()=>{},{unmount:o,clear:n}=ev(tv.createElement(Mu,{store:e,command:t.command,onCancel:()=>void r()}),{exitOnCtrlC:!1,maxFps:Gu}),i=async()=>{ot(e,"cancelled"),await Fu(e),o();let a=t.cancelHint?` ${t.cancelHint}`:"";process.stdout.write(`
|
|
113
|
+
${y.cancelled} Cancelled.${a}
|
|
114
|
+
`),process.exit(130)};r=i,process.once("SIGINT",i),process.once("SIGTERM",i);try{await t.runFlow(e)}catch(a){e.setError(a)}finally{process.off("SIGINT",i),process.off("SIGTERM",i)}await Fu(e);let s=Uu(e);s&&(n(),o(),await kn(e.currentState.step,s,oi(e))),o(),process.stdout.write(`
|
|
115
|
+
`),ju(e)}function Uu(e){if(!e.currentState.error)return e.currentState.data.dockerGroupSwitch}function ju(e){let t=e.currentState.error?1:Number(process.exitCode??0),r=[process.stdout,process.stderr].filter(n=>n.writableLength>0);r.length===0&&process.exit(t);let o=r.length;for(let n of r)n.once("drain",()=>{o-=1,o===0&&process.exit(t)})}import*as gt from"fs";import*as Hu from"os";import*as Bt from"path";import*as cn from"node:fs";import*as qu from"node:path";var nv=e=>new Promise(t=>setTimeout(t,e));async function ln(e){e.setStep("Setup Mode"),e.setStatus("Choose how to run GAIA\u2026");let t=await e.waitForInput("setup_mode");return e.updateData("setupMode",t),t}async function mr(e,t,r,o,n){e.setStep("Environment Setup"),e.setStatus("Configuring GAIA\u2026"),e.updateData("setupMode",r),e.setStatus("Configuring GAIA\u2026");let i=await e.waitForInput("env_method");e.updateData("envMethod",i);let s={ENV:r==="selfhost"?"selfhost":"development"};r==="selfhost"&&(s.AUTH_MODE="local");for(let d of wr()){let p=yr(d,r);p&&(s[d]=p)}Object.assign(s,Ws(r));let a={};n?.domain&&(a.HOST=`https://${n.domain}`,a.FRONTEND_URL=`https://${n.domain}`),i==="infisical"?(await sv(e,a),e.setStatus("Infisical credentials saved. Ensure your Infisical project contains all required variables.")):await cv(e,a,r,n?.llmProvider===void 0);let c=cn.existsSync(je(t))?cn.readFileSync(je(t),"utf-8"):null,l=iv({defaults:s,existing:Ct(c),existingMode:await F(t),answers:a,setupMode:r});o&&Hs(l,o,r),r==="selfhost"&&Object.assign(l,io(c));try{await lv(e,t,l,r,o,n?.domain)}catch(d){e.setError(d);return}await nv(1e3)}function iv(e){let{defaults:t,existing:r,existingMode:o,answers:n,setupMode:i}=e,s=o===i;return{...s?t:r,...s?r:t,...n,SETUP_MODE:i}}async function sv(e,t){e.setStatus("Configuring Infisical\u2026");let r=await e.waitForInput("env_infisical");t.INFISICAL_PROJECT_ID=r.INFISICAL_PROJECT_ID,t.INFISICAL_MACHINE_IDENTITY_CLIENT_ID=r.INFISICAL_MACHINE_IDENTITY_CLIENT_ID,t.INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET=r.INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET}function av(e){let t=[],r=new Set,o=new Set;for(let n of e)if(n.alternativeGroup&&!o.has(n.name)){let i=e.find(s=>s.name===n.alternativeGroup);i&&(t.push([n,i]),r.add(n.name),r.add(i.name),o.add(n.name),o.add(i.name))}return{alternativePairs:t,alternativeGroupNames:r}}async function cv(e,t,r,o){e.setStatus("Parsing environment variables\u2026");let n=Vs(eo(),r).filter(g=>r!=="selfhost"||g.selfhostSetup),{alternativePairs:i,alternativeGroupNames:s}=av(n),a=n.filter(g=>g.variables.length===1&&!s.has(g.name)),c=n.filter(g=>g.variables.length>1&&!s.has(g.name));for(let g of o?i:[]){e.updateData("alternativeGroups",g);let v=await e.ask("env_alternatives","Choose an AI provider\u2026");for(let[E,b]of Object.entries(v.values))b&&(t[E]=b)}let l=wr(),p=[...a.flatMap(g=>g.variables).filter(g=>!l.includes(g.name))].sort((g,v)=>g.required&&!v.required?-1:!g.required&&v.required?1:0);e.updateData("envVarTotal",p.length);for(let g=0;g<p.length;g++){let v=p[g];if(!v)continue;e.updateData("currentEnvVar",v),e.updateData("envVarIndex",g);let E=await e.ask("env_var",`Configuring ${v.name}\u2026`,{varName:v.name});(E||v.required||v.defaultValue)&&(t[v.name]=E||v.defaultValue||"")}let m=[...c].filter(g=>!g.variables.every(v=>l.includes(v.name))).sort((g,v)=>{let E=g.variables.some(C=>C.required),b=v.variables.some(C=>C.required);return E&&!b?-1:!E&&b?1:0});e.updateData("envGroupTotal",m.length);for(let g=0;g<m.length;g++){let v=m[g];if(!v)continue;e.updateData("currentEnvGroup",v),e.updateData("envGroupIndex",g);let E=await e.ask("env_group",`Configuring ${v.name}\u2026`,{groupName:v.name});for(let[b,C]of Object.entries(E)){let M=v.variables.find(O=>O.name===b);(C||M?.required||M?.defaultValue)&&(t[b]=C||M?.defaultValue||"")}}}async function lv(e,t,r,o,n,i){e.setStatus("Saving GAIA's settings\u2026");try{let s=qu.join(t,"apps","api");br(s,r),e.setStatus("Saved GAIA's settings")}catch(s){throw new Error(`Failed to write API .env file: ${s.message}`)}if(o==="selfhost"){e.setStatus("Saving Docker's settings\u2026");try{On(t,n??{},o,{dockerSocketGid:Cs(),domain:i}),e.setStatus("Saved Docker's settings")}catch(s){throw new Error(`Failed to write Docker Compose .env: ${s.message}`)}return}e.setStatus("Saving the web app's settings\u2026");try{Ys(t,o,n),e.setStatus("Saved the web app's settings")}catch(s){throw new Error(`Failed to write web .env file: ${s.message}`)}if(n&&Object.keys(n).length>0){e.setStatus("Saving Docker's settings\u2026");try{ea(t),On(t,n,o),e.setStatus("Saved Docker's settings")}catch(s){throw new Error(`Failed to write Docker Compose .env: ${s.message}`)}}}var uv=5e3,dv=5*6e4,pv=5e3;async function mv(e,t={}){let r=t.intervalMs??uv,o=Date.now()+(t.timeoutMs??dv),n=new Map(e.map(i=>[i.label,i]));for(;;){if(await Promise.all([...n.values()].map(async i=>{await fv(i)&&n.delete(i.label)})),n.size===0)return{ready:!0};if(Date.now()>=o)return{ready:!1,stillStarting:[...n.keys()].join(", ")};t.onProgress?.([...n.keys()]),await z(r)}}async function fv(e){try{let t=await fetch(e.url,{signal:AbortSignal.timeout(pv)});return e.requireOk?t.ok:!0}catch{return!1}}async function un(e,t){let r=await mv([{label:"API",url:`${t.apiUrl}/ping`,requireOk:!0},{label:"Web",url:`http://localhost:${t.webPort}/login`,requireOk:!1}],{onProgress:o=>{gv(e,o)}});return e.updateData("dependencyPhase",r.ready?"GAIA is answering":`Still starting: ${r.stillStarting}`),e.updateData("dependencyComplete",!0),r}function gv(e,t){let r=`Waiting for ${t.join(" and ")} to come online\u2026`;e.setStatus(r),e.updateData("dependencyComplete",!1),e.updateData("dependencyPhase",r)}var hv=process.env.GAIA_CLI_DEV==="true";async function Vu(e,t){e.setStep("Welcome"),e.setStatus("Waiting for user input\u2026"),await e.waitForInput("welcome");let r=ko(e);if(e.setStep("Prerequisites"),e.setStatus("Checking system requirements\u2026"),!await Ro(e))return;let o=await ln(e),n=await er(e,o);if(n===null||o==="developer"&&!await To(e))return;let i="";if(hv){if(i=Xt()||"",!i){e.setError(new Error("DEV_MODE: Could not find workspace root. Run from within the gaia repo."));return}e.setStep("Repository Setup"),e.setStatus("[DEV MODE] Using current workspace\u2026"),await z(500),e.setStatus("Repository ready")}else{e.setStep("Repository Setup");let a=o==="selfhost"?Bt.join(Hu.homedir(),"gaia"):Bt.resolve("gaia"),c=!0;for(i=a;;){if(i=await e.waitForInput("repo_path",{default:a}),Bt.isAbsolute(i)||(i=Bt.resolve(i)),gt.existsSync(i)){if(!gt.statSync(i).isDirectory()){e.setError(new Error(`Path ${i} exists and is not a directory.`)),await z(2e3),e.setError(null);continue}if(Qe(i)){e.updateData("existingRepoPath",i);let p=await e.waitForInput("existing_repo");if(p==="use_existing"){c=!1;break}else if(p==="delete_reclone"){e.setStatus("Removing existing installation\u2026");try{gt.rmSync(i,{recursive:!0,force:!0})}catch(m){e.setError(new Error(`Failed to remove directory: ${m.message}
|
|
116
|
+
Try removing it manually: rm -rf "${i}"`));return}break}else{if(p==="different_path")continue;e.setError(new Error("Setup cancelled by user."));return}}if(gt.readdirSync(i).length>0){e.setError(new Error(`Directory ${i} is not empty and is not a GAIA installation. Please choose another path.`)),await z(2e3),e.setError(null);continue}}break}if(c){e.setStep("Repository Setup"),e.setStatus("Preparing repository\u2026"),e.updateData("repoProgress",0),e.updateData("repoPhase","");try{await lo(i,"https://github.com/theexperiencecompany/gaia.git",(l,d)=>{e.updateData("repoProgress",l),d?(e.updateData("repoPhase",d),e.setStatus(`${d}\u2026`)):e.setStatus(`Cloning repository to ${i}... ${l}%`)},t),e.setStatus("Repository ready")}catch(l){e.setError(l);return}}else e.setStatus("Using the existing repository")}if(await z(1e3),await mr(e,i,o,n),e.currentState.error)return;if(o==="selfhost"){e.setStep("Project Setup"),e.setStatus("Building and starting all services in Docker\u2026"),e.updateData("dependencyPhase","Building and starting Docker services\u2026"),e.updateData("dependencyProgress",0),e.updateData("dependencyLogs",[]),e.updateData("dependencyComplete",!1);let a=Dc(e),c=!1;try{e.setStatus("Pulling pre-built images from registry\u2026"),await oe(i,"selfhost",p=>e.setStatus(p),n,a,{pull:"missing"}),c=!0}catch(p){let m=p.message?.split(`
|
|
117
|
+
`)[0]??"unknown error";e.setStatus(`Registry pull failed (${m}) \u2014 building images locally (this takes a few minutes)\u2026`)}if(!c)try{await oe(i,"selfhost",p=>e.setStatus(p),n,a,{build:!0})}catch(p){e.setError(new Error(`Failed to start services: ${p.message}`));return}e.updateData("dependencyProgress",100),e.updateData("dependencyComplete",!0);let l=e.currentState.data.envMethod||"manual";Xr({version:$,setupComplete:!0,setupMethod:l,repoPath:i,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()}),e.updateData("setupMode",o);let d=await un(e,{apiUrl:se("selfhost",n),webPort:n[A]??A});e.updateData("stillStarting",!d.ready),e.setStep("Finished"),e.setStatus(d.ready?"Set up. GAIA is running.":"Containers are up but not answering yet \u2014 give it a minute, then open the setup link below."),await e.waitForInput("exit");return}e.setStep("Install Tools"),e.setStatus("Installing toolchain\u2026"),e.updateData("dependencyPhase","Initializing mise\u2026"),e.updateData("dependencyProgress",0),e.updateData("dependencyLogs",[]);try{e.updateData("dependencyPhase","Trusting mise configuration\u2026"),await ne("mise",["trust"],i,void 0,r),e.updateData("dependencyProgress",50),e.updateData("dependencyPhase","Installing tools (node, python, uv, nx)\u2026"),await ne("mise",["install"],i,a=>{e.updateData("dependencyProgress",50+a*.5)},r),e.updateData("dependencyProgress",100),e.updateData("toolComplete",!0)}catch(a){e.setError(new Error(`Failed to install tools: ${a.message}`));return}await z(1e3),e.setStep("Project Setup"),e.updateData("dependencyPhase","Setting up project\u2026"),e.updateData("dependencyProgress",0),e.updateData("dependencyComplete",!1),e.updateData("repoPath",i),e.updateData("dependencyLogs",[]);try{e.updateData("dependencyProgress",0),e.updateData("dependencyPhase","Running mise setup (all dependencies)\u2026");let a=Object.keys(n).length>0?ze(n):void 0;await ne("mise",["setup"],i,c=>{e.updateData("dependencyProgress",c)},r,a),e.updateData("dependencyProgress",100),e.updateData("dependencyPhase","Set up"),e.updateData("dependencyComplete",!0)}catch(a){e.setError(new Error(`Failed to setup project: ${a.message}`));return}await z(1e3);let s=e.currentState.data.envMethod||"manual";Xr({version:$,setupComplete:!0,setupMethod:s,repoPath:i,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()}),e.setStep("Finished"),e.setStatus("Set up. Run 'gaia dev' to start development mode."),await e.waitForInput("exit")}async function Wu(e={}){await ve({command:"init",whenNonInteractive:"fail",runFlow:t=>Vu(t,e.branch)})}import*as ke from"node:fs";import*as Re from"node:path";import{execa as dn}from"execa";function ls(e){if(e.fromDir){let t=Re.resolve(e.fromDir),r=vs(t);if(!r)return{volumeFiles:[]};let o=jt(t,r),n=i=>ke.existsSync(i)?i:void 0;return{mongoFile:e.mongoFile??n(o.mongoFile),postgresFile:e.postgresFile??n(o.postgresFile),apiEnvFile:e.apiEnvFile??n(o.apiEnvFile),volumeFiles:o.volumeFiles.filter(i=>ke.existsSync(i.file))}}return{mongoFile:e.mongoFile,postgresFile:e.postgresFile,apiEnvFile:e.apiEnvFile,volumeFiles:[]}}function Ku(e){return!e.mongoFile||e.apiEnvFile?[]:["Restoring MongoDB without the backup's apps/api/.env: the stored provider credentials decrypt only under the INSTANCE_SECRET they were saved with. If this install's apps/api/.env is not the one the dump was taken with, they will not decrypt. Pass the backup's api-env-<stamp>.env with --env, or restore with --from <dir>."]}function us(e){let{mongoFile:t,postgresFile:r,apiEnvFile:o,volumeFiles:n}=e,i=[];o&&i.push(`install -m 600 ${o} ../../apps/api/.env`),t&&i.push(`docker compose -f docker-compose.selfhost.yml exec -T mongo mongorestore --archive --gzip --drop < ${t}`),r&&(i.push("docker compose -f docker-compose.selfhost.yml exec -T postgres psql -U postgres -d langgraph -c 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;'"),i.push(`cat ${r} | docker compose -f docker-compose.selfhost.yml exec -T postgres psql -U postgres -d langgraph`));for(let{volume:s,file:a}of n)i.push(`docker run --rm -v ${s}:/data -v ${Re.dirname(a)}:/backups alpine sh -c "${hr(Re.basename(a))}"`);return i}async function Yu(e,t){let r=_();if(!r)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let o=Re.join(r,"infra","docker"),n=Re.join(o,"docker-compose.selfhost.yml");if(!ke.existsSync(n))throw new Error(`Compose file not found: ${n}`);let i=ls(e),{mongoFile:s,postgresFile:a,apiEnvFile:c,volumeFiles:l}=i,d=us(i);if(!s&&!a&&!c&&l.length===0)throw new Error(["No backup files specified.","Use --mongo <file> --postgres <file> or --from <backup-dir> containing mongo-*.gz and postgres-*.sql.","Example: gaia restore --from backups","Example: gaia restore --mongo backups/mongo-2026-08-27T09-30-00Z.gz --postgres backups/postgres-2026-08-27T09-30-00Z.sql"].join(`
|
|
118
|
+
`));if(c&&!ke.existsSync(c))throw new Error(`apps/api/.env backup not found: ${c}`);if(s&&!ke.existsSync(s))throw new Error(`Mongo backup not found: ${s}`);if(a&&!ke.existsSync(a))throw new Error(`Postgres backup not found: ${a}`);for(let{label:m,file:g}of l)if(!ke.existsSync(g))throw new Error(`${m} backup not found: ${g}`);if(e.dryRun)return{...i,commands:d};let p=await J();if(p!=="ready"){let m=await Ue(p);throw new Error([`${m.summary}, so nothing can be restored.`,m.fix,"Or run the restore commands yourself:",...d.map(g=>` ${g}`)].join(`
|
|
119
|
+
`))}if(c&&Sv(c,r),s)try{let m=dn("docker",["compose","-f","docker-compose.selfhost.yml","exec","-T","mongo","mongorestore","--archive","--gzip","--drop"],{cwd:o,stdin:"pipe",stderr:"pipe"}),g=ke.createReadStream(s);if(!m.stdin)throw new Error("Failed to pipe mongo restore stdin");g.pipe(m.stdin),await m}catch(m){throw new Error(`MongoDB restore failed: ${m.message}`)}if(a){try{await dn("docker",["compose","-f","docker-compose.selfhost.yml","exec","-T","postgres","psql","-U","postgres","-d","langgraph","-c","DROP SCHEMA public CASCADE; CREATE SCHEMA public;"],{cwd:o})}catch(m){throw new Error(`Postgres schema reset failed: ${m.message}`)}try{let m=dn("docker",["compose","-f","docker-compose.selfhost.yml","exec","-T","postgres","psql","-U","postgres","-d","langgraph"],{cwd:o,stdin:"pipe",stderr:"pipe"}),g=ke.createReadStream(a);if(!m.stdin)throw new Error("Failed to pipe postgres restore stdin");g.pipe(m.stdin),await m}catch(m){throw new Error(`PostgreSQL restore failed: ${m.message}`)}}for(let{file:m,volume:g,label:v}of l)try{await dn("docker",["run","--rm","-v",`${g}:/data`,"-v",`${Re.dirname(m)}:/backups`,"alpine","sh","-c",hr(Re.basename(m))],{cwd:o})}catch(E){throw new Error(`${v} restore failed: ${E.message}`)}return t("Restarting services so they load the restored data and settings\u2026"),await oe(r,"selfhost",t,N(r)),{...i,commands:d}}function Sv(e,t){oo(e,je(t))}function Be(e=""){process.stdout.write(`${e}
|
|
120
|
+
`)}function vv(e=""){process.stderr.write(`${e}
|
|
121
|
+
`)}async function zu(e={}){let t={mongoFile:e.mongo,postgresFile:e.postgres,apiEnvFile:e.env,fromDir:e.from},r=ls(t);for(let o of Ku(r))vv(`${y.warn} ${o}`);if(e.dryRun){let o=us(r);if(o.length===0){Be("No backup files resolved. Use --from <dir> or --mongo/--postgres/--env <file>.");return}Be("Restore commands (dry run \u2014 not executed):");for(let n of o)Be(` ${n}`);return}try{Be("Starting GAIA restore\u2026");let o=await Yu(t,n=>Be(` ${n}`));o.apiEnvFile&&Be(`Restored apps/api/.env from ${o.apiEnvFile}`),o.mongoFile&&Be(`Restored MongoDB from ${o.mongoFile}`),o.postgresFile&&Be(`Restored PostgreSQL from ${o.postgresFile}`);for(let{label:n,file:i}of o.volumeFiles)Be(`Restored ${n} from ${i}`);Be("Restore complete. Run 'gaia doctor' to confirm every dependency is ready.")}catch(o){le(o.message),process.exitCode=1}}async function Xu(e){e.setStep("Detect Repo"),e.setStatus("Looking for GAIA repository\u2026");let t=Xt();if(!t){e.setError(new Error("Could not find GAIA repository. Run this command from within a cloned gaia repo, or use 'gaia init' to set up from scratch."));return}if(e.updateData("repoPath",t),e.setStatus(`Found repository at ${t}`),await z(1e3),e.setStep("Prerequisites"),e.setStatus("Checking system requirements\u2026"),!await Ro(e))return;let r=await ln(e),o=await er(e,r);if(o===null||r==="developer"&&!await To(e)||(await mr(e,t,r,o),e.currentState.error))return;if(r==="selfhost"){let a=e.currentState.data.envMethod||"manual";ye({setupComplete:!0,setupMethod:a,repoPath:t}),e.updateData("setupMode",r),e.setStep("Finished"),e.setStatus("Set up. Run 'gaia start' to start GAIA."),await e.waitForInput("exit");return}let n=ko(e);if(!await Oc(e,t,o,n))return;await z(1e3);let s=e.currentState.data.envMethod||"manual";ye({setupComplete:!0,setupMethod:s,repoPath:t}),e.updateData("setupMode",r),e.setStep("Finished"),e.setStatus("Set up. Run 'gaia dev' to start development mode."),await e.waitForInput("exit")}async function Ju(){await ve({command:"setup",whenNonInteractive:"fail",runFlow:Xu})}async function Qu(e,t){e.setStep("Starting"),e.setStatus("Locating GAIA repository\u2026");let r=_();if(!r){e.setError(new Error("Could not find GAIA repository. Run from within a cloned gaia repo."));return}e.updateData("repoPath",r);let o=await F(r);if(!o){e.setError(new Error("No .env file found. Run 'gaia init' for fresh setup, or 'gaia setup' to configure an existing repo."));return}if(o==="developer"){e.setError(new Error("Developer mode runs in foreground. Use 'gaia dev' or 'gaia dev full' instead of 'gaia start'."));return}if(o==="selfhost"){e.setStatus("Checking Docker\u2026");let s=await J();if(s!=="ready"){e.setError(await xt(s));return}}let n=N(r),i=n[A]??A;e.updateData("setupMode",o),e.updateData("webUrl",et(r,i)),e.updateData("dockerLogs",[]),e.setStatus("Starting GAIA\u2026");try{await oe(r,o,s=>e.setStatus(s),n,(s,a)=>{e.setStatus(s.label),e.updateData("dockerLogs",a.slice(-gr))},t)}catch(s){e.setError(new Error(`GAIA didn't start. ${s.message}`));return}e.setStep("Running"),e.setStatus("GAIA is running."),e.updateData("started",!0)}async function Zu(e){await ve({command:"start",whenNonInteractive:"plain",runFlow:t=>Qu(t,e),cancelHint:"GAIA may be partly started. Run 'gaia start' again to finish, or 'gaia stop'."})}var ed=8;function ht(e=""){process.stdout.write(`${e}
|
|
122
|
+
`)}function td(e){let t=e.currentState.data[jr];return t?{facts:t,report:sn(t)}:null}function yv(e){let t=td(e);if(!t)return;let{facts:r,report:o}=t,n=o.headline.kind==="ok"?y.active:y.fail;ht(`${n} ${o.headline.text}`),o.headline.url&&ht(` ${o.headline.url}`),o.hint&&ht(` ${o.hint}`),o.rows.length>0&&ht();for(let i of o.rows){let s=i.items.map(c=>`${c.ok?y.ok:y.fail} ${c.name}`).join(" "),a=i.items.length===0?i.note??"":"";ht(` ${i.label.padEnd(ed)}${s}${a}`.trimEnd()),i.items.length>0&&i.note&&ht(` ${" ".repeat(ed)}${i.note}`)}r.installed&&(ht(),ht(` Installed at ${r.install}`))}async function rd(e={}){await ve({command:"status",whenNonInteractive:"plain",autoResolve:[["exit_or_refresh","exit"]],runFlow:async t=>{await Pu(t,e),td(t)?.report.unhealthy&&(process.exitCode=1)},onPlainComplete:yv})}async function od(e,t){e.setStep("Stopping"),e.setStatus("Finding your GAIA install\u2026");let r=_();if(!r){e.setError(new Error("GAIA isn't installed here, so there is nothing to stop."));return}e.updateData("repoPath",r),e.updateData("stopMode",t?.forcePorts?"force-ports":"safe");let o=N(r);try{await Oa(r,n=>e.setStatus(n),o,t)}catch(n){e.setError(new Error(`GAIA didn't stop. ${n.message}`));return}e.setStep("Stopped"),e.setStatus("GAIA stopped. Start it again with 'gaia start'."),e.updateData("stopped",!0)}async function nd(e){await ve({command:"stop",whenNonInteractive:"plain",runFlow:t=>od(t,e),cancelHint:"GAIA may still be partly running. Run 'gaia stop' again."})}import*as pn from"fs";import*as mn from"path";function wv(e){let t=mn.join(e,".env");return pn.existsSync(t)?["--env-file",".env"]:[]}async function id(){let e=_();if(!e)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let t=await F(e);if(!t)throw new Error("No .env file found. Run 'gaia init' for fresh setup, or 'gaia setup' to configure an existing repo.");let r=mn.join(e,"infra","docker"),o=wv(r),n=N(e),i=Object.keys(n).length>0?ze(n):void 0;if(t==="selfhost"){await ir("docker",["compose",...Je(zt()),...o,"logs","-f","--tail","200"],r,i);return}let s=["compose",...o,"logs","-f","--tail","200"],a=mn.join(e,Ta),c=qn(e),l=typeof c=="number"&&mo(c);if(pn.existsSync(a)&&l){console.log("Streaming app and infrastructure logs\u2026"),process.platform==="win32"?await qo([{cmd:"powershell",args:["-Command",`Get-Content -Path '${a.replace(/'/g,"''")}' -Wait -Tail 200`],cwd:e},{cmd:"docker",args:s,cwd:r,env:i}]):await qo([{cmd:"tail",args:["-n","200","-f",a],cwd:e},{cmd:"docker",args:s,cwd:r,env:i}]);return}pn.existsSync(a)&&!l?(console.log("Detected stale developer app logs from a previous run. Streaming Docker logs only."),await ir("docker",s,r,i)):(console.log("No active developer process detected. Streaming Docker service logs. Run `gaia dev` in another terminal for live Nx app logs."),await ir("docker",s,r,i))}import{execFile as Iv}from"node:child_process";import*as md from"node:os";import*as sd from"node:os";import*as ad from"node:path";var bv=80,Ev=443,cd=ad.join(sd.homedir(),"gaia");function ld(){let e=L()?.repoPath;return e&&Qe(e)?e:null}function ud(e){let t={};return e.domain&&(t[A]=bv,t[Tr]=Ev),e.webPort&&(t[A]=e.webPort),t}function xv(){return L()?.values??{}}function Cv(e){return eo().flatMap(t=>t.variables).find(t=>t.name===e)}function dd(e){let{repoPath:t,interactive:r=fe(),setupMode:o="selfhost"}=e,n=xv(),i=new Set(wr()),s=new Map,a=l=>(s.has(l)||s.set(l,Cv(l)?.required===!0),s.get(l)===!0),c=l=>{let d=n[l]??yr(l,o);if(d)return d;if(!r&&a(l))throw new Error(`${l} is required but could not be resolved in non-interactive mode \u2014 provide it via a GAIA flag or an apps/api/.env file.`);return""};return(l,d)=>{switch(l){case"setup_mode":return"selfhost";case"env_method":return"manual";case"env_alternatives":return{selectedGroups:[],values:{}};case"env_group":return{};case"env_var":{let p=d?.varName;return!p||i.has(p)?"":c(p)}case"repo_path":return t;case"existing_repo":return"use_existing";case"port_conflicts":return"accept";default:return}}}var fd="gaia up --build",kv="usually 10-20 minutes \xB7 safe to leave running",Rv={building:"Building GAIA",downloading:"Downloading GAIA's images",unpacking:"Unpacking GAIA's images",starting:"Starting GAIA",stopping:"Stopping GAIA"};function Tv(e,t){let r=e.llmProvider?lr[e.llmProvider]:null;return[{id:"check",label:"Checking Git and Docker",doneLabel:"Git and Docker are ready"},t?{id:"download",label:"Downloading GAIA",doneLabel:"Downloaded GAIA"}:{id:"download",label:"Finding your install",doneLabel:"Using your install"},{id:"configure",label:"Configuring GAIA",doneLabel:"Configured GAIA"},...e.noStart?[]:[e.build?{id:"start",label:"Building GAIA",doneLabel:"Built and started GAIA"}:{id:"start",label:"Starting GAIA",doneLabel:"Started GAIA"},{id:"wait",label:"Waiting for GAIA to answer",doneLabel:"GAIA is answering"}],...r?[{id:"provider",label:`Checking your ${r} key`,doneLabel:`Saved your ${r} key`}]:[]]}function qr(e,t){ot(e,"failed"),e.setError(t)}async function gd(e,t={}){gu(t);let r=Math.min(Date.now(),...Object.values(Zr())),o=ld(),n=o??cd,i=!Qe(n);e.pushAnswerResolver(dd({repoPath:n})),xc(e,Tv(t,i)),e.setStep("Prerequisites"),rt(e,"check");try{if(await Io(e,{needGit:i,assumeYes:t.yes===!0,onInstallStart:g=>rt(e,"check",{label:`Installing ${Zt(g)}`,doneLabel:`Installed ${Zt(g)}`,startedAt:Date.now()})})==="relaunch")return}catch(m){qr(e,m);return}if(!t.build&&!await Av(e,n,i))return;let s=await er(e,"selfhost");if(s===null){ot(e,"failed");return}if(Object.assign(s,ud(t)),!i&&n!==o&&!t.forceDevTree&&await F(n)==="developer"){qr(e,new Error(`${n} is set up for development (apps/api/.env is in developer mode), and 'gaia up' would overwrite its settings.
|
|
123
|
+
Run it with --force-dev-tree to go ahead anyway.`));return}if(Tt(e,"check"),e.setStep("Repository Setup"),rt(e,"download"),!await Pv(e,n,i))return;if(ye(t.codeSandbox===void 0?{repoPath:n}:{repoPath:n,codeSandbox:t.codeSandbox}),Tt(e,"download",i?void 0:`Using your install at ${Pe(n)}`),e.setStep("Environment Setup"),rt(e,"configure"),await mr(e,n,"selfhost",s,{llmProvider:t.llmProvider,domain:t.domain}),e.currentState.error){ot(e,"failed");return}Tt(e,"configure");let a=s[A]??A,c={webUrl:Wn(a,t.domain),reachableUrls:qa(a,t.domain),noStart:t.noStart===!0,stillStarting:!1,setupComplete:!1,codeSandbox:L()?.codeSandbox===!0,joinedDockerGroup:Ls(),elapsedMs:0,startedServices:0};if(t.noStart){pd(e,n,{...c,elapsedMs:Date.now()-r});return}e.setStep("Project Setup");try{c.startedServices=await Ov(e,n,s,t)}catch(m){qr(e,m);return}rt(e,"wait");let l=se("selfhost",s),d=await un(e,{apiUrl:l,webPort:a});d.ready?Tt(e,"wait"):He(e,"wait",{state:"failed",endedAt:Date.now()}),c.stillStarting=!d.ready,c.setupComplete=d.ready&&await $v(l);let p=await Dv(e,n,t,d.ready);if(t.llmProvider&&(p?c.unsavedProvider=t.llmProvider:c.savedProvider=t.llmProvider),pd(e,n,{...c,elapsedMs:Date.now()-r}),p){e.setError(p);return}d.ready&&_v(c.webUrl,t)}async function Av(e,t,r){let o=r?Ke:Te(t);e.setStatus(`Checking that GAIA ${o} is available for this computer\u2026`);let n=await Qt(o,L()?.bots??[]);if(!n)return!0;let{cause:i,next:s}=Yt(n,fd);return qr(e,new Error(`${i}
|
|
124
|
+
${s}`)),!1}async function Pv(e,t,r){if(!r)return!0;He(e,"download",{detail:"Connecting to GitHub\u2026",percent:0});try{await pa(t,ua,(o,n)=>{He(e,"download",n?{percent:o,detail:n}:{percent:o})})}catch(o){return qr(e,new Error(`Couldn't download GAIA into ${t}: ${o.message}`)),!1}return!0}function _v(e,t){let r=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;!t.yes&&r&&md.platform()==="darwin"&&Iv("open",[`${e}/setup`],()=>{})}async function Dv(e,t,r,o){let{llmProvider:n}=r;if(!n)return null;let i=lr[n];if(rt(e,"provider"),!o)return ot(e,"failed"),new Error(`GAIA didn't answer in time, so your ${i} key wasn't saved.
|
|
125
|
+
Once 'gaia status' shows it running, run 'gaia up' again with the same flags.`);try{await hu(t,{...r,llmProvider:n})}catch(s){return ot(e,"failed"),new Error(`Your ${i} key wasn't saved: ${s.message}
|
|
126
|
+
Check the key and run 'gaia up --llm-provider ${n} --llm-key <key>' again, or add it on the setup page above.`)}return Tt(e,"provider"),null}async function Ov(e,t,r,o){rt(e,"start",o.build?{hint:kv}:{});let{startedServices:n}=await oe(t,"selfhost",i=>He(e,"start",{detail:i}),r,i=>He(e,"start",{label:Rv[i.stage],detail:i.label,percent:i.percent}),{...o.build?{build:!0}:{pull:"missing"},rebuildCommand:fd,onLogFile:i=>e.updateData("logPath",i)});return Tt(e,"start",n===0?"GAIA was already running":void 0),n}async function $v(e){let t=await _e(e,"status");return"data"in t&&!t.data.needs_setup}function pd(e,t,r){ye({version:$,setupComplete:!0,setupMethod:e.currentState.data.envMethod||"manual",repoPath:t}),e.updateData("setupMode","selfhost"),e.updateData("upOutcome",r),e.updateData("finished",!0),e.setStep("Finished")}var Lv=16,Mv=14;function Hr(e=""){process.stdout.write(`${e}
|
|
127
|
+
`)}function Nv(e){let t=e.currentState.data.upOutcome;if(!t)return;let r=Zo(t);Hr(),Hr(`${r.tone==="success"?`${y.ok} `:""}${r.headline}`);for(let o of r.rows)Hr(` ${o.label.padEnd(Lv)}${o.text}`);Hr();for(let[o,n]of Qo)Hr(` ${o.padEnd(Mv)}${n}`)}async function hd(e={}){await ve({command:"up",whenNonInteractive:"plain",runFlow:t=>gd(t,e),cancelHint:"GAIA may be partly set up. Run 'gaia up' again to finish, or 'gaia stop'.",onPlainComplete:Nv})}import*as kd from"node:readline";var Fv="https://api.github.com/repos/theexperiencecompany/gaia/releases/tags",Bv=5e3,Gv=5,Uv=["Features","Bug Fixes"],jv=/^\* (.+)$/,qv=/^\*\*[^*]+:\*\*\s*/,Hv=/(\s*\(\[[^\]]+\]\([^)]+\)\))+$/;function Vv(e){let t=e.replace(qv,"").replace(Hv,"");return t.charAt(0).toUpperCase()+t.slice(1)}function Wv(e){let t=new Map,r="";for(let o of e.split(`
|
|
128
|
+
`)){let n=/^#{2,3} (.+)$/.exec(o.trim());if(n?.[1]){r=n[1];continue}let i=jv.exec(o.trim())?.[1];i&&t.set(r,[...t.get(r)??[],Vv(i)])}return Uv.flatMap(o=>t.get(o)??[]).slice(0,Gv)}async function Sd(e){let t=await fetch(`${Fv}/${Kt(e)}`,{headers:{Accept:"application/vnd.github+json"},signal:AbortSignal.timeout(Bv)});if(!t.ok)throw new Error(`GitHub answered HTTP ${t.status}`);let{body:r}=await t.json();return Wv(r??"")}import{execa as Vr}from"execa";var Kv=["apps/web","apps/api","infra/docker"];function vd(e){let{current:t,target:r,explicit:o,gap:n}=e;if(!o){if(tt(t)===null)return{kind:"development-build"};if(!qe(r,t))return{kind:"up-to-date"}}return n?{kind:"unavailable",gap:n}:{kind:"offer",downgrade:qe(t,r)}}async function St(e,t){let{stdout:r}=await Vr("git",t,{cwd:e});return r.trim()}async function yd(e){let t=await Vr("git",["rev-parse","--is-inside-work-tree"],{cwd:e,reject:!1});return t.exitCode!==0||t.stdout.trim()!=="true"?!1:(await Vr("git",["remote","get-url","origin"],{cwd:e,reject:!1})).exitCode===0}function wd(e){return e.split(`
|
|
129
|
+
`).map(t=>t.trim()).filter(Boolean)}async function Yv(e,t){let r=await St(e,["log",t,"--oneline","--",...Kv]);return{commits:wd(r)}}async function bd(e,t){let r=Te(e),o=Kt(t);if(!await yd(e))return{repoPath:e,fromVersion:r,toVersion:t,checkout:null};await Gn("origin",t,e);let n=`refs/tags/${o}`,i=await Vr("git",["fetch","--no-tags","origin",`+${n}:${n}`],{cwd:e,reject:!1});if(i.exitCode!==0)throw new Error(`Could not fetch ${o} from origin: ${i.stderr.trim()}`);let[s,a,c]=await Promise.all([St(e,["rev-parse","HEAD"]),St(e,["rev-parse",`${o}^{commit}`]),St(e,["rev-parse","--short","HEAD"])]);return{repoPath:e,fromVersion:r,toVersion:t,checkout:{fromRef:c,toTag:o,atTag:s===a}}}function Ed(e){return e.fromVersion===e.toVersion&&(e.checkout===null||e.checkout.atTag)}async function xd(e,t){if(e.checkout&&!e.checkout.atTag){let r=wd(await St(e.repoPath,["status","--porcelain","--untracked-files=no"]));if(r.length>0)throw new Error(`Local changes to tracked files would be overwritten:
|
|
125
130
|
${r.join(`
|
|
126
131
|
`)}
|
|
127
|
-
Commit or discard them, or update this checkout yourself with 'gaia update --git'.`)}t(`Downloading GAIA ${e.toVersion}\u2026`),await
|
|
128
|
-
`)}function
|
|
129
|
-
|
|
130
|
-
${
|
|
131
|
-
|
|
132
|
-
No terminal to confirm in: rerun with --yes to apply.`),!1)}async function zS(e,t){let r=Ie(e),o=t.version??He,n=t.version!==void 0,s=n||Qe(r)!==null&&Be(o,r)?await Ht(o,$()?.bots??[]):null,a=Ku({current:r,target:o,explicit:n,gap:s});switch(a.kind){case"development-build":L(`This install runs a development build of GAIA (${lo(r)}), not a release, so there is nothing to update.`),L(`To switch it to the ${o} release: gaia update --version ${o}`);return;case"up-to-date":L(`GAIA ${r} is up to date.`);for(let l of Xs(O))L(l);return;case"unavailable":L(`${Gt(a.gap,"gaia up --build").cause} Nothing was changed.`),n&&(process.exitCode=1);return;case"offer":break}let c=await zu(e,o);if(Qu(c)){L(`GAIA ${r} is up to date.`);return}L(a.downgrade?`
|
|
132
|
+
Commit or discard them, or update this checkout yourself with 'gaia update --git'.`)}t(`Downloading GAIA ${e.toVersion}\u2026`),await Da(e.repoPath,e.toVersion),e.checkout&&!e.checkout.atTag&&(t(`Updating the setup files to ${e.toVersion}\u2026`),await St(e.repoPath,["checkout","--detach",e.checkout.toTag])),t(`Switching to GAIA ${e.toVersion}\u2026`),Un(e.repoPath,e.toVersion),t("Restarting GAIA\u2026"),await oe(e.repoPath,"selfhost",t,N(e.repoPath),void 0,{pull:"missing"})}async function Cd(e){if(!await yd(e))throw new Error(`${e} is not a git checkout with an origin remote; run 'gaia update' without --git.`);if((await Vr("git",["symbolic-ref","-q","--short","HEAD"],{cwd:e,reject:!1})).exitCode!==0)throw new Error(`${e} is on a release tag, not a branch. Switch to one first: git -C ${e} checkout master`);return await St(e,["fetch","origin"]),Yv(e,"HEAD..@{upstream}")}async function Id(e,t){t("Pulling the latest commits (git pull --ff-only)\u2026"),await St(e,["pull","--ff-only"]),t("Rebuilding images from this checkout and restarting\u2026"),await oe(e,"selfhost",t,N(e),void 0,{build:!0})}var zv=5,Xv="https://docs.heygaia.io/release-notes";function R(e=""){process.stdout.write(`${Ze(e)}
|
|
133
|
+
`)}async function Jv(e){let t=kd.createInterface({input:process.stdin,output:process.stdout});t.on("SIGINT",()=>{t.close(),R(`
|
|
134
|
+
${y.cancelled} Cancelled \xB7 nothing changed.`),process.exit(130)});let r=await new Promise(n=>{t.question(`${e} [y/N] `,i=>n(i))});t.close();let o=r.trim().toLowerCase();return o==="y"||o==="yes"}function Qv(e,t){let r=t?e.commits:e.commits.slice(0,zv);for(let n of r)R(` ${n}`);let o=e.commits.length-r.length;o>0&&R(` and ${o} more (--verbose lists them)`)}async function Zv(e){try{for(let t of await Sd(e))R(` - ${t}`)}catch(t){R(` (couldn't read what's new in ${e}: ${t.message})`)}}async function Rd(e,t){return e.yes?!0:fe()?Jv(`
|
|
135
|
+
${t}`):(R(`
|
|
136
|
+
No terminal to confirm in: rerun with --yes to apply.`),!1)}async function ey(e,t){let r=Te(e),o=t.version??Ke,n=t.version!==void 0,s=n||tt(r)!==null&&qe(o,r)?await Qt(o,L()?.bots??[]):null,a=vd({current:r,target:o,explicit:n,gap:s});switch(a.kind){case"development-build":R(`This install runs a development build of GAIA (${yo(r)}), not a release, so there is nothing to update.`),R(`To switch it to the ${o} release: gaia update --version ${o}`);return;case"up-to-date":R(`GAIA ${r} is up to date.`);for(let l of da($))R(l);return;case"unavailable":R(`${Yt(a.gap,"gaia up --build").cause} Nothing was changed.`),n&&(process.exitCode=1);return;case"offer":break}let c=await bd(e,o);if(Ed(c)){R(`GAIA ${r} is up to date.`);return}R(a.downgrade?`
|
|
133
137
|
Switch GAIA ${r} back to ${o}`:`
|
|
134
|
-
Update available: GAIA ${r} \u2192 ${o}`),
|
|
135
|
-
${
|
|
136
|
-
${r.commits.length} new commit(s) touch the self-host stack:`),
|
|
137
|
-
Updated and restarted from source.`))}async function
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
Update available: GAIA ${r} \u2192 ${o}`),await Zv(o),R(`What's new: ${Xv}`),R("Your data and settings are kept."),await Rd(t,"Update and restart now?")&&(await xd(c,l=>R(` ${l}`)),R(`
|
|
139
|
+
${y.ok} GAIA is on ${o}.`),R("Run 'gaia doctor' to check that everything is ready."))}async function ty(e,t){let r=await Cd(e);if(r.commits.length===0){R("Already up to date with the upstream branch.");return}R(`
|
|
140
|
+
${r.commits.length} new commit(s) touch the self-host stack:`),Qv(r,t.verbose===!0),R("The images are rebuilt from this checkout (slow on small machines)."),await Rd(t,"Pull, rebuild and restart now?")&&(await Id(e,o=>R(` ${o}`)),R(`
|
|
141
|
+
Updated and restarted from source.`))}async function Td(e={}){await Rt({showUpdate:!1});let t=_();if(!t){le(`GAIA isn't installed here, so there is nothing to update.
|
|
142
|
+
Install it with 'gaia up'.`),process.exitCode=1;return}if(e.git&&e.version){le(`--version and --git can't be used together.
|
|
143
|
+
--version moves to a published release; --git builds from source. Pick one.`),process.exitCode=1;return}R(`Checking for updates in ${Pe(t)}\u2026`);try{await(e.git?ty(t,e):ey(t,e))}catch(r){R(),le(`GAIA wasn't updated: ${r.message}
|
|
144
|
+
Your data is untouched. Fix the cause above, then run 'gaia update' again.`),process.exitCode=1}}var ny=new Set(["-V","--version"]),K=new ry,ds="For contributors:",iy=20;K.name("gaia").description("Run GAIA, your proactive personal assistant, on your own computer or server").option("-V, --version","Show the CLI's version").helpOption("-h, --help","Show help for a command").helpCommand("help [command]","Show help for a command").configureHelp({minWidthToWrap:iy}).enablePositionalOptions().addHelpText("after",`
|
|
145
|
+
New here? Run: gaia up`);K.command("up").description(U.up).option("--yes","Answer yes to every question, including installing Git and Docker").addOption(new oy("--llm-provider <provider>","AI provider to save once GAIA is running (checked first, as the setup page does)").choices(zi)).option("--llm-key <key>","API key for --llm-provider (openrouter, gemini, openai, custom)").option("--llm-base-url <url>","Address of --llm-provider ollama (default http://host.docker.internal:11434) or custom").option("--llm-model <model>","Model for --llm-provider ollama (optional) or custom (required)").option("--web-port <port>","Port GAIA is served on (default 3000)",Number.parseInt).option("--domain <domain>","Serve GAIA at https://<domain> with an automatic certificate (uses ports 80 and 443)").option("-b, --build","Build GAIA from source on this machine instead of downloading it (slow)").option("--code-sandbox","Let GAIA run code in containers on this machine (gives it control of Docker; kept on later starts)").option("--no-code-sandbox","Turn that off again (running code then needs an E2B key)").option("--no-start","Set everything up, but don't start GAIA").option("--force-dev-tree","Allow 'gaia up' on a development copy of GAIA that isn't your install").action(async e=>{let{start:t,...r}=e;await hd({...r,noStart:t===!1})});K.command("status").description(U.status).option("--watch","Stay open; press r to check again").action(async e=>{await rd({watch:e.watch})});K.command("stop").description(U.stop).option("--force-ports","Also stop whatever else listens on GAIA's ports (may stop other programs)").action(async e=>{await nd({forcePorts:e.forcePorts})});K.command("start").description(U.start).option("-b, --build","Build GAIA from source before starting (slow)").option("--pull","Download GAIA's images again before starting").action(async e=>{await Zu({build:e.build,pull:e.pull?"always":void 0})});K.command("update").description(U.update).option("--yes","Update without asking").option("--version <tag>","Move to this GAIA release (v<x.y.z>) instead of the one this CLI installs").option("--git","For development copies: pull the current branch and rebuild from source").option("--verbose","With --git, list every new commit").action(async e=>{await Td(e)});K.command("doctor").description(U.doctor).action(async()=>{await eu()});K.command("logs").description(U.logs).action(async()=>{try{await id()}catch(e){console.error(e instanceof Error?e.message:String(e)),process.exit(1)}});K.addCommand(Or);K.addCommand($l);K.addCommand(Ve);K.command("backup").description(U.backup).option("--output <dir>","Folder to save the backup in (default: ./backups)").option("--dry-run","Print the commands without running them").action(async e=>{await Ga({output:e.output,dryRun:e.dryRun})});K.command("restore").description(U.restore).option("--mongo <file>","MongoDB archive file (mongodump --archive)").option("--postgres <file>","PostgreSQL dump file").option("--env <file>","The backup's apps/api/.env (api-env-<stamp>.env): its INSTANCE_SECRET decrypts the saved keys").option("--from <dir>","Restore everything from a backup folder (its newest backup)").option("--dry-run","Print the commands without running them").action(async e=>{await zu({mongo:e.mongo,postgres:e.postgres,env:e.env,from:e.from,dryRun:e.dryRun})});K.command("init").helpGroup(ds).description(U.init).option("--branch <branch>","Git branch to clone").action(async e=>{await Wu({branch:e.branch})});K.command("setup").helpGroup(ds).description(U.setup).action(async()=>{await Ju()});K.command("dev [profile]").helpGroup(ds).description(U.dev).action(async e=>{try{await Ml(e)}catch(t){console.error(t instanceof Error?t.message:String(t)),process.exit(1)}});ny.has(process.argv[2]??"")&&(await mc(),process.exit(0));process.argv.slice(2).length||(K.outputHelp(),process.exit(0));K.parse();
|