@heygaia/cli 0.1.15 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +33 -156
  2. package/dist/index.js +54 -30
  3. package/package.json +46 -42
package/README.md CHANGED
@@ -1,52 +1,37 @@
1
1
  # @heygaia/cli
2
2
 
3
- CLI tool for setting up and managing [GAIA](https://heygaia.io) — your proactive personal AI assistant.
3
+ ![GAIA CLI](../../apps/web/public/images/screenshots/cli.png)
4
4
 
5
- The CLI provides an interactive terminal UI that guides you through cloning, configuring, and running a self-hosted GAIA instance.
5
+ CLI tool for setting up and managing [GAIA](https://heygaia.io).
6
6
 
7
7
  ## Requirements
8
8
 
9
- - **Node.js 18+** (for npm/npx) or **Bun** (alternative)
9
+ - **Node.js 20+** and one package manager (npm, pnpm, or bun)
10
10
  - **macOS or Linux** (Windows via WSL2)
11
11
  - **Docker** installed and running
12
12
  - **Git** installed
13
13
 
14
- The CLI checks prerequisites at startup and tells you what's missing.
14
+ The CLI checks prerequisites at startup and reports what is missing.
15
15
 
16
16
  ## Installation
17
17
 
18
- ### Quick Install (Recommended)
19
-
20
- ```bash
21
- curl -fsSL https://heygaia.io/install.sh | sh
22
- ```
23
-
24
- This automatically detects your system and installs using npm or bun.
25
-
26
- ### Manual Installation
18
+ Install globally with your preferred package manager:
27
19
 
28
20
  ```bash
29
21
  npm install -g @heygaia/cli
30
- # or
31
22
  pnpm add -g @heygaia/cli
32
- # or
33
23
  bun add -g @heygaia/cli
34
24
  ```
35
25
 
36
- ### Alternative: Run Without Installing
37
-
38
- ```bash
39
- npx @heygaia/cli init
40
- ```
41
-
42
- You'll need to prefix every command with `npx @heygaia/cli` instead of just `gaia`. Global installation is recommended.
43
-
44
26
  ## Commands
45
27
 
46
28
  ```bash
47
29
  gaia init # Full setup from scratch
48
30
  gaia setup # Configure existing repo
49
- gaia start # Start all services
31
+ gaia start # Start services in self-host mode
32
+ gaia dev # Developer mode (Nx TUI)
33
+ gaia dev full # Developer mode + workers (Nx TUI)
34
+ gaia logs # Stream running logs
50
35
  gaia stop # Stop all services
51
36
  gaia status # Check service health
52
37
  gaia --version # Show CLI version
@@ -55,27 +40,15 @@ gaia --help # Show all commands
55
40
 
56
41
  ### `gaia init`
57
42
 
58
- Interactive wizard for first-time setup. Handles everything from zero to a running GAIA instance.
59
-
60
- **Options:**
43
+ Interactive first-time setup.
61
44
 
62
45
  | Flag | Description |
63
46
  |------|-------------|
64
- | `--branch <name>` | Clone a specific branch instead of the default |
65
-
66
- **What it does:**
67
-
68
- 1. **Prerequisites check** — Verifies Git, Docker, and [Mise](https://mise.jdx.dev) are installed. Auto-installs Mise if missing.
69
- 2. **Port conflict detection** — Checks ports 3000, 5432, 6379, 8000, 8080, 27017, 5672. Suggests alternatives if any are in use.
70
- 3. **Repository clone** — Clones the GAIA repo to your chosen directory with progress tracking.
71
- 4. **Tool installation** — Installs Node.js, Python, uv, and Nx via Mise.
72
- 5. **Environment configuration** — Choose a setup mode and configure variables (see below).
73
- 6. **Project setup** — Runs `mise setup` to install all dependencies, start Docker services, and seed the database.
74
- 7. **Service startup** — Optionally starts all services immediately.
47
+ | `--branch <name>` | Clone a specific branch |
75
48
 
76
49
  ### `gaia setup`
77
50
 
78
- For existing repos — skips cloning and tool installation, goes straight to environment setup. Use when you want to reconfigure environment variables, switch between self-host and developer modes, or reinstall dependencies.
51
+ Reconfigure an existing GAIA repo:
79
52
 
80
53
  ```bash
81
54
  cd /path/to/gaia
@@ -84,140 +57,48 @@ gaia setup
84
57
 
85
58
  ### `gaia start`
86
59
 
87
- Starts all GAIA services. Auto-detects the setup mode from your `.env` configuration.
88
-
89
- **Options:**
90
-
91
- | Flag | Description |
92
- |------|-------------|
93
- | `--build` | Rebuild Docker images before starting |
94
- | `--pull` | Pull latest base images before starting |
95
-
96
- **What it does:**
97
-
98
- - **Self-host mode**: Runs `docker compose --profile all up -d` (everything in Docker, runs in background)
99
- - **Developer mode**: Runs `mise dev` (databases in Docker, API + web locally with hot reload). Logs are written to `dev-start.log` in the repo root:
60
+ Starts services for **self-host mode**.
100
61
 
101
62
  ```bash
102
- tail -f dev-start.log
63
+ gaia start
103
64
  ```
104
65
 
105
- **Access your instance:**
106
- - Web: http://localhost:3000
107
- - API: http://localhost:8000
108
- - API Docs: http://localhost:8000/docs
109
-
110
- ### `gaia stop`
111
-
112
- Stops all running GAIA services gracefully — Docker containers, local processes on ports 8000 and 3000, and background workers. Your data is preserved.
113
-
114
- ### `gaia status`
115
-
116
- Shows a live health dashboard with latency for all services.
117
-
118
- | Service | Port | Health Check |
119
- |---------|------|--------------|
120
- | API | 8000 | HTTP `GET /health` |
121
- | Web | 3000 | HTTP `GET /` |
122
- | PostgreSQL | 5432 | TCP connection |
123
- | Redis | 6379 | TCP connection |
124
- | MongoDB | 27017 | TCP connection |
125
- | RabbitMQ | 5672 | TCP connection |
126
- | ChromaDB | 8080 | TCP connection |
127
-
128
- Press `r` to refresh. Status indicators: ✓ (healthy), ✗ (down), - (checking).
66
+ Optional flags:
129
67
 
130
- ## Setup Modes
131
-
132
- During `gaia init` or `gaia setup`, you choose a mode:
133
-
134
- - **Self-Host (Docker)** — Everything runs in Docker containers. Best for deployment and non-developers.
135
- - **Developer (Local)** — Databases in Docker, API + web run locally with hot reload. Best for contributing.
136
-
137
- ### Port Overrides
138
-
139
- When the CLI detects port conflicts, it automatically selects alternative ports and writes them to `infra/docker/.env`. These persist across `gaia start` / `gaia stop` cycles. To change port assignments after setup, edit `infra/docker/.env` directly:
140
-
141
- | Variable | Service |
142
- |----------|---------|
143
- | `API_HOST_PORT` | FastAPI backend |
144
- | `WEB_HOST_PORT` | Next.js web app |
145
- | `POSTGRES_HOST_PORT` | PostgreSQL |
146
- | `REDIS_HOST_PORT` | Redis |
147
- | `MONGO_HOST_PORT` | MongoDB |
148
- | `RABBITMQ_HOST_PORT` | RabbitMQ |
149
- | `CHROMA_HOST_PORT` | ChromaDB |
150
-
151
- After editing, run `gaia stop` and `gaia start` to apply changes.
68
+ - `--build` rebuild Docker images before starting
69
+ - `--pull` pull latest base images before starting
152
70
 
153
- ## Environment Variable Configuration
71
+ ### `gaia dev` / `gaia dev full`
154
72
 
155
- Two methods are available:
73
+ Runs developer mode in foreground Nx TUI:
156
74
 
157
- - **Manual** Interactive prompts for each variable with descriptions, documentation links, and defaults.
158
- - **Infisical** Enter your Infisical credentials for centralized secret management.
75
+ - `gaia dev` -> `mise dev`
76
+ - `gaia dev full` -> `mise dev:full`
159
77
 
160
- ### Auto-Discovery
78
+ ### `gaia logs`
161
79
 
162
- The CLI discovers environment variables from the codebase at runtime:
80
+ Streams logs for currently running services.
163
81
 
164
- - **API variables** — Extracted from `apps/api/app/config/settings.py` and `settings_validator.py` via Python AST parsing
165
- - **Web variables** — Parsed from `apps/web/.env`
166
-
167
- When a developer adds a new variable to either location, the CLI picks it up automatically — no CLI updates needed.
168
-
169
- ## Upgrading
170
-
171
- ### Updating GAIA
172
-
173
- ```bash
174
- cd /path/to/gaia
175
- git pull
176
- gaia setup # if dependencies changed
177
- ```
82
+ ### `gaia stop`
178
83
 
179
- ### Updating the CLI
84
+ Stops running GAIA services.
180
85
 
181
- ```bash
182
- npm install -g @heygaia/cli
183
- # or
184
- pnpm add -g @heygaia/cli
185
- # or
186
- bun add -g @heygaia/cli
187
- ```
86
+ ### `gaia status`
188
87
 
189
- ## Uninstalling
88
+ Shows health and latency for core services.
190
89
 
191
- 1. Stop all running services: `gaia stop`
192
- 2. Remove the repo: `rm -rf /path/to/gaia`
193
- 3. Remove CLI metadata: `rm -rf ~/.gaia`
194
- 4. Uninstall the CLI:
90
+ ## Setup Modes
195
91
 
196
- ```bash
197
- npm uninstall -g @heygaia/cli
198
- # or
199
- pnpm remove -g @heygaia/cli
200
- # or
201
- bun remove -g @heygaia/cli
202
- ```
92
+ - **Self-Host (Docker)** — everything in Docker
93
+ - **Developer (Local)** — infra in Docker, app in local Nx TUI
203
94
 
204
- ## Troubleshooting
95
+ ## Port Overrides
205
96
 
206
- | Issue | Fix |
207
- |-------|-----|
208
- | `command not found: gaia` | Ensure the global bin directory is in PATH. For npm: `export PATH="$(npm config get prefix)/bin:$PATH"`. For bun: `export PATH="$HOME/.bun/bin:$PATH"` |
209
- | Raw mode not supported | The CLI requires an interactive terminal — don't run in background or pipe |
210
- | Port conflicts not detected | Ensure `lsof` is available (macOS/Linux). Windows requires WSL2 |
211
- | Env vars not discovered | Check that `settings_validator.py` and `apps/web/.env` exist in the repo |
212
- | `Python 3 not found` | The CLI requires Python 3 to parse API environment variables. Install it or run `mise install python` |
213
- | Docker prerequisite fails | Ensure Docker Desktop/Engine is running, not just installed |
97
+ When port conflicts are detected, overrides are written to `infra/docker/.env`.
214
98
 
215
99
  ## Development
216
100
 
217
101
  ```bash
218
- # Dev mode (watch, no build needed)
219
- GAIA_CLI_DEV=true pnpm tsx packages/cli/src/index.ts <command>
220
-
221
102
  # Build
222
103
  cd packages/cli && pnpm run build
223
104
 
@@ -228,11 +109,7 @@ cd packages/cli && pnpm run build
228
109
  ./packages/cli/test-cli.sh
229
110
  ```
230
111
 
231
- ### Install Script
232
-
233
- Source of truth: `packages/cli/install.sh`. The web app serves it at `https://heygaia.io/install.sh` by fetching directly from GitHub — no manual sync needed.
234
-
235
- ### Publishing
112
+ ## Publishing
236
113
 
237
114
  1. Update version in `package.json`
238
115
  2. Build: `pnpm run build`
package/dist/index.js CHANGED
@@ -1,34 +1,58 @@
1
1
  #!/usr/bin/env node
2
- import{Command as jo}from"commander";import{render as Ro}from"ink";import Do from"react";import{Box as Le,Text as le}from"ink";import to from"react";import{ProgressBar as Rt,Select as Ke,Spinner as Dt}from"@inkjs/ui";import{Box as d,Text as p,useInput as ne}from"ink";import ve from"ink-text-input";import{useEffect as be,useRef as $r,useState as $}from"react";import{Box as ye,Text as De}from"ink";var T="#00bbff";import{Box as kr,Text as _r}from"ink";import{jsx as Ct}from"react/jsx-runtime";var Et=({status:e,step:t})=>t.toLowerCase()==="welcome"?null:Ct(kr,{width:"100%",paddingX:1,marginTop:1,children:Ct(_r,{color:"gray",dimColor:!0,children:e})});import{Box as Br}from"ink";import Or from"ink-big-text";import Lr from"ink-gradient";import{jsx as Qe}from"react/jsx-runtime";var de=()=>Qe(Br,{flexDirection:"column",marginTop:1,marginBottom:1,children:Qe(Lr,{colors:[T,"#b0eaff",T],children:Qe(Or,{text:"GAIA",font:"3d"})})});import{jsx as ce,jsxs as Te}from"react/jsx-runtime";var Mr=["Welcome","Prerequisites","Setup Mode","Repository Setup","Environment Setup","Install Tools","Project Setup","Installing CLI","Finished"],Pt=["Detect Repo","Prerequisites","Environment Setup","Project Setup","Finished"],Fr={Welcome:"Welcome",Prerequisites:"Prereqs","Setup Mode":"Mode","Repository Setup":"Repo","Environment Setup":"Env","Install Tools":"Tools","Project Setup":"Setup","Installing CLI":"CLI","Detect Repo":"Detect",Finished:"Done"},Nr=({currentStep:e,steps:t})=>{let r=t.indexOf(e);return ce(ye,{marginBottom:1,flexWrap:"nowrap",children:t.map((o,n)=>{let a=n<r,c=n===r,i=Fr[o]??o;return Te(ye,{flexShrink:0,children:[n>0&&Te(De,{color:"gray",dimColor:!0,children:[" ","\xB7"," "]}),a&&Te(De,{color:"green",children:["\u2713 ",i]}),c&&ce(De,{color:T,bold:!0,children:i}),!a&&!c&&ce(De,{color:"gray",dimColor:!0,children:i})]},o)})})},Ae=({children:e,status:t,step:r,steps:o=Mr})=>Te(ye,{flexDirection:"column",height:"100%",width:"100%",children:[Te(ye,{flexGrow:1,flexDirection:"column",children:[ce(de,{}),ce(Nr,{currentStep:r,steps:o}),ce(ye,{flexDirection:"column",flexGrow:1,children:e})]}),ce(Et,{status:t,step:r})]});import{Spinner as wt}from"@inkjs/ui";import{Box as q,Text as O,useInput as Gr}from"ink";import{jsx as R,jsxs as V}from"react/jsx-runtime";var ke=({checks:e})=>V(q,{flexDirection:"column",borderStyle:"round",paddingX:1,borderColor:T,children:[R(O,{bold:!0,children:"System Checks"}),V(q,{flexDirection:"column",marginTop:1,children:[R(Ye,{label:"Git",status:e.git}),R(Ye,{label:"Docker",status:e.docker}),R(Ye,{label:"Mise",status:e.mise})]})]}),_e=({status:e})=>V(q,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:T,children:[R(O,{bold:!0,children:"Environment Setup"}),R(q,{marginTop:1,children:R(wt,{label:e||"Configuring environment..."})})]}),Be=({message:e})=>V(q,{flexDirection:"column",borderStyle:"single",borderColor:"red",padding:1,marginTop:2,children:[V(O,{color:"red",children:["Error: ",e]}),R(q,{marginTop:1,children:V(O,{dimColor:!0,children:[R(O,{bold:!0,children:"Enter"})," to exit"]})})]}),Ye=({label:e,status:t})=>V(q,{children:[R(q,{marginRight:1,children:t==="pending"?R(wt,{type:"dots"}):t==="success"?R(O,{color:"green",children:"\u2714"}):t==="error"?R(O,{color:"red",children:"\u2716"}):R(O,{color:"yellow",children:"\u26A0"})}),R(O,{children:e})]}),Oe=({portResults:e,onAccept:t,onAbort:r})=>{Gr((n,a)=>{a.return?t():a.escape&&r()});let o=e.filter(n=>!n.available);return V(q,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:"yellow",children:[R(q,{marginBottom:1,children:R(O,{bold:!0,color:"yellow",children:"Port Conflicts Detected"})}),e.map(n=>V(q,{children:[V(O,{color:n.available?"green":n.alternative?"yellow":"red",children:[n.available?"\u2714":n.alternative?"\u26A0":"\u2716"," "]}),V(O,{children:[n.service," (:",n.port,")"]}),!n.available&&V(O,{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)&&R(q,{marginTop:1,children:R(O,{color:"red",children:"Some ports have no available alternative. Free them and retry."})}),!o.some(n=>!n.alternative)&&o.some(n=>n.alternative)&&R(q,{marginTop:1,children:R(O,{color:"gray",children:"Alternative ports will be used for conflicting services."})}),R(q,{marginTop:1,children:V(O,{dimColor:!0,children:[R(O,{bold:!0,children:"Enter"})," continue \xB7 ",R(O,{bold:!0,children:"ESC"})," abort"]})})]})};import{Fragment as Tn,jsx as s,jsxs as h}from"react/jsx-runtime";var qr=({onConfirm:e})=>(ne((t,r)=>{r.return&&e()}),h(d,{flexDirection:"column",paddingX:2,borderStyle:"round",borderColor:T,children:[s(p,{bold:!0,children:"Welcome to GAIA Setup"}),h(d,{flexDirection:"column",marginTop:1,marginBottom:1,children:[s(p,{children:"This wizard will guide you through the setup process:"}),s(p,{children:" 1. Check prerequisites and choose setup mode"}),s(p,{children:" 2. Clone repository"}),s(p,{children:" 3. Configure environment variables"}),s(p,{children:" 4. Install tools and dependencies"})]}),s(p,{dimColor:!0,children:"~5-15 min depending on network speed"}),s(d,{marginTop:1,children:h(p,{color:T,children:[s(p,{bold:!0,children:"Enter"})," to start"]})})]})),Hr=({defaultValue:e,onSubmit:t})=>{let[r,o]=$(e);return h(d,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:T,children:[s(p,{children:"Clone repository to:"}),s(p,{color:"gray",dimColor:!0,children:"Press Enter for default, or type a custom path"}),h(d,{marginTop:1,children:[s(p,{color:T,children:"\u2192 "}),s(ve,{value:r,onChange:o,onSubmit:t})]})]})},jr=({repoPath:e,onAction:t})=>h(d,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:"yellow",children:[s(d,{marginBottom:1,children:s(p,{bold:!0,color:"yellow",children:"Existing Installation Found"})}),h(p,{children:["Found a GAIA installation at"," ",s(p,{color:"cyan",bold:!0,children:e})]}),s(d,{marginTop:1,children:s(p,{color:"gray",children:"What would you like to do?"})}),s(d,{marginTop:1,children:s(Ke,{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)})})]}),Wr=({setupMode:e,portOverrides:t,onConfirm:r})=>{ne((a,c)=>{c.return&&r()});let o=t?.[3e3]??3e3,n=t?.[8e3]??8e3;return e==="selfhost"?h(d,{flexDirection:"column",marginTop:2,borderStyle:"round",borderColor:"green",padding:1,children:[s(p,{bold:!0,color:"green",children:"GAIA is Running!"}),s(d,{marginTop:1,children:s(p,{color:"green",children:"\u2713 All services started"})}),h(d,{marginTop:1,flexDirection:"column",children:[h(p,{children:["Web:"," ",h(p,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),h(p,{children:["API:"," ",h(p,{color:"cyan",bold:!0,children:["http://localhost:",n]})]})]}),s(d,{marginTop:1,children:s(p,{color:"gray",children:"gaia stop \xB7 gaia status \xB7 gaia setup"})}),s(d,{marginTop:1,children:h(p,{dimColor:!0,children:[s(p,{bold:!0,children:"Enter"})," to exit"]})})]}):h(d,{flexDirection:"column",marginTop:2,borderStyle:"round",borderColor:T,padding:1,children:[s(p,{color:T,bold:!0,children:"You're all set!"}),h(d,{marginTop:1,children:[s(p,{bold:!0,children:"Run: "}),s(p,{color:"cyan",children:"$ gaia start"})]}),h(d,{marginTop:1,flexDirection:"column",children:[h(p,{children:["Web:"," ",h(p,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),h(p,{children:["API:"," ",h(p,{color:"cyan",bold:!0,children:["http://localhost:",n]})]})]}),s(d,{marginTop:1,children:s(p,{color:"gray",children:"gaia stop \xB7 gaia status \xB7 gaia setup"})}),s(d,{marginTop:1,children:h(p,{dimColor:!0,children:[s(p,{bold:!0,children:"Enter"})," to exit"]})})]})},Vr=8,At=({logs:e,height:t=Vr})=>{let[r,o]=$(0),n=$r(e.length);be(()=>{e.length!==n.current&&(n.current=e.length,o(0))},[e.length]),ne((S,m)=>{m.upArrow?o(x=>Math.min(x+1,Math.max(0,e.length-t))):m.downArrow&&o(x=>Math.max(0,x-1))});let a=e.length,c=Math.max(0,a-t-r),i=Math.max(0,a-r),l=e.slice(c,i),u=c,g=r;return h(d,{flexDirection:"column",marginTop:1,marginLeft:1,children:[u>0&&h(p,{color:"gray",dimColor:!0,children:["\u2191 ",u," more line",u!==1?"s":""]}),s(d,{flexDirection:"column",height:t,overflow:"hidden",children:l.map((S,m)=>s(p,{color:"gray",wrap:"truncate",children:S},`${c}-${m}`))}),g>0?h(p,{color:"gray",dimColor:!0,children:["\u2193 ",g," more line",g!==1?"s":""]}):s(p,{color:"gray",dimColor:!0,children:"\u2191\u2193 scroll"})]})},Je=({phase:e,progress:t,isComplete:r,logs:o,title:n})=>h(d,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:T,children:[s(d,{marginBottom:1,children:s(p,{bold:!0,color:T,children:n||"Installing Dependencies"})}),h(d,{flexDirection:"column",gap:1,children:[s(d,{children:r?h(p,{color:"green",children:["\u2713 ",e]}):s(Dt,{label:e||"Preparing..."})}),!r&&t>0&&s(d,{width:50,children:s(Rt,{value:t})}),!r&&o&&o.length>0&&s(At,{logs:o}),!r&&s(d,{marginTop:1,children:s(p,{color:"gray",dimColor:!0,children:"This may take a few minutes..."})})]})]});var ze=({onSelect:e})=>h(d,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:T,children:[s(p,{bold:!0,children:"Setup Mode"}),s(d,{marginTop:1,children:s(p,{color:"gray",children:"How do you want to run GAIA?"})}),s(d,{marginTop:1,children:s(Ke,{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)})})]}),Ze=({onSelect:e})=>h(d,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:T,children:[s(p,{bold:!0,children:"Environment Variables Setup"}),s(d,{marginTop:1,children:s(p,{color:"gray",children:"Choose how you want to configure environment variables:"})}),s(d,{marginTop:1,children:s(Ke,{options:[{label:"Manual Setup (Recommended)",value:"manual"},{label:"Infisical (Advanced)",value:"infisical"}],onChange:r=>e(r)})}),h(d,{marginTop:1,flexDirection:"column",children:[s(p,{color:"gray",dimColor:!0,children:"Manual Setup: Configure variables interactively (recommended for most users)"}),s(p,{color:"gray",dimColor:!0,children:"Infisical: All secrets managed in Infisical dashboard (requires pre-configuration)"})]})]}),et=({onSubmit:e})=>{let[t,r]=$({INFISICAL_TOKEN:"",INFISICAL_PROJECT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET:""}),[o,n]=$(0),[a,c]=$(null),i=[{key:"INFISICAL_TOKEN",description:"Service token from project settings (st.xxx...)"},{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"}];ne((u,g)=>{if(g.tab||g.downArrow)n(S=>S<i.length-1?S+1:S);else if(g.upArrow)n(S=>S>0?S-1:S);else if(g.return){if(o<i.length-1){n(m=>m+1);return}let S=i.filter(m=>!t[m.key].trim());if(S.length>0){c(`Required: ${S.map(x=>x.key).join(", ")}`);let m=i.findIndex(x=>!t[x.key].trim());m>=0&&n(m);return}e(t)}});let l=i[o];return h(d,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:T,children:[s(d,{marginBottom:1,children:s(p,{bold:!0,color:T,children:"Infisical Configuration"})}),s(d,{marginBottom:1,children:s(p,{color:"gray",children:"All secrets managed in your Infisical project. Only credentials stored locally."})}),h(d,{marginBottom:1,flexDirection:"column",children:[s(p,{color:"gray",children:"Configure your Infisical credentials."}),h(p,{color:"gray",dimColor:!0,children:["Visit"," ",s(p,{color:"cyan",underline:!0,children:"app.infisical.com"})," ","to get these values."]})]}),i.map((u,g)=>{let S=u.key.includes("SECRET")||u.key.includes("TOKEN");return h(d,{flexDirection:"column",marginBottom:1,children:[s(d,{children:h(p,{color:g===o?T:"white",children:[g===o?"\u25B8 ":" ",u.key,":"]})}),s(d,{marginLeft:2,children:s(p,{color:"gray",dimColor:!0,children:u.description})}),g===o?s(d,{marginLeft:2,children:s(ve,{value:t[u.key],onChange:m=>{r(x=>({...x,[u.key]:m})),c(null)},placeholder:"Enter value...",mask:S?"*":void 0})}):s(d,{marginLeft:2,children:s(p,{color:t[u.key]?"green":"gray",children:t[u.key]?S?`\u2713 ${"*".repeat(8)}`:`\u2713 ${t[u.key]}`:"(not set)"})})]},u.key)}),a&&s(d,{marginTop:1,children:s(p,{color:"red",children:a})}),s(d,{marginTop:1,children:h(p,{dimColor:!0,children:[s(p,{bold:!0,children:"Enter"})," confirm \xB7 ",s(p,{bold:!0,children:"\u2191\u2193"})," navigate"]})})]})},tt=({category:e,currentIndex:t,totalGroups:r,onSubmit:o})=>{let[n,a]=$(()=>{let m={};for(let x of e.variables)m[x.name]=x.defaultValue||"";return m}),[c,i]=$(0),[l,u]=$(null);be(()=>{let m={};for(let x of e.variables)m[x.name]=x.defaultValue||"";a(m),i(0),u(null)},[e.name]),ne((m,x)=>{if(x.tab||x.downArrow)i(f=>f<e.variables.length-1?f+1:f);else if(x.upArrow)i(f=>f>0?f-1:f);else if(x.escape){let f=e.variables.filter(y=>y.required&&!n[y.name]?.trim());if(f.length>0){u(`Required fields cannot be skipped: ${f.map(y=>y.name).join(", ")}`);return}o(n)}});let g=()=>{if(c<e.variables.length-1)i(c+1);else{let m=e.variables.filter(x=>x.required&&!n[x.name]?.trim());if(m.length>0){u(`Required fields are missing: ${m.map(x=>x.name).join(", ")}`);return}u(null),o(n)}},S=e.variables.some(m=>m.required);return h(d,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:l?"red":T,children:[h(d,{justifyContent:"space-between",children:[h(p,{bold:!0,children:["Configure ",e.name]}),h(p,{color:"gray",children:["Group ",t+1," / ",r]})]}),s(d,{marginTop:1,children:s(p,{color:"gray",children:e.description})}),s(d,{marginTop:1,flexDirection:"column",children:e.variables.map((m,x)=>{let f=x===c,y=!!m.defaultValue;return h(d,{flexDirection:"column",marginBottom:1,children:[h(d,{children:[h(p,{color:f?T:"gray",bold:f,children:[f?"\u279C ":" ",m.name]}),m.required&&h(p,{color:"red",bold:!0,children:[" ","*"]}),y&&!f&&h(p,{color:"gray",dimColor:!0,children:[" ","(default: ",m.defaultValue,")"]})]}),f&&s(d,{marginLeft:2,children:s(ve,{value:n[m.name]||"",onChange:v=>{a(b=>({...b,[m.name]:v})),l&&u(null)},onSubmit:g,placeholder:y?`Default: ${m.defaultValue}`:m.required?"Enter a value (required)":"Press Enter to skip"})})]},m.name)})}),l&&s(d,{marginTop:1,children:h(p,{color:"red",bold:!0,children:["\u26A0 ",l]})}),s(d,{marginTop:1,children:h(p,{dimColor:!0,children:[s(p,{bold:!0,children:"Enter"})," next \xB7 ",s(p,{bold:!0,children:"\u2191\u2193"})," navigate",!S&&h(p,{children:[" ","\xB7 ",s(p,{bold:!0,children:"ESC"})," skip"]})]})})]})},rt=({alternatives:e,onSubmit:t})=>{let[r,o]=$(new Set),[n,a]=$({}),[c,i]=$(0),[l,u]=$(null);be(()=>{let v={};for(let b of e)for(let P of b.variables)v[P.name]=P.defaultValue||"";a(v)},[e]);let g=[];for(let v=0;v<e.length;v++)if(g.push({type:"provider",categoryIndex:v}),r.has(v)){let b=e[v];if(b)for(let P=0;P<b.variables.length;P++)g.push({type:"field",categoryIndex:v,fieldIndex:P})}g.push({type:"submit"});let S=g[c],m=S?.type==="field",x=S?.type==="submit";ne((v,b)=>{let P=Math.min(c,g.length-1);if(P!==c){i(P);return}if(m)b.upArrow?i(w=>Math.max(0,w-1)):(b.downArrow||b.tab)&&i(w=>Math.min(g.length-1,w+1));else if(x)b.upArrow?i(w=>Math.max(0,w-1)):(b.return||v===" ")&&y();else if(b.upArrow)i(w=>Math.max(0,w-1));else if(b.downArrow||b.tab)i(w=>Math.min(g.length-1,w+1));else if((b.return||v===" ")&&S?.type==="provider"){let w=S.categoryIndex;o(ee=>{let k=new Set(ee);return k.has(w)?k.delete(w):k.add(w),k}),l&&u(null)}});let f=()=>{l&&u(null),i(v=>Math.min(g.length-1,v+1))},y=()=>{let v=[],b={};for(let P of r){let w=e[P];if(!w)continue;if(w.variables.some(k=>n[k.name]?.trim())){v.push(w.name);for(let k of w.variables){let Re=n[k.name];Re&&(b[k.name]=Re)}}}if(v.length===0){r.size===0?u("Enable at least one provider (press Space or Enter)"):u("Enter a value for at least one field");return}t(v,b)};return h(d,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:l?"red":T,children:[h(d,{justifyContent:"space-between",children:[s(p,{bold:!0,children:"Configure AI Provider"}),s(p,{color:"yellow",children:"* At least one required"})]}),s(d,{marginTop:1,children:s(p,{color:"gray",children:"Enable and configure at least one AI provider below:"})}),s(d,{marginTop:1,flexDirection:"column",children:e.map((v,b)=>{let P=r.has(b),w=g.findIndex(k=>k.type==="provider"&&k.categoryIndex===b),ee=c===w;return h(d,{flexDirection:"column",marginBottom:1,children:[h(d,{children:[s(p,{color:ee?T:void 0,bold:ee,children:ee?"\u279C ":" "}),s(p,{color:P?"green":"gray",children:P?"[\u2714]":"[ ]"}),h(p,{color:P?T:"gray",bold:P,children:[" ",v.name]}),v.description&&h(p,{color:"gray",dimColor:!0,children:[" ","- ",v.description]})]}),ee&&v.docsUrl&&h(d,{marginLeft:6,children:[s(p,{color:"yellow",children:"\u{1F4D6} "}),s(p,{color:"blue",underline:!0,children:v.docsUrl})]}),P&&s(d,{marginLeft:4,flexDirection:"column",marginTop:1,children:v.variables.map((k,Re)=>{let Dr=g.findIndex(xe=>xe.type==="field"&&xe.categoryIndex===b&&xe.fieldIndex===Re),pe=c===Dr,It=!!k.defaultValue,Xe=n[k.name]||"";return h(d,{flexDirection:"column",marginBottom:1,children:[h(d,{children:[h(p,{color:pe?T:"gray",bold:pe,children:[pe?" \u279C ":" ",k.name]}),!pe&&Xe&&s(p,{color:"green",children:" \u2713"}),!pe&&!Xe&&It&&h(p,{color:"gray",dimColor:!0,children:[" ","(default: ",k.defaultValue,")"]})]}),pe&&s(d,{marginLeft:4,children:s(ve,{value:Xe,onChange:xe=>{a(Ar=>({...Ar,[k.name]:xe})),l&&u(null)},onSubmit:f,placeholder:It?`Default: ${k.defaultValue}`:"Enter value..."})})]},k.name)})})]},v.name)})}),l&&s(d,{marginTop:1,children:h(p,{color:"red",bold:!0,children:["\u26A0 ",l]})}),h(d,{marginTop:1,children:[s(p,{color:x?T:void 0,bold:x,children:x?"\u279C ":" "}),s(d,{borderStyle:"round",borderColor:x?T:"gray",paddingX:2,children:s(p,{color:x?T:"gray",bold:x,children:"Continue \u2192"})})]}),s(d,{marginTop:1,children:s(p,{color:"gray",dimColor:!0,children:"\u2191/\u2193 navigate \u2022 Space/Enter toggle/select \u2022 Tab skip field"})})]})},ot=({currentVar:e,currentIndex:t,totalCount:r,onSubmit:o,onSkip:n})=>{let[a,c]=$(e.defaultValue||""),[i,l]=$(null);be(()=>{c(e.defaultValue||""),l(null)},[e.name]),ne((S,m)=>{if(m.escape){if(e.required&&!a.trim()){l("This field is required and cannot be skipped");return}n()}});let u=S=>{if(e.required&&!S.trim()){l("This field is required");return}l(null),o(S)},g=!!e.defaultValue;return h(d,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:i?"red":T,children:[h(d,{justifyContent:"space-between",children:[h(d,{children:[s(p,{color:T,bold:!0,children:e.name}),e.required?s(p,{color:"red",children:" *"}):h(p,{color:"gray",dimColor:!0,children:[" ","optional"]})]}),h(p,{color:"gray",children:[t+1,"/",r]})]}),s(d,{marginLeft:1,children:s(p,{color:"gray",children:e.description})}),h(d,{marginTop:1,children:[s(p,{color:T,children:"\u2192 "}),s(ve,{value:a,onChange:S=>{c(S),i&&l(null)},onSubmit:u,placeholder:g?`Default: ${e.defaultValue}`:e.required?"required":"skip with Enter"})]}),i&&s(d,{marginTop:1,children:s(p,{color:"red",children:i})}),s(d,{marginTop:1,children:h(p,{dimColor:!0,children:[s(p,{bold:!0,children:"Enter"})," confirm",!e.required&&h(p,{children:[" ","\xB7 ",s(p,{bold:!0,children:"ESC"})," skip"]})]})})]})},kt=({store:e})=>{let[t,r]=$(e.currentState);return be(()=>{let o=()=>r({...e.currentState});return e.on("change",o),()=>{e.off("change",o)}},[e]),ne((o,n)=>{(n.return||n.escape)&&t.error&&e.submitInput("exit")}),h(Ae,{status:t.status,step:t.step,children:[t.step==="Welcome"&&t.inputRequest?.id==="welcome"&&s(qr,{onConfirm:()=>e.submitInput(!0)}),t.step==="Prerequisites"&&t.data.checks&&s(ke,{checks:t.data.checks}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&s(Oe,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="repo_path"&&s(Hr,{defaultValue:t.inputRequest.meta.default,onSubmit:o=>e.submitInput(o)}),t.inputRequest?.id==="existing_repo"&&t.data.existingRepoPath&&s(jr,{repoPath:t.data.existingRepoPath,onAction:o=>e.submitInput(o)}),t.step==="Repository Setup"&&!t.inputRequest&&h(d,{flexDirection:"column",borderStyle:"round",padding:1,borderColor:T,children:[s(p,{bold:!0,children:"Cloning Repository"}),h(d,{marginTop:1,flexDirection:"column",children:[s(Rt,{value:t.data.repoProgress||0}),t.data.repoPhase&&s(d,{marginTop:1,children:s(p,{color:"gray",children:t.data.repoPhase})})]})]}),t.inputRequest?.id==="setup_mode"&&s(ze,{onSelect:o=>e.submitInput(o)}),t.inputRequest?.id==="env_method"&&s(Ze,{onSelect:o=>e.submitInput(o)}),t.inputRequest?.id==="env_infisical"&&s(et,{onSubmit:o=>e.submitInput(o)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&s(ot,{categories:t.data.envCategories||[],currentVar:t.data.currentEnvVar,currentIndex:t.data.envVarIndex||0,totalCount:t.data.envVarTotal||0,onSubmit:o=>e.submitInput(o),onSkip:()=>e.submitInput("")}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_group"&&t.data.currentEnvGroup&&s(tt,{category:t.data.currentEnvGroup,currentIndex:t.data.envGroupIndex||0,totalGroups:t.data.envGroupTotal||0,onSubmit:o=>e.submitInput(o)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_alternatives"&&t.data.alternativeGroups&&s(rt,{alternatives:t.data.alternativeGroups,onSubmit:(o,n)=>e.submitInput({selectedGroups:o,values:n})}),t.step==="Environment Setup"&&!t.inputRequest&&s(_e,{status:t.status}),t.step==="Finished"&&s(Wr,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,onConfirm:()=>e.submitInput("exit")}),(t.step==="Install Tools"||t.step==="Project Setup")&&s(Je,{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.step==="Installing CLI"&&h(d,{flexDirection:"column",borderStyle:"round",padding:1,borderColor:T,children:[s(p,{bold:!0,color:T,children:"Installing CLI"}),s(d,{marginTop:1,children:s(Dt,{label:t.status||"Installing gaia CLI globally..."})}),t.data.cliInstallLogs&&t.data.cliInstallLogs.length>0&&s(At,{logs:t.data.cliInstallLogs})]}),t.error&&s(Be,{message:t.error.message})]})};import{Spinner as Ur}from"@inkjs/ui";import{Box as F,Text as C,useInput as _t}from"ink";import{useEffect as Bt,useRef as Xr,useState as Ot}from"react";import{jsx as L,jsxs as I}from"react/jsx-runtime";var nt=8,Qr=({logs:e})=>{let[t,r]=Ot(0),o=Xr(e.length);Bt(()=>{e.length!==o.current&&(o.current=e.length,r(0))},[e.length]),_t((g,S)=>{S.upArrow?r(m=>Math.min(m+1,Math.max(0,e.length-nt))):S.downArrow&&r(m=>Math.max(0,m-1))});let n=e.length,a=Math.max(0,n-nt-t),c=Math.max(0,n-t),i=e.slice(a,c),l=a,u=t;return I(F,{flexDirection:"column",marginTop:1,marginLeft:1,children:[l>0&&I(C,{color:"gray",dimColor:!0,children:["\u2191 ",l," more line",l!==1?"s":""]}),L(F,{flexDirection:"column",height:nt,overflow:"hidden",children:i.map((g,S)=>L(C,{color:"gray",wrap:"truncate",children:g},a+S))}),u>0?I(C,{color:"gray",dimColor:!0,children:["\u2193 ",u," more line",u!==1?"s":""]}):L(C,{color:"gray",dimColor:!0,children:"\u2191\u2193 scroll"})]})},Lt=({store:e})=>{let[t,r]=Ot(e.currentState);return Bt(()=>{let o=()=>r({...e.currentState});return e.on("change",o),()=>{e.off("change",o)}},[e]),_t((o,n)=>{(n.return||n.escape)&&(t.data.started||t.data.stopped||t.error)&&e.submitInput("exit")}),I(F,{flexDirection:"column",width:"100%",children:[L(de,{}),(t.step==="Starting"||t.step==="Stopping")&&I(F,{flexDirection:"column",marginTop:1,paddingX:2,borderStyle:"round",borderColor:T,children:[L(Ur,{label:t.status||"Working..."}),t.data.repoPath&&L(F,{marginTop:1,children:I(C,{color:"gray",children:["Repository: ",t.data.repoPath]})}),t.data.setupMode&&L(F,{children:I(C,{color:"gray",children:["Mode: ",t.data.setupMode]})}),t.data.dockerLogs&&t.data.dockerLogs.length>0&&L(Qr,{logs:t.data.dockerLogs})]}),t.step==="Running"&&t.data.started&&I(F,{flexDirection:"column",marginTop:1,paddingX:2,paddingY:1,borderStyle:"round",borderColor:"green",children:[I(C,{color:"green",bold:!0,children:["\u2713"," GAIA is running!"]}),t.data.setupMode!=="developer"&&I(F,{marginTop:1,flexDirection:"column",children:[I(C,{children:["Web:"," ",I(C,{color:"cyan",bold:!0,children:["http://localhost:",t.data.webPort||3e3]})]}),I(C,{children:["API:"," ",I(C,{color:"cyan",bold:!0,children:["http://localhost:",t.data.apiPort||8e3]})]})]}),t.data.setupMode==="developer"&&I(F,{marginTop:1,flexDirection:"column",children:[I(F,{flexDirection:"column",children:[I(C,{children:["Web:"," ",I(C,{color:"cyan",bold:!0,children:["http://localhost:",t.data.webPort||3e3]})]}),I(C,{children:["API:"," ",I(C,{color:"cyan",bold:!0,children:["http://localhost:",t.data.apiPort||8e3]})]})]}),I(F,{marginTop:1,flexDirection:"column",children:[L(C,{color:"gray",children:"Dev servers started in background."}),I(C,{color:"gray",children:["Logs: ",L(C,{color:T,children:"dev-start.log"})," in your repo root."]}),I(C,{color:"gray",children:["Run ",L(C,{color:T,children:"gaia stop"})," to shut down."]})]})]}),L(F,{marginTop:1,children:I(C,{dimColor:!0,children:[L(C,{bold:!0,children:"Enter"})," to exit"]})})]}),t.step==="Stopped"&&t.data.stopped&&I(F,{flexDirection:"column",marginTop:1,paddingX:2,paddingY:1,borderStyle:"round",borderColor:T,children:[I(C,{color:T,bold:!0,children:["\u2713"," All GAIA services stopped."]}),L(F,{marginTop:1,children:I(C,{dimColor:!0,children:[L(C,{bold:!0,children:"Enter"})," to exit"]})})]}),t.error&&I(F,{borderStyle:"single",borderColor:"red",padding:1,marginTop:2,children:[I(C,{color:"red",children:["Error: ",t.error.message]}),L(F,{marginTop:1,children:I(C,{dimColor:!0,children:[L(C,{bold:!0,children:"Enter"})," to exit"]})})]})]})};import{Spinner as Yr}from"@inkjs/ui";import{Box as ie,Text as X,useInput as Mt}from"ink";import{useEffect as Kr,useState as Jr}from"react";import{jsx as D,jsxs as K}from"react/jsx-runtime";var Ft=({store:e})=>{let[t,r]=Jr(e.currentState);return Kr(()=>{let o=()=>r({...e.currentState});return e.on("change",o),()=>{e.off("change",o)}},[e]),Mt((o,n)=>{(n.return||n.escape)&&t.error&&e.submitInput("exit")}),K(Ae,{status:t.status,step:t.step,steps:Pt,children:[t.step==="Detect Repo"&&K(ie,{flexDirection:"column",paddingX:2,borderStyle:"round",borderColor:T,children:[D(X,{bold:!0,children:"Detecting GAIA Repository"}),D(ie,{marginTop:1,children:D(Yr,{label:"Searching for repository..."})}),t.data.repoPath&&D(ie,{marginTop:1,children:K(X,{color:"green",children:["Found: ",t.data.repoPath]})})]}),t.step==="Prerequisites"&&t.data.checks&&D(ke,{checks:t.data.checks}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&D(Oe,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="setup_mode"&&D(ze,{onSelect:o=>e.submitInput(o)}),t.inputRequest?.id==="env_method"&&D(Ze,{onSelect:o=>e.submitInput(o)}),t.inputRequest?.id==="env_infisical"&&D(et,{onSubmit:o=>e.submitInput(o)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&D(ot,{categories:t.data.envCategories||[],currentVar:t.data.currentEnvVar,currentIndex:t.data.envVarIndex||0,totalCount:t.data.envVarTotal||0,onSubmit:o=>e.submitInput(o),onSkip:()=>e.submitInput("")}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_group"&&t.data.currentEnvGroup&&D(tt,{category:t.data.currentEnvGroup,currentIndex:t.data.envGroupIndex||0,totalGroups:t.data.envGroupTotal||0,onSubmit:o=>e.submitInput(o)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_alternatives"&&t.data.alternativeGroups&&D(rt,{alternatives:t.data.alternativeGroups,onSubmit:(o,n)=>e.submitInput({selectedGroups:o,values:n})}),t.step==="Environment Setup"&&!t.inputRequest&&D(_e,{status:t.status}),t.step==="Project Setup"&&D(Je,{title:"Project Setup",phase:t.data.dependencyPhase||"",progress:t.data.dependencyProgress||0,isComplete:t.data.dependencyComplete||!1,logs:t.data.dependencyLogs||[]}),t.step==="Finished"&&D(zr,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,onConfirm:()=>e.submitInput("exit")}),t.error&&D(Be,{message:t.error.message})]})},zr=({portOverrides:e,onConfirm:t})=>{Mt((n,a)=>{a.return&&t()});let r=e?.[3e3]??3e3,o=e?.[8e3]??8e3;return K(ie,{flexDirection:"column",marginTop:2,borderStyle:"round",borderColor:T,padding:1,children:[D(X,{color:T,bold:!0,children:"Setup Complete!"}),K(ie,{marginTop:1,children:[D(X,{bold:!0,children:"Run: "}),D(X,{color:"cyan",children:"$ gaia start"})]}),K(ie,{marginTop:1,flexDirection:"column",children:[K(X,{children:["Web:"," ",K(X,{color:"cyan",bold:!0,children:["http://localhost:",r]})]}),K(X,{children:["API:"," ",K(X,{color:"cyan",bold:!0,children:["http://localhost:",o]})]})]}),D(ie,{marginTop:1,children:D(X,{color:"gray",children:"gaia stop \xB7 gaia status \xB7 gaia setup"})}),D(ie,{marginTop:1,children:K(X,{dimColor:!0,children:[D(X,{bold:!0,children:"Enter"})," to exit"]})})]})};import{Spinner as Zr}from"@inkjs/ui";import{Box as _,Text as A,useInput as eo}from"ink";import{useEffect as Nt,useState as it}from"react";import{jsx as E,jsxs as N}from"react/jsx-runtime";var Gt=({store:e})=>{let[t,r]=it(e.currentState),[o,n]=it(!1),[a,c]=it(null);return Nt(()=>{let i=()=>r({...e.currentState});return e.on("change",i),()=>{e.off("change",i)}},[e]),Nt(()=>{n(!1),c(new Date().toLocaleTimeString())},[t.data.services]),eo((i,l)=>{(l.return||l.escape)&&t.step==="Results"&&e.submitInput("exit"),i==="r"&&t.step==="Results"&&t.data.refreshable&&!o&&(n(!0),e.submitInput("refresh"))}),N(_,{flexDirection:"column",width:"100%",children:[E(de,{}),t.step==="Checking"&&E(_,{marginTop:1,children:E(Zr,{label:t.data.services?"Refreshing service health...":"Checking service health..."})}),t.step==="Results"&&t.data.services&&N(_,{flexDirection:"column",children:[N(_,{flexDirection:"column",borderStyle:"round",borderColor:T,paddingX:2,paddingY:1,children:[N(_,{justifyContent:"space-between",children:[E(A,{bold:!0,color:T,children:"GAIA Service Status"}),a&&N(A,{color:"gray",dimColor:!0,children:["checked ",a," \xB7 ",E(A,{bold:!0,children:"r"})," refresh"]})]}),N(_,{marginTop:1,flexDirection:"column",children:[N(_,{children:[E(_,{width:22,children:E(A,{bold:!0,children:"Service"})}),E(_,{width:10,children:E(A,{bold:!0,children:"Status"})}),E(_,{width:10,children:E(A,{bold:!0,children:"Latency"})})]}),E(A,{color:"gray",children:"\u2500".repeat(42)}),[...t.data.services].sort((i,l)=>i.status==="down"&&l.status!=="down"?-1:i.status!=="down"&&l.status==="down"?1:i.name.localeCompare(l.name)).map(i=>N(_,{children:[E(_,{width:22,children:N(A,{children:[i.name," (:",i.port,")"]})}),E(_,{width:10,children:E(A,{color:i.status==="up"?"green":"red",bold:!0,children:i.status==="up"?"\u2713 UP":"\u2717 DOWN"})}),E(_,{width:10,children:E(A,{color:"gray",children:i.latency?`${i.latency}ms`:"--"})})]},i.name))]})]}),t.data.docker&&N(_,{flexDirection:"column",borderStyle:"round",borderColor:"gray",paddingX:2,paddingY:1,marginTop:1,children:[E(A,{bold:!0,children:"Docker Containers"}),N(A,{color:"gray",children:["Docker:"," ",t.data.docker.running?E(A,{color:"green",children:"Running"}):E(A,{color:"red",children:"Not running"})]}),t.data.docker.containers?.length>0&&E(_,{marginTop:1,flexDirection:"column",children:t.data.docker.containers.map(i=>N(_,{children:[N(A,{color:i.status==="running"?"green":"red",children:[i.status==="running"?"\u2713":"\u2717"," "]}),E(A,{children:i.name}),i.health&&N(A,{color:"gray",children:[" (",i.health,")"]})]},i.name))})]}),E(_,{marginTop:1,children:N(A,{dimColor:!0,children:[E(A,{bold:!0,children:"Enter"})," exit \xB7 ",E(A,{bold:!0,children:"r"})," refresh"]})})]}),t.error&&E(_,{borderStyle:"single",borderColor:"red",padding:1,marginTop:2,children:N(A,{color:"red",children:["Error: ",t.error.message]})})]})};import{jsx as Q,jsxs as Ie}from"react/jsx-runtime";var ro=["init","setup","status","start","stop"],at=class extends to.Component{constructor(t){super(t),this.state={error:null}}static getDerivedStateFromError(t){return{error:t}}render(){return this.state.error?Ie(Le,{flexDirection:"column",padding:1,children:[Q(le,{color:"red",bold:!0,children:"An unexpected error occurred:"}),Q(le,{color:"red",children:this.state.error.message}),this.state.error.stack&&Q(Le,{marginTop:1,children:Q(le,{color:"gray",dimColor:!0,children:this.state.error.stack})})]}):this.props.children}},oo=({store:e,command:t})=>{switch(t){case"init":return Q(kt,{store:e});case"setup":return Q(Ft,{store:e});case"status":return Q(Gt,{store:e});case"start":case"stop":return Q(Lt,{store:e,command:t});default:return Ie(Le,{flexDirection:"column",padding:1,children:[Ie(le,{color:"red",children:["Unknown command: ",t]}),Ie(Le,{marginTop:1,flexDirection:"column",children:[Q(le,{bold:!0,children:"Available commands:"}),ro.map(r=>Ie(le,{children:[" ",Q(le,{color:"cyan",children:r})]},r))]})]})}},J=({store:e,command:t})=>Q(at,{children:Q(oo,{store:e,command:t})});import{EventEmitter as no}from"events";var io=150,st=class extends no{state={step:"init",status:"",error:null,data:{},inputRequest:null};inputResolver=null;emitTimer=null;emitPending=!1;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))},io))}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()}waitForInput(t,r,o){return this.state.inputRequest={id:t,meta:r},this.emitNow(),new Promise(n=>{if(this.inputResolver=n,o!=null){let a=setTimeout(()=>{this.inputResolver&&(this.inputResolver=null,this.state.inputRequest=null,this.emitNow(),n(null))},o),c=this.inputResolver;this.inputResolver=i=>{clearTimeout(a),c(i)}}})}submitInput(t){this.inputResolver&&(this.inputResolver(t),this.inputResolver=null,this.state.inputRequest=null,this.emitNow())}},z=()=>new st;import*as oe from"fs";import*as fr from"os";import*as ae from"path";import*as te from"fs";import*as $t from"os";import*as ut from"path";var ct=ut.join($t.homedir(),".gaia"),lt=ut.join(ct,"config.json"),Me="0.1.10";function ao(){te.existsSync(ct)||te.mkdirSync(ct,{recursive:!0})}function pt(){try{if(!te.existsSync(lt))return null;let e=te.readFileSync(lt,"utf-8");return JSON.parse(e)}catch{return null}}function Fe(e){ao(),te.writeFileSync(lt,`${JSON.stringify(e,null,2)}
3
- `)}function Ce(e){let r={...pt()??{version:Me,setupComplete:!1,setupMethod:"manual",repoPath:"",createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()},...e,updatedAt:new Date().toISOString()};Fe(r)}import*as tr from"path";import*as fe from"node:fs";import*as me from"node:path";import{execa as qt}from"execa";var dt={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/"}},Ht={selfhost:{HOST:"http://localhost:8000",FRONTEND_URL:"http://localhost:3000",GAIA_BACKEND_URL:"http://gaia-backend:80",SETUP_MODE:"selfhost"},developer:{HOST:"http://localhost:8000",FRONTEND_URL:"http://localhost:3000",GAIA_BACKEND_URL:"http://host.docker.internal:8000",SETUP_MODE:"developer"}};function mt(e,t){return dt[t][e]??Ht[t][e]}async function jt(e){let t=me.join(e,"apps/api/scripts/dump_config_schema.py"),r=me.join(e,"apps/api/app/config/settings_validator.py"),o=me.join(e,"apps/api/app/config/settings.py");if(!fe.existsSync(t))throw new Error("dump_config_schema.py not found in apps/api/scripts");try{try{let{stdout:n}=await qt("python3",[t,r,o],{cwd:e});return JSON.parse(n)}catch{let{stdout:n}=await qt("python",[t,r,o],{cwd:e});return JSON.parse(n)}}catch(n){throw new Error(`Failed to parse settings schema: ${n.message}. Ensure python is installed.`)}}function Wt(e){let t=me.join(e,"apps","web",".env.local"),r=fe.existsSync(t)?t:me.join(e,"apps","web",".env");if(!fe.existsSync(r))return[];let o=fe.readFileSync(r,"utf-8"),n=[],a="General";for(let c of o.split(`
4
- `)){let i=c.trim();if(i.startsWith("#")&&!i.startsWith("#=")){let S=i.replace(/^#+\s*/,"").trim();S&&!S.startsWith("These are")&&(a=S);continue}if(!i||i.startsWith("#"))continue;let l=i.indexOf("=");if(l===-1)continue;let u=i.substring(0,l).trim(),g=i.substring(l+1).trim();n.push({name:u,value:g,category:a})}return n}function Vt(e,t){return{NEXT_PUBLIC_API_BASE_URL:`http://localhost:${t?.[8e3]??8e3}/api/v1/`}}function Ut(e,t,r){let o=r==="selfhost"?new Set(Object.keys(dt.selfhost)):new Set;for(let[n,a]of Object.entries(t)){let c=Number(n),i=Number(a);for(let[l,u]of Object.entries(e)){if(o.has(l))continue;if(u===String(c)){e[l]=String(i);continue}let g=new RegExp(`:${c}(?=[/\\s]|$)`,"g");e[l]=u.replaceAll(g,`:${i}`)}}}function Xt(e,t){return e.map(r=>({...r,variables:r.variables.map(o=>{let n=mt(o.name,t);return{...o,defaultValue:n||o.defaultValue}})}))}function ft(){return Object.keys(dt.selfhost)}function Qt(e){return{...Ht[e]}}import*as H from"fs";import*as ge from"path";function gt(e){H.existsSync(e)&&H.copyFileSync(e,`${e}.bak`)}function Kt(e,t){let r=ge.join(e,".env");gt(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","MEM0","E2B","DODO","NEXT_PUBLIC","GAIA"];function a(i){for(let u of n)if(i===u||i.startsWith(`${u}_`))return u;let l=i.split("_");return l.length===1?"Core":l[0]||"Core"}let c=new Map;for(let[i,l]of Object.entries(t)){let u=a(i);c.has(u)||c.set(u,[]);let S=/[\s#"'\\]/.test(l)||l===""?`"${l.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`:l;c.get(u).push(`${i}=${S}`)}for(let[i,l]of c.entries())o.push(`# ${i} Configuration`),o.push(...l),o.push("");H.writeFileSync(r,o.join(`
5
- `),"utf-8")}function Jt(e,t,r){let o=ge.join(e,"apps","web",".env.local");gt(o);let n=Wt(e),a=Vt(t,r),c=["# GAIA Web App Environment Configuration","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""],i=new Map;for(let l of n){i.has(l.category)||i.set(l.category,[]);let u=a[l.name]??l.value;i.get(l.category).push({name:l.name,value:u})}if(n.length===0){c.push("# Core URLs");for(let[l,u]of Object.entries(a))c.push(`${l}=${u}`);c.push("")}else for(let[l,u]of i.entries()){c.push(`# ${l}`);for(let{name:g,value:S}of u)c.push(`${g}=${S}`);c.push("")}H.writeFileSync(o,c.join(`
6
- `),"utf-8")}var zt={8e3:"API_HOST_PORT",5432:"POSTGRES_HOST_PORT",6379:"REDIS_HOST_PORT",27017:"MONGO_HOST_PORT",5672:"RABBITMQ_HOST_PORT",8080:"CHROMADB_HOST_PORT",8083:"MONGO_EXPRESS_HOST_PORT",3e3:"WEB_HOST_PORT"};function Zt(e,t,r){let o=ge.join(e,"infra","docker",".env");gt(o);let n=["# Docker Compose environment overrides","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""];for(let[a,c]of Object.entries(t)){let i=Number(a),l=zt[i];l&&n.push(`${l}=${c}`)}if(r==="selfhost"){let a=t[8e3]??8e3;n.push(""),n.push("# Web build args"),n.push(`NEXT_PUBLIC_API_BASE_URL=http://localhost:${a}/api/v1/`)}n.push(""),H.writeFileSync(o,n.join(`
7
- `),"utf-8")}function he(e){let t={};for(let[r,o]of Object.entries(e)){let n=Number(r),a=zt[n];a&&(t[a]=String(o))}return t}function er(e){let t=ge.join(e,"infra","docker","docker-compose.yml");if(!H.existsSync(t))return;let r=H.readFileSync(t,"utf-8"),o=[{varName:"API_HOST_PORT",hostPort:8e3,containerPort:80},{varName:"CHROMADB_HOST_PORT",hostPort:8080,containerPort:8e3},{varName:"POSTGRES_HOST_PORT",hostPort:5432,containerPort:5432},{varName:"REDIS_HOST_PORT",hostPort:6379,containerPort:6379},{varName:"MONGO_HOST_PORT",hostPort:27017,containerPort:27017},{varName:"RABBITMQ_HOST_PORT",hostPort:5672,containerPort:5672},{varName:"MONGO_EXPRESS_HOST_PORT",hostPort:8083,containerPort:8081},{varName:"WEB_HOST_PORT",hostPort:3e3,containerPort:3e3}],n=!1;for(let{varName:a,hostPort:c,containerPort:i}of o){let l=`"${c}:${i}"`,u=`"\${${a}:-${c}}:${i}"`;r.includes(l)&&(r=r.replaceAll(l,u),n=!0)}n&&H.writeFileSync(t,r,"utf-8")}var Yt={API_HOST_PORT:8e3,POSTGRES_HOST_PORT:5432,REDIS_HOST_PORT:6379,MONGO_HOST_PORT:27017,RABBITMQ_HOST_PORT:5672,CHROMADB_HOST_PORT:8080,MONGO_EXPRESS_HOST_PORT:8083,WEB_HOST_PORT:3e3};function Se(e){let t=ge.join(e,"infra","docker",".env"),r={};if(!H.existsSync(t))return r;let o=H.readFileSync(t,"utf-8");for(let n of o.split(`
8
- `)){let a=n.trim();if(a&&!a.startsWith("#")){let[c,...i]=a.split("=");if(c&&Yt[c]){let l=i.join("=").trim().replace(/^["']|["']$/g,""),u=Number(l);!Number.isNaN(u)&&u>0&&u<=65535&&(r[Yt[c]]=u)}}}return r}var lo=e=>new Promise(t=>setTimeout(t,e));async function Ne(e){e.setStep("Setup Mode"),e.setStatus("Choose how to run GAIA...");let t=await e.waitForInput("setup_mode");return e.updateData("setupMode",t),t}async function Ge(e,t,r,o){e.setStep("Environment Setup"),e.setStatus("Configuring environment..."),e.updateData("setupMode",r),e.setStatus("Configuring environment variables...");let n=await e.waitForInput("env_method");e.updateData("envMethod",n);let a={};a.ENV="development";let c=ft();for(let l of c){let u=mt(l,r);u&&(a[l]=u)}let i=Qt(r);for(let[l,u]of Object.entries(i))a[l]=u;if(n==="infisical")await uo(e,a),e.setStatus("Infisical credentials saved. Ensure your Infisical project contains all required variables.");else try{await po(e,t,a,r)}catch(l){e.setError(l);return}o&&Ut(a,o,r);try{await mo(e,t,a,r,o)}catch(l){e.setError(l);return}await lo(1e3)}async function uo(e,t){e.setStatus("Configuring Infisical...");let r=await e.waitForInput("env_infisical");t.INFISICAL_TOKEN=r.INFISICAL_TOKEN,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}async function po(e,t,r,o){e.setStatus("Parsing environment variables...");let n;try{n=await jt(t),n=Xt(n,o)}catch(f){throw o==="selfhost"?new Error(`Manual environment setup requires Python to parse config schema.
2
+ import{Command as Qs}from"commander";var le={init:"Full setup from scratch (clone, configure, start)",setup:"Configure an existing GAIA repository",status:"Check health of all GAIA services",start:"Start GAIA services (self-host mode)",dev:"Run developer mode in Nx TUI (`gaia dev` or `gaia dev full`)",logs:"Stream logs for running GAIA services",stop:"Stop all GAIA services (safe mode by default)"};import{Command as Ni}from"commander";import{existsSync as ot,mkdirSync as Jn,readFileSync as Ur,writeFileSync as Gt}from"node:fs";import{homedir as jr}from"node:os";import{join as jt}from"node:path";import{sep as kn}from"node:path";var A={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"},Dt="https://api.heygaia.io",ye="filesystem",Qe=kn,At=500,Ot=6e4,Lt=5e3,Mt=1e6,Nt=5e6,ze=9e4,Ze=1e6;import{homedir as _n}from"node:os";import{join as Dn}from"node:path";var An={info:e=>console.error(e),error:e=>console.error(e)},Bt={},On=null;function B(){return On??An}function ee(){return{stateDir:Bt.stateDir??Dn(_n(),".gaia","bridge"),env:Bt.env??process.env,shell:Bt.shell??process.env.SHELL??"/bin/sh"}}import{Client as qn}from"@modelcontextprotocol/sdk/client/index.js";import{getDefaultEnvironment as Hn,StdioClientTransport as Vn}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as Wn}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{InMemoryTransport as Xn}from"@modelcontextprotocol/sdk/inMemory.js";import{lstat as Ln,readdir as Mr,readFile as Ar,realpath as Mn,stat as Nn,writeFile as Bn}from"node:fs/promises";import{dirname as Or,extname as Fn,join as Nr,resolve as $n,sep as Ft}from"node:path";import{McpServer as Gn}from"@modelcontextprotocol/sdk/server/mcp.js";import{z as Ie}from"zod";var jn={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".gif":"image/gif"},Pe=class extends Error{};async function $t(e){try{return await Mn(e)}catch{return null}}async function Un(e){try{return(await Ln(e)).isSymbolicLink()}catch{return!1}}function Lr(e,t){return t===Ft?e.startsWith(Ft):e===t||e.startsWith(t+Ft)}async function et(e,t,r){let o=$n(e),n=await $t(o);if(n){if(t.some(a=>Lr(n,a)))return n;throw new Pe(`Path is outside your approved folders: ${e}`)}if(r)throw new Pe(`No such file or directory: ${e}`);let i=await $t(Or(o));if(!i||!t.some(a=>Lr(i,a)))throw new Pe(`Path is outside your approved folders: ${e}`);if(await Un(o))throw new Pe(`Refusing to write through a symlink: ${e}`);return Nr(i,o.slice(Or(o).length+1))}async function Br(e,t,r,o){if(o.length>=r)return;let n;try{n=await Mr(e,{withFileTypes:!0})}catch{return}for(let i of n){if(o.length>=r)return;let a=Nr(e,i.name);i.name.toLowerCase().includes(t.toLowerCase())&&o.push(a),i.isDirectory()&&!i.isSymbolicLink()&&await Br(a,t,r,o)}}function Fr(e){let t=new Gn({name:"gaia-filesystem",version:"0.1.0"}),r=null,o=()=>(r||(r=Promise.all(e.allow.map($t)).then(i=>i.filter(a=>a!==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:Ie.string().describe("Absolute path to a directory")}},async({path:i})=>{try{let a=await et(i,await o(),!0);return{content:[{type:"text",text:(await Mr(a,{withFileTypes:!0})).map(u=>`${u.isDirectory()?"dir ":"file"} ${u.name}`).join(`
3
+ `)||"(empty)"}]}}catch(a){return n(a instanceof Error?a.message:String(a))}}),t.registerTool("read_file",{description:"Read the contents of a text or image file on the user's machine.",inputSchema:{path:Ie.string().describe("Absolute path to a file")}},async({path:i})=>{try{let a=await et(i,await o(),!0),s=await Nn(a);if(!s.isFile())return n(`Not a file: ${i}`);let c=jn[Fn(a).toLowerCase()];if(c){if(s.size>Nt)return n(`Image is too large to read (${s.size} bytes).`);let d=await Ar(a);return{content:[{type:"text",text:`Image file ${a} (${c}, ${s.size} bytes) \u2014 shown below.`},{type:"image",data:d.toString("base64"),mimeType:c}]}}return s.size>Mt?n(`File is too large to read (${s.size} bytes).`):{content:[{type:"text",text:await Ar(a,"utf-8")}]}}catch(a){return n(a instanceof Error?a.message:String(a))}}),t.registerTool("search_files",{description:"Recursively find files/folders whose name contains a query, under a directory.",inputSchema:{path:Ie.string().describe("Absolute path to the directory to search under"),query:Ie.string().describe("Substring to match against names")}},async({path:i,query:a})=>{try{let s=await et(i,await o(),!0),c=[];return await Br(s,a,200,c),{content:[{type:"text",text:c.join(`
4
+ `)||"(no matches)"}]}}catch(s){return n(s instanceof Error?s.message:String(s))}}),e.allowWrite&&t.registerTool("write_file",{description:"Write text to a file on the user's machine (overwrites if it exists).",inputSchema:{path:Ie.string().describe("Absolute path to the file to write"),content:Ie.string().describe("Text content to write")}},async({path:i,content:a})=>{try{let s=await et(i,await o(),!1);return await Bn(s,a,"utf-8"),{content:[{type:"text",text:`Wrote ${a.length} bytes to ${i}`}]}}catch(s){return n(s instanceof Error?s.message:String(s))}}),t}var Yn=new Set(["localhost","127.0.0.1","::1"]),$r=5;function ue(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(!Yn.has(r))throw new Error("url servers must point at this machine (localhost / 127.0.0.1 / ::1)");return t}function Kn(e){return new URL(typeof e=="string"?e:e instanceof URL?e.href:e.url)}async function Gr(e,t){let r=Kn(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 a=i.headers.get("location"),s=a?new URL(a,r.href):null;if(await i.body?.cancel(),!s||s.origin!==r.origin)throw new Error(`refusing ${i.status} redirect to ${a??"(no location)"} \u2014 an MCP server must be addressed directly, not via a redirect`);if(n>=$r)throw new Error(`too many redirects (>${$r}) \u2014 refusing to follow`);r=s,o={...t,redirect:"manual"}}}async function tt(e){if(e.type==="url"){let n=ue(e.url),i=new Wn(n,{requestInit:{...e.headers?{headers:e.headers}:{}},fetch:Gr});return{transport:i,close:()=>i.close()}}if(e.type==="stdio"){let n=ee().env,i=new Vn({command:e.command,args:e.args,env:{...Hn(),...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]=Xn.createLinkedPair(),o=Fr(e);return await o.connect(r),{transport:t,close:async()=>{await o.close(),await t.close()}}}async function rt(e){let t=await tt(e),r=new qn({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 Ut(){return ee().stateDir}function qt(){return jt(Ut(),"credentials.json")}function qr(){return jt(Ut(),"config.json")}function Hr(){let e=Ut();ot(e)||Jn(e,{recursive:!0,mode:448})}function te(){let e=qt();if(!ot(e))return null;try{return JSON.parse(Ur(e,"utf-8"))}catch{return null}}function Ne(e){Hr(),Gt(qt(),JSON.stringify(e,null,2),{mode:384})}function Be(){let e=qt();ot(e)&&Gt(e,"{}",{mode:384})}function $(){let e=qr();if(!ot(e))return{servers:[]};try{return{servers:JSON.parse(Ur(e,"utf-8")).servers??[]}}catch{return{servers:[]}}}function Vr(e){Hr(),Gt(qr(),JSON.stringify(e,null,2),{mode:384})}function nt(e){e.type==="url"&&ue(e.url);let t=$(),r=t.servers.findIndex(o=>o.key===e.key);r>=0?t.servers[r]=e:t.servers.push(e),Vr(t)}function Fe(e){let t=$(),r=t.servers.length;return t.servers=t.servers.filter(o=>o.key!==e),Vr(t),t.servers.length<r}function Ht(e){return e==="~"?jr():e.startsWith("~/")?jt(jr(),e.slice(2)):e}function Vt(e,t){return{type:"filesystem",key:ye,name:"Local Files",allow:e,allowWrite:t}}function $e(e){if(e)return e.replace(/\/$/,"");let t=te();return t?.apiUrl?t.apiUrl.replace(/\/$/,""):(process.env.GAIA_API_URL??Dt).replace(/\/$/,"")}import{hostname as zn,platform as Zn}from"node:os";var J=class extends Error{constructor(r,o){super(r);this.status=o;this.name="ApiError"}};async function it(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)});if(!n.ok){let i=`${n.status} ${n.statusText}`;try{let a=await n.json();a.detail&&(i=a.detail)}catch{}throw new J(i,n.status)}return await n.json()}async function Qn(e,t,r){let o=await fetch(`${e}/api/v1${t}`,{method:"DELETE",headers:{authorization:`Bearer ${r}`}});if(!o.ok){let n=`${o.status} ${o.statusText}`;try{let i=await o.json();i.detail&&(n=i.detail)}catch{}throw new J(n,o.status)}return await o.json()}function Wt(e,t,r,o){return it(e,"/device/pair/start",{name:t,platform:r,daemon_version:o})}function Xt(e,t){return it(e,"/device/pair/poll",{device_code:t})}function Yt(e,t){return it(e,"/device/token",{refresh_token:t})}function Kt(e,t,r,o,n){return it(e,"/device/servers",{server_key:r,display_name:o,kind:n},t)}function Wr(e,t,r){return Qn(e,`/device/servers/${encodeURIComponent(r)}`,t)}async function ei(e){await new Promise(t=>setTimeout(t,e))}function Jt(){return!!te()?.refreshToken}async function Xr(e,t){let r=$e(t.api),o=t.name||zn(),n=await Wt(r,o,Zn(),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 ei(n.interval*1e3);let a;try{a=await Xt(r,n.device_code)}catch(s){B().error(`[gaia bridge] poll failed, retrying: ${s instanceof Error?s.message:s}`);continue}if(a.status==="approved"&&a.device_id&&a.refresh_token){Ne({apiUrl:r,deviceId:a.device_id,refreshToken:a.refresh_token}),e.onStatus?.(`
5
+ Paired as "${o}".
6
+ `);return}if(a.status==="denied"||a.status==="expired")throw new Error(`pairing ${a.status}`)}throw new Error("pairing timed out")}var Yr={name:"@heygaia/cli",description:"CLI tool for setting up and managing GAIA",version:"0.6.0",type:"module",files:["dist","README.md"],scripts:{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.29.0",commander:"^14.0.3",execa:"^9.6.1",ink:"^6.8.0","ink-big-text":"^2.0.0","ink-gradient":"^3.0.0","ink-text-input":"^6.0.0",react:"19.1.0","react-dom":"19.1.0","simple-git":"^3.36.0",ws:"^8.21.0",zod:"^4.3.6"},devDependencies:{"@biomejs/biome":"^2.5.7","@gaia/shared":"workspace:*","@types/node":"^24.13.3","@types/react":"^19.2.17","@types/react-dom":"^19.2.3","@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 ne=Yr.version;var ri={onPrompt(e,t){console.info(`
7
+ To pair this device, open:
8
+ `),console.info(` ${e}`),console.info(`
9
+ and enter this code: ${t}
10
+ `)},onStatus(e){console.info(e)}};async function Re(e={}){await Xr(ri,{...e,daemonVersion:ne})}import{spawn as yi}from"node:child_process";import{existsSync as zt,mkdirSync as xi,openSync as wi,readFileSync as Ei,unlinkSync as to,writeFileSync as bi}from"node:fs";import{homedir as Ti}from"node:os";import{join as Zt}from"node:path";import{mkdirSync as Kr,readFileSync as oi,rmSync as Jr,writeFileSync as ni}from"node:fs";import{dirname as ii,join as Qr}from"node:path";var si=3e4,ai=3e4,ci=50,li=e=>new Promise(t=>setTimeout(t,e));function zr(){return Qr(ee().stateDir,"credentials.lock")}function ui(){return Qr(zr(),"stamp")}async function pi(e){let t=zr(),r=ui();Kr(ii(t),{recursive:!0});let o=Date.now()+ai;for(;;){try{Kr(t);break}catch(i){if(i?.code!=="EEXIST")throw i}let n=null;try{let i=Number(oi(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<si){if(Date.now()>o)throw new Error("another gaia process is rotating the device credential \u2014 try again");await li(ci);continue}try{Jr(t,{recursive:!0,force:!0})}catch{}}try{return ni(r,String(Date.now()),{mode:384}),await e()}finally{try{Jr(t,{recursive:!0,force:!0})}catch{}}}async function Ge(){return pi(async()=>{let e=te();if(!e?.refreshToken)throw new J("not paired \u2014 run: gaia bridge login",401);let t=await Yt(e.apiUrl,e.refreshToken),r={...e,refreshToken:t.refresh_token};return Ne(r),{creds:r,accessToken:t.access_token}})}async function ke(){let e=$().servers;if(e.length===0)throw new Error("no servers configured \u2014 run: gaia bridge add");let{creds:t,accessToken:r}=await Ge();await Promise.all(e.map(o=>Kt(t.apiUrl,r,o.key,o.name,o.type)))}async function Qt(e){let t=Fe(e);try{let{creds:r,accessToken:o}=await Ge();await Wr(r.apiUrl,o,e)}catch(r){B().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 Si}from"node:crypto";import eo from"ws";import{spawn as di}from"node:child_process";import{appendFileSync as mi,mkdirSync as fi}from"node:fs";import{homedir as gi}from"node:os";import{join as hi}from"node:path";function vi(e,t){try{let r=ee().stateDir;fi(r,{recursive:!0,mode:448});let o=t?` (cwd: ${t})`:"";mi(hi(r,"exec-audit.log"),`${new Date().toISOString()}${o} $ ${e}
11
+ `)}catch{}}async function Zr(e,t,r){vi(e,t);let o=di(ee().shell,["-c",e],{cwd:t||gi(),env:ee().env,stdio:["ignore","pipe","pipe"]}),n=0,i=!1,a=c=>u=>{if(i)return;let d=Ze-n,m=u.length>d?u.subarray(0,d):u;m.length>0&&(n+=m.length,r[c](m.toString("utf-8"))),n>=Ze&&(i=!0,r.stderr(`
12
+ [gaia bridge] output truncated \u2014 cap reached
13
+ `),o.kill("SIGKILL"))};o.stdout.on("data",a("stdout")),o.stderr.on("data",a("stderr"));let s=setTimeout(()=>{r.stderr(`
14
+ [gaia bridge] killed \u2014 exceeded ${ze/1e3}s timeout
15
+ `),o.kill("SIGKILL")},ze);await new Promise(c=>{o.on("error",u=>{clearTimeout(s),r.stderr(`[gaia bridge] could not start command: ${u.message}
16
+ `),r.exit(127),c()}),o.on("close",u=>{clearTimeout(s),r.exit(u??-1),c()})})}var je=class{constructor(t){this.creds=t}ws=null;sessions=new Map;reconnectDelay=At;stopped=!1;async run(){for(;!this.stopped;){try{await this.connectOnce()}catch(t){t instanceof J&&t.status===401?(B().error("[gaia bridge] this device is no longer authorized (revoked or unpaired). Re-pair with: gaia bridge login"),this.stopped=!0):B().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 Ge();this.creds=t;let o=`${this.creds.apiUrl.replace(/^http/,"ws")}/api/v1/ws/device`,n=new eo(o,{headers:{authorization:`Bearer ${r}`}});this.ws=n,await new Promise((i,a)=>{let s=!1,c=!1,u=d=>{c||(c=!0,d())};n.on("open",()=>{s=!0,this.reconnectDelay=Lt;let d=$().servers.map(m=>m.key);this.send({t:A.HELLO,servers:d}),B().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,u(()=>s?i():a(new Error("socket closed before open")))}),n.on("error",d=>{s||u(()=>a(d))})})}async onFrame(t){let r;try{r=JSON.parse(t)}catch{return}switch(r.t){case A.PING:this.send({t:A.PONG});return;case A.MCP_OPEN:await this.openSession(r);return;case A.MCP_MSG:await this.forwardToServer(r);return;case A.MCP_CLOSE:await this.closeSession(r.sid);return;case A.EXEC_OPEN:await this.runExec(r);return;case A.REVOKE:B().error("[gaia bridge] this device was revoked \u2014 exiting."),await this.stop();return;case A.SERVER_REMOVE:r.key&&Fe(r.key)&&B().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=$().servers.find(s=>s.key===o);if(!i){this.send({t:A.MCP_ERROR,sid:r,pod:n,error:`Unknown server '${o}'`});return}let a=Date.now();B().info(`[gaia bridge] opening MCP session for '${o}'\u2026`);try{let s=await tt(i);s.transport.onmessage=c=>{this.send({t:A.MCP_MSG,sid:r,pod:n,data:JSON.stringify(c)})},s.transport.onclose=()=>{this.sessions.has(r)&&this.send({t:A.MCP_ERROR,sid:r,pod:n,error:`Local server '${o}' exited`}),this.guardRejection(this.closeSession(r),"session close error")},await s.transport.start(),this.sessions.set(r,s),this.send({t:A.MCP_OPENED,sid:r,pod:n}),B().info(`[gaia bridge] MCP session for '${o}' ready in ${Date.now()-a}ms`)}catch(s){let c=s instanceof Error?s.message:String(s);B().error(`[gaia bridge] MCP session for '${o}' failed after ${Date.now()-a}ms: ${c}`),this.send({t:A.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){B().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 Zr(n,t.cwd,{stdout:i=>this.send({t:A.EXEC_STDOUT,sid:r,pod:o,data:i}),stderr:i=>this.send({t:A.EXEC_STDERR,sid:r,pod:o,data:i}),exit:i=>this.send({t:A.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===eo.OPEN&&this.ws.send(JSON.stringify(t))}guardRejection(t,r){t.catch(o=>{B().error(`[gaia bridge] ${r}: ${o instanceof Error?o.message:o}`)})}async backoff(){let t=Si(this.reconnectDelay);B().info(`[gaia bridge] reconnecting in ${t}ms\u2026`),await new Promise(r=>setTimeout(r,t)),this.reconnectDelay=Math.min(this.reconnectDelay*2,Ot)}};var er=Zt(Ti(),".gaia","bridge"),xe=Zt(er,"daemon.pid"),ro=Zt(er,"daemon.log");function tr(){if(!zt(xe))return null;let e=Number(Ei(xe,"utf-8").trim());if(!e)return null;try{return process.kill(e,0),e}catch{return null}}function oo(){let e=tr();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 no(){let e=tr();if(!e){zt(xe)&&to(xe),console.info("No bridge tunnel is running.");return}try{process.kill(e,"SIGTERM")}catch{}zt(xe)&&to(xe),console.info(`Stopped the bridge tunnel (pid ${e}).`)}async function st(){let e=tr();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=$().servers.filter(a=>a.type==="url"&&a.headers&&Object.keys(a.headers).length>0);t.length>0&&console.error(`[gaia bridge] forwarding request headers (credentials) to ${t.length} local url server(s).`);try{await ke()}catch(a){if(a instanceof J&&a.status===401)console.error(`[gaia bridge] this device is no longer authorized (revoked or unpaired). Let's re-pair.
17
+ `),Be(),await Re(),await ke();else throw a}let r=process.argv[1];if(!r)throw new Error("cannot locate the gaia CLI entrypoint to start the daemon");xi(er,{recursive:!0,mode:448});let o=wi(ro,"a"),n={detached:!0,stdio:["ignore",o,o]},i=yi(process.execPath,[...process.execArgv,r,"bridge","up","--serve"],n);i.unref(),bi(xe,String(i.pid??""),{mode:384}),console.info(`
18
+ Bridge tunnel started in the background (pid ${i.pid}).
19
+ Logs: ${ro}
20
+ Stop: gaia bridge down`)}async function io(){let e=te();if(!e?.refreshToken)throw new Error("not paired \u2014 run: gaia bridge login");let t=new je(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 po}from"node:path";import{resolve as Ci}from"node:path";function rr(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)}function or(e){let t=[],r="",o=null;for(let a of e.trim())o?a===o?o=null:r+=a:a==='"'||a==="'"?o=a:/\s/.test(a)?r&&(t.push(r),r=""):r+=a;r&&t.push(r);let[n,...i]=t;if(!n)throw new Error("Empty command");return{command:n,args:i}}function so(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 ao(e){let t=rr(e??"");if(!e||!t||t===ye)throw new Error("--name is required and must contain letters or digits");return t}function co(e){if(e.type==="stdio"){if(!e.command)throw new Error("--command is required for --type stdio");let{command:t,args:r}=or(e.command);return{type:"stdio",key:ao(e.name),name:e.name,command:t,args:r,env:so(e.env,"=","--env")}}if(e.type==="url"){if(!e.url)throw new Error("--url is required for --type url");ue(e.url);let t=so(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:ao(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(Qe)?[Qe]:t.map(o=>Ci(Ht(o)));return Vt(r,!!e.write)}throw new Error("--type must be one of: stdio, url, filesystem")}import{createInterface as lo}from"node:readline/promises";import{Writable as Ii}from"node:stream";async function pe(e,t){let r=lo({input:process.stdin,output:process.stdout});try{let o=t?` [${t}]`:"";return(await r.question(`${e}${o}: `)).trim()||t||""}finally{r.close()}}async function uo(e){process.stdout.write(`${e}: `);let t=new Ii({write(o,n,i){i()}}),r=lo({input:process.stdin,output:t,terminal:!0});try{let o=(await r.question("")).trim();return process.stdout.write(`
21
+ `),o}finally{r.close()}}async function de(e,t=!0){let r=await pe(`${e} (${t?"Y/n":"y/N"})`);return r?/^y(es)?$/i.test(r):t}async function at(e,t){for(process.stdout.write(`
22
+ ${e}
23
+ `),t.forEach((r,o)=>{process.stdout.write(` ${o+1}. ${r}
24
+ `)});;){let r=await pe(`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.
25
+ `)}}function Pi(e,t){let o=[...t].reverse().filter(n=>!n.startsWith("-"))[0]??e;return po(o).replace(/@[^@]*$/,"")}function Ri(e){try{let t=new URL(e);return t.port?`local-${t.port}`:t.hostname}catch{return""}}async function mo(e){for(;;){let t=await pe("Name for this server",e),r=rr(t);if(!t||!r||r===ye){console.info("Pick a different name.");continue}if(!($().servers.some(o=>o.key===r)&&!await de(`'${r}' already exists \u2014 overwrite?`,!1)))return{name:t,key:r}}}function ki(e,t){if(po(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 nr(e){let t=process.env[e];if(t!==void 0&&t!==""&&await de(` Found ${e} in your environment \u2014 use that value?`,!0))return t;for(;;){let r=await uo(` 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 fo(e,t){let r={};for(let n of ki(e,t))console.info(`
26
+ The command needs ${n}.`),r[n]=await nr(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 de(o,!1))return r;for(console.info("Enter each variable's name; leave blank when done.");;){let n=(await pe(" Variable name")).trim();if(!n)break;if(n in r){console.info(" Already added.");continue}r[n]=await nr(n)}return r}async function _i(){console.info(`
27
+ Examples: npx -y my-mcp-server \xB7 uvx my-server \xB7 docker run -i --rm my/image`);let e=await pe("Command that starts your MCP server");if(!e)throw new Error("a command is required");let{command:t,args:r}=or(e),o=await fo(t,r),{name:n,key:i}=await mo(Pi(t,r));return{type:"stdio",key:i,name:n,command:t,args:r,env:o}}async function Di(){let e={};if(!await de("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 pe(" Header name")).trim();if(!t)break;if(t in e){console.info(" Already added.");continue}e[t]=await nr(t)}return e}async function Ai(){let e=await pe("Server URL (e.g. http://localhost:3000/mcp)");if(!e)throw new Error("a URL is required");ue(e);let t=await Di();if(Object.keys(t).length>0&&new URL(e).protocol==="http:"&&(console.info(`
28
+ Heads up: these headers travel unencrypted over local HTTP. Anyone else on this machine (or the receiving server's logs) can read them.`),!await de("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 mo(Ri(e));return{type:"url",key:o,name:r,url:e,...Object.keys(t).length?{headers:t}:{}}}async function Oi(e){for(;;){console.info(`
29
+ Testing the connection (this may download/start the server)\u2026`);try{let t=await rt(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 at("What now?",r)];if(o==="Re-enter environment variables"&&e.type==="stdio")e.env=await fo(e.command,e.args);else{if(o==="Save anyway (fix it later)")return!0;if(o==="Abort")return!1}}}}async function Li(e){let t=co(e),r;try{r=await rt(t)}catch(o){throw new Error(`Could not start '${t.key}': ${o instanceof Error?o.message:o}`)}nt(t),await ke(),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 go(e={}){if(!Jt()){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 Re()}if(e.type){await Li(e);return}let r=await at("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 _i():await Ai();if(!await Oi(r))throw new Error("aborted");nt(r),console.info(`
30
+ Saved '${r.key}'.`);try{await ke(),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 de("Keep this device connected in the background now?")?await st():console.info("Run `gaia bridge up` whenever you're ready.")}function Mi(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 ho(e){if(e){let n=await Qt(e);console.info(n?`Removed '${e}' from this device and GAIA.`:`No server '${e}'.`);return}let t=$().servers;if(t.length===0){console.info("No servers configured \u2014 nothing to remove.");return}let r=await at("Which server do you want to remove?",t.map(Mi)),o=t[r];if(o){if(!await de(`Remove '${o.key}'?`,!1)){console.info("Left it in place.");return}await Qt(o.key),console.info(`Removed '${o.key}'. The tunnel stops serving it right away, and GAIA drops it too.`)}}function Bi(){let e=te();console.info(e?.deviceId?`Paired (device ${e.deviceId}, ${$e()})`:"Not paired \u2014 run: gaia bridge login"),console.info(oo());let t=$().servers;if(t.length===0){console.info("No servers configured \u2014 run: gaia bridge add");return}console.info(`
31
+ 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(", ")}`)}}async function we(e){try{await e()}catch(t){console.error(`Error: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}}var ie=new Ni("bridge").description("Connect this machine's local MCP servers and files to GAIA (outbound-only, no inbound ports)").addHelpText("after",`
32
+ Revoke a device anytime from GAIA \u2192 Settings \u2192 Devices.`);ie.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 we(()=>go(e))});ie.command("login").description("Pair this machine with your GAIA account").option("--api <url>","GAIA API base URL").option("--name <name>","Name to show for this device in Settings").action(async e=>{await we(async()=>{await Re({...e.api!==void 0?{api:e.api}:{},...e.name!==void 0?{name:e.name}:{}}),console.info("Next: gaia bridge add")})});ie.command("ls").alias("list").description("Show pairing status and configured servers").action(async()=>{await we(Bi)});ie.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 we(()=>ho(e))});ie.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 we(e.serve?io:st)});ie.command("down").alias("stop").description("Stop the background tunnel started by `gaia bridge up`").action(async()=>{await we(no)});ie.command("logout").description("Forget local credentials").action(async()=>{await we(()=>{Be(),console.info("Logged out. Your device record remains until you revoke it in GAIA settings.")})});import*as dt from"fs";import*as Mo from"path";import{spawn as Fi}from"child_process";async function _e(e,t,r,o,n,i=!1){await ct([{cmd:e,args:t,cwd:r,env:o,onSpawn:n,detached:i}])}async function ct(e){e.length!==0&&await new Promise((t,r)=>{let o=e.map(m=>Fi(m.cmd,m.args,{cwd:m.cwd,stdio:"inherit",shell:!1,detached:m.detached??!1,env:m.env?{...process.env,...m.env}:process.env}));o.forEach((m,f)=>{e[f]?.onSpawn?.(m.pid)});let n=!1,i=0,a=!1,s,c=()=>{process.off("SIGINT",d),process.off("SIGTERM",d)},u=()=>{if(!a){a=!0;for(let[m,f]of o.entries()){let S=e[m];try{process.platform!=="win32"&&S?.detached&&typeof f.pid=="number"?process.kill(-f.pid,"SIGTERM"):f.kill("SIGTERM")}catch{}}s=setTimeout(()=>{for(let[m,f]of o.entries()){let S=e[m];try{process.platform!=="win32"&&S?.detached&&typeof f.pid=="number"?process.kill(-f.pid,"SIGKILL"):f.kill("SIGKILL")}catch{}}},1e3)}},d=()=>{u()};process.on("SIGINT",d),process.on("SIGTERM",d),o.forEach((m,f)=>{let S=e[f];m.on("error",v=>{n||(n=!0,c(),u(),r(v))}),m.on("close",(v,y)=>{if(i+=1,!(v===0||(y==="SIGINT"||y==="SIGTERM"||v===130||v===143||a))&&!n){n=!0,c(),u(),r(new Error(`Command failed with code ${String(v)}: ${S?.cmd??"unknown"} ${S?.args.join(" ")??""}`));return}i>=o.length&&!n&&(n=!0,c(),s&&clearTimeout(s),t())})})})}import*as Q from"fs";import*as W from"path";import*as se from"fs";import*as vo from"os";import*as ar from"path";var ir=ar.join(vo.homedir(),".gaia"),sr=ar.join(ir,"config.json");function $i(){se.existsSync(ir)||se.mkdirSync(ir,{recursive:!0})}function cr(){try{if(!se.existsSync(sr))return null;let e=se.readFileSync(sr,"utf-8");return JSON.parse(e)}catch{return null}}function lt(e){$i(),se.writeFileSync(sr,`${JSON.stringify(e,null,2)}
33
+ `)}function Ue(e){let r={...cr()??{version:ne,setupComplete:!1,setupMethod:"manual",repoPath:"",createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()},...e,updatedAt:new Date().toISOString()};lt(r)}import*as j from"fs";import*as Oe from"path";import*as Ae from"node:fs";import*as De from"node:path";import{execa as So}from"execa";var lr={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/"}},yo={selfhost:{HOST:"http://localhost:8000",FRONTEND_URL:"http://localhost:3000",GAIA_BACKEND_URL:"http://gaia-backend:80",SETUP_MODE:"selfhost"},developer:{HOST:"http://localhost:8000",FRONTEND_URL:"http://localhost:3000",GAIA_BACKEND_URL:"http://host.docker.internal:8000",SETUP_MODE:"developer"}};function ur(e,t){return lr[t][e]??yo[t][e]}async function xo(e){let t=De.join(e,"apps/api/scripts/dump_config_schema.py"),r=De.join(e,"apps/api/app/config/settings_validator.py"),o=De.join(e,"apps/api/app/config/settings.py");if(!Ae.existsSync(t))throw new Error("dump_config_schema.py not found in apps/api/scripts");try{try{let{stdout:n}=await So("python3",[t,r,o],{cwd:e});return JSON.parse(n)}catch{let{stdout:n}=await So("python",[t,r,o],{cwd:e});return JSON.parse(n)}}catch(n){throw new Error(`Failed to parse settings schema: ${n.message}. Ensure python is installed.`)}}function wo(e){let t=De.join(e,"apps","web",".env.local"),r=Ae.existsSync(t)?t:De.join(e,"apps","web",".env");if(!Ae.existsSync(r))return[];let o=Ae.readFileSync(r,"utf-8"),n=[],i="General";for(let a of o.split(`
34
+ `)){let s=a.trim();if(s.startsWith("#")&&!s.startsWith("#=")){let m=s.replace(/^#+\s*/,"").trim();m&&!m.startsWith("These are")&&(i=m);continue}if(!s||s.startsWith("#"))continue;let c=s.indexOf("=");if(c===-1)continue;let u=s.substring(0,c).trim(),d=s.substring(c+1).trim();n.push({name:u,value:d,category:i})}return n}function Eo(e,t){return{NEXT_PUBLIC_API_BASE_URL:`http://localhost:${t?.[8e3]??8e3}/api/v1/`}}function bo(e,t,r){let o=r==="selfhost"?new Set(Object.keys(lr.selfhost)):new Set;for(let[n,i]of Object.entries(t)){let a=Number(n),s=Number(i);for(let[c,u]of Object.entries(e)){if(o.has(c))continue;if(u===String(a)){e[c]=String(s);continue}let d=new RegExp(`:${a}(?=[/\\s]|$)`,"g");e[c]=u.replaceAll(d,`:${s}`)}}}function To(e,t){return e.map(r=>({...r,variables:r.variables.map(o=>{let n=ur(o.name,t);return{...o,defaultValue:n||o.defaultValue}})}))}function pr(){return Object.keys(lr.selfhost)}function Co(e){return{...yo[e]}}function dr(e){j.existsSync(e)&&j.copyFileSync(e,`${e}.bak`)}function Po(e,t){let r=Oe.join(e,".env");dr(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(s){for(let u of n)if(s===u||s.startsWith(`${u}_`))return u;let c=s.split("_");return c.length===1?"Core":c[0]||"Core"}let a=new Map;for(let[s,c]of Object.entries(t)){let u=i(s);a.has(u)||a.set(u,[]);let m=/[\s#"'\\]/.test(c)||c===""?`"${c.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`:c;a.get(u).push(`${s}=${m}`)}for(let[s,c]of a.entries())o.push(`# ${s} Configuration`),o.push(...c),o.push("");j.writeFileSync(r,o.join(`
35
+ `),"utf-8")}function Ro(e,t,r){let o=Oe.join(e,"apps","web",".env.local");dr(o);let n=wo(e),i=Eo(t,r),a=["# GAIA Web App Environment Configuration","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""],s=new Map;for(let c of n){s.has(c.category)||s.set(c.category,[]);let u=i[c.name]??c.value;s.get(c.category).push({name:c.name,value:u})}if(n.length===0){a.push("# Core URLs");for(let[c,u]of Object.entries(i))a.push(`${c}=${u}`);a.push("")}else for(let[c,u]of s.entries()){a.push(`# ${c}`);for(let{name:d,value:m}of u)a.push(`${d}=${m}`);a.push("")}j.writeFileSync(o,a.join(`
36
+ `),"utf-8")}var ko={8e3:"API_HOST_PORT",5432:"POSTGRES_HOST_PORT",6379:"REDIS_HOST_PORT",27017:"MONGO_HOST_PORT",5672:"RABBITMQ_HOST_PORT",8080:"CHROMADB_HOST_PORT",8083:"MONGO_EXPRESS_HOST_PORT",3e3:"WEB_HOST_PORT"};function _o(e,t,r){let o=Oe.join(e,"infra","docker",".env");dr(o);let n=["# Docker Compose environment overrides","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""];for(let[i,a]of Object.entries(t)){let s=Number(i),c=ko[s];c&&n.push(`${c}=${a}`)}if(r==="selfhost"){let i=t[8e3]??8e3;n.push(""),n.push("# Web build args"),n.push(`NEXT_PUBLIC_API_BASE_URL=http://localhost:${i}/api/v1/`)}n.push(""),j.writeFileSync(o,n.join(`
37
+ `),"utf-8")}function me(e){let t={};for(let[r,o]of Object.entries(e)){let n=Number(r),i=ko[n];i&&(t[i]=String(o))}return t}function Do(e){let t=Oe.join(e,"infra","docker","docker-compose.yml");if(!j.existsSync(t))return;let r=j.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:a,containerPort:s}of o){let c=`"${a}:${s}"`,u=`"\${${i}:-${a}}:${s}"`;r.includes(c)&&(r=r.replaceAll(c,u),n=!0)}n&&j.writeFileSync(t,r,"utf-8")}var Io={API_HOST_PORT:8e3,POSTGRES_HOST_PORT:5432,REDIS_HOST_PORT:6379,MONGO_HOST_PORT:27017,RABBITMQ_HOST_PORT:5672,CHROMADB_HOST_PORT:8080,MONGO_EXPRESS_HOST_PORT:8083,WEB_HOST_PORT:3e3};function fe(e){let t=Oe.join(e,"infra","docker",".env"),r={};if(!j.existsSync(t))return r;let o=j.readFileSync(t,"utf-8");for(let n of o.split(`
38
+ `)){let i=n.trim();if(i&&!i.startsWith("#")){let[a,...s]=i.split("=");if(a&&Io[a]){let c=s.join("=").trim().replace(/^["']|["']$/g,""),u=Number(c);!Number.isNaN(u)&&u>0&&u<=65535&&(r[Io[a]]=u)}}}return r}var Ui=e=>new Promise(t=>setTimeout(t,e)),Ao="dev-start.log",pt=".gaia-dev.pid";function Oo(e){let t=W.join(e,".env");return Q.existsSync(t)?["--env-file",".env"]:[]}var qi=60;function Hi(){let e=process.env.GAIA_START_TIMEOUT_MIN?.trim(),t=e?Number(e):Number.NaN,r=Number.isFinite(t)&&t>=0?t:qi;return r===0?void 0:r*60*1e3}function Vi(e,t){let r=["compose","-f","docker-compose.selfhost.yml",...e,"up","-d","--remove-orphans"];return t?.build&&r.push("--build"),t?.pull&&r.push("--pull","always"),r}function mr(e){let t=W.join(e,pt);if(!Q.existsSync(t))return null;try{let r=Number.parseInt(Q.readFileSync(t,"utf-8").trim(),10);return Number.isNaN(r)||r<=0?null:r}catch{return null}}function ut(e){try{return process.kill(e,0),!0}catch(t){return t.code==="EPERM"}}async function qe(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 and starting all services in Docker...":"Starting all services in Docker (selfhost mode)...");let a=W.join(e,"infra/docker"),s=o&&Object.keys(o).length>0?me(o):void 0;await H("docker",Vi(Oo(a),i),a,void 0,n,s,Hi()),r?.("All services started in Docker!")}async function Lo(e,t,r,o){let n=W.join(e,"infra/docker"),i=await Ee(e);t?.("Stopping Docker services...");try{let a=Oo(n),s=i==="selfhost"?["compose","-f","docker-compose.selfhost.yml",...a,"down"]:["compose",...a,"down"];await H("docker",s,n)}catch{}if(i!=="selfhost"){t?.("Stopping GAIA-managed local processes (safe mode)...");let a=W.join(e,pt),s=!1,c=mr(e),u=typeof c=="number";if(c&&ut(c))try{if(process.platform==="win32")await H("taskkill",["/PID",String(c),"/T","/F"],e),s=!0;else{try{process.kill(-c,"SIGTERM"),s=!0}catch{process.kill(c,"SIGTERM"),s=!0}if(await Ui(800),ut(c))try{process.kill(-c,"SIGKILL")}catch{process.kill(c,"SIGKILL")}}}catch{}try{Q.unlinkSync(a)}catch{}if(!s&&o?.forcePorts){t?.("No GAIA PID found. Force-stopping listeners on app ports...");try{let d=r?.[8e3]??8e3,m=r?.[3e3]??3e3;if(process.platform==="win32")for(let f of[d,m])try{await H("powershell",["-Command",`Get-NetTCPConnection -LocalPort ${f} -ErrorAction SilentlyContinue | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force -ErrorAction SilentlyContinue }`],e)}catch{}else for(let f of[d,m])try{await H("sh",["-c",`lsof -ti :${f} -sTCP:LISTEN | xargs kill 2>/dev/null || true`],e)}catch{}}catch{}}else s||t?.(u?"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.")}t?.("All services stopped.")}async function Ee(e){let t=W.join(e,"apps","api",".env");if(!Q.existsSync(t))return null;let r=Q.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")}async function H(e,t,r,o,n,i,a){let{spawn:s}=await import("child_process");return new Promise((c,u)=>{let d=s(e,t,{cwd:r,stdio:["ignore","pipe","pipe"],shell:!0,env:i?{...process.env,...i}:void 0}),m="",f=0,S=!1,v;a&&(v=setTimeout(()=>{S=!0,d.kill("SIGTERM"),u(new Error(`Command timed out after ${Math.round(a/6e4)}m. Check \`docker compose logs\` to debug.`))},a)),d.stdout?.on("data",y=>{let w=y.toString();m+=w,n?.(w),f=Math.min(f+5,95),o?.(f)}),d.stderr?.on("data",y=>{let w=y.toString();m+=w,n?.(w),f=Math.min(f+5,95),o?.(f)}),d.on("close",y=>{v&&clearTimeout(v),!S&&(y===0?(o?.(100),c()):u(new Error(`Command failed with code ${y}: ${m.slice(-500)}`)))}),d.on("error",y=>{v&&clearTimeout(v),!S&&u(y)})})}function U(e){let t=e||process.cwd();for(;t!==W.dirname(t);){if(Q.existsSync(W.join(t,"apps/api/app/config/settings_validator.py")))return t;t=W.dirname(t)}let r=cr();if(r?.repoPath){if(Q.existsSync(W.join(r.repoPath,"apps/api/app/config/settings_validator.py")))return r.repoPath;console.warn(`Warning: Saved repo path "${r.repoPath}" is no longer a valid GAIA installation. Resetting config.`),Ue({repoPath:"",setupComplete:!1})}return null}async function No(e){if(e&&e!=="full")throw new Error(`Invalid developer profile: '${e}'. Use 'gaia dev' or 'gaia dev full'.`);let t=U();if(!t)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let r=await Ee(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=Mo.join(t,pt);try{await _e("mise",[e==="full"?"dev:full":"dev"],t,void 0,n=>{typeof n=="number"&&n>0&&dt.writeFileSync(o,`${n}
39
+ `)},process.platform!=="win32")}finally{try{dt.unlinkSync(o)}catch{}}}import{render as bs}from"ink";import Ts from"react";import{Box as yt,Text as Te}from"ink";import Ss from"react";import{ProgressBar as jo,Select as hr,Spinner as ts}from"@inkjs/ui";import{Box as g,Text as p,useInput as ge}from"ink";import We from"ink-text-input";import{useEffect as Xe,useRef as rs,useState as G}from"react";import{Box as He,Text as mt}from"ink";var x="#00bbff";import{Box as Wi,Text as Xi}from"ink";import{jsx as Bo}from"react/jsx-runtime";var Fo=({status:e,step:t})=>t.toLowerCase()==="welcome"?null:Bo(Wi,{width:"100%",paddingX:1,marginTop:1,children:Bo(Xi,{color:"gray",dimColor:!0,children:e})});import{Box as Yi}from"ink";import Ki from"ink-big-text";import Ji from"ink-gradient";import{jsx as fr}from"react/jsx-runtime";var Le=()=>fr(Yi,{flexDirection:"column",marginTop:1,marginBottom:1,children:fr(Ji,{colors:[x,"#b0eaff",x],children:fr(Ki,{text:"GAIA",font:"3d"})})});import{jsx as be,jsxs as Ve}from"react/jsx-runtime";var Qi=["Welcome","Prerequisites","Setup Mode","Repository Setup","Environment Setup","Install Tools","Project Setup","Finished"],$o=["Detect Repo","Prerequisites","Environment Setup","Project Setup","Finished"],zi={Welcome:"Welcome",Prerequisites:"Prereqs","Setup Mode":"Mode","Repository Setup":"Repo","Environment Setup":"Env","Install Tools":"Tools","Project Setup":"Setup","Detect Repo":"Detect",Finished:"Done"},Zi=({currentStep:e,steps:t})=>{let r=t.indexOf(e);return be(He,{marginBottom:1,flexWrap:"nowrap",children:t.map((o,n)=>{let i=n<r,a=n===r,s=zi[o]??o;return Ve(He,{flexShrink:0,children:[n>0&&Ve(mt,{color:"gray",dimColor:!0,children:[" ","\xB7"," "]}),i&&Ve(mt,{color:"green",children:["\u2713 ",s]}),a&&be(mt,{color:x,bold:!0,children:s}),!i&&!a&&be(mt,{color:"gray",dimColor:!0,children:s})]},o)})})},ft=({children:e,status:t,step:r,steps:o=Qi})=>Ve(He,{flexDirection:"column",height:"100%",width:"100%",children:[Ve(He,{flexGrow:1,flexDirection:"column",children:[be(Le,{}),be(Zi,{currentStep:r,steps:o}),be(He,{flexDirection:"column",flexGrow:1,children:e})]}),be(Fo,{status:t,step:r})]});import{Spinner as Go}from"@inkjs/ui";import{Box as q,Text as M,useInput as es}from"ink";import{jsx as R,jsxs as V}from"react/jsx-runtime";var gt=({checks:e})=>V(q,{flexDirection:"column",borderStyle:"round",paddingX:1,borderColor:x,children:[R(M,{bold:!0,children:"System Checks"}),V(q,{flexDirection:"column",marginTop:1,children:[R(gr,{label:"Git",status:e.git}),R(gr,{label:"Docker",status:e.docker}),e.mise&&R(gr,{label:"Mise",status:e.mise})]})]}),ht=({status:e})=>V(q,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:x,children:[R(M,{bold:!0,children:"Environment Setup"}),R(q,{marginTop:1,children:R(Go,{label:e||"Configuring environment..."})})]}),vt=({message:e})=>V(q,{flexDirection:"column",borderStyle:"single",borderColor:"red",padding:1,marginTop:2,children:[V(M,{color:"red",children:["Error: ",e]}),R(q,{marginTop:1,children:V(M,{dimColor:!0,children:[R(M,{bold:!0,children:"Enter"})," to exit"]})})]}),gr=({label:e,status:t})=>V(q,{children:[R(q,{marginRight:1,children:t==="pending"?R(Go,{type:"dots"}):t==="success"?R(M,{color:"green",children:"\u2714"}):t==="error"?R(M,{color:"red",children:"\u2716"}):R(M,{color:"yellow",children:"\u26A0"})}),R(M,{children:e})]}),St=({portResults:e,onAccept:t,onAbort:r})=>{es((n,i)=>{i.return?t():i.escape&&r()});let o=e.filter(n=>!n.available);return V(q,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:"yellow",children:[R(q,{marginBottom:1,children:R(M,{bold:!0,color:"yellow",children:"Port Conflicts Detected"})}),e.map(n=>V(q,{children:[V(M,{color:n.available?"green":n.alternative?"yellow":"red",children:[n.available?"\u2714":n.alternative?"\u26A0":"\u2716"," "]}),V(M,{children:[n.service," (:",n.port,")"]}),!n.available&&V(M,{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)&&R(q,{marginTop:1,children:R(M,{color:"red",children:"Some ports have no available alternative. Free them and retry."})}),!o.some(n=>!n.alternative)&&o.some(n=>n.alternative)&&R(q,{marginTop:1,children:R(M,{color:"gray",children:"Alternative ports will be used for conflicting services."})}),R(q,{marginTop:1,children:V(M,{dimColor:!0,children:[R(M,{bold:!0,children:"Enter"})," continue \xB7 ",R(M,{bold:!0,children:"ESC"})," abort"]})})]})};import{jsx as l,jsxs as h}from"react/jsx-runtime";var os=({onConfirm:e})=>(ge((t,r)=>{r.return&&e()}),h(g,{flexDirection:"column",paddingX:2,borderStyle:"round",borderColor:x,children:[l(p,{bold:!0,children:"Welcome to GAIA Setup"}),h(g,{flexDirection:"column",marginTop:1,marginBottom:1,children:[l(p,{children:"This wizard will guide you through the setup process:"}),l(p,{children:" 1. Check prerequisites and choose setup mode"}),l(p,{children:" 2. Clone repository"}),l(p,{children:" 3. Configure environment variables"}),l(p,{children:" 4. Install tools and dependencies"})]}),l(p,{dimColor:!0,children:"~5-15 min depending on network speed"}),l(g,{marginTop:1,children:h(p,{color:x,children:[l(p,{bold:!0,children:"Enter"})," to start"]})})]})),ns=({defaultValue:e,onSubmit:t})=>{let[r,o]=G(e);return h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:x,children:[l(p,{children:"Clone repository to:"}),l(p,{color:"gray",dimColor:!0,children:"Press Enter for default, or type a custom path"}),h(g,{marginTop:1,children:[l(p,{color:x,children:"\u2192 "}),l(We,{value:r,onChange:o,onSubmit:t})]})]})},is=({repoPath:e,onAction:t})=>h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:"yellow",children:[l(g,{marginBottom:1,children:l(p,{bold:!0,color:"yellow",children:"Existing Installation Found"})}),h(p,{children:["Found a GAIA installation at"," ",l(p,{color:"cyan",bold:!0,children:e})]}),l(g,{marginTop:1,children:l(p,{color:"gray",children:"What would you like to do?"})}),l(g,{marginTop:1,children:l(hr,{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)})})]}),ss=({setupMode:e,portOverrides:t,onConfirm:r})=>{ge((i,a)=>{a.return&&r()});let o=t?.[3e3]??3e3,n=t?.[8e3]??8e3;return e==="selfhost"?h(g,{flexDirection:"column",marginTop:2,borderStyle:"round",borderColor:"green",padding:1,children:[l(p,{bold:!0,color:"green",children:"GAIA is Running!"}),l(g,{marginTop:1,children:l(p,{color:"green",children:"\u2713 All services started"})}),h(g,{marginTop:1,flexDirection:"column",children:[h(p,{children:["Web:"," ",h(p,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),h(p,{children:["API:"," ",h(p,{color:"cyan",bold:!0,children:["http://localhost:",n]})]})]}),l(g,{marginTop:1,children:l(p,{color:"gray",children:"gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup"})}),l(g,{marginTop:1,children:h(p,{dimColor:!0,children:[l(p,{bold:!0,children:"Enter"})," to exit"]})})]}):h(g,{flexDirection:"column",marginTop:2,borderStyle:"round",borderColor:x,padding:1,children:[l(p,{color:x,bold:!0,children:"You're all set!"}),h(g,{marginTop:1,children:[l(p,{bold:!0,children:"Run: "}),l(p,{color:"cyan",children:"$ gaia dev"})]}),h(g,{marginTop:1,flexDirection:"column",children:[h(p,{children:["Web:"," ",h(p,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),h(p,{children:["API:"," ",h(p,{color:"cyan",bold:!0,children:["http://localhost:",n]})]})]}),l(g,{marginTop:1,children:l(p,{color:"gray",children:"gaia dev full \xB7 gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup"})}),l(g,{marginTop:1,children:h(p,{dimColor:!0,children:[l(p,{bold:!0,children:"Enter"})," to exit"]})})]})},as=8,cs=({logs:e,height:t=as})=>{let[r,o]=G(0),n=rs(e.length);Xe(()=>{e.length!==n.current&&(n.current=e.length,o(0))},[e.length]),ge((m,f)=>{f.upArrow?o(S=>Math.min(S+1,Math.max(0,e.length-t))):f.downArrow&&o(S=>Math.max(0,S-1))});let i=e.length,a=Math.max(0,i-t-r),s=Math.max(0,i-r),c=e.slice(a,s),u=a,d=r;return h(g,{flexDirection:"column",marginTop:1,marginLeft:1,children:[u>0&&h(p,{color:"gray",dimColor:!0,children:["\u2191 ",u," more line",u!==1?"s":""]}),l(g,{flexDirection:"column",height:t,overflow:"hidden",children:c.map((m,f)=>l(p,{color:"gray",wrap:"truncate",children:m},`${a}-${f}`))}),d>0?h(p,{color:"gray",dimColor:!0,children:["\u2193 ",d," more line",d!==1?"s":""]}):l(p,{color:"gray",dimColor:!0,children:"\u2191\u2193 scroll"})]})},vr=({phase:e,progress:t,isComplete:r,logs:o,title:n})=>h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:x,children:[l(g,{marginBottom:1,children:l(p,{bold:!0,color:x,children:n||"Installing Dependencies"})}),h(g,{flexDirection:"column",gap:1,children:[l(g,{children:r?h(p,{color:"green",children:["\u2713 ",e]}):l(ts,{label:e||"Preparing..."})}),!r&&t>0&&l(g,{width:50,children:l(jo,{value:t})}),!r&&o&&o.length>0&&l(cs,{logs:o}),!r&&l(g,{marginTop:1,children:l(p,{color:"gray",dimColor:!0,children:"This may take a few minutes..."})})]})]}),Sr=({onSelect:e})=>h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:x,children:[l(p,{bold:!0,children:"Setup Mode"}),l(g,{marginTop:1,children:l(p,{color:"gray",children:"How do you want to run GAIA?"})}),l(g,{marginTop:1,children:l(hr,{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)})})]}),yr=({onSelect:e})=>h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:x,children:[l(p,{bold:!0,children:"Environment Variables Setup"}),l(g,{marginTop:1,children:l(p,{color:"gray",children:"Choose how you want to configure environment variables:"})}),l(g,{marginTop:1,children:l(hr,{options:[{label:"Manual Setup (Recommended)",value:"manual"},{label:"Infisical (Advanced)",value:"infisical"}],onChange:r=>e(r)})}),h(g,{marginTop:1,flexDirection:"column",children:[l(p,{color:"gray",dimColor:!0,children:"Manual Setup: Configure variables interactively (recommended for most users)"}),l(p,{color:"gray",dimColor:!0,children:"Infisical: All secrets managed in Infisical dashboard (requires pre-configuration)"})]})]}),xr=({onSubmit:e})=>{let[t,r]=G({INFISICAL_PROJECT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET:""}),[o,n]=G(0),[i,a]=G(null),s=[{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"}];ge((u,d)=>{if(d.tab||d.downArrow)n(m=>m<s.length-1?m+1:m);else if(d.upArrow)n(m=>m>0?m-1:m);else if(d.return){if(o<s.length-1){n(f=>f+1);return}let m=s.filter(f=>!t[f.key].trim());if(m.length>0){a(`Required: ${m.map(S=>S.key).join(", ")}`);let f=s.findIndex(S=>!t[S.key].trim());f>=0&&n(f);return}e(t)}});let c=s[o];return h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:x,children:[l(g,{marginBottom:1,children:l(p,{bold:!0,color:x,children:"Infisical Configuration"})}),l(g,{marginBottom:1,children:l(p,{color:"gray",children:"All secrets managed in your Infisical project. Only credentials stored locally."})}),h(g,{marginBottom:1,flexDirection:"column",children:[l(p,{color:"gray",children:"Configure your Infisical credentials."}),h(p,{color:"gray",dimColor:!0,children:["Visit"," ",l(p,{color:"cyan",underline:!0,children:"app.infisical.com"})," ","to get these values."]})]}),s.map((u,d)=>{let m=u.key.includes("SECRET")||u.key.includes("TOKEN");return h(g,{flexDirection:"column",marginBottom:1,children:[l(g,{children:h(p,{color:d===o?x:"white",children:[d===o?"\u25B8 ":" ",u.key,":"]})}),l(g,{marginLeft:2,children:l(p,{color:"gray",dimColor:!0,children:u.description})}),d===o?l(g,{marginLeft:2,children:l(We,{value:t[u.key],onChange:f=>{r(S=>({...S,[u.key]:f})),a(null)},placeholder:"Enter value...",mask:m?"*":void 0})}):l(g,{marginLeft:2,children:l(p,{color:t[u.key]?"green":"gray",children:t[u.key]?m?`\u2713 ${"*".repeat(8)}`:`\u2713 ${t[u.key]}`:"(not set)"})})]},u.key)}),i&&l(g,{marginTop:1,children:l(p,{color:"red",children:i})}),l(g,{marginTop:1,children:h(p,{dimColor:!0,children:[l(p,{bold:!0,children:"Enter"})," confirm \xB7 ",l(p,{bold:!0,children:"\u2191\u2193"})," navigate"]})})]})},wr=({category:e,currentIndex:t,totalGroups:r,onSubmit:o})=>{let[n,i]=G(()=>{let f={};for(let S of e.variables)f[S.name]=S.defaultValue||"";return f}),[a,s]=G(0),[c,u]=G(null);Xe(()=>{let f={};for(let S of e.variables)f[S.name]=S.defaultValue||"";i(f),s(0),u(null)},[e.name]),ge((f,S)=>{if(S.tab||S.downArrow)s(v=>v<e.variables.length-1?v+1:v);else if(S.upArrow)s(v=>v>0?v-1:v);else if(S.escape){let v=e.variables.filter(y=>y.required&&!n[y.name]?.trim());if(v.length>0){u(`Required fields cannot be skipped: ${v.map(y=>y.name).join(", ")}`);return}o(n)}});let d=()=>{if(a<e.variables.length-1)s(a+1);else{let f=e.variables.filter(S=>S.required&&!n[S.name]?.trim());if(f.length>0){u(`Required fields are missing: ${f.map(S=>S.name).join(", ")}`);return}u(null),o(n)}},m=e.variables.some(f=>f.required);return h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:c?"red":x,children:[h(g,{justifyContent:"space-between",children:[h(p,{bold:!0,children:["Configure ",e.name]}),h(p,{color:"gray",children:["Group ",t+1," / ",r]})]}),l(g,{marginTop:1,children:l(p,{color:"gray",children:e.description})}),l(g,{marginTop:1,flexDirection:"column",children:e.variables.map((f,S)=>{let v=S===a,y=!!f.defaultValue;return h(g,{flexDirection:"column",marginBottom:1,children:[h(g,{children:[h(p,{color:v?x:"gray",bold:v,children:[v?"\u279C ":" ",f.name]}),f.required&&h(p,{color:"red",bold:!0,children:[" ","*"]}),y&&!v&&h(p,{color:"gray",dimColor:!0,children:[" ","(default: ",f.defaultValue,")"]})]}),v&&l(g,{marginLeft:2,children:l(We,{value:n[f.name]||"",onChange:w=>{i(E=>({...E,[f.name]:w})),c&&u(null)},onSubmit:d,placeholder:y?`Default: ${f.defaultValue}`:f.required?"Enter a value (required)":"Press Enter to skip"})})]},f.name)})}),c&&l(g,{marginTop:1,children:h(p,{color:"red",bold:!0,children:["\u26A0 ",c]})}),l(g,{marginTop:1,children:h(p,{dimColor:!0,children:[l(p,{bold:!0,children:"Enter"})," next \xB7 ",l(p,{bold:!0,children:"\u2191\u2193"})," navigate",!m&&h(p,{children:[" ","\xB7 ",l(p,{bold:!0,children:"ESC"})," skip"]})]})})]})},Er=({alternatives:e,onSubmit:t})=>{let[r,o]=G(new Set),[n,i]=G({}),[a,s]=G(0),[c,u]=G(null);Xe(()=>{let w={};for(let E of e)for(let I of E.variables)w[I.name]=I.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 E=e[w];if(E)for(let I=0;I<E.variables.length;I++)d.push({type:"field",categoryIndex:w,fieldIndex:I})}d.push({type:"submit"});let m=d[a],f=m?.type==="field",S=m?.type==="submit";ge((w,E)=>{let I=Math.min(a,d.length-1);if(I!==a){s(I);return}if(f)E.upArrow?s(P=>Math.max(0,P-1)):(E.downArrow||E.tab)&&s(P=>Math.min(d.length-1,P+1));else if(S)E.upArrow?s(P=>Math.max(0,P-1)):(E.return||w===" ")&&y();else if(E.upArrow)s(P=>Math.max(0,P-1));else if(E.downArrow||E.tab)s(P=>Math.min(d.length-1,P+1));else if((E.return||w===" ")&&m?.type==="provider"){let P=m.categoryIndex;o(oe=>{let D=new Set(oe);return D.has(P)?D.delete(P):D.add(P),D}),c&&u(null)}});let v=()=>{c&&u(null),s(w=>Math.min(d.length-1,w+1))},y=()=>{let w=[],E={};for(let I of r){let P=e[I];if(!P)continue;if(P.variables.some(D=>n[D.name]?.trim())){w.push(P.name);for(let D of P.variables){let Je=n[D.name];Je&&(E[D.name]=Je)}}}if(w.length===0){r.size===0?u("Enable at least one provider (press Space or Enter)"):u("Enter a value for at least one field");return}t(w,E)};return h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:c?"red":x,children:[h(g,{justifyContent:"space-between",children:[l(p,{bold:!0,children:"Configure AI Provider"}),l(p,{color:"yellow",children:"* At least one required"})]}),l(g,{marginTop:1,children:l(p,{color:"gray",children:"Enable and configure at least one AI provider below:"})}),l(g,{marginTop:1,flexDirection:"column",children:e.map((w,E)=>{let I=r.has(E),P=d.findIndex(D=>D.type==="provider"&&D.categoryIndex===E),oe=a===P;return h(g,{flexDirection:"column",marginBottom:1,children:[h(g,{children:[l(p,{color:oe?x:void 0,bold:oe,children:oe?"\u279C ":" "}),l(p,{color:I?"green":"gray",children:I?"[\u2714]":"[ ]"}),h(p,{color:I?x:"gray",bold:I,children:[" ",w.name]}),w.description&&h(p,{color:"gray",dimColor:!0,children:[" ","- ",w.description]})]}),oe&&w.docsUrl&&h(g,{marginLeft:6,children:[l(p,{color:"yellow",children:"\u{1F4D6} "}),l(p,{color:"blue",underline:!0,children:w.docsUrl})]}),I&&l(g,{marginLeft:4,flexDirection:"column",marginTop:1,children:w.variables.map((D,Je)=>{let Pn=d.findIndex(Me=>Me.type==="field"&&Me.categoryIndex===E&&Me.fieldIndex===Je),Ce=a===Pn,Dr=!!D.defaultValue,_t=n[D.name]||"";return h(g,{flexDirection:"column",marginBottom:1,children:[h(g,{children:[h(p,{color:Ce?x:"gray",bold:Ce,children:[Ce?" \u279C ":" ",D.name]}),!Ce&&_t&&l(p,{color:"green",children:" \u2713"}),!Ce&&!_t&&Dr&&h(p,{color:"gray",dimColor:!0,children:[" ","(default: ",D.defaultValue,")"]})]}),Ce&&l(g,{marginLeft:4,children:l(We,{value:_t,onChange:Me=>{i(Rn=>({...Rn,[D.name]:Me})),c&&u(null)},onSubmit:v,placeholder:Dr?`Default: ${D.defaultValue}`:"Enter value..."})})]},D.name)})})]},w.name)})}),c&&l(g,{marginTop:1,children:h(p,{color:"red",bold:!0,children:["\u26A0 ",c]})}),h(g,{marginTop:1,children:[l(p,{color:S?x:void 0,bold:S,children:S?"\u279C ":" "}),l(g,{borderStyle:"round",borderColor:S?x:"gray",paddingX:2,children:l(p,{color:S?x:"gray",bold:S,children:"Continue \u2192"})})]}),l(g,{marginTop:1,children:l(p,{color:"gray",dimColor:!0,children:"\u2191/\u2193 navigate \u2022 Space/Enter toggle/select \u2022 Tab skip field"})})]})},br=({currentVar:e,currentIndex:t,totalCount:r,onSubmit:o,onSkip:n})=>{let[i,a]=G(e.defaultValue||""),[s,c]=G(null);Xe(()=>{a(e.defaultValue||""),c(null)},[e.name]),ge((m,f)=>{if(f.escape){if(e.required&&!i.trim()){c("This field is required and cannot be skipped");return}n()}});let u=m=>{if(e.required&&!m.trim()){c("This field is required");return}c(null),o(m)},d=!!e.defaultValue;return h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:s?"red":x,children:[h(g,{justifyContent:"space-between",children:[h(g,{children:[l(p,{color:x,bold:!0,children:e.name}),e.required?l(p,{color:"red",children:" *"}):h(p,{color:"gray",dimColor:!0,children:[" ","optional"]})]}),h(p,{color:"gray",children:[t+1,"/",r]})]}),l(g,{marginLeft:1,children:l(p,{color:"gray",children:e.description})}),h(g,{marginTop:1,children:[l(p,{color:x,children:"\u2192 "}),l(We,{value:i,onChange:m=>{a(m),s&&c(null)},onSubmit:u,placeholder:d?`Default: ${e.defaultValue}`:e.required?"required":"skip with Enter"})]}),s&&l(g,{marginTop:1,children:l(p,{color:"red",children:s})}),l(g,{marginTop:1,children:h(p,{dimColor:!0,children:[l(p,{bold:!0,children:"Enter"})," confirm",!e.required&&h(p,{children:[" ","\xB7 ",l(p,{bold:!0,children:"ESC"})," skip"]})]})})]})},Uo=({store:e})=>{let[t,r]=G(e.currentState);return Xe(()=>{let o=()=>r({...e.currentState});return e.on("change",o),()=>{e.off("change",o)}},[e]),ge((o,n)=>{(n.return||n.escape)&&t.error&&e.submitInput("exit")}),h(ft,{status:t.status,step:t.step,children:[t.step==="Welcome"&&t.inputRequest?.id==="welcome"&&l(os,{onConfirm:()=>e.submitInput(!0)}),t.step==="Prerequisites"&&t.data.checks&&l(gt,{checks:t.data.checks}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&l(St,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="repo_path"&&l(ns,{defaultValue:t.inputRequest.meta.default,onSubmit:o=>e.submitInput(o)}),t.inputRequest?.id==="existing_repo"&&t.data.existingRepoPath&&l(is,{repoPath:t.data.existingRepoPath,onAction:o=>e.submitInput(o)}),t.step==="Repository Setup"&&!t.inputRequest&&h(g,{flexDirection:"column",borderStyle:"round",padding:1,borderColor:x,children:[l(p,{bold:!0,children:"Cloning Repository"}),h(g,{marginTop:1,flexDirection:"column",children:[l(jo,{value:t.data.repoProgress||0}),t.data.repoPhase&&l(g,{marginTop:1,children:l(p,{color:"gray",children:t.data.repoPhase})})]})]}),t.inputRequest?.id==="setup_mode"&&l(Sr,{onSelect:o=>e.submitInput(o)}),t.inputRequest?.id==="env_method"&&l(yr,{onSelect:o=>e.submitInput(o)}),t.inputRequest?.id==="env_infisical"&&l(xr,{onSubmit:o=>e.submitInput(o)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&l(br,{categories:t.data.envCategories||[],currentVar:t.data.currentEnvVar,currentIndex:t.data.envVarIndex||0,totalCount:t.data.envVarTotal||0,onSubmit:o=>e.submitInput(o),onSkip:()=>e.submitInput("")}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_group"&&t.data.currentEnvGroup&&l(wr,{category:t.data.currentEnvGroup,currentIndex:t.data.envGroupIndex||0,totalGroups:t.data.envGroupTotal||0,onSubmit:o=>e.submitInput(o)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_alternatives"&&t.data.alternativeGroups&&l(Er,{alternatives:t.data.alternativeGroups,onSubmit:(o,n)=>e.submitInput({selectedGroups:o,values:n})}),t.step==="Environment Setup"&&!t.inputRequest&&l(ht,{status:t.status}),t.step==="Finished"&&l(ss,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,onConfirm:()=>e.submitInput("exit")}),(t.step==="Install Tools"||t.step==="Project Setup")&&l(vr,{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&&l(vt,{message:t.error.message})]})};import{Spinner as ls}from"@inkjs/ui";import{Box as N,Text as T,useInput as qo}from"ink";import{useEffect as Ho,useRef as us,useState as Vo}from"react";import{jsx as O,jsxs as b}from"react/jsx-runtime";var Tr=8,ps=({logs:e})=>{let[t,r]=Vo(0),o=us(e.length);Ho(()=>{e.length!==o.current&&(o.current=e.length,r(0))},[e.length]),qo((d,m)=>{m.upArrow?r(f=>Math.min(f+1,Math.max(0,e.length-Tr))):m.downArrow&&r(f=>Math.max(0,f-1))});let n=e.length,i=Math.max(0,n-Tr-t),a=Math.max(0,n-t),s=e.slice(i,a),c=i,u=t;return b(N,{flexDirection:"column",marginTop:1,marginLeft:1,children:[c>0&&b(T,{color:"gray",dimColor:!0,children:["\u2191 ",c," more line",c!==1?"s":""]}),O(N,{flexDirection:"column",height:Tr,overflow:"hidden",children:s.map((d,m)=>O(T,{color:"gray",wrap:"truncate",children:d},i+m))}),u>0?b(T,{color:"gray",dimColor:!0,children:["\u2193 ",u," more line",u!==1?"s":""]}):O(T,{color:"gray",dimColor:!0,children:"\u2191\u2193 scroll"})]})},Wo=({store:e})=>{let[t,r]=Vo(e.currentState);return Ho(()=>{let o=()=>r({...e.currentState});return e.on("change",o),()=>{e.off("change",o)}},[e]),qo((o,n)=>{(n.return||n.escape)&&(t.data.started||t.data.stopped||t.error)&&e.submitInput("exit")}),b(N,{flexDirection:"column",width:"100%",children:[O(Le,{}),(t.step==="Starting"||t.step==="Stopping")&&b(N,{flexDirection:"column",marginTop:1,paddingX:2,borderStyle:"round",borderColor:x,children:[O(ls,{label:t.status||"Working..."}),t.data.repoPath&&O(N,{marginTop:1,children:b(T,{color:"gray",children:["Repository: ",t.data.repoPath]})}),t.data.setupMode&&O(N,{children:b(T,{color:"gray",children:["Mode: ",t.data.setupMode]})}),t.data.dockerLogs&&t.data.dockerLogs.length>0&&O(ps,{logs:t.data.dockerLogs})]}),t.step==="Running"&&t.data.started&&b(N,{flexDirection:"column",marginTop:1,paddingX:2,paddingY:1,borderStyle:"round",borderColor:"green",children:[b(T,{color:"green",bold:!0,children:["\u2713"," GAIA is running!"]}),t.data.setupMode!=="developer"&&b(N,{marginTop:1,flexDirection:"column",children:[b(T,{children:["Web:"," ",b(T,{color:"cyan",bold:!0,children:["http://localhost:",t.data.webPort||3e3]})]}),b(T,{children:["API:"," ",b(T,{color:"cyan",bold:!0,children:["http://localhost:",t.data.apiPort||8e3]})]})]}),t.data.setupMode==="developer"&&b(N,{marginTop:1,flexDirection:"column",children:[b(N,{flexDirection:"column",children:[b(T,{children:["Web:"," ",b(T,{color:"cyan",bold:!0,children:["http://localhost:",t.data.webPort||3e3]})]}),b(T,{children:["API:"," ",b(T,{color:"cyan",bold:!0,children:["http://localhost:",t.data.apiPort||8e3]})]})]}),b(N,{marginTop:1,flexDirection:"column",children:[O(T,{color:"gray",children:"Use gaia dev / gaia dev full for foreground Nx TUI."}),b(T,{color:"gray",children:["Run ",O(T,{color:x,children:"gaia logs"})," to stream logs."]}),b(T,{color:"gray",children:["Run ",O(T,{color:x,children:"gaia stop"})," to shut down."]})]})]}),O(N,{marginTop:1,children:b(T,{dimColor:!0,children:[O(T,{bold:!0,children:"Enter"})," to exit"]})})]}),t.step==="Stopped"&&t.data.stopped&&b(N,{flexDirection:"column",marginTop:1,paddingX:2,paddingY:1,borderStyle:"round",borderColor:x,children:[b(T,{color:x,bold:!0,children:["\u2713"," ",t.status||"All GAIA services stopped."]}),t.data.stopMode==="force-ports"&&O(N,{marginTop:1,children:O(T,{color:"yellow",children:"Force-port cleanup was enabled and may have stopped non-GAIA listeners on app ports."})}),O(N,{marginTop:1,children:b(T,{dimColor:!0,children:[O(T,{bold:!0,children:"Enter"})," to exit"]})})]}),t.error&&b(N,{borderStyle:"single",borderColor:"red",padding:1,marginTop:2,children:[b(T,{color:"red",children:["Error: ",t.error.message]}),O(N,{marginTop:1,children:b(T,{dimColor:!0,children:[O(T,{bold:!0,children:"Enter"})," to exit"]})})]})]})};import{Spinner as ds}from"@inkjs/ui";import{Box as he,Text as X,useInput as Xo}from"ink";import{useEffect as ms,useState as fs}from"react";import{jsx as k,jsxs as z}from"react/jsx-runtime";var Yo=({store:e})=>{let[t,r]=fs(e.currentState);return ms(()=>{let o=()=>r({...e.currentState});return e.on("change",o),()=>{e.off("change",o)}},[e]),Xo((o,n)=>{(n.return||n.escape)&&t.error&&e.submitInput("exit")}),z(ft,{status:t.status,step:t.step,steps:$o,children:[t.step==="Detect Repo"&&z(he,{flexDirection:"column",paddingX:2,borderStyle:"round",borderColor:x,children:[k(X,{bold:!0,children:"Detecting GAIA Repository"}),k(he,{marginTop:1,children:k(ds,{label:"Searching for repository..."})}),t.data.repoPath&&k(he,{marginTop:1,children:z(X,{color:"green",children:["Found: ",t.data.repoPath]})})]}),t.step==="Prerequisites"&&t.data.checks&&k(gt,{checks:t.data.checks}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&k(St,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="setup_mode"&&k(Sr,{onSelect:o=>e.submitInput(o)}),t.inputRequest?.id==="env_method"&&k(yr,{onSelect:o=>e.submitInput(o)}),t.inputRequest?.id==="env_infisical"&&k(xr,{onSubmit:o=>e.submitInput(o)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&k(br,{categories:t.data.envCategories||[],currentVar:t.data.currentEnvVar,currentIndex:t.data.envVarIndex||0,totalCount:t.data.envVarTotal||0,onSubmit:o=>e.submitInput(o),onSkip:()=>e.submitInput("")}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_group"&&t.data.currentEnvGroup&&k(wr,{category:t.data.currentEnvGroup,currentIndex:t.data.envGroupIndex||0,totalGroups:t.data.envGroupTotal||0,onSubmit:o=>e.submitInput(o)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_alternatives"&&t.data.alternativeGroups&&k(Er,{alternatives:t.data.alternativeGroups,onSubmit:(o,n)=>e.submitInput({selectedGroups:o,values:n})}),t.step==="Environment Setup"&&!t.inputRequest&&k(ht,{status:t.status}),t.step==="Project Setup"&&k(vr,{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(gs,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,onConfirm:()=>e.submitInput("exit")}),t.error&&k(vt,{message:t.error.message})]})},gs=({setupMode:e,portOverrides:t,onConfirm:r})=>{Xo((a,s)=>{s.return&&r()});let o=t?.[3e3]??3e3,n=t?.[8e3]??8e3,i=e==="selfhost";return z(he,{flexDirection:"column",marginTop:2,borderStyle:"round",borderColor:x,padding:1,children:[k(X,{color:x,bold:!0,children:"Setup Complete!"}),z(he,{marginTop:1,children:[k(X,{bold:!0,children:"Run: "}),k(X,{color:"cyan",children:i?"$ gaia start":"$ gaia dev"})]}),z(he,{marginTop:1,flexDirection:"column",children:[z(X,{children:["Web:"," ",z(X,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),z(X,{children:["API:"," ",z(X,{color:"cyan",bold:!0,children:["http://localhost:",n]})]})]}),k(he,{marginTop:1,children:k(X,{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(he,{marginTop:1,children:z(X,{dimColor:!0,children:[k(X,{bold:!0,children:"Enter"})," to exit"]})})]})};import{Spinner as hs}from"@inkjs/ui";import{Box as L,Text as _,useInput as vs}from"ink";import{useEffect as Ko,useState as Cr}from"react";import{jsx as C,jsxs as F}from"react/jsx-runtime";var Jo=({store:e})=>{let[t,r]=Cr(e.currentState),[o,n]=Cr(!1),[i,a]=Cr(null);return Ko(()=>{let s=()=>r({...e.currentState});return e.on("change",s),()=>{e.off("change",s)}},[e]),Ko(()=>{n(!1),a(new Date().toLocaleTimeString())},[t.data.services]),vs((s,c)=>{(c.return||c.escape)&&t.step==="Results"&&e.submitInput("exit"),s==="r"&&t.step==="Results"&&t.data.refreshable&&!o&&(n(!0),e.submitInput("refresh"))}),F(L,{flexDirection:"column",width:"100%",children:[C(Le,{}),t.step==="Checking"&&C(L,{marginTop:1,children:C(hs,{label:t.data.services?"Refreshing service health...":"Checking service health..."})}),t.step==="Results"&&t.data.services&&F(L,{flexDirection:"column",children:[F(L,{flexDirection:"column",borderStyle:"round",borderColor:x,paddingX:2,paddingY:1,children:[F(L,{justifyContent:"space-between",children:[C(_,{bold:!0,color:x,children:"GAIA Service Status"}),i&&F(_,{color:"gray",dimColor:!0,children:["checked ",i," \xB7 ",C(_,{bold:!0,children:"r"})," refresh"]})]}),F(L,{marginTop:1,flexDirection:"column",children:[F(L,{children:[C(L,{width:22,children:C(_,{bold:!0,children:"Service"})}),C(L,{width:10,children:C(_,{bold:!0,children:"Status"})}),C(L,{width:10,children:C(_,{bold:!0,children:"Latency"})})]}),C(_,{color:"gray",children:"\u2500".repeat(42)}),[...t.data.services].sort((s,c)=>s.status==="down"&&c.status!=="down"?-1:s.status!=="down"&&c.status==="down"?1:s.name.localeCompare(c.name)).map(s=>F(L,{children:[C(L,{width:22,children:F(_,{children:[s.name," (:",s.port,")"]})}),C(L,{width:10,children:C(_,{color:s.status==="up"?"green":"red",bold:!0,children:s.status==="up"?"\u2713 UP":"\u2717 DOWN"})}),C(L,{width:10,children:C(_,{color:"gray",children:s.latency?`${s.latency}ms`:"--"})})]},s.name))]})]}),t.data.docker&&F(L,{flexDirection:"column",borderStyle:"round",borderColor:"gray",paddingX:2,paddingY:1,marginTop:1,children:[C(_,{bold:!0,children:"Docker Containers"}),F(_,{color:"gray",children:["Docker:"," ",t.data.docker.running?C(_,{color:"green",children:"Running"}):C(_,{color:"red",children:"Not running"})]}),t.data.docker.containers?.length>0&&C(L,{marginTop:1,flexDirection:"column",children:t.data.docker.containers.map(s=>F(L,{children:[F(_,{color:s.status==="running"?"green":"red",children:[s.status==="running"?"\u2713":"\u2717"," "]}),C(_,{children:s.name}),s.health&&F(_,{color:"gray",children:[" (",s.health,")"]})]},s.name))})]}),C(L,{marginTop:1,children:F(_,{dimColor:!0,children:[C(_,{bold:!0,children:"Enter"})," exit \xB7 ",C(_,{bold:!0,children:"r"})," refresh"]})})]}),t.error&&C(L,{borderStyle:"single",borderColor:"red",padding:1,marginTop:2,children:F(_,{color:"red",children:["Error: ",t.error.message]})})]})};import{jsx as Y,jsxs as Ye}from"react/jsx-runtime";var ys=["init","setup","status","start","stop"],Ir=class extends Ss.Component{constructor(t){super(t),this.state={error:null}}static getDerivedStateFromError(t){return{error:t}}render(){return this.state.error?Ye(yt,{flexDirection:"column",padding:1,children:[Y(Te,{color:"red",bold:!0,children:"An unexpected error occurred:"}),Y(Te,{color:"red",children:this.state.error.message}),this.state.error.stack&&Y(yt,{marginTop:1,children:Y(Te,{color:"gray",dimColor:!0,children:this.state.error.stack})})]}):this.props.children}},xs=({store:e,command:t})=>{switch(t){case"init":return Y(Uo,{store:e});case"setup":return Y(Yo,{store:e});case"status":return Y(Jo,{store:e});case"start":case"stop":return Y(Wo,{store:e,command:t});default:return Ye(yt,{flexDirection:"column",padding:1,children:[Ye(Te,{color:"red",children:["Unknown command: ",t]}),Ye(yt,{marginTop:1,flexDirection:"column",children:[Y(Te,{bold:!0,children:"Available commands:"}),ys.map(r=>Ye(Te,{children:[" ",Y(Te,{color:"cyan",children:r})]},r))]})]})}},Qo=({store:e,command:t})=>Y(Ir,{children:Y(xs,{store:e,command:t})});import{EventEmitter as ws}from"events";var Es=150,Pr=class extends ws{state={step:"init",status:"",error:null,data:{},inputRequest:null};inputResolver=null;emitTimer=null;emitPending=!1;autoResolveInputs=new Map;setAutoResolve(t,r="exit"){this.autoResolveInputs.set(t,r)}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))},Es))}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()}waitForInput(t,r,o){return this.autoResolveInputs.has(t)?(this.state.inputRequest=null,this.emitNow(),Promise.resolve(this.autoResolveInputs.get(t))):(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),a=this.inputResolver;this.inputResolver=s=>{clearTimeout(i),a(s)}}}))}submitInput(t){this.inputResolver&&(this.inputResolver(t),this.inputResolver=null,this.state.inputRequest=null,this.emitNow())}},zo=()=>new Pr;function Rr(){return process.stdin.isTTY===!0&&process.stdout.isTTY===!0}function Zo(e){if(Rr())return;let t=e?`'gaia ${e}'`:"this command";console.error(`Error: ${t} needs an interactive terminal (TTY) to prompt for input.`),console.error("Re-run it from a regular shell session \u2014 not a pipe, redirect, or non-TTY environment."),process.exit(1)}function en(e){let t="",r="",o="";e.on("change",n=>{n.step&&n.step!==t&&(t=n.step,console.info(`
40
+ [${n.step}]`)),n.status&&n.status!==r&&(r=n.status,console.info(` ${n.status}`)),n.error&&n.error.message!==o&&(o=n.error.message,console.error(` Error: ${n.error.message}`))})}var Cs=50,Is=130;async function re(e){let t=zo();if(e.whenNonInteractive==="fail"){Zo(e.command),await tn(t,e);return}Rr()?await tn(t,e):await Ps(t,e)}async function Ps(e,t){en(e);for(let[r,o]of t.autoResolve??[])e.setAutoResolve(r,o);try{await t.runFlow(e),t.onPlainComplete?.(e)}catch(r){e.setError(r)}rn(e)}async function tn(e,t){let{unmount:r}=bs(Ts.createElement(Qo,{store:e,command:t.command})),o=()=>{r(),process.exit(Is)};process.once("SIGINT",o),process.once("SIGTERM",o),await new Promise(n=>setTimeout(n,Cs));try{await t.runFlow(e)}catch(n){e.setError(n)}finally{process.off("SIGINT",o),process.off("SIGTERM",o)}e.currentState.error&&await e.waitForInput("exit"),r(),rn(e)}function rn(e){let t=e.currentState.error?1: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 ce from"fs";import*as pn from"os";import*as Se from"path";import*as on from"path";var Rs=e=>new Promise(t=>setTimeout(t,e));async function xt(e){e.setStep("Setup Mode"),e.setStatus("Choose how to run GAIA...");let t=await e.waitForInput("setup_mode");return e.updateData("setupMode",t),t}async function wt(e,t,r,o){e.setStep("Environment Setup"),e.setStatus("Configuring environment..."),e.updateData("setupMode",r),e.setStatus("Configuring environment variables...");let n=await e.waitForInput("env_method");e.updateData("envMethod",n);let i={};i.ENV="development";let a=pr();for(let c of a){let u=ur(c,r);u&&(i[c]=u)}let s=Co(r);for(let[c,u]of Object.entries(s))i[c]=u;if(n==="infisical")await ks(e,i),e.setStatus("Infisical credentials saved. Ensure your Infisical project contains all required variables.");else try{await _s(e,t,i,r)}catch(c){e.setError(c);return}o&&bo(i,o,r);try{await Ds(e,t,i,r,o)}catch(c){e.setError(c);return}await Rs(1e3)}async function ks(e,t){e.setStatus("Configuring Infisical...");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}async function _s(e,t,r,o){e.setStatus("Parsing environment variables...");let n;try{n=await xo(t),n=To(n,o)}catch(v){throw o==="selfhost"?new Error(`Manual environment setup requires Python to parse config schema.
9
41
  For self-host mode, we recommend using Infisical for secret management.
10
42
  Alternatively, install Python 3.11+ and try again.
11
43
 
12
- Original error: ${f.message}`):new Error(`Failed to parse settings: ${f.message}`)}let a=new Set,c=[],i=new Set;for(let f of n)if(f.alternativeGroup&&!i.has(f.name)){let y=n.find(v=>v.name===f.alternativeGroup);y&&(c.push([f,y]),a.add(f.name),a.add(y.name),i.add(f.name),i.add(y.name))}let l=n.filter(f=>f.variables.length===1&&!a.has(f.name)),u=n.filter(f=>f.variables.length>1&&!a.has(f.name));for(let f of c){e.updateData("alternativeGroups",f),e.setStatus("Choose an AI provider...");let y=await e.waitForInput("env_alternatives");for(let[v,b]of Object.entries(y.values))b&&(r[v]=b)}let g=ft(),m=[...l.flatMap(f=>f.variables).filter(f=>!g.includes(f.name))].sort((f,y)=>f.required&&!y.required?-1:!f.required&&y.required?1:0);e.updateData("envVarTotal",m.length);for(let f=0;f<m.length;f++){let y=m[f];if(!y)continue;e.updateData("currentEnvVar",y),e.updateData("envVarIndex",f),e.setStatus(`Configuring ${y.name}...`);let v=await e.waitForInput("env_var",{varName:y.name});(v||y.required||y.defaultValue)&&(r[y.name]=v||y.defaultValue||"")}let x=[...u].filter(f=>!f.variables.every(y=>g.includes(y.name))).sort((f,y)=>{let v=f.variables.some(P=>P.required),b=y.variables.some(P=>P.required);return v&&!b?-1:!v&&b?1:0});e.updateData("envGroupTotal",x.length);for(let f=0;f<x.length;f++){let y=x[f];if(!y)continue;e.updateData("currentEnvGroup",y),e.updateData("envGroupIndex",f),e.setStatus(`Configuring ${y.name}...`);let v=await e.waitForInput("env_group",{groupName:y.name});for(let[b,P]of Object.entries(v)){let w=y.variables.find(ee=>ee.name===b);(P||w?.required||w?.defaultValue)&&(r[b]=P||w?.defaultValue||"")}}}async function mo(e,t,r,o,n){e.setStatus("Writing API environment file...");try{let c=tr.join(t,"apps","api");Kt(c,r),e.setStatus("API environment variables configured!")}catch(c){throw new Error(`Failed to write API .env file: ${c.message}`)}e.setStatus("Writing web environment file...");try{Jt(t,o,n),e.setStatus("Web environment variables configured!")}catch(c){throw new Error(`Failed to write web .env file: ${c.message}`)}let a=n&&Object.keys(n).length>0;if(a||o==="selfhost"){e.setStatus("Writing Docker Compose environment...");try{a&&er(t),Zt(t,n??{},o),e.setStatus("Docker Compose environment configured!")}catch(c){throw new Error(`Failed to write Docker Compose .env: ${c.message}`)}}}import{execa as re}from"execa";var Y={git:"https://git-scm.com/downloads",docker:"https://docs.docker.com/get-docker/",mise:"https://mise.jdx.dev/getting-started.html"},fo={8e3:"API Server",5432:"PostgreSQL",6379:"Redis",27017:"MongoDB",5672:"RabbitMQ",3e3:"Web Frontend",8080:"ChromaDB",8083:"Mongo Express"};async function rr(){try{return await re("git",["--version"]),"success"}catch{return"error"}}async function $e(){let e=!1,t=!1,r;try{await re("docker",["--version"]),e=!0}catch{return{name:"Docker",installUrl:Y.docker,installed:!1,working:!1,errorMessage:"Docker is not installed"}}try{await re("docker",["info"],{timeout:5e3}),t=!0}catch{r="Docker is installed but the daemon is not running. Please start Docker Desktop or the Docker daemon."}return{name:"Docker",installUrl:Y.docker,installed:e,working:t,errorMessage:r}}async function qe(){try{return await re("mise",["--version"]),"success"}catch{return"missing"}}async function or(){if((await import("node:os")).platform()==="win32")try{return await re("powershell",["-Command","irm https://mise.jdx.dev/install.ps1 | iex"]),!0}catch{return!1}try{return await re("sh",["-c","curl https://mise.jdx.dev/install.sh | sh"]),!0}catch{return!1}}async function nr(e){let t=await import("node:net"),r=[],o=n=>new Promise(a=>{let c=t.createServer();c.once("error",()=>a(!1)),c.once("listening",()=>{c.close(()=>a(!0))}),c.listen(n)});for(let n of e){let a=fo[n]||`Port ${n}`;if(await o(n))r.push({port:n,service:a,available:!0});else{let i=await go(n),l=await ho(n+1,n+100,o);r.push({port:n,service:a,available:!1,usedBy:i,alternative:l||void 0})}}return r}async function go(e){if((await import("node:os")).platform()==="win32"){try{let{stdout:o}=await re("netstat",["-ano","-p","TCP"]),n=o.trim().split(`
13
- `);for(let a of n)if(a.includes(`:${e}`)&&a.includes("LISTENING")){let c=a.trim().split(/\s+/),i=c[c.length-1];if(i)try{let{stdout:l}=await re("tasklist",["/FI",`PID eq ${i}`,"/FO","CSV","/NH"]);return l.trim().split(",")[0]?.replace(/"/g,"")||`PID ${i}`}catch{return`PID ${i}`}}}catch{}return}try{let{stdout:o}=await re("lsof",["-i",`:${e}`,"-sTCP:LISTEN","-P","-n"]),n=o.trim().split(`
14
- `);if(n.length>1)return n[1]?.split(/\s+/)?.[0]||void 0}catch{}}async function ho(e,t,r){for(let o=e;o<=t;o++)if(await r(o))return o;return null}import*as M from"fs";import*as U from"path";var So=e=>new Promise(t=>setTimeout(t,e)),xo="dev-start.log";var ir=".gaia-dev.pid";function ar(e){let t=U.join(e,".env");return M.existsSync(t)?["--env-file",".env"]:[]}async function Ee(e,t,r,o,n,a){if(t==="selfhost"){let c=a?.build??!1,i=a?.pull??!1;r?.(c?"Building and starting all services in Docker...":"Starting all services in Docker (selfhost mode)...");let l=U.join(e,"infra/docker"),u=ar(l),g=o&&Object.keys(o).length>0?he(o):void 0,S=["compose","-f","docker-compose.selfhost.yml",...u,"up","-d","--remove-orphans"];c&&S.push("--build"),i&&S.push("--pull","always");let m=c?900*1e3:300*1e3;await j("docker",S,l,void 0,n,g,m),r?.("All services started in Docker!")}else{r?.("Starting development servers...");let{spawn:c}=await import("child_process"),i=U.join(e,xo),l=U.join(e,ir),u=M.openSync(i,"w"),g;try{g=c("mise",["dev"],{cwd:e,stdio:["ignore",u,u],detached:!0,shell:!0}),g.unref()}finally{M.closeSync(u)}if(g.pid!=null&&M.writeFileSync(l,String(g.pid),"utf-8"),await So(1500),g.pid!=null)try{process.kill(g.pid,0)}catch{throw new Error(`Development servers crashed on startup. Check logs at: ${i}`)}r?.(`Development servers started! Logs: ${i}`)}}async function sr(e,t,r){let o=U.join(e,"infra/docker"),n=await St(e);t?.("Stopping Docker services...");try{let a=ar(o),c=n==="selfhost"?["compose","-f","docker-compose.selfhost.yml",...a,"down"]:["compose",...a,"down"];await j("docker",c,o)}catch{}if(n!=="selfhost"){t?.("Stopping local processes...");let a=U.join(e,ir),c=!1;if(M.existsSync(a)){try{let i=Number.parseInt(M.readFileSync(a,"utf-8").trim(),10);if(!Number.isNaN(i)&&i>0)try{process.kill(-i,"SIGTERM"),c=!0}catch{}}catch{}try{M.unlinkSync(a)}catch{}}if(!c)try{let i=r?.[8e3]??8e3,l=r?.[3e3]??3e3;if(process.platform==="win32")for(let u of[i,l])try{await j("powershell",["-Command",`Get-NetTCPConnection -LocalPort ${u} -ErrorAction SilentlyContinue | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force -ErrorAction SilentlyContinue }`],e)}catch{}else for(let u of[i,l])try{await j("sh",["-c",`lsof -ti :${u} -sTCP:LISTEN | xargs kill 2>/dev/null || true`],e)}catch{}}catch{}}t?.("All services stopped.")}async function St(e){let t=U.join(e,"apps","api",".env");if(!M.existsSync(t))return null;let r=M.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")}async function j(e,t,r,o,n,a,c){let{spawn:i}=await import("child_process");return new Promise((l,u)=>{let g=i(e,t,{cwd:r,stdio:["ignore","pipe","pipe"],shell:!0,env:a?{...process.env,...a}:void 0}),S="",m=0,x=!1,f;c&&(f=setTimeout(()=>{x=!0,g.kill("SIGTERM"),u(new Error(`Command timed out after ${Math.round(c/6e4)}m. Check \`docker compose logs\` to debug.`))},c)),g.stdout?.on("data",y=>{let v=y.toString();S+=v,n?.(v),m=Math.min(m+5,95),o?.(m)}),g.stderr?.on("data",y=>{let v=y.toString();S+=v,n?.(v),m=Math.min(m+5,95),o?.(m)}),g.on("close",y=>{f&&clearTimeout(f),!x&&(y===0?(o?.(100),l()):u(new Error(`Command failed with code ${y}: ${S.slice(-500)}`)))}),g.on("error",y=>{f&&clearTimeout(f),!x&&u(y)})})}function Z(e){let t=e||process.cwd();for(;t!==U.dirname(t);){if(M.existsSync(U.join(t,"apps/api/app/config/settings_validator.py")))return t;t=U.dirname(t)}let r=pt();if(r?.repoPath){if(M.existsSync(U.join(r.repoPath,"apps/api/app/config/settings_validator.py")))return r.repoPath;console.warn(`Warning: Saved repo path "${r.repoPath}" is no longer a valid GAIA installation. Resetting config.`),Ce({repoPath:"",setupComplete:!1})}return null}var W=e=>new Promise(t=>setTimeout(t,e)),He=(e,t="dependencyLogs")=>r=>{let o=e.currentState.data[t]||[],n=r.split(`
15
- `).filter(a=>a.trim()!=="");e.updateData(t,[...o,...n].slice(-30))};async function je(e){e.updateData("checks",{git:"pending",docker:"pending",mise:"pending"}),await W(500);let t=await rr();e.updateData("checks",{...e.currentState.data.checks,git:t});let r=await $e(),o=r.working?"success":"error";e.updateData("checks",{...e.currentState.data.checks,docker:o}),r.working||e.updateData("dockerError",r.errorMessage);let n=await qe();e.updateData("checks",{...e.currentState.data.checks,mise:n}),n==="missing"&&(e.setStatus("Installing Mise..."),n=await or()?"success":"error",e.updateData("checks",{...e.currentState.data.checks,mise:n}));let a=[];if(t==="error"&&a.push({name:"Git"}),o==="error"&&a.push({name:"Docker",message:r.errorMessage}),a.length>0){let c=["Prerequisites failed:"];for(let i of a)c.push(` \u2022 ${i.name}: ${i.message||"Not installed or not working"}`);return c.push(`
16
- Installation guides:`),t==="error"&&c.push(` \u2022 Git: ${Y.git}`),o==="error"&&(r.installed?c.push(" \u2022 Docker: Start Docker Desktop or run 'sudo systemctl start docker'"):c.push(` \u2022 Docker: ${Y.docker}`)),e.setError(new Error(c.join(`
17
- `))),null}return{gitStatus:t,dockerStatus:o,dockerInfo:r,miseStatus:n}}async function We(e){e.setStatus("Checking Ports...");let r=await nr([8e3,5432,6379,27017,5672,3e3,8080,8083]),o={},n=r.filter(a=>!a.available);if(n.length>0){let a=n.filter(i=>!i.alternative);if(a.length>0)return e.setError(new Error(`Cannot find free alternative ports for: ${a.map(i=>`${i.port} (${i.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 i of r)!i.available&&i.alternative&&(o[i.port]=i.alternative)}return e.updateData("portOverrides",o),e.setStatus("Prerequisites check complete!"),await W(1e3),o}async function cr(e,t,r,o){e.setStep("Project Setup"),e.updateData("dependencyPhase","Setting up project..."),e.updateData("dependencyProgress",0),e.updateData("dependencyComplete",!1),e.updateData("dependencyLogs",[]);try{e.updateData("dependencyPhase","Trusting mise configuration..."),await j("mise",["trust"],t,void 0,o),e.updateData("dependencyProgress",20),e.updateData("dependencyPhase","Installing tools..."),await j("mise",["install"],t,a=>{e.updateData("dependencyProgress",20+a*.3)},o),e.updateData("dependencyPhase","Running mise setup...");let n=Object.keys(r).length>0?he(r):void 0;return await j("mise",["setup"],t,a=>{e.updateData("dependencyProgress",50+a*.5)},o,n),e.updateData("dependencyProgress",100),e.updateData("dependencyPhase","Setup complete!"),e.updateData("dependencyComplete",!0),!0}catch(n){return e.setError(new Error(`Failed to setup project: ${n.message}`)),!1}}import{execa as yo}from"execa";import Ve from"fs";import To from"simple-git";async function lr(e,t,r,o){if(Ve.existsSync(e)){let n=`${e}/.git`;if(!Ve.existsSync(n))throw new Error(`Directory ${e} exists but is not a git repository`);await To().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 a=yo("git",n);a.stderr?.on("data",c=>{let i=c.toString();i.includes("Counting objects")?r(5,"Counting objects"):i.includes("Compressing objects")&&r(10,"Compressing objects");let l=i.match(/Receiving objects:\s+(\d+)%\s+\((\d+)\/(\d+)\)/);if(l?.[1]){let g=Math.min(100,parseInt(l[1],10)),S=l[2],m=l[3];r(10+Math.floor(g*.5),`Receiving objects: ${S}/${m}`)}let u=i.match(/Resolving deltas:\s+(\d+)%\s+\((\d+)\/(\d+)\)/);if(u?.[1]){let g=Math.min(100,parseInt(u[1],10)),S=u[2],m=u[3];r(60+Math.floor(g*.4),`Resolving deltas: ${S}/${m}`)}}),await a,r(100,"Clone complete")}catch(n){throw Ve.existsSync(e)&&Ve.rmSync(e,{recursive:!0,force:!0}),n}}import{execSync as xt}from"child_process";import*as B from"fs";import*as Ue from"os";import*as G from"path";var Pe=process.platform==="win32";function we(e){try{return xt(e,{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return null}}function ur(){let e=we("npm config get prefix");return e?Pe?e:G.join(e,"bin"):null}function pr(){let e=we("pnpm bin -g");if(e&&B.existsSync(e))return e;let t=we("pnpm root -g");if(t){let r=G.join(G.dirname(t),"bin");if(B.existsSync(r))return r}return null}function dr(){let e=G.join(Ue.homedir(),".bun","bin");return B.existsSync(e)?e:null}function mr(){let e=we("yarn global bin");return e&&B.existsSync(e)?e:null}function bo(){let e=Pe?"gaia.cmd":"gaia";for(let t of[ur,pr,dr,mr]){let r=t();if(r&&B.existsSync(G.join(r,e)))return r}if(Pe)for(let t of[ur,pr,dr,mr]){let r=t();if(r&&B.existsSync(G.join(r,"gaia")))return r}return null}function Io(){try{return xt(Pe?"where gaia":"command -v gaia",{stdio:["pipe","pipe","pipe"]}),!0}catch{return!1}}function Co(){let e=process.env.SHELL||"",t=Ue.homedir();if(e.includes("zsh"))return G.join(t,".zshrc");if(e.includes("bash")){let r=G.join(t,".bashrc"),o=G.join(t,".bash_profile");return B.existsSync(r)?r:o}return e.includes("fish")?G.join(t,".config","fish","config.fish"):null}function Eo(e,t){try{if((B.existsSync(t)?B.readFileSync(t,"utf-8"):"").includes(e))return!0;let n=t.includes("fish")?`
18
- set -gx PATH "${e}" $PATH # Added by GAIA CLI
19
- `:`
20
- export PATH="${e}:$PATH" # Added by GAIA CLI
21
- `;return B.appendFileSync(t,n),!0}catch{return!1}}function Po(e){try{let t=we(`powershell -Command "[Environment]::GetEnvironmentVariable('Path', 'User')"`);if(t&&t.includes(e))return!0;xt(`setx PATH "${e};${t||""}"`,{stdio:["pipe","pipe","pipe"]});let r=G.join(Ue.homedir(),"Documents","PowerShell","Microsoft.PowerShell_profile.ps1"),o=G.dirname(r);return B.existsSync(o)||B.mkdirSync(o,{recursive:!0}),(B.existsSync(r)?B.readFileSync(r,"utf-8"):"").includes(e)||B.appendFileSync(r,`
22
- $env:Path = "${e};" + $env:Path # Added by GAIA CLI
23
- `),!0}catch{return!1}}async function yt(){if(Io())return{success:!0,message:"gaia command is ready.",inPath:!0,pathAdded:!1};let e=bo();if(!e)return{success:!1,message:"Could not find gaia binary. Run manually: npm install -g @heygaia/cli",inPath:!1,pathAdded:!1};if(Pe)return Po(e)?{success:!0,message:"Added to PATH. Restart your terminal for the 'gaia' command to be available.",inPath:!1,pathAdded:!0}:{success:!1,message:`Add to your PATH manually: setx PATH "${e};%PATH%"`,inPath:!1,pathAdded:!1};let t=Co();if(!t)return{success:!1,message:`Add to your PATH: export PATH="${e}:$PATH"`,inPath:!1,pathAdded:!1};if(Eo(e,t)){let o=G.basename(t);return{success:!0,message:`Added to PATH via ~/${o}. Restart terminal or run: source ~/${o}`,inPath:!1,pathAdded:!0}}return{success:!1,message:`Could not write to ${t}. Add manually: export PATH="${e}:$PATH"`,inPath:!1,pathAdded:!1}}var wo=process.env.GAIA_CLI_DEV==="true",Tt=new RegExp("\x1B\\[[0-9;]*m","g");async function gr(e,t){e.setStep("Welcome"),e.setStatus("Waiting for user input..."),await e.waitForInput("welcome");let r=He(e);e.setStep("Prerequisites"),e.setStatus("Checking system requirements...");let o=await je(e);if(!o)return;let{miseStatus:n}=o,a=await We(e);if(a===null)return;let c=await Ne(e),i="";if(wo){if(i=Z()||"",!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..."),await W(500),e.setStatus("Repository ready!")}else{e.setStep("Repository Setup");let u=c==="selfhost"?ae.join(fr.homedir(),"gaia"):ae.resolve("gaia"),g=!0;for(i=u;;){if(i=await e.waitForInput("repo_path",{default:u}),ae.isAbsolute(i)||(i=ae.resolve(i)),oe.existsSync(i)){if(!oe.statSync(i).isDirectory()){e.setError(new Error(`Path ${i} exists and is not a directory.`)),await W(2e3),e.setError(null);continue}if(oe.existsSync(ae.join(i,"apps/api/app/config/settings_validator.py"))){e.updateData("existingRepoPath",i);let f=await e.waitForInput("existing_repo");if(f==="use_existing"){g=!1;break}else if(f==="delete_reclone"){e.setStatus("Removing existing installation...");try{oe.rmSync(i,{recursive:!0,force:!0})}catch(y){e.setError(new Error(`Failed to remove directory: ${y.message}
24
- Try removing it manually: rm -rf "${i}"`));return}break}else{if(f==="different_path")continue;e.setError(new Error("Setup cancelled by user."));return}}if(oe.readdirSync(i).length>0){e.setError(new Error(`Directory ${i} is not empty and is not a GAIA installation. Please choose another path.`)),await W(2e3),e.setError(null);continue}}break}if(g){e.setStep("Repository Setup"),e.setStatus("Preparing repository..."),e.updateData("repoProgress",0),e.updateData("repoPhase","");try{await lr(i,"https://github.com/theexperiencecompany/gaia.git",(S,m)=>{e.updateData("repoProgress",S),m?(e.updateData("repoPhase",m),e.setStatus(`${m}...`)):e.setStatus(`Cloning repository to ${i}... ${S}%`)},t),e.setStatus("Repository ready!")}catch(S){e.setError(S);return}}else e.setStatus("Using existing repository!")}if(await W(1e3),await Ge(e,i,c,a),e.currentState.error)return;if(c==="selfhost"){e.setStep("Installing CLI"),e.setStatus("Installing gaia CLI globally...");try{await j("npm",["install","-g","@heygaia/cli"],i,void 0,f=>{let y=f.split(`
25
- `).map(b=>b.replace(Tt,"").trim()).filter(b=>b.length>0);if(y.length===0)return;let v=e.currentState.data.cliInstallLogs||[];e.updateData("cliInstallLogs",[...v,...y].slice(-30))}),e.setStatus("Verifying PATH...");let x=await yt();x.inPath?e.setStatus("CLI installed! gaia command is ready."):(x.pathAdded,e.setStatus(x.message))}catch{e.setStatus("CLI install failed. Install manually: npm install -g @heygaia/cli")}await W(500),e.setStep("Project Setup"),e.setStatus("Building and starting all services in Docker..."),e.updateData("dependencyPhase","Building and starting Docker services..."),e.updateData("dependencyProgress",0),e.updateData("dependencyLogs",[]),e.updateData("dependencyComplete",!1);let u=m=>{let x=m.split(`
26
- `).map(y=>y.replace(Tt,"").trim()).filter(y=>y.length>0);if(x.length===0)return;let f=e.currentState.data.dependencyLogs||[];e.updateData("dependencyLogs",[...f,...x].slice(-30))},g=!1;try{e.setStatus("Pulling pre-built images from registry..."),await Ee(i,"selfhost",m=>e.setStatus(m),a,u,{pull:!0}),g=!0}catch(m){let x=m.message?.split(`
27
- `)[0]??"unknown error";e.setStatus(`Registry pull failed (${x}) \u2014 building images locally (this takes a few minutes)...`)}if(!g)try{await Ee(i,"selfhost",m=>e.setStatus(m),a,u,{build:!0})}catch(m){e.setError(new Error(`Failed to start services: ${m.message}`));return}e.updateData("dependencyProgress",100),e.updateData("dependencyComplete",!0);let S=e.currentState.data.envMethod||"manual";Fe({version:Me,setupComplete:!0,setupMethod:S,repoPath:i,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()}),e.updateData("setupMode",c),e.setStep("Finished"),e.setStatus("Setup complete! GAIA is running."),await e.waitForInput("exit");return}if(n==="error"){e.setError(new Error(`Developer mode requires Mise but it failed to install.
28
- \u2022 Mise: ${Y.mise}`));return}e.setStep("Install Tools"),e.setStatus("Installing toolchain..."),e.updateData("dependencyPhase","Initializing mise..."),e.updateData("dependencyProgress",0),e.updateData("dependencyLogs",[]);try{e.updateData("dependencyPhase","Trusting mise configuration..."),await j("mise",["trust"],i,void 0,r),e.updateData("dependencyProgress",50),e.updateData("dependencyPhase","Installing tools (node, python, uv, nx)..."),await j("mise",["install"],i,u=>{e.updateData("dependencyProgress",50+u*.5)},r),e.updateData("dependencyProgress",100),e.updateData("toolComplete",!0)}catch(u){e.setError(new Error(`Failed to install tools: ${u.message}`));return}await W(1e3),e.setStep("Project Setup"),e.updateData("dependencyPhase","Setting up project..."),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)...");let u=Object.keys(a).length>0?he(a):void 0;await j("mise",["setup"],i,g=>{e.updateData("dependencyProgress",g)},r,u),e.updateData("dependencyProgress",100),e.updateData("dependencyPhase","Setup complete!"),e.updateData("dependencyComplete",!0)}catch(u){e.setError(new Error(`Failed to setup project: ${u.message}`));return}await W(1e3);let l=e.currentState.data.envMethod||"manual";Fe({version:Me,setupComplete:!0,setupMethod:l,repoPath:i,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()}),e.setStep("Installing CLI"),e.setStatus("Installing gaia CLI globally...");try{await j("npm",["install","-g","@heygaia/cli"],i,void 0,S=>{let m=S.split(`
29
- `).map(f=>f.replace(Tt,"").trim()).filter(f=>f.length>0);if(m.length===0)return;let x=e.currentState.data.cliInstallLogs||[];e.updateData("cliInstallLogs",[...x,...m].slice(-30))}),e.setStatus("Verifying PATH...");let g=await yt();g.inPath?e.setStatus("CLI installed! gaia command is ready."):(g.pathAdded,e.setStatus(g.message))}catch{e.setStatus("CLI install failed. Install manually: npm install -g @heygaia/cli")}await W(500),e.setStep("Finished"),e.setStatus("Setup complete!"),await e.waitForInput("exit")}async function hr(e={}){let t=z(),{unmount:r}=Ro(Do.createElement(J,{store:t,command:"init"})),o=()=>{r(),process.exit(130)};process.once("SIGINT",o),process.once("SIGTERM",o);try{await gr(t,e.branch)}catch(n){t.setError(n)}finally{process.off("SIGINT",o),process.off("SIGTERM",o)}t.currentState.error&&await t.waitForInput("exit"),r(),process.exit(t.currentState.error?1:0)}import{render as Ao}from"ink";import ko from"react";async function Sr(e){e.setStep("Detect Repo"),e.setStatus("Looking for GAIA repository...");let t=Z();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}e.updateData("repoPath",t),e.setStatus(`Found repository at ${t}`),await W(1e3),e.setStep("Prerequisites"),e.setStatus("Checking system requirements...");let r=await je(e);if(!r)return;let{miseStatus:o}=r,n=await We(e);if(n===null)return;let a=await Ne(e);if(await Ge(e,t,a,n),e.currentState.error)return;if(a==="selfhost"){let u=e.currentState.data.envMethod||"manual";Ce({setupComplete:!0,setupMethod:u,repoPath:t}),e.setStep("Finished"),e.setStatus("Setup complete! Run 'gaia start' to build and start all services in Docker."),await e.waitForInput("exit");return}if(o==="error"){e.setError(new Error(`Developer mode requires Mise but it failed to install.
30
- \u2022 Mise: ${Y.mise}`));return}let c=He(e);if(!await cr(e,t,n,c))return;await W(1e3);let l=e.currentState.data.envMethod||"manual";Ce({setupComplete:!0,setupMethod:l,repoPath:t}),e.setStep("Finished"),e.setStatus("Setup complete!"),await e.waitForInput("exit")}async function xr(){let e=z(),{unmount:t}=Ao(ko.createElement(J,{store:e,command:"setup"})),r=()=>{t(),process.exit(130)};process.once("SIGINT",r),process.once("SIGTERM",r);try{await Sr(e)}catch(o){e.setError(o)}finally{process.off("SIGINT",r),process.off("SIGTERM",r)}e.currentState.error&&await e.waitForInput("exit"),t(),process.exit(e.currentState.error?1:0)}import{render as Bo}from"ink";import Oo from"react";var _o=new RegExp("\x1B\\[[0-9;]*m","g");async function yr(e,t){e.setStep("Starting"),e.setStatus("Locating GAIA repository...");let r=Z();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 St(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==="selfhost"){e.setStatus("Checking Docker...");let l=await $e();if(!l.working){e.setError(new Error(l.errorMessage||`Docker is not running. Please start Docker and try again.
31
- ${Y.docker}`));return}}else{e.setStatus("Checking Mise...");let l=await qe();if(l==="missing"||l==="error"){e.setError(new Error(`Developer mode requires Mise but it is not installed.
32
- Install: ${Y.mise}`));return}}let n=Se(r),a=n[3e3]??3e3,c=n[8e3]??8e3;e.updateData("setupMode",o),e.updateData("webPort",a),e.updateData("apiPort",c),e.updateData("dockerLogs",[]),e.setStatus(`Starting GAIA in ${o} mode...`);let i=l=>{let u=l.split(`
33
- `).map(S=>S.replace(_o,"").trim()).filter(S=>S.length>0);if(u.length===0)return;let g=e.currentState.data.dockerLogs||[];e.updateData("dockerLogs",[...g,...u].slice(-30))};try{await Ee(r,o,l=>{e.setStatus(l)},n,i,t),e.setStep("Running"),e.setStatus("GAIA is running!"),e.updateData("started",!0)}catch(l){e.setError(new Error(`Failed to start services: ${l.message}`));return}await e.waitForInput("exit")}async function Tr(e){let t=z(),{unmount:r}=Bo(Oo.createElement(J,{store:t,command:"start"})),o=()=>{r(),process.exit(130)};process.once("SIGINT",o),process.once("SIGTERM",o),await new Promise(n=>setTimeout(n,50));try{await yr(t,e)}catch(n){t.setError(n)}finally{process.off("SIGINT",o),process.off("SIGTERM",o)}t.currentState.error&&await t.waitForInput("exit"),r(),process.exit(t.currentState.error?1:0)}import{render as Go}from"ink";import $o from"react";import{execa as bt}from"execa";var vt=["gaia-backend","gaia-web","chromadb","postgres","redis","mongo","rabbitmq","arq_worker"];async function vr(){try{let{stdout:e}=await bt("docker",["inspect","--format","{{.Name}}|{{.State.Status}}|{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}",...vt]),t=new Map;for(let r of e.trim().split(`
34
- `)){if(!r)continue;let[o,n,a]=r.split("|"),c=o?.replace(/^\//,"")??"";t.set(c,{name:c,status:n==="running"?"running":"stopped",health:a!=="none"?a:void 0})}return vt.map(r=>t.get(r)??{name:r,status:"not_found"})}catch{let e=vt.map(async t=>{try{let{stdout:r}=await bt("docker",["inspect","--format","{{.State.Status}}|{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}",t]),[o,n]=r.trim().split("|");return{name:t,status:o==="running"?"running":"stopped",health:n!=="none"?n:void 0}}catch{return{name:t,status:"not_found"}}});return Promise.all(e)}}async function br(){try{return await bt("docker",["info"]),!0}catch{return!1}}var Lo=[{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 Ir(e){let r=Lo.map(o=>({...o,port:e?.[o.port]??o.port})).map(o=>o.type==="http"?Mo(o.name,o.port,o.path):Fo(o.name,o.port));return Promise.all(r)}async function Mo(e,t,r){let o=Date.now();try{let n=await fetch(`http://localhost:${t}${r}`,{signal:AbortSignal.timeout(5e3)}),a=Date.now()-o;return{name:e,port:t,status:n.ok?"up":"down",latency:a,details:n.ok?`HTTP ${n.status}`:`HTTP ${n.status} (error)`}}catch{return{name:e,port:t,status:"down",details:"Connection failed"}}}async function Fo(e,t){let r=await import("node:net"),o=Date.now();return new Promise(n=>{let a=new r.Socket;a.setTimeout(3e3),a.on("connect",()=>{let c=Date.now()-o;a.destroy(),n({name:e,port:t,status:"up",latency:c})}),a.on("timeout",()=>{a.destroy(),n({name:e,port:t,status:"down"})}),a.on("error",()=>{a.destroy(),n({name:e,port:t,status:"down"})}),a.connect(t,"localhost")})}async function Cr(){return await br()?{running:!0,containers:await vr()}:{running:!1,containers:[]}}async function No(e){e.setStep("Checking"),e.setStatus("Checking service health..."),e.updateData("refreshable",!1);let t=Z(),r=t?Se(t):void 0,[o,n]=await Promise.all([Ir(r),Cr()]);e.updateData("services",o),e.updateData("docker",n);let a=o.filter(i=>i.status==="up").length,c=o.length;e.setStep("Results"),e.setStatus(`${a}/${c} services running`),e.updateData("refreshable",!0)}async function Er(e){for(;await No(e),await e.waitForInput("exit_or_refresh")==="refresh";);}async function Pr(){let e=z(),{unmount:t}=Go($o.createElement(J,{store:e,command:"status"}));await new Promise(r=>setTimeout(r,50));try{await Er(e)}catch(r){e.setError(r)}e.currentState.error&&await e.waitForInput("exit"),t(),process.exit(e.currentState.error?1:0)}import{render as qo}from"ink";import Ho from"react";async function wr(e){e.setStep("Stopping"),e.setStatus("Locating GAIA repository...");let t=Z();if(!t){e.setError(new Error("Could not find GAIA repository. Run from within a cloned gaia repo."));return}e.updateData("repoPath",t);let r=Se(t);try{await sr(t,o=>{e.setStatus(o)},r),e.setStep("Stopped"),e.setStatus("All services stopped."),e.updateData("stopped",!0)}catch(o){e.setError(new Error(`Failed to stop services: ${o.message}`));return}await e.waitForInput("exit")}async function Rr(){let e=z(),{unmount:t}=qo(Ho.createElement(J,{store:e,command:"stop"})),r=()=>{t(),process.exit(130)};process.once("SIGINT",r),process.once("SIGTERM",r),await new Promise(o=>setTimeout(o,50));try{await wr(e)}catch(o){e.setError(o)}finally{process.off("SIGINT",r),process.off("SIGTERM",r)}e.currentState.error&&await e.waitForInput("exit"),t(),process.exit(e.currentState.error?1:0)}var se=new jo;se.name("gaia").description("CLI tool for setting up and managing GAIA").version("0.1.0");se.command("init").description("Full setup from scratch (clone, configure, start)").option("--branch <branch>","Git branch to clone").action(async e=>{await hr({branch:e.branch})});se.command("setup").description("Configure an existing GAIA repository").action(async()=>{await xr()});se.command("status").description("Check health of all GAIA services").action(async()=>{await Pr()});se.command("start").description("Start GAIA services").option("-b, --build","Rebuild Docker images before starting").option("--pull","Pull latest base images before starting").action(async e=>{await Tr({build:e.build,pull:e.pull})});se.command("stop").description("Stop all GAIA services").action(async()=>{await Rr()});process.argv.slice(2).length||(se.outputHelp(),process.exit(0));se.parse();
44
+ Original error: ${v.message}`):new Error(`Failed to parse settings: ${v.message}`)}let i=new Set,a=[],s=new Set;for(let v of n)if(v.alternativeGroup&&!s.has(v.name)){let y=n.find(w=>w.name===v.alternativeGroup);y&&(a.push([v,y]),i.add(v.name),i.add(y.name),s.add(v.name),s.add(y.name))}let c=n.filter(v=>v.variables.length===1&&!i.has(v.name)),u=n.filter(v=>v.variables.length>1&&!i.has(v.name));for(let v of a){e.updateData("alternativeGroups",v),e.setStatus("Choose an AI provider...");let y=await e.waitForInput("env_alternatives");for(let[w,E]of Object.entries(y.values))E&&(r[w]=E)}let d=pr(),f=[...c.flatMap(v=>v.variables).filter(v=>!d.includes(v.name))].sort((v,y)=>v.required&&!y.required?-1:!v.required&&y.required?1:0);e.updateData("envVarTotal",f.length);for(let v=0;v<f.length;v++){let y=f[v];if(!y)continue;e.updateData("currentEnvVar",y),e.updateData("envVarIndex",v),e.setStatus(`Configuring ${y.name}...`);let w=await e.waitForInput("env_var",{varName:y.name});(w||y.required||y.defaultValue)&&(r[y.name]=w||y.defaultValue||"")}let S=[...u].filter(v=>!v.variables.every(y=>d.includes(y.name))).sort((v,y)=>{let w=v.variables.some(I=>I.required),E=y.variables.some(I=>I.required);return w&&!E?-1:!w&&E?1:0});e.updateData("envGroupTotal",S.length);for(let v=0;v<S.length;v++){let y=S[v];if(!y)continue;e.updateData("currentEnvGroup",y),e.updateData("envGroupIndex",v),e.setStatus(`Configuring ${y.name}...`);let w=await e.waitForInput("env_group",{groupName:y.name});for(let[E,I]of Object.entries(w)){let P=y.variables.find(oe=>oe.name===E);(I||P?.required||P?.defaultValue)&&(r[E]=I||P?.defaultValue||"")}}}async function Ds(e,t,r,o,n){e.setStatus("Writing API environment file...");try{let a=on.join(t,"apps","api");Po(a,r),e.setStatus("API environment variables configured!")}catch(a){throw new Error(`Failed to write API .env file: ${a.message}`)}e.setStatus("Writing web environment file...");try{Ro(t,o,n),e.setStatus("Web environment variables configured!")}catch(a){throw new Error(`Failed to write web .env file: ${a.message}`)}let i=n&&Object.keys(n).length>0;if(i||o==="selfhost"){e.setStatus("Writing Docker Compose environment...");try{i&&Do(t),_o(t,n??{},o),e.setStatus("Docker Compose environment configured!")}catch(a){throw new Error(`Failed to write Docker Compose .env: ${a.message}`)}}}import{execa as ae}from"execa";var ve={git:"https://git-scm.com/downloads",docker:"https://docs.docker.com/get-docker/",mise:"https://mise.jdx.dev/getting-started.html"},As={8e3:"API Server",5432:"PostgreSQL",6379:"Redis",27017:"MongoDB",5672:"RabbitMQ",3e3:"Web Frontend",8080:"ChromaDB",8083:"Mongo Express"};async function nn(){try{return await ae("git",["--version"]),"success"}catch{return"error"}}async function Et(){let e=!1,t=!1,r;try{await ae("docker",["--version"]),e=!0}catch{return{name:"Docker",installUrl:ve.docker,installed:!1,working:!1,errorMessage:"Docker is not installed"}}try{await ae("docker",["info"],{timeout:5e3}),t=!0}catch{r="Docker is installed but the daemon is not running. Please start Docker Desktop or the Docker daemon."}return{name:"Docker",installUrl:ve.docker,installed:e,working:t,errorMessage:r}}async function sn(){try{return await ae("mise",["--version"]),"success"}catch{return"missing"}}async function an(){if((await import("node:os")).platform()==="win32")try{return await ae("powershell",["-Command","irm https://mise.jdx.dev/install.ps1 | iex"]),!0}catch{return!1}try{return await ae("sh",["-c","curl https://mise.jdx.dev/install.sh | sh"]),!0}catch{return!1}}async function cn(e){let t=await import("node:net"),r=[],o=n=>new Promise(i=>{let a=t.createServer();a.once("error",()=>i(!1)),a.once("listening",()=>{a.close(()=>i(!0))}),a.listen(n)});for(let n of e){let i=As[n]||`Port ${n}`;if(await o(n))r.push({port:n,service:i,available:!0});else{let s=await Os(n),c=await Ls(n+1,n+100,o);r.push({port:n,service:i,available:!1,usedBy:s,alternative:c||void 0})}}return r}async function Os(e){if((await import("node:os")).platform()==="win32"){try{let{stdout:o}=await ae("netstat",["-ano","-p","TCP"]),n=o.trim().split(`
45
+ `);for(let i of n)if(i.includes(`:${e}`)&&i.includes("LISTENING")){let a=i.trim().split(/\s+/),s=a[a.length-1];if(s)try{let{stdout:c}=await ae("tasklist",["/FI",`PID eq ${s}`,"/FO","CSV","/NH"]);return c.trim().split(",")[0]?.replace(/"/g,"")||`PID ${s}`}catch{return`PID ${s}`}}}catch{}return}try{let{stdout:o}=await ae("lsof",["-i",`:${e}`,"-sTCP:LISTEN","-P","-n"]),n=o.trim().split(`
46
+ `);if(n.length>1)return n[1]?.split(/\s+/)?.[0]||void 0}catch{}}async function Ls(e,t,r){for(let o=e;o<=t;o++)if(await r(o))return o;return null}var K=e=>new Promise(t=>setTimeout(t,e)),bt=(e,t="dependencyLogs")=>r=>{let o=e.currentState.data[t]||[],n=r.split(`
47
+ `).filter(i=>i.trim()!=="");e.updateData(t,[...o,...n].slice(-30))};async function Tt(e){e.updateData("checks",{git:"pending",docker:"pending"}),await K(500);let t=await nn();e.updateData("checks",{...e.currentState.data.checks,git:t});let r=await Et(),o=r.working?"success":"error";e.updateData("checks",{...e.currentState.data.checks,docker:o}),r.working||e.updateData("dockerError",r.errorMessage);let n=[];if(t==="error"&&n.push({name:"Git"}),o==="error"&&n.push({name:"Docker",message:r.errorMessage}),n.length>0){let i=["Prerequisites failed:"];for(let a of n)i.push(` \u2022 ${a.name}: ${a.message||"Not installed or not working"}`);return i.push(`
48
+ Installation guides:`),t==="error"&&i.push(` \u2022 Git: ${ve.git}`),o==="error"&&(r.installed?i.push(" \u2022 Docker: Start Docker Desktop or run 'sudo systemctl start docker'"):i.push(` \u2022 Docker: ${ve.docker}`)),e.setError(new Error(i.join(`
49
+ `))),null}return{gitStatus:t,dockerStatus:o,dockerInfo:r}}async function Ct(e){e.updateData("checks",{...e.currentState.data.checks,mise:"pending"});let t=await sn();return e.updateData("checks",{...e.currentState.data.checks,mise:t}),t==="missing"&&(e.setStatus("Installing Mise..."),t=await an()?"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.
50
+ \u2022 Mise: ${ve.mise}`)),null):"success"}async function It(e){e.setStatus("Checking Ports...");let r=await cn([8e3,5432,6379,27017,5672,3e3,8080,8083]),o={},n=r.filter(i=>!i.available);if(n.length>0){let i=n.filter(s=>!s.alternative);if(i.length>0)return e.setError(new Error(`Cannot find free alternative ports for: ${i.map(s=>`${s.port} (${s.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 s of r)!s.available&&s.alternative&&(o[s.port]=s.alternative)}return e.updateData("portOverrides",o),e.setStatus("Prerequisites check complete!"),await K(1e3),o}async function ln(e,t,r,o){e.setStep("Project Setup"),e.updateData("dependencyPhase","Setting up project..."),e.updateData("dependencyProgress",0),e.updateData("dependencyComplete",!1),e.updateData("dependencyLogs",[]);try{e.updateData("dependencyPhase","Trusting mise configuration..."),await H("mise",["trust"],t,void 0,o),e.updateData("dependencyProgress",20),e.updateData("dependencyPhase","Installing tools..."),await H("mise",["install"],t,i=>{e.updateData("dependencyProgress",20+i*.3)},o),e.updateData("dependencyPhase","Running mise setup...");let n=Object.keys(r).length>0?me(r):void 0;return await H("mise",["setup"],t,i=>{e.updateData("dependencyProgress",50+i*.5)},o,n),e.updateData("dependencyProgress",100),e.updateData("dependencyPhase","Setup complete!"),e.updateData("dependencyComplete",!0),!0}catch(n){return e.setError(new Error(`Failed to setup project: ${n.message}`)),!1}}import{execa as Ns}from"execa";import Pt from"fs";import Bs from"simple-git";async function un(e,t,r,o){if(Pt.existsSync(e)){let n=`${e}/.git`;if(!Pt.existsSync(n))throw new Error(`Directory ${e} exists but is not a git repository`);await Bs().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=Ns("git",n);i.stderr?.on("data",a=>{let s=a.toString();s.includes("Counting objects")?r(5,"Counting objects"):s.includes("Compressing objects")&&r(10,"Compressing objects");let c=s.match(/Receiving objects:\s+(\d+)%\s+\((\d+)\/(\d+)\)/);if(c?.[1]){let d=Math.min(100,parseInt(c[1],10)),m=c[2],f=c[3];r(10+Math.floor(d*.5),`Receiving objects: ${m}/${f}`)}let u=s.match(/Resolving deltas:\s+(\d+)%\s+\((\d+)\/(\d+)\)/);if(u?.[1]){let d=Math.min(100,parseInt(u[1],10)),m=u[2],f=u[3];r(60+Math.floor(d*.4),`Resolving deltas: ${m}/${f}`)}}),await i,r(100,"Clone complete")}catch(n){throw Pt.existsSync(e)&&Pt.rmSync(e,{recursive:!0,force:!0}),n}}var $s=process.env.GAIA_CLI_DEV==="true",Gs=new RegExp("\x1B\\[[0-9;]*m","g");async function dn(e,t){e.setStep("Welcome"),e.setStatus("Waiting for user input..."),await e.waitForInput("welcome");let r=bt(e);if(e.setStep("Prerequisites"),e.setStatus("Checking system requirements..."),!await Tt(e))return;let o=await It(e);if(o===null)return;let n=await xt(e);if(n==="developer"&&!await Ct(e))return;let i="";if($s){if(i=U()||"",!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..."),await K(500),e.setStatus("Repository ready!")}else{e.setStep("Repository Setup");let s=n==="selfhost"?Se.join(pn.homedir(),"gaia"):Se.resolve("gaia"),c=!0;for(i=s;;){if(i=await e.waitForInput("repo_path",{default:s}),Se.isAbsolute(i)||(i=Se.resolve(i)),ce.existsSync(i)){if(!ce.statSync(i).isDirectory()){e.setError(new Error(`Path ${i} exists and is not a directory.`)),await K(2e3),e.setError(null);continue}if(ce.existsSync(Se.join(i,"apps/api/app/config/settings_validator.py"))){e.updateData("existingRepoPath",i);let f=await e.waitForInput("existing_repo");if(f==="use_existing"){c=!1;break}else if(f==="delete_reclone"){e.setStatus("Removing existing installation...");try{ce.rmSync(i,{recursive:!0,force:!0})}catch(S){e.setError(new Error(`Failed to remove directory: ${S.message}
51
+ Try removing it manually: rm -rf "${i}"`));return}break}else{if(f==="different_path")continue;e.setError(new Error("Setup cancelled by user."));return}}if(ce.readdirSync(i).length>0){e.setError(new Error(`Directory ${i} is not empty and is not a GAIA installation. Please choose another path.`)),await K(2e3),e.setError(null);continue}}break}if(c){e.setStep("Repository Setup"),e.setStatus("Preparing repository..."),e.updateData("repoProgress",0),e.updateData("repoPhase","");try{await un(i,"https://github.com/theexperiencecompany/gaia.git",(u,d)=>{e.updateData("repoProgress",u),d?(e.updateData("repoPhase",d),e.setStatus(`${d}...`)):e.setStatus(`Cloning repository to ${i}... ${u}%`)},t),e.setStatus("Repository ready!")}catch(u){e.setError(u);return}}else e.setStatus("Using existing repository!")}if(await K(1e3),await wt(e,i,n,o),e.currentState.error)return;if(n==="selfhost"){e.setStep("Project Setup"),e.setStatus("Building and starting all services in Docker..."),e.updateData("dependencyPhase","Building and starting Docker services..."),e.updateData("dependencyProgress",0),e.updateData("dependencyLogs",[]),e.updateData("dependencyComplete",!1);let s=d=>{let m=d.split(`
52
+ `).map(S=>S.replace(Gs,"").trim()).filter(S=>S.length>0);if(m.length===0)return;let f=e.currentState.data.dependencyLogs||[];e.updateData("dependencyLogs",[...f,...m].slice(-30))},c=!1;try{e.setStatus("Pulling pre-built images from registry..."),await qe(i,"selfhost",d=>e.setStatus(d),o,s,{pull:!0}),c=!0}catch(d){let m=d.message?.split(`
53
+ `)[0]??"unknown error";e.setStatus(`Registry pull failed (${m}) \u2014 building images locally (this takes a few minutes)...`)}if(!c)try{await qe(i,"selfhost",d=>e.setStatus(d),o,s,{build:!0})}catch(d){e.setError(new Error(`Failed to start services: ${d.message}`));return}e.updateData("dependencyProgress",100),e.updateData("dependencyComplete",!0);let u=e.currentState.data.envMethod||"manual";lt({version:ne,setupComplete:!0,setupMethod:u,repoPath:i,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()}),e.updateData("setupMode",n),e.setStep("Finished"),e.setStatus("Setup complete! GAIA is running."),await e.waitForInput("exit");return}e.setStep("Install Tools"),e.setStatus("Installing toolchain..."),e.updateData("dependencyPhase","Initializing mise..."),e.updateData("dependencyProgress",0),e.updateData("dependencyLogs",[]);try{e.updateData("dependencyPhase","Trusting mise configuration..."),await H("mise",["trust"],i,void 0,r),e.updateData("dependencyProgress",50),e.updateData("dependencyPhase","Installing tools (node, python, uv, nx)..."),await H("mise",["install"],i,s=>{e.updateData("dependencyProgress",50+s*.5)},r),e.updateData("dependencyProgress",100),e.updateData("toolComplete",!0)}catch(s){e.setError(new Error(`Failed to install tools: ${s.message}`));return}await K(1e3),e.setStep("Project Setup"),e.updateData("dependencyPhase","Setting up project..."),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)...");let s=Object.keys(o).length>0?me(o):void 0;await H("mise",["setup"],i,c=>{e.updateData("dependencyProgress",c)},r,s),e.updateData("dependencyProgress",100),e.updateData("dependencyPhase","Setup complete!"),e.updateData("dependencyComplete",!0)}catch(s){e.setError(new Error(`Failed to setup project: ${s.message}`));return}await K(1e3);let a=e.currentState.data.envMethod||"manual";lt({version:ne,setupComplete:!0,setupMethod:a,repoPath:i,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()}),e.setStep("Finished"),e.setStatus("Setup complete! Run 'gaia dev' to start development mode."),await e.waitForInput("exit")}async function mn(e={}){await re({command:"init",whenNonInteractive:"fail",runFlow:t=>dn(t,e.branch)})}async function fn(e){e.setStep("Detect Repo"),e.setStatus("Looking for GAIA repository...");let t=U();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 K(1e3),e.setStep("Prerequisites"),e.setStatus("Checking system requirements..."),!await Tt(e))return;let r=await It(e);if(r===null)return;let o=await xt(e);if(o==="developer"&&!await Ct(e)||(await wt(e,t,o,r),e.currentState.error))return;if(o==="selfhost"){let s=e.currentState.data.envMethod||"manual";Ue({setupComplete:!0,setupMethod:s,repoPath:t}),e.updateData("setupMode",o),e.setStep("Finished"),e.setStatus("Setup complete! Run 'gaia start' to build and start all services in Docker."),await e.waitForInput("exit");return}let n=bt(e);if(!await ln(e,t,r,n))return;await K(1e3);let a=e.currentState.data.envMethod||"manual";Ue({setupComplete:!0,setupMethod:a,repoPath:t}),e.updateData("setupMode",o),e.setStep("Finished"),e.setStatus("Setup complete! Run 'gaia dev' to start development mode."),await e.waitForInput("exit")}async function gn(){await re({command:"setup",whenNonInteractive:"fail",runFlow:fn})}var js=new RegExp("\x1B\\[[0-9;]*m","g");async function hn(e,t){e.setStep("Starting"),e.setStatus("Locating GAIA repository...");let r=U();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 Ee(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...");let c=await Et();if(!c.working){e.setError(new Error(c.errorMessage||`Docker is not running. Please start Docker and try again.
54
+ ${ve.docker}`));return}}let n=fe(r),i=n[3e3]??3e3,a=n[8e3]??8e3;e.updateData("setupMode",o),e.updateData("webPort",i),e.updateData("apiPort",a),e.updateData("dockerLogs",[]),e.setStatus(`Starting GAIA in ${o} mode...`);let s=c=>{let u=c.split(`
55
+ `).map(m=>m.replace(js,"").trim()).filter(m=>m.length>0);if(u.length===0)return;let d=e.currentState.data.dockerLogs||[];e.updateData("dockerLogs",[...d,...u].slice(-30))};try{await qe(r,o,c=>{e.setStatus(c)},n,s,t),e.setStep("Running"),e.setStatus("GAIA is running!"),e.updateData("started",!0)}catch(c){e.setError(new Error(`Failed to start services: ${c.message}`));return}await e.waitForInput("exit")}async function vn(e){await re({command:"start",whenNonInteractive:"plain",autoResolve:[["exit"]],runFlow:t=>hn(t,e)})}import{execa as _r}from"execa";var kr=["gaia-backend","gaia-web","chromadb","postgres","redis","mongo","rabbitmq","arq_worker"];async function Sn(){try{let{stdout:e}=await _r("docker",["inspect","--format","{{.Name}}|{{.State.Status}}|{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}",...kr]),t=new Map;for(let r of e.trim().split(`
56
+ `)){if(!r)continue;let[o,n,i]=r.split("|"),a=o?.replace(/^\//,"")??"";t.set(a,{name:a,status:n==="running"?"running":"stopped",health:i!=="none"?i:void 0})}return kr.map(r=>t.get(r)??{name:r,status:"not_found"})}catch{let e=kr.map(async t=>{try{let{stdout:r}=await _r("docker",["inspect","--format","{{.State.Status}}|{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}",t]),[o,n]=r.trim().split("|");return{name:t,status:o==="running"?"running":"stopped",health:n!=="none"?n:void 0}}catch{return{name:t,status:"not_found"}}});return Promise.all(e)}}async function yn(){try{return await _r("docker",["info"]),!0}catch{return!1}}var Us=[{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 xn(e){let r=Us.map(o=>({...o,port:e?.[o.port]??o.port})).map(o=>o.type==="http"?qs(o.name,o.port,o.path):Hs(o.name,o.port));return Promise.all(r)}async function qs(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 Hs(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 a=Date.now()-o;i.destroy(),n({name:e,port:t,status:"up",latency:a})}),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 wn(){return await yn()?{running:!0,containers:await Sn()}:{running:!1,containers:[]}}async function Vs(e){e.setStep("Checking"),e.setStatus("Checking service health..."),e.updateData("refreshable",!1);let t=U(),r=t?fe(t):void 0,[o,n]=await Promise.all([xn(r),wn()]);e.updateData("services",o),e.updateData("docker",n);let i=o.filter(s=>s.status==="up").length,a=o.length;e.setStep("Results"),e.setStatus(`${i}/${a} services running`),e.updateData("refreshable",!0)}async function En(e){for(;await Vs(e),await e.waitForInput("exit_or_refresh")==="refresh";);}async function bn(){await re({command:"status",whenNonInteractive:"plain",autoResolve:[["exit_or_refresh","exit"]],runFlow:En,onPlainComplete:Ws})}function Ws(e){let t=e.currentState.data.services??[],r=e.currentState.data.docker;Ys(t),Ks(r)}function Xs(e){return e==="up"?"UP":e==="down"?"DOWN":"UNKNOWN"}function Ys(e){if(e.length!==0){console.log(`
57
+ Services:`);for(let t of e){let r=Xs(t.status),o=t.latency===void 0?"--":`${t.latency}ms`,n=t.name.padEnd(12);console.log(` ${n} :${t.port} ${r} ${o}`)}}}function Ks(e){if(e){console.log(`
58
+ Docker: ${e.running?"running":"not running"}`);for(let t of e.containers??[]){let r=t.health?` (${t.health})`:"",o=t.name.padEnd(14);console.log(` ${o} ${t.status}${r}`)}}}async function Tn(e,t){e.setStep("Stopping"),e.setStatus("Locating GAIA repository...");let r=U();if(!r){e.setError(new Error("Could not find GAIA repository. Run from within a cloned gaia repo."));return}e.updateData("repoPath",r),e.updateData("stopMode",t?.forcePorts?"force-ports":"safe");let o=fe(r);try{await Lo(r,n=>{e.setStatus(n)},o,t),e.setStep("Stopped"),e.setStatus(t?.forcePorts?"All services stopped (force-port mode).":"All services stopped (safe mode)."),e.updateData("stopped",!0)}catch(n){e.setError(new Error(`Failed to stop services: ${n.message}`));return}await e.waitForInput("exit")}async function Cn(e){await re({command:"stop",whenNonInteractive:"plain",autoResolve:[["exit"]],runFlow:t=>Tn(t,e)})}import*as Rt from"fs";import*as kt from"path";function Js(e){let t=kt.join(e,".env");return Rt.existsSync(t)?["--env-file",".env"]:[]}async function In(){let e=U();if(!e)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let t=await Ee(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=kt.join(e,"infra","docker"),o=Js(r),n=fe(e),i=Object.keys(n).length>0?me(n):void 0;if(t==="selfhost"){await _e("docker",["compose","-f","docker-compose.selfhost.yml",...o,"logs","-f","--tail","200"],r,i);return}let a=["compose",...o,"logs","-f","--tail","200"],s=kt.join(e,Ao),c=mr(e),u=typeof c=="number"&&ut(c);if(Rt.existsSync(s)&&u){console.log("Streaming app and infrastructure logs..."),process.platform==="win32"?await ct([{cmd:"powershell",args:["-Command",`Get-Content -Path '${s.replace(/'/g,"''")}' -Wait -Tail 200`],cwd:e},{cmd:"docker",args:a,cwd:r,env:i}]):await ct([{cmd:"tail",args:["-n","200","-f",s],cwd:e},{cmd:"docker",args:a,cwd:r,env:i}]);return}Rt.existsSync(s)&&!u?(console.log("Detected stale developer app logs from a previous run. Streaming Docker logs only."),await _e("docker",a,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 _e("docker",a,r,i))}var Z=new Qs;Z.name("gaia").description("CLI tool for setting up and managing GAIA").version(ne);Z.addCommand(ie);Z.command("init").description(le.init).option("--branch <branch>","Git branch to clone").action(async e=>{await mn({branch:e.branch})});Z.command("setup").description(le.setup).action(async()=>{await gn()});Z.command("status").description(le.status).action(async()=>{await bn()});Z.command("start").description(le.start).option("-b, --build","Rebuild Docker images before starting").option("--pull","Pull latest base images before starting").action(async e=>{await vn({build:e.build,pull:e.pull})});Z.command("dev [profile]").description(le.dev).action(async e=>{try{await No(e)}catch(t){console.error(t instanceof Error?t.message:String(t)),process.exit(1)}});Z.command("logs").description(le.logs).action(async()=>{try{await In()}catch(e){console.error(e instanceof Error?e.message:String(e)),process.exit(1)}});Z.command("stop").description(le.stop).option("--force-ports","Aggressively stop processes listening on API/Web ports (may affect non-GAIA processes)").action(async e=>{await Cn({forcePorts:e.forcePorts})});process.argv.slice(2).length||(Z.outputHelp(),process.exit(0));Z.parse();
package/package.json CHANGED
@@ -1,67 +1,71 @@
1
1
  {
2
2
  "name": "@heygaia/cli",
3
- "version": "0.1.15",
4
3
  "description": "CLI tool for setting up and managing GAIA",
4
+ "version": "0.6.0",
5
5
  "type": "module",
6
- "bin": {
7
- "gaia": "./dist/index.js"
8
- },
9
6
  "files": [
10
7
  "dist",
11
8
  "README.md"
12
9
  ],
13
10
  "scripts": {
14
- "dev": "tsx watch src/index.ts",
15
- "build": "esbuild src/index.ts --bundle --platform=node --target=node18 --format=esm --packages=external --outfile=dist/index.js --minify && chmod +x dist/index.js",
16
- "start": "NODE_ENV=production node dist/index.js",
17
- "type-check": "tsc --noEmit",
11
+ "build": "node esbuild.config.mjs && chmod +x dist/index.js",
18
12
  "check": "biome check src",
13
+ "dev": "tsx watch src/index.ts",
19
14
  "fix": "biome check --write src",
15
+ "format": "biome format --write src",
20
16
  "lint": "pnpm run check",
21
17
  "lint:fix": "pnpm run fix",
22
- "format": "biome format --write src",
23
- "prepublishOnly": "pnpm run build"
24
- },
25
- "engines": {
26
- "node": ">=18"
27
- },
28
- "repository": {
29
- "type": "git",
30
- "url": "https://github.com/heygaia/gaia.git",
31
- "directory": "packages/cli"
32
- },
33
- "publishConfig": {
34
- "access": "public"
18
+ "prepublishOnly": "pnpm run build",
19
+ "start": "NODE_ENV=production node dist/index.js",
20
+ "type-check": "tsc --noEmit"
35
21
  },
36
- "keywords": [
37
- "gaia",
38
- "cli",
39
- "ai-assistant",
40
- "setup"
41
- ],
42
- "license": "MIT",
43
22
  "dependencies": {
44
23
  "@inkjs/ui": "^2.0.0",
24
+ "@modelcontextprotocol/sdk": "^1.29.0",
45
25
  "commander": "^14.0.3",
46
26
  "execa": "^9.6.1",
47
- "ink": "^6.6.0",
27
+ "ink": "^6.8.0",
48
28
  "ink-big-text": "^2.0.0",
49
29
  "ink-gradient": "^3.0.0",
50
- "ink-image": "^2.0.0",
51
- "ink-progress-bar": "^3.0.0",
52
30
  "ink-text-input": "^6.0.0",
53
- "react": "^19",
54
- "react-dom": "^19",
55
- "remove": "^0.1.5",
56
- "simple-git": "^3.30.0"
31
+ "react": "19.1.0",
32
+ "react-dom": "19.1.0",
33
+ "simple-git": "^3.36.0",
34
+ "ws": "^8.21.0",
35
+ "zod": "^4.3.6"
57
36
  },
58
37
  "devDependencies": {
59
- "@biomejs/biome": "2.3.7",
60
- "@types/node": "^25.2.2",
61
- "@types/react": "^19",
62
- "@types/react-dom": "^19",
63
- "esbuild": "latest",
64
- "tsx": "latest",
65
- "typescript": "^5.9.2"
38
+ "@biomejs/biome": "^2.5.7",
39
+ "@gaia/shared": "workspace:*",
40
+ "@types/node": "^24.13.3",
41
+ "@types/react": "^19.2.17",
42
+ "@types/react-dom": "^19.2.3",
43
+ "@types/ws": "^8.18.1",
44
+ "esbuild": "^0.25.12",
45
+ "tsx": "^4.23.11",
46
+ "typescript": "^7.0.2",
47
+ "vite": "^7.3.6",
48
+ "vitest": "^4.1.10"
49
+ },
50
+ "bin": {
51
+ "gaia": "./dist/index.js"
52
+ },
53
+ "engines": {
54
+ "node": ">=20"
55
+ },
56
+ "keywords": [
57
+ "ai-assistant",
58
+ "cli",
59
+ "gaia",
60
+ "setup"
61
+ ],
62
+ "license": "MIT",
63
+ "publishConfig": {
64
+ "access": "public"
65
+ },
66
+ "repository": {
67
+ "type": "git",
68
+ "url": "git+https://github.com/theexperiencecompany/gaia.git",
69
+ "directory": "packages/cli"
66
70
  }
67
71
  }