@heygaia/cli 0.1.15 → 0.5.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.
- package/README.md +33 -156
- package/dist/index.js +48 -30
- package/package.json +44 -41
package/README.md
CHANGED
|
@@ -1,52 +1,37 @@
|
|
|
1
1
|
# @heygaia/cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+

|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
CLI tool for setting up and managing [GAIA](https://heygaia.io).
|
|
6
6
|
|
|
7
7
|
## Requirements
|
|
8
8
|
|
|
9
|
-
- **Node.js
|
|
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
|
|
14
|
+
The CLI checks prerequisites at startup and reports what is missing.
|
|
15
15
|
|
|
16
16
|
## Installation
|
|
17
17
|
|
|
18
|
-
|
|
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
|
|
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
|
|
59
|
-
|
|
60
|
-
**Options:**
|
|
43
|
+
Interactive first-time setup.
|
|
61
44
|
|
|
62
45
|
| Flag | Description |
|
|
63
46
|
|------|-------------|
|
|
64
|
-
| `--branch <name>` | Clone a specific branch
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
63
|
+
gaia start
|
|
103
64
|
```
|
|
104
65
|
|
|
105
|
-
|
|
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
|
-
|
|
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
|
-
|
|
71
|
+
### `gaia dev` / `gaia dev full`
|
|
154
72
|
|
|
155
|
-
|
|
73
|
+
Runs developer mode in foreground Nx TUI:
|
|
156
74
|
|
|
157
|
-
-
|
|
158
|
-
-
|
|
75
|
+
- `gaia dev` -> `mise dev`
|
|
76
|
+
- `gaia dev full` -> `mise dev:full`
|
|
159
77
|
|
|
160
|
-
###
|
|
78
|
+
### `gaia logs`
|
|
161
79
|
|
|
162
|
-
|
|
80
|
+
Streams logs for currently running services.
|
|
163
81
|
|
|
164
|
-
|
|
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
|
-
|
|
84
|
+
Stops running GAIA services.
|
|
180
85
|
|
|
181
|
-
|
|
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
|
-
|
|
88
|
+
Shows health and latency for core services.
|
|
190
89
|
|
|
191
|
-
|
|
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
|
-
|
|
197
|
-
|
|
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
|
-
##
|
|
95
|
+
## Port Overrides
|
|
205
96
|
|
|
206
|
-
|
|
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
|
-
|
|
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,52 @@
|
|
|
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
|
-
|
|
4
|
-
`)
|
|
5
|
-
|
|
6
|
-
`),"
|
|
7
|
-
|
|
8
|
-
`)
|
|
2
|
+
import{Command as qi}from"commander";var ie={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{homedir as Ar}from"node:os";import{join as Tn,resolve as Cn}from"node:path";import{Command as In}from"commander";import{existsSync as qe,mkdirSync as Wo,readFileSync as ir,writeFileSync as wt}from"node:fs";import{homedir as Vo}from"node:os";import{join as bt}from"node:path";var j={PING:"ping",MCP_OPEN:"mcp.open",MCP_CLOSE:"mcp.close",MCP_MSG:"mcp.msg",REVOKE:"revoke",PONG:"pong",HELLO:"hello",MCP_OPENED:"mcp.opened",MCP_ERROR:"mcp.error"},Zt="https://api.heygaia.io",ye="filesystem",er=500,tr=6e4,rr=5e3,or=1e6,nr=5e6;var je=bt(Vo(),".gaia","bridge"),De=bt(je,"credentials.json"),xt=bt(je,"config.json");function sr(){qe(je)||Wo(je,{recursive:!0,mode:448})}function de(){if(!qe(De))return null;try{return JSON.parse(ir(De,"utf-8"))}catch{return null}}function xe(e){sr(),wt(De,JSON.stringify(e,null,2),{mode:384})}function ar(){qe(De)&&wt(De,"{}",{mode:384})}function q(){if(!qe(xt))return{servers:[]};try{return{servers:JSON.parse(ir(xt,"utf-8")).servers??[]}}catch{return{servers:[]}}}function cr(e){sr(),wt(xt,JSON.stringify(e,null,2),{mode:384})}function Ue(e){let t=q(),r=t.servers.findIndex(o=>o.key===e.key);r>=0?t.servers[r]=e:t.servers.push(e),cr(t)}function lr(e){let t=q(),r=t.servers.length;return t.servers=t.servers.filter(o=>o.key!==e),cr(t),t.servers.length<r}function pr(){return q().servers.find(e=>e.type==="filesystem"&&e.key===ye)}function He(e){if(e)return e.replace(/\/$/,"");let t=de();return t?.apiUrl?t.apiUrl.replace(/\/$/,""):(process.env.GAIA_API_URL??Zt).replace(/\/$/,"")}import{hostname as Xo,platform as Jo}from"node:os";var ur={name:"@heygaia/cli",description:"CLI tool for setting up and managing GAIA",version:"0.5.0",type:"module",files:["dist","README.md"],scripts:{build:"esbuild src/index.ts --bundle --platform=node --target=node18 --format=esm --packages=external --outfile=dist/index.js --minify && 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","@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 ee=ur.version;var ke=class extends Error{constructor(r,o){super(r);this.status=o;this.name="ApiError"}};async function We(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 ke(i,n.status)}return await n.json()}function dr(e,t,r,o){return We(e,"/device/pair/start",{name:t,platform:r,daemon_version:o})}function mr(e,t){return We(e,"/device/pair/poll",{device_code:t})}function Ve(e,t){return We(e,"/device/token",{refresh_token:t})}function fr(e,t,r,o){return We(e,"/device/servers",{server_key:r,display_name:o},t)}async function Ko(e){await new Promise(t=>setTimeout(t,e))}function gr(){return!!de()?.refreshToken}async function Ye(e={}){let t=He(e.api),r=e.name||Xo(),o=await dr(t,r,Jo(),ee);console.info(`
|
|
3
|
+
To pair this device, open:
|
|
4
|
+
`),console.info(` ${o.verification_url}`),console.info(`
|
|
5
|
+
and enter this code: ${o.user_code}
|
|
6
|
+
`),console.info("Waiting for approval\u2026");let n=Date.now()+o.expires_in*1e3;for(;Date.now()<n;){await Ko(o.interval*1e3);let i;try{i=await mr(t,o.device_code)}catch(a){console.error(`[gaia bridge] poll failed, retrying: ${a instanceof Error?a.message:a}`);continue}if(i.status==="approved"&&i.device_id&&i.refresh_token){xe({apiUrl:t,deviceId:i.device_id,refreshToken:i.refresh_token}),console.info(`
|
|
7
|
+
Paired as "${r}".
|
|
8
|
+
`);return}if(i.status==="denied"||i.status==="expired")throw new Error(`pairing ${i.status}`)}throw new Error("pairing timed out")}import{randomInt as mn}from"node:crypto";import Cr from"ws";import{Client as cn}from"@modelcontextprotocol/sdk/client/index.js";import{getDefaultEnvironment as ln,StdioClientTransport as pn}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as un}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{InMemoryTransport as dn}from"@modelcontextprotocol/sdk/inMemory.js";import{lstat as Qo,readdir as yr,readFile as hr,realpath as zo,stat as Zo,writeFile as en}from"node:fs/promises";import{dirname as vr,extname as tn,join as xr,resolve as rn,sep as on}from"node:path";import{McpServer as nn}from"@modelcontextprotocol/sdk/server/mcp.js";import{z as we}from"zod";var sn={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".gif":"image/gif"},be=class extends Error{};async function Tt(e){try{return await zo(e)}catch{return null}}async function an(e){try{return(await Qo(e)).isSymbolicLink()}catch{return!1}}function Sr(e,t){return e===t||e.startsWith(t+on)}async function Xe(e,t,r){let o=rn(e),n=await Tt(o);if(n){if(t.some(a=>Sr(n,a)))return n;throw new be(`Path is outside your approved folders: ${e}`)}if(r)throw new be(`No such file or directory: ${e}`);let i=await Tt(vr(o));if(!i||!t.some(a=>Sr(i,a)))throw new be(`Path is outside your approved folders: ${e}`);if(await an(o))throw new be(`Refusing to write through a symlink: ${e}`);return xr(i,o.slice(vr(o).length+1))}async function wr(e,t,r,o){if(o.length>=r)return;let n;try{n=await yr(e,{withFileTypes:!0})}catch{return}for(let i of n){if(o.length>=r)return;let a=xr(e,i.name);i.name.toLowerCase().includes(t.toLowerCase())&&o.push(a),i.isDirectory()&&!i.isSymbolicLink()&&await wr(a,t,r,o)}}function br(e){let t=new nn({name:"gaia-filesystem",version:"0.1.0"}),r=null,o=()=>(r||(r=Promise.all(e.allow.map(Tt)).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:we.string().describe("Absolute path to a directory")}},async({path:i})=>{try{let a=await Xe(i,await o(),!0);return{content:[{type:"text",text:(await yr(a,{withFileTypes:!0})).map(p=>`${p.isDirectory()?"dir ":"file"} ${p.name}`).join(`
|
|
9
|
+
`)||"(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:we.string().describe("Absolute path to a file")}},async({path:i})=>{try{let a=await Xe(i,await o(),!0),s=await Zo(a);if(!s.isFile())return n(`Not a file: ${i}`);let c=sn[tn(a).toLowerCase()];if(c){if(s.size>nr)return n(`Image is too large to read (${s.size} bytes).`);let f=await hr(a);return{content:[{type:"text",text:`Image file ${a} (${c}, ${s.size} bytes) \u2014 shown below.`},{type:"image",data:f.toString("base64"),mimeType:c}]}}return s.size>or?n(`File is too large to read (${s.size} bytes).`):{content:[{type:"text",text:await hr(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:we.string().describe("Absolute path to the directory to search under"),query:we.string().describe("Substring to match against names")}},async({path:i,query:a})=>{try{let s=await Xe(i,await o(),!0),c=[];return await wr(s,a,200,c),{content:[{type:"text",text:c.join(`
|
|
10
|
+
`)||"(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:we.string().describe("Absolute path to the file to write"),content:we.string().describe("Text content to write")}},async({path:i,content:a})=>{try{let s=await Xe(i,await o(),!1);return await en(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}async function Ct(e){if(e.type==="url"){let n=new un(new URL(e.url));return{transport:n,close:()=>n.close()}}if(e.type==="stdio"){let n=new pn({command:e.command,args:e.args,env:{...ln(),...e.env}});return{transport:n,close:()=>n.close()}}let[t,r]=dn.createLinkedPair(),o=br(e);return await o.connect(r),{transport:t,close:async()=>{await o.close(),await t.close()}}}async function Tr(e){let t=await Ct(e),r=new cn({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{}}}var Je=class{constructor(t){this.creds=t}ws=null;sessions=new Map;reconnectDelay=er;stopped=!1;async run(){for(;!this.stopped;){try{await this.connectOnce()}catch(t){t instanceof ke&&t.status===401?(console.error("[gaia bridge] this device is no longer authorized (revoked or unpaired). Re-pair with: gaia bridge login"),this.stopped=!0):console.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 t=await Ve(this.creds.apiUrl,this.creds.refreshToken);this.creds={...this.creds,refreshToken:t.refresh_token},xe(this.creds);let r=`${this.creds.apiUrl.replace(/^http/,"ws")}/api/v1/ws/device`,o=new Cr(r,{headers:{authorization:`Bearer ${t.access_token}`}});this.ws=o,await new Promise((n,i)=>{let a=!1,s=!1,c=p=>{s||(s=!0,p())};o.on("open",()=>{a=!0,this.reconnectDelay=rr;let p=q().servers.map(f=>f.key);this.send({t:j.HELLO,servers:p}),console.error(`[gaia bridge] connected \u2014 exposing: ${p.join(", ")||"(nothing configured)"}`)}),o.on("message",p=>{this.onFrame(p.toString())}),o.on("close",()=>{this.closeAllSessions(),this.ws=null,c(()=>a?n():i(new Error("socket closed before open")))}),o.on("error",p=>{a||c(()=>i(p))})})}async onFrame(t){let r;try{r=JSON.parse(t)}catch{return}switch(r.t){case j.PING:this.send({t:j.PONG});return;case j.MCP_OPEN:await this.openSession(r);return;case j.MCP_MSG:await this.forwardToServer(r);return;case j.MCP_CLOSE:await this.closeSession(r.sid);return;case j.REVOKE:console.error("[gaia bridge] this device was revoked \u2014 exiting."),await this.stop();return;default:return}}async openSession(t){let r=t.sid,o=t.server,n=t.pod;if(!r||!o)return;let i=q().servers.find(a=>a.key===o);if(!i){this.send({t:j.MCP_ERROR,sid:r,pod:n,error:`Unknown server '${o}'`});return}try{let a=await Ct(i);a.transport.onmessage=s=>{this.send({t:j.MCP_MSG,sid:r,pod:n,data:JSON.stringify(s)})},a.transport.onclose=()=>{this.sessions.has(r)&&this.send({t:j.MCP_ERROR,sid:r,pod:n,error:`Local server '${o}' exited`}),this.closeSession(r)},await a.transport.start(),this.sessions.set(r,a),this.send({t:j.MCP_OPENED,sid:r,pod:n})}catch(a){this.send({t:j.MCP_ERROR,sid:r,pod:n,error:a instanceof Error?a.message:String(a)})}}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){console.error(`[gaia bridge] forward error: ${o instanceof Error?o.message:o}`)}}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===Cr.OPEN&&this.ws.send(JSON.stringify(t))}async backoff(){let t=mn(this.reconnectDelay);console.error(`[gaia bridge] reconnecting in ${t}ms\u2026`),await new Promise(r=>setTimeout(r,t)),this.reconnectDelay=Math.min(this.reconnectDelay*2,tr)}};async function Ke(){let e=de();if(!e?.refreshToken)throw new Error("not paired \u2014 run: gaia bridge login");if(q().servers.length===0)throw new Error("no servers configured \u2014 run: gaia bridge add");pr()?.allowWrite&&console.error("[gaia bridge] filesystem WRITES are enabled for this device.");let t=await Ve(e.apiUrl,e.refreshToken);xe({...e,refreshToken:t.refresh_token});for(let n of q().servers)await fr(e.apiUrl,t.access_token,n.key,n.name);let r=new Je({...e,refreshToken:t.refresh_token}),o=async()=>{console.error(`
|
|
11
|
+
[gaia bridge] shutting down\u2026`),await r.stop(),process.exit(0)};process.on("SIGINT",()=>void o()),process.on("SIGTERM",()=>void o()),await r.run()}import{basename as Rr}from"node:path";import{createInterface as Ir}from"node:readline/promises";import{Writable as fn}from"node:stream";async function me(e,t){let r=Ir({input:process.stdin,output:process.stdout});try{let o=t?` [${t}]`:"";return(await r.question(`${e}${o}: `)).trim()||t||""}finally{r.close()}}async function Er(e){process.stdout.write(`${e}: `);let t=new fn({write(o,n,i){i()}}),r=Ir({input:process.stdin,output:t,terminal:!0});try{let o=(await r.question("")).trim();return process.stdout.write(`
|
|
12
|
+
`),o}finally{r.close()}}async function _e(e,t=!0){let r=await me(`${e} (${t?"Y/n":"y/N"})`);return r?/^y(es)?$/i.test(r):t}async function It(e,t){for(process.stdout.write(`
|
|
13
|
+
${e}
|
|
14
|
+
`),t.forEach((r,o)=>{process.stdout.write(` ${o+1}. ${r}
|
|
15
|
+
`)});;){let r=await me(`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.
|
|
16
|
+
`)}}function gn(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)}function hn(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 vn(e,t){let o=[...t].reverse().filter(n=>!n.startsWith("-"))[0]??e;return Rr(o).replace(/@[^@]*$/,"")}function Sn(e){try{let t=new URL(e);return t.port?`local-${t.port}`:t.hostname}catch{return""}}async function Dr(e){for(;;){let t=await me("Name for this server",e),r=gn(t);if(!t||!r||r===ye){console.info("Pick a different name.");continue}if(!(q().servers.some(o=>o.key===r)&&!await _e(`'${r}' already exists \u2014 overwrite?`,!1)))return{name:t,key:r}}}function yn(e,t){if(Rr(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 Pr(e){let t=process.env[e];if(t!==void 0&&t!==""&&await _e(` Found ${e} in your environment \u2014 use that value?`,!0))return t;for(;;){let r=await Er(` 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 kr(e,t){let r={};for(let n of yn(e,t))console.info(`
|
|
17
|
+
The command needs ${n}.`),r[n]=await Pr(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 _e(o,!1))return r;for(console.info("Enter each variable's name; leave blank when done.");;){let n=(await me(" Variable name")).trim();if(!n)break;if(n in r){console.info(" Already added.");continue}r[n]=await Pr(n)}return r}async function xn(){console.info(`
|
|
18
|
+
Examples: npx -y my-mcp-server \xB7 uvx my-server \xB7 docker run -i --rm my/image`);let e=await me("Command that starts your MCP server");if(!e)throw new Error("a command is required");let{command:t,args:r}=hn(e),o=await kr(t,r),{name:n,key:i}=await Dr(vn(t,r));return{type:"stdio",key:i,name:n,command:t,args:r,env:o}}async function wn(){let e=await me("Server URL (e.g. http://localhost:3000/mcp)");if(!e)throw new Error("a URL is required");let{name:t,key:r}=await Dr(Sn(e));return{type:"url",key:r,name:t,url:e}}async function bn(e){for(;;){console.info(`
|
|
19
|
+
Testing the connection (this may download/start the server)\u2026`);try{let t=await Tr(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 It("What now?",r)];if(o==="Re-enter environment variables"&&e.type==="stdio")e.env=await kr(e.command,e.args);else{if(o==="Save anyway (fix it later)")return!0;if(o==="Abort")return!1}}}}async function _r(){gr()||(console.info("This device isn't paired with GAIA yet \u2014 let's do that first."),await Ye());let t=await It("How does your MCP server run?",["A command starts it (stdio) \u2014 npx / uvx / docker / python \u2026","It's already running at a local URL \u2014 e.g. http://localhost:3000/mcp"])===0?await xn():await wn();if(!await bn(t))throw new Error("aborted");Ue(t),console.info(`
|
|
20
|
+
Saved '${t.key}'.`),await _e("Connect to GAIA now (gaia bridge up)?")?await Ke():console.info("Run `gaia bridge up` whenever you're ready.")}function En(e){return e==="~"?Ar():e.startsWith("~/")?Tn(Ar(),e.slice(2)):e}function Pn(e,t){let r=e.map(o=>Cn(En(o)));Ue({type:"filesystem",key:ye,name:"Local Files",allow:r,allowWrite:t}),console.info(`Filesystem access configured for:
|
|
21
|
+
${r.join(`
|
|
22
|
+
`)}
|
|
23
|
+
Writes: ${t?"ENABLED":"disabled (read-only)"}
|
|
24
|
+
Run: gaia bridge up`)}function Rn(){let e=de();console.info(e?.deviceId?`Paired (device ${e.deviceId}, ${He()})`:"Not paired \u2014 run: gaia bridge login");let t=q().servers;if(t.length===0){console.info("No servers configured \u2014 run: gaia bridge add");return}console.info(`
|
|
25
|
+
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}`)}async function fe(e){try{await e()}catch(t){console.error(`Error: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}}var te=new In("bridge").description("Connect this machine's local MCP servers and files to GAIA (outbound-only, no inbound ports)").addHelpText("after",`
|
|
26
|
+
Revoke a device anytime from GAIA \u2192 Settings \u2192 Devices.`);te.command("add").description("Connect a local MCP server (guided \u2014 start here!)").action(async()=>{await fe(_r)});te.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 fe(async()=>{await Ye({...e.api!==void 0?{api:e.api}:{},...e.name!==void 0?{name:e.name}:{}}),console.info("Next: gaia bridge add")})});te.command("fs").description("Expose folders for file access (read-only unless --write)").argument("<dirs...>","Folders to expose, e.g. ~/Documents").option("--write","Allow GAIA to write to these folders").action(async(e,t)=>{await fe(()=>Pn(e,t.write===!0))});te.command("ls").alias("list").description("Show pairing status and configured servers").action(async()=>{await fe(Rn)});te.command("rm").alias("remove").description("Remove a configured server").argument("<key>","Server key from `gaia bridge ls`").action(async e=>{await fe(()=>{console.info(lr(e)?`Removed '${e}'`:`No server '${e}'`)})});te.command("up").alias("start").description("Connect and serve (holds the tunnel; Ctrl+C to stop)").action(async()=>{await fe(Ke)});te.command("logout").description("Forget local credentials").action(async()=>{await fe(()=>{ar(),console.info("Logged out. Your device record remains until you revoke it in GAIA settings.")})});import*as tt from"fs";import*as Qr from"path";import{spawn as Dn}from"child_process";async function Te(e,t,r,o,n,i=!1){await Qe([{cmd:e,args:t,cwd:r,env:o,onSpawn:n,detached:i}])}async function Qe(e){e.length!==0&&await new Promise((t,r)=>{let o=e.map(d=>Dn(d.cmd,d.args,{cwd:d.cwd,stdio:"inherit",shell:!1,detached:d.detached??!1,env:d.env?{...process.env,...d.env}:process.env}));o.forEach((d,m)=>{e[m]?.onSpawn?.(d.pid)});let n=!1,i=0,a=!1,s,c=()=>{process.off("SIGINT",f),process.off("SIGTERM",f)},p=()=>{if(!a){a=!0;for(let[d,m]of o.entries()){let S=e[d];try{process.platform!=="win32"&&S?.detached&&typeof m.pid=="number"?process.kill(-m.pid,"SIGTERM"):m.kill("SIGTERM")}catch{}}s=setTimeout(()=>{for(let[d,m]of o.entries()){let S=e[d];try{process.platform!=="win32"&&S?.detached&&typeof m.pid=="number"?process.kill(-m.pid,"SIGKILL"):m.kill("SIGKILL")}catch{}}},1e3)}},f=()=>{p()};process.on("SIGINT",f),process.on("SIGTERM",f),o.forEach((d,m)=>{let S=e[m];d.on("error",v=>{n||(n=!0,c(),p(),r(v))}),d.on("close",(v,y)=>{if(i+=1,!(v===0||(y==="SIGINT"||y==="SIGTERM"||v===130||v===143||a))&&!n){n=!0,c(),p(),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 J from"fs";import*as W from"path";import*as re from"fs";import*as Or from"os";import*as Rt from"path";var Et=Rt.join(Or.homedir(),".gaia"),Pt=Rt.join(Et,"config.json");function kn(){re.existsSync(Et)||re.mkdirSync(Et,{recursive:!0})}function Dt(){try{if(!re.existsSync(Pt))return null;let e=re.readFileSync(Pt,"utf-8");return JSON.parse(e)}catch{return null}}function ze(e){kn(),re.writeFileSync(Pt,`${JSON.stringify(e,null,2)}
|
|
27
|
+
`)}function Ae(e){let r={...Dt()??{version:ee,setupComplete:!1,setupMethod:"manual",repoPath:"",createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()},...e,updatedAt:new Date().toISOString()};ze(r)}import*as F from"fs";import*as Ee from"path";import*as Ie from"node:fs";import*as Ce from"node:path";import{execa as Mr}from"execa";var kt={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/"}},Nr={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 _t(e,t){return kt[t][e]??Nr[t][e]}async function Lr(e){let t=Ce.join(e,"apps/api/scripts/dump_config_schema.py"),r=Ce.join(e,"apps/api/app/config/settings_validator.py"),o=Ce.join(e,"apps/api/app/config/settings.py");if(!Ie.existsSync(t))throw new Error("dump_config_schema.py not found in apps/api/scripts");try{try{let{stdout:n}=await Mr("python3",[t,r,o],{cwd:e});return JSON.parse(n)}catch{let{stdout:n}=await Mr("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 Br(e){let t=Ce.join(e,"apps","web",".env.local"),r=Ie.existsSync(t)?t:Ce.join(e,"apps","web",".env");if(!Ie.existsSync(r))return[];let o=Ie.readFileSync(r,"utf-8"),n=[],i="General";for(let a of o.split(`
|
|
28
|
+
`)){let s=a.trim();if(s.startsWith("#")&&!s.startsWith("#=")){let d=s.replace(/^#+\s*/,"").trim();d&&!d.startsWith("These are")&&(i=d);continue}if(!s||s.startsWith("#"))continue;let c=s.indexOf("=");if(c===-1)continue;let p=s.substring(0,c).trim(),f=s.substring(c+1).trim();n.push({name:p,value:f,category:i})}return n}function Fr(e,t){return{NEXT_PUBLIC_API_BASE_URL:`http://localhost:${t?.[8e3]??8e3}/api/v1/`}}function $r(e,t,r){let o=r==="selfhost"?new Set(Object.keys(kt.selfhost)):new Set;for(let[n,i]of Object.entries(t)){let a=Number(n),s=Number(i);for(let[c,p]of Object.entries(e)){if(o.has(c))continue;if(p===String(a)){e[c]=String(s);continue}let f=new RegExp(`:${a}(?=[/\\s]|$)`,"g");e[c]=p.replaceAll(f,`:${s}`)}}}function Gr(e,t){return e.map(r=>({...r,variables:r.variables.map(o=>{let n=_t(o.name,t);return{...o,defaultValue:n||o.defaultValue}})}))}function At(){return Object.keys(kt.selfhost)}function jr(e){return{...Nr[e]}}function Ot(e){F.existsSync(e)&&F.copyFileSync(e,`${e}.bak`)}function Ur(e,t){let r=Ee.join(e,".env");Ot(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 p of n)if(s===p||s.startsWith(`${p}_`))return p;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 p=i(s);a.has(p)||a.set(p,[]);let d=/[\s#"'\\]/.test(c)||c===""?`"${c.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`:c;a.get(p).push(`${s}=${d}`)}for(let[s,c]of a.entries())o.push(`# ${s} Configuration`),o.push(...c),o.push("");F.writeFileSync(r,o.join(`
|
|
29
|
+
`),"utf-8")}function Hr(e,t,r){let o=Ee.join(e,"apps","web",".env.local");Ot(o);let n=Br(e),i=Fr(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 p=i[c.name]??c.value;s.get(c.category).push({name:c.name,value:p})}if(n.length===0){a.push("# Core URLs");for(let[c,p]of Object.entries(i))a.push(`${c}=${p}`);a.push("")}else for(let[c,p]of s.entries()){a.push(`# ${c}`);for(let{name:f,value:d}of p)a.push(`${f}=${d}`);a.push("")}F.writeFileSync(o,a.join(`
|
|
30
|
+
`),"utf-8")}var Wr={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 Vr(e,t,r){let o=Ee.join(e,"infra","docker",".env");Ot(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=Wr[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(""),F.writeFileSync(o,n.join(`
|
|
31
|
+
`),"utf-8")}function se(e){let t={};for(let[r,o]of Object.entries(e)){let n=Number(r),i=Wr[n];i&&(t[i]=String(o))}return t}function Yr(e){let t=Ee.join(e,"infra","docker","docker-compose.yml");if(!F.existsSync(t))return;let r=F.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}"`,p=`"\${${i}:-${a}}:${s}"`;r.includes(c)&&(r=r.replaceAll(c,p),n=!0)}n&&F.writeFileSync(t,r,"utf-8")}var qr={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 ae(e){let t=Ee.join(e,"infra","docker",".env"),r={};if(!F.existsSync(t))return r;let o=F.readFileSync(t,"utf-8");for(let n of o.split(`
|
|
32
|
+
`)){let i=n.trim();if(i&&!i.startsWith("#")){let[a,...s]=i.split("=");if(a&&qr[a]){let c=s.join("=").trim().replace(/^["']|["']$/g,""),p=Number(c);!Number.isNaN(p)&&p>0&&p<=65535&&(r[qr[a]]=p)}}}return r}var On=e=>new Promise(t=>setTimeout(t,e)),Xr="dev-start.log",et=".gaia-dev.pid";function Jr(e){let t=W.join(e,".env");return J.existsSync(t)?["--env-file",".env"]:[]}var Mn=60;function Nn(){let e=process.env.GAIA_START_TIMEOUT_MIN?.trim(),t=e?Number(e):Number.NaN,r=Number.isFinite(t)&&t>=0?t:Mn;return r===0?void 0:r*60*1e3}function Ln(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 Mt(e){let t=W.join(e,et);if(!J.existsSync(t))return null;try{let r=Number.parseInt(J.readFileSync(t,"utf-8").trim(),10);return Number.isNaN(r)||r<=0?null:r}catch{return null}}function Ze(e){try{return process.kill(e,0),!0}catch(t){return t.code==="EPERM"}}async function Oe(e,t,r,o,n,i){if(t!=="selfhost")throw r?.("Developer mode must run in foreground."),new Error("Developer mode runs in foreground. Use 'gaia dev' or 'gaia dev full' instead of 'gaia start'.");r?.(i?.build?"Building 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?se(o):void 0;await U("docker",Ln(Jr(a),i),a,void 0,n,s,Nn()),r?.("All services started in Docker!")}async function Kr(e,t,r,o){let n=W.join(e,"infra/docker"),i=await ge(e);t?.("Stopping Docker services...");try{let a=Jr(n),s=i==="selfhost"?["compose","-f","docker-compose.selfhost.yml",...a,"down"]:["compose",...a,"down"];await U("docker",s,n)}catch{}if(i!=="selfhost"){t?.("Stopping GAIA-managed local processes (safe mode)...");let a=W.join(e,et),s=!1,c=Mt(e),p=typeof c=="number";if(c&&Ze(c))try{if(process.platform==="win32")await U("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 On(800),Ze(c))try{process.kill(-c,"SIGKILL")}catch{process.kill(c,"SIGKILL")}}}catch{}try{J.unlinkSync(a)}catch{}if(!s&&o?.forcePorts){t?.("No GAIA PID found. Force-stopping listeners on app ports...");try{let f=r?.[8e3]??8e3,d=r?.[3e3]??3e3;if(process.platform==="win32")for(let m of[f,d])try{await U("powershell",["-Command",`Get-NetTCPConnection -LocalPort ${m} -ErrorAction SilentlyContinue | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force -ErrorAction SilentlyContinue }`],e)}catch{}else for(let m of[f,d])try{await U("sh",["-c",`lsof -ti :${m} -sTCP:LISTEN | xargs kill 2>/dev/null || true`],e)}catch{}}catch{}}else s||t?.(p?"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 ge(e){let t=W.join(e,"apps","api",".env");if(!J.existsSync(t))return null;let r=J.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 U(e,t,r,o,n,i,a){let{spawn:s}=await import("child_process");return new Promise((c,p)=>{let f=s(e,t,{cwd:r,stdio:["ignore","pipe","pipe"],shell:!0,env:i?{...process.env,...i}:void 0}),d="",m=0,S=!1,v;a&&(v=setTimeout(()=>{S=!0,f.kill("SIGTERM"),p(new Error(`Command timed out after ${Math.round(a/6e4)}m. Check \`docker compose logs\` to debug.`))},a)),f.stdout?.on("data",y=>{let w=y.toString();d+=w,n?.(w),m=Math.min(m+5,95),o?.(m)}),f.stderr?.on("data",y=>{let w=y.toString();d+=w,n?.(w),m=Math.min(m+5,95),o?.(m)}),f.on("close",y=>{v&&clearTimeout(v),!S&&(y===0?(o?.(100),c()):p(new Error(`Command failed with code ${y}: ${d.slice(-500)}`)))}),f.on("error",y=>{v&&clearTimeout(v),!S&&p(y)})})}function $(e){let t=e||process.cwd();for(;t!==W.dirname(t);){if(J.existsSync(W.join(t,"apps/api/app/config/settings_validator.py")))return t;t=W.dirname(t)}let r=Dt();if(r?.repoPath){if(J.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.`),Ae({repoPath:"",setupComplete:!1})}return null}async function zr(e){if(e&&e!=="full")throw new Error(`Invalid developer profile: '${e}'. Use 'gaia dev' or 'gaia dev full'.`);let t=$();if(!t)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let r=await ge(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=Qr.join(t,et);try{await Te("mise",[e==="full"?"dev:full":"dev"],t,void 0,n=>{typeof n=="number"&&n>0&&tt.writeFileSync(o,`${n}
|
|
33
|
+
`)},process.platform!=="win32")}finally{try{tt.unlinkSync(o)}catch{}}}import{render as fi}from"ink";import gi from"react";import{Box as ct,Text as ve}from"ink";import li from"react";import{ProgressBar as oo,Select as Bt,Spinner as Vn}from"@inkjs/ui";import{Box as g,Text as u,useInput as ce}from"ink";import Le from"ink-text-input";import{useEffect as Be,useRef as Yn,useState as B}from"react";import{Box as Me,Text as rt}from"ink";var x="#00bbff";import{Box as Bn,Text as Fn}from"ink";import{jsx as Zr}from"react/jsx-runtime";var eo=({status:e,step:t})=>t.toLowerCase()==="welcome"?null:Zr(Bn,{width:"100%",paddingX:1,marginTop:1,children:Zr(Fn,{color:"gray",dimColor:!0,children:e})});import{Box as $n}from"ink";import Gn from"ink-big-text";import jn from"ink-gradient";import{jsx as Nt}from"react/jsx-runtime";var Pe=()=>Nt($n,{flexDirection:"column",marginTop:1,marginBottom:1,children:Nt(jn,{colors:[x,"#b0eaff",x],children:Nt(Gn,{text:"GAIA",font:"3d"})})});import{jsx as he,jsxs as Ne}from"react/jsx-runtime";var qn=["Welcome","Prerequisites","Setup Mode","Repository Setup","Environment Setup","Install Tools","Project Setup","Finished"],to=["Detect Repo","Prerequisites","Environment Setup","Project Setup","Finished"],Un={Welcome:"Welcome",Prerequisites:"Prereqs","Setup Mode":"Mode","Repository Setup":"Repo","Environment Setup":"Env","Install Tools":"Tools","Project Setup":"Setup","Detect Repo":"Detect",Finished:"Done"},Hn=({currentStep:e,steps:t})=>{let r=t.indexOf(e);return he(Me,{marginBottom:1,flexWrap:"nowrap",children:t.map((o,n)=>{let i=n<r,a=n===r,s=Un[o]??o;return Ne(Me,{flexShrink:0,children:[n>0&&Ne(rt,{color:"gray",dimColor:!0,children:[" ","\xB7"," "]}),i&&Ne(rt,{color:"green",children:["\u2713 ",s]}),a&&he(rt,{color:x,bold:!0,children:s}),!i&&!a&&he(rt,{color:"gray",dimColor:!0,children:s})]},o)})})},ot=({children:e,status:t,step:r,steps:o=qn})=>Ne(Me,{flexDirection:"column",height:"100%",width:"100%",children:[Ne(Me,{flexGrow:1,flexDirection:"column",children:[he(Pe,{}),he(Hn,{currentStep:r,steps:o}),he(Me,{flexDirection:"column",flexGrow:1,children:e})]}),he(eo,{status:t,step:r})]});import{Spinner as ro}from"@inkjs/ui";import{Box as G,Text as M,useInput as Wn}from"ink";import{jsx as R,jsxs as H}from"react/jsx-runtime";var nt=({checks:e})=>H(G,{flexDirection:"column",borderStyle:"round",paddingX:1,borderColor:x,children:[R(M,{bold:!0,children:"System Checks"}),H(G,{flexDirection:"column",marginTop:1,children:[R(Lt,{label:"Git",status:e.git}),R(Lt,{label:"Docker",status:e.docker}),e.mise&&R(Lt,{label:"Mise",status:e.mise})]})]}),it=({status:e})=>H(G,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:x,children:[R(M,{bold:!0,children:"Environment Setup"}),R(G,{marginTop:1,children:R(ro,{label:e||"Configuring environment..."})})]}),st=({message:e})=>H(G,{flexDirection:"column",borderStyle:"single",borderColor:"red",padding:1,marginTop:2,children:[H(M,{color:"red",children:["Error: ",e]}),R(G,{marginTop:1,children:H(M,{dimColor:!0,children:[R(M,{bold:!0,children:"Enter"})," to exit"]})})]}),Lt=({label:e,status:t})=>H(G,{children:[R(G,{marginRight:1,children:t==="pending"?R(ro,{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})]}),at=({portResults:e,onAccept:t,onAbort:r})=>{Wn((n,i)=>{i.return?t():i.escape&&r()});let o=e.filter(n=>!n.available);return H(G,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:"yellow",children:[R(G,{marginBottom:1,children:R(M,{bold:!0,color:"yellow",children:"Port Conflicts Detected"})}),e.map(n=>H(G,{children:[H(M,{color:n.available?"green":n.alternative?"yellow":"red",children:[n.available?"\u2714":n.alternative?"\u26A0":"\u2716"," "]}),H(M,{children:[n.service," (:",n.port,")"]}),!n.available&&H(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(G,{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(G,{marginTop:1,children:R(M,{color:"gray",children:"Alternative ports will be used for conflicting services."})}),R(G,{marginTop:1,children:H(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 Xn=({onConfirm:e})=>(ce((t,r)=>{r.return&&e()}),h(g,{flexDirection:"column",paddingX:2,borderStyle:"round",borderColor:x,children:[l(u,{bold:!0,children:"Welcome to GAIA Setup"}),h(g,{flexDirection:"column",marginTop:1,marginBottom:1,children:[l(u,{children:"This wizard will guide you through the setup process:"}),l(u,{children:" 1. Check prerequisites and choose setup mode"}),l(u,{children:" 2. Clone repository"}),l(u,{children:" 3. Configure environment variables"}),l(u,{children:" 4. Install tools and dependencies"})]}),l(u,{dimColor:!0,children:"~5-15 min depending on network speed"}),l(g,{marginTop:1,children:h(u,{color:x,children:[l(u,{bold:!0,children:"Enter"})," to start"]})})]})),Jn=({defaultValue:e,onSubmit:t})=>{let[r,o]=B(e);return h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:x,children:[l(u,{children:"Clone repository to:"}),l(u,{color:"gray",dimColor:!0,children:"Press Enter for default, or type a custom path"}),h(g,{marginTop:1,children:[l(u,{color:x,children:"\u2192 "}),l(Le,{value:r,onChange:o,onSubmit:t})]})]})},Kn=({repoPath:e,onAction:t})=>h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:"yellow",children:[l(g,{marginBottom:1,children:l(u,{bold:!0,color:"yellow",children:"Existing Installation Found"})}),h(u,{children:["Found a GAIA installation at"," ",l(u,{color:"cyan",bold:!0,children:e})]}),l(g,{marginTop:1,children:l(u,{color:"gray",children:"What would you like to do?"})}),l(g,{marginTop:1,children:l(Bt,{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)})})]}),Qn=({setupMode:e,portOverrides:t,onConfirm:r})=>{ce((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(u,{bold:!0,color:"green",children:"GAIA is Running!"}),l(g,{marginTop:1,children:l(u,{color:"green",children:"\u2713 All services started"})}),h(g,{marginTop:1,flexDirection:"column",children:[h(u,{children:["Web:"," ",h(u,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),h(u,{children:["API:"," ",h(u,{color:"cyan",bold:!0,children:["http://localhost:",n]})]})]}),l(g,{marginTop:1,children:l(u,{color:"gray",children:"gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup"})}),l(g,{marginTop:1,children:h(u,{dimColor:!0,children:[l(u,{bold:!0,children:"Enter"})," to exit"]})})]}):h(g,{flexDirection:"column",marginTop:2,borderStyle:"round",borderColor:x,padding:1,children:[l(u,{color:x,bold:!0,children:"You're all set!"}),h(g,{marginTop:1,children:[l(u,{bold:!0,children:"Run: "}),l(u,{color:"cyan",children:"$ gaia dev"})]}),h(g,{marginTop:1,flexDirection:"column",children:[h(u,{children:["Web:"," ",h(u,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),h(u,{children:["API:"," ",h(u,{color:"cyan",bold:!0,children:["http://localhost:",n]})]})]}),l(g,{marginTop:1,children:l(u,{color:"gray",children:"gaia dev full \xB7 gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup"})}),l(g,{marginTop:1,children:h(u,{dimColor:!0,children:[l(u,{bold:!0,children:"Enter"})," to exit"]})})]})},zn=8,Zn=({logs:e,height:t=zn})=>{let[r,o]=B(0),n=Yn(e.length);Be(()=>{e.length!==n.current&&(n.current=e.length,o(0))},[e.length]),ce((d,m)=>{m.upArrow?o(S=>Math.min(S+1,Math.max(0,e.length-t))):m.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),p=a,f=r;return h(g,{flexDirection:"column",marginTop:1,marginLeft:1,children:[p>0&&h(u,{color:"gray",dimColor:!0,children:["\u2191 ",p," more line",p!==1?"s":""]}),l(g,{flexDirection:"column",height:t,overflow:"hidden",children:c.map((d,m)=>l(u,{color:"gray",wrap:"truncate",children:d},`${a}-${m}`))}),f>0?h(u,{color:"gray",dimColor:!0,children:["\u2193 ",f," more line",f!==1?"s":""]}):l(u,{color:"gray",dimColor:!0,children:"\u2191\u2193 scroll"})]})},Ft=({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(u,{bold:!0,color:x,children:n||"Installing Dependencies"})}),h(g,{flexDirection:"column",gap:1,children:[l(g,{children:r?h(u,{color:"green",children:["\u2713 ",e]}):l(Vn,{label:e||"Preparing..."})}),!r&&t>0&&l(g,{width:50,children:l(oo,{value:t})}),!r&&o&&o.length>0&&l(Zn,{logs:o}),!r&&l(g,{marginTop:1,children:l(u,{color:"gray",dimColor:!0,children:"This may take a few minutes..."})})]})]}),$t=({onSelect:e})=>h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:x,children:[l(u,{bold:!0,children:"Setup Mode"}),l(g,{marginTop:1,children:l(u,{color:"gray",children:"How do you want to run GAIA?"})}),l(g,{marginTop:1,children:l(Bt,{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)})})]}),Gt=({onSelect:e})=>h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:x,children:[l(u,{bold:!0,children:"Environment Variables Setup"}),l(g,{marginTop:1,children:l(u,{color:"gray",children:"Choose how you want to configure environment variables:"})}),l(g,{marginTop:1,children:l(Bt,{options:[{label:"Manual Setup (Recommended)",value:"manual"},{label:"Infisical (Advanced)",value:"infisical"}],onChange:r=>e(r)})}),h(g,{marginTop:1,flexDirection:"column",children:[l(u,{color:"gray",dimColor:!0,children:"Manual Setup: Configure variables interactively (recommended for most users)"}),l(u,{color:"gray",dimColor:!0,children:"Infisical: All secrets managed in Infisical dashboard (requires pre-configuration)"})]})]}),jt=({onSubmit:e})=>{let[t,r]=B({INFISICAL_PROJECT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET:""}),[o,n]=B(0),[i,a]=B(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"}];ce((p,f)=>{if(f.tab||f.downArrow)n(d=>d<s.length-1?d+1:d);else if(f.upArrow)n(d=>d>0?d-1:d);else if(f.return){if(o<s.length-1){n(m=>m+1);return}let d=s.filter(m=>!t[m.key].trim());if(d.length>0){a(`Required: ${d.map(S=>S.key).join(", ")}`);let m=s.findIndex(S=>!t[S.key].trim());m>=0&&n(m);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(u,{bold:!0,color:x,children:"Infisical Configuration"})}),l(g,{marginBottom:1,children:l(u,{color:"gray",children:"All secrets managed in your Infisical project. Only credentials stored locally."})}),h(g,{marginBottom:1,flexDirection:"column",children:[l(u,{color:"gray",children:"Configure your Infisical credentials."}),h(u,{color:"gray",dimColor:!0,children:["Visit"," ",l(u,{color:"cyan",underline:!0,children:"app.infisical.com"})," ","to get these values."]})]}),s.map((p,f)=>{let d=p.key.includes("SECRET")||p.key.includes("TOKEN");return h(g,{flexDirection:"column",marginBottom:1,children:[l(g,{children:h(u,{color:f===o?x:"white",children:[f===o?"\u25B8 ":" ",p.key,":"]})}),l(g,{marginLeft:2,children:l(u,{color:"gray",dimColor:!0,children:p.description})}),f===o?l(g,{marginLeft:2,children:l(Le,{value:t[p.key],onChange:m=>{r(S=>({...S,[p.key]:m})),a(null)},placeholder:"Enter value...",mask:d?"*":void 0})}):l(g,{marginLeft:2,children:l(u,{color:t[p.key]?"green":"gray",children:t[p.key]?d?`\u2713 ${"*".repeat(8)}`:`\u2713 ${t[p.key]}`:"(not set)"})})]},p.key)}),i&&l(g,{marginTop:1,children:l(u,{color:"red",children:i})}),l(g,{marginTop:1,children:h(u,{dimColor:!0,children:[l(u,{bold:!0,children:"Enter"})," confirm \xB7 ",l(u,{bold:!0,children:"\u2191\u2193"})," navigate"]})})]})},qt=({category:e,currentIndex:t,totalGroups:r,onSubmit:o})=>{let[n,i]=B(()=>{let m={};for(let S of e.variables)m[S.name]=S.defaultValue||"";return m}),[a,s]=B(0),[c,p]=B(null);Be(()=>{let m={};for(let S of e.variables)m[S.name]=S.defaultValue||"";i(m),s(0),p(null)},[e.name]),ce((m,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){p(`Required fields cannot be skipped: ${v.map(y=>y.name).join(", ")}`);return}o(n)}});let f=()=>{if(a<e.variables.length-1)s(a+1);else{let m=e.variables.filter(S=>S.required&&!n[S.name]?.trim());if(m.length>0){p(`Required fields are missing: ${m.map(S=>S.name).join(", ")}`);return}p(null),o(n)}},d=e.variables.some(m=>m.required);return h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:c?"red":x,children:[h(g,{justifyContent:"space-between",children:[h(u,{bold:!0,children:["Configure ",e.name]}),h(u,{color:"gray",children:["Group ",t+1," / ",r]})]}),l(g,{marginTop:1,children:l(u,{color:"gray",children:e.description})}),l(g,{marginTop:1,flexDirection:"column",children:e.variables.map((m,S)=>{let v=S===a,y=!!m.defaultValue;return h(g,{flexDirection:"column",marginBottom:1,children:[h(g,{children:[h(u,{color:v?x:"gray",bold:v,children:[v?"\u279C ":" ",m.name]}),m.required&&h(u,{color:"red",bold:!0,children:[" ","*"]}),y&&!v&&h(u,{color:"gray",dimColor:!0,children:[" ","(default: ",m.defaultValue,")"]})]}),v&&l(g,{marginLeft:2,children:l(Le,{value:n[m.name]||"",onChange:w=>{i(b=>({...b,[m.name]:w})),c&&p(null)},onSubmit:f,placeholder:y?`Default: ${m.defaultValue}`:m.required?"Enter a value (required)":"Press Enter to skip"})})]},m.name)})}),c&&l(g,{marginTop:1,children:h(u,{color:"red",bold:!0,children:["\u26A0 ",c]})}),l(g,{marginTop:1,children:h(u,{dimColor:!0,children:[l(u,{bold:!0,children:"Enter"})," next \xB7 ",l(u,{bold:!0,children:"\u2191\u2193"})," navigate",!d&&h(u,{children:[" ","\xB7 ",l(u,{bold:!0,children:"ESC"})," skip"]})]})})]})},Ut=({alternatives:e,onSubmit:t})=>{let[r,o]=B(new Set),[n,i]=B({}),[a,s]=B(0),[c,p]=B(null);Be(()=>{let w={};for(let b of e)for(let E of b.variables)w[E.name]=E.defaultValue||"";i(w)},[e]);let f=[];for(let w=0;w<e.length;w++)if(f.push({type:"provider",categoryIndex:w}),r.has(w)){let b=e[w];if(b)for(let E=0;E<b.variables.length;E++)f.push({type:"field",categoryIndex:w,fieldIndex:E})}f.push({type:"submit"});let d=f[a],m=d?.type==="field",S=d?.type==="submit";ce((w,b)=>{let E=Math.min(a,f.length-1);if(E!==a){s(E);return}if(m)b.upArrow?s(P=>Math.max(0,P-1)):(b.downArrow||b.tab)&&s(P=>Math.min(f.length-1,P+1));else if(S)b.upArrow?s(P=>Math.max(0,P-1)):(b.return||w===" ")&&y();else if(b.upArrow)s(P=>Math.max(0,P-1));else if(b.downArrow||b.tab)s(P=>Math.min(f.length-1,P+1));else if((b.return||w===" ")&&d?.type==="provider"){let P=d.categoryIndex;o(Z=>{let _=new Set(Z);return _.has(P)?_.delete(P):_.add(P),_}),c&&p(null)}});let v=()=>{c&&p(null),s(w=>Math.min(f.length-1,w+1))},y=()=>{let w=[],b={};for(let E of r){let P=e[E];if(!P)continue;if(P.variables.some(_=>n[_.name]?.trim())){w.push(P.name);for(let _ of P.variables){let Ge=n[_.name];Ge&&(b[_.name]=Ge)}}}if(w.length===0){r.size===0?p("Enable at least one provider (press Space or Enter)"):p("Enter a value for at least one field");return}t(w,b)};return h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:c?"red":x,children:[h(g,{justifyContent:"space-between",children:[l(u,{bold:!0,children:"Configure AI Provider"}),l(u,{color:"yellow",children:"* At least one required"})]}),l(g,{marginTop:1,children:l(u,{color:"gray",children:"Enable and configure at least one AI provider below:"})}),l(g,{marginTop:1,flexDirection:"column",children:e.map((w,b)=>{let E=r.has(b),P=f.findIndex(_=>_.type==="provider"&&_.categoryIndex===b),Z=a===P;return h(g,{flexDirection:"column",marginBottom:1,children:[h(g,{children:[l(u,{color:Z?x:void 0,bold:Z,children:Z?"\u279C ":" "}),l(u,{color:E?"green":"gray",children:E?"[\u2714]":"[ ]"}),h(u,{color:E?x:"gray",bold:E,children:[" ",w.name]}),w.description&&h(u,{color:"gray",dimColor:!0,children:[" ","- ",w.description]})]}),Z&&w.docsUrl&&h(g,{marginLeft:6,children:[l(u,{color:"yellow",children:"\u{1F4D6} "}),l(u,{color:"blue",underline:!0,children:w.docsUrl})]}),E&&l(g,{marginLeft:4,flexDirection:"column",marginTop:1,children:w.variables.map((_,Ge)=>{let Uo=f.findIndex(Re=>Re.type==="field"&&Re.categoryIndex===b&&Re.fieldIndex===Ge),Se=a===Uo,zt=!!_.defaultValue,yt=n[_.name]||"";return h(g,{flexDirection:"column",marginBottom:1,children:[h(g,{children:[h(u,{color:Se?x:"gray",bold:Se,children:[Se?" \u279C ":" ",_.name]}),!Se&&yt&&l(u,{color:"green",children:" \u2713"}),!Se&&!yt&&zt&&h(u,{color:"gray",dimColor:!0,children:[" ","(default: ",_.defaultValue,")"]})]}),Se&&l(g,{marginLeft:4,children:l(Le,{value:yt,onChange:Re=>{i(Ho=>({...Ho,[_.name]:Re})),c&&p(null)},onSubmit:v,placeholder:zt?`Default: ${_.defaultValue}`:"Enter value..."})})]},_.name)})})]},w.name)})}),c&&l(g,{marginTop:1,children:h(u,{color:"red",bold:!0,children:["\u26A0 ",c]})}),h(g,{marginTop:1,children:[l(u,{color:S?x:void 0,bold:S,children:S?"\u279C ":" "}),l(g,{borderStyle:"round",borderColor:S?x:"gray",paddingX:2,children:l(u,{color:S?x:"gray",bold:S,children:"Continue \u2192"})})]}),l(g,{marginTop:1,children:l(u,{color:"gray",dimColor:!0,children:"\u2191/\u2193 navigate \u2022 Space/Enter toggle/select \u2022 Tab skip field"})})]})},Ht=({currentVar:e,currentIndex:t,totalCount:r,onSubmit:o,onSkip:n})=>{let[i,a]=B(e.defaultValue||""),[s,c]=B(null);Be(()=>{a(e.defaultValue||""),c(null)},[e.name]),ce((d,m)=>{if(m.escape){if(e.required&&!i.trim()){c("This field is required and cannot be skipped");return}n()}});let p=d=>{if(e.required&&!d.trim()){c("This field is required");return}c(null),o(d)},f=!!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(u,{color:x,bold:!0,children:e.name}),e.required?l(u,{color:"red",children:" *"}):h(u,{color:"gray",dimColor:!0,children:[" ","optional"]})]}),h(u,{color:"gray",children:[t+1,"/",r]})]}),l(g,{marginLeft:1,children:l(u,{color:"gray",children:e.description})}),h(g,{marginTop:1,children:[l(u,{color:x,children:"\u2192 "}),l(Le,{value:i,onChange:d=>{a(d),s&&c(null)},onSubmit:p,placeholder:f?`Default: ${e.defaultValue}`:e.required?"required":"skip with Enter"})]}),s&&l(g,{marginTop:1,children:l(u,{color:"red",children:s})}),l(g,{marginTop:1,children:h(u,{dimColor:!0,children:[l(u,{bold:!0,children:"Enter"})," confirm",!e.required&&h(u,{children:[" ","\xB7 ",l(u,{bold:!0,children:"ESC"})," skip"]})]})})]})},no=({store:e})=>{let[t,r]=B(e.currentState);return Be(()=>{let o=()=>r({...e.currentState});return e.on("change",o),()=>{e.off("change",o)}},[e]),ce((o,n)=>{(n.return||n.escape)&&t.error&&e.submitInput("exit")}),h(ot,{status:t.status,step:t.step,children:[t.step==="Welcome"&&t.inputRequest?.id==="welcome"&&l(Xn,{onConfirm:()=>e.submitInput(!0)}),t.step==="Prerequisites"&&t.data.checks&&l(nt,{checks:t.data.checks}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&l(at,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="repo_path"&&l(Jn,{defaultValue:t.inputRequest.meta.default,onSubmit:o=>e.submitInput(o)}),t.inputRequest?.id==="existing_repo"&&t.data.existingRepoPath&&l(Kn,{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(u,{bold:!0,children:"Cloning Repository"}),h(g,{marginTop:1,flexDirection:"column",children:[l(oo,{value:t.data.repoProgress||0}),t.data.repoPhase&&l(g,{marginTop:1,children:l(u,{color:"gray",children:t.data.repoPhase})})]})]}),t.inputRequest?.id==="setup_mode"&&l($t,{onSelect:o=>e.submitInput(o)}),t.inputRequest?.id==="env_method"&&l(Gt,{onSelect:o=>e.submitInput(o)}),t.inputRequest?.id==="env_infisical"&&l(jt,{onSubmit:o=>e.submitInput(o)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&l(Ht,{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(qt,{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(Ut,{alternatives:t.data.alternativeGroups,onSubmit:(o,n)=>e.submitInput({selectedGroups:o,values:n})}),t.step==="Environment Setup"&&!t.inputRequest&&l(it,{status:t.status}),t.step==="Finished"&&l(Qn,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,onConfirm:()=>e.submitInput("exit")}),(t.step==="Install Tools"||t.step==="Project Setup")&&l(Ft,{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(st,{message:t.error.message})]})};import{Spinner as ei}from"@inkjs/ui";import{Box as N,Text as C,useInput as io}from"ink";import{useEffect as so,useRef as ti,useState as ao}from"react";import{jsx as A,jsxs as T}from"react/jsx-runtime";var Wt=8,ri=({logs:e})=>{let[t,r]=ao(0),o=ti(e.length);so(()=>{e.length!==o.current&&(o.current=e.length,r(0))},[e.length]),io((f,d)=>{d.upArrow?r(m=>Math.min(m+1,Math.max(0,e.length-Wt))):d.downArrow&&r(m=>Math.max(0,m-1))});let n=e.length,i=Math.max(0,n-Wt-t),a=Math.max(0,n-t),s=e.slice(i,a),c=i,p=t;return T(N,{flexDirection:"column",marginTop:1,marginLeft:1,children:[c>0&&T(C,{color:"gray",dimColor:!0,children:["\u2191 ",c," more line",c!==1?"s":""]}),A(N,{flexDirection:"column",height:Wt,overflow:"hidden",children:s.map((f,d)=>A(C,{color:"gray",wrap:"truncate",children:f},i+d))}),p>0?T(C,{color:"gray",dimColor:!0,children:["\u2193 ",p," more line",p!==1?"s":""]}):A(C,{color:"gray",dimColor:!0,children:"\u2191\u2193 scroll"})]})},co=({store:e})=>{let[t,r]=ao(e.currentState);return so(()=>{let o=()=>r({...e.currentState});return e.on("change",o),()=>{e.off("change",o)}},[e]),io((o,n)=>{(n.return||n.escape)&&(t.data.started||t.data.stopped||t.error)&&e.submitInput("exit")}),T(N,{flexDirection:"column",width:"100%",children:[A(Pe,{}),(t.step==="Starting"||t.step==="Stopping")&&T(N,{flexDirection:"column",marginTop:1,paddingX:2,borderStyle:"round",borderColor:x,children:[A(ei,{label:t.status||"Working..."}),t.data.repoPath&&A(N,{marginTop:1,children:T(C,{color:"gray",children:["Repository: ",t.data.repoPath]})}),t.data.setupMode&&A(N,{children:T(C,{color:"gray",children:["Mode: ",t.data.setupMode]})}),t.data.dockerLogs&&t.data.dockerLogs.length>0&&A(ri,{logs:t.data.dockerLogs})]}),t.step==="Running"&&t.data.started&&T(N,{flexDirection:"column",marginTop:1,paddingX:2,paddingY:1,borderStyle:"round",borderColor:"green",children:[T(C,{color:"green",bold:!0,children:["\u2713"," GAIA is running!"]}),t.data.setupMode!=="developer"&&T(N,{marginTop:1,flexDirection:"column",children:[T(C,{children:["Web:"," ",T(C,{color:"cyan",bold:!0,children:["http://localhost:",t.data.webPort||3e3]})]}),T(C,{children:["API:"," ",T(C,{color:"cyan",bold:!0,children:["http://localhost:",t.data.apiPort||8e3]})]})]}),t.data.setupMode==="developer"&&T(N,{marginTop:1,flexDirection:"column",children:[T(N,{flexDirection:"column",children:[T(C,{children:["Web:"," ",T(C,{color:"cyan",bold:!0,children:["http://localhost:",t.data.webPort||3e3]})]}),T(C,{children:["API:"," ",T(C,{color:"cyan",bold:!0,children:["http://localhost:",t.data.apiPort||8e3]})]})]}),T(N,{marginTop:1,flexDirection:"column",children:[A(C,{color:"gray",children:"Use gaia dev / gaia dev full for foreground Nx TUI."}),T(C,{color:"gray",children:["Run ",A(C,{color:x,children:"gaia logs"})," to stream logs."]}),T(C,{color:"gray",children:["Run ",A(C,{color:x,children:"gaia stop"})," to shut down."]})]})]}),A(N,{marginTop:1,children:T(C,{dimColor:!0,children:[A(C,{bold:!0,children:"Enter"})," to exit"]})})]}),t.step==="Stopped"&&t.data.stopped&&T(N,{flexDirection:"column",marginTop:1,paddingX:2,paddingY:1,borderStyle:"round",borderColor:x,children:[T(C,{color:x,bold:!0,children:["\u2713"," ",t.status||"All GAIA services stopped."]}),t.data.stopMode==="force-ports"&&A(N,{marginTop:1,children:A(C,{color:"yellow",children:"Force-port cleanup was enabled and may have stopped non-GAIA listeners on app ports."})}),A(N,{marginTop:1,children:T(C,{dimColor:!0,children:[A(C,{bold:!0,children:"Enter"})," to exit"]})})]}),t.error&&T(N,{borderStyle:"single",borderColor:"red",padding:1,marginTop:2,children:[T(C,{color:"red",children:["Error: ",t.error.message]}),A(N,{marginTop:1,children:T(C,{dimColor:!0,children:[A(C,{bold:!0,children:"Enter"})," to exit"]})})]})]})};import{Spinner as oi}from"@inkjs/ui";import{Box as le,Text as V,useInput as lo}from"ink";import{useEffect as ni,useState as ii}from"react";import{jsx as D,jsxs as K}from"react/jsx-runtime";var po=({store:e})=>{let[t,r]=ii(e.currentState);return ni(()=>{let o=()=>r({...e.currentState});return e.on("change",o),()=>{e.off("change",o)}},[e]),lo((o,n)=>{(n.return||n.escape)&&t.error&&e.submitInput("exit")}),K(ot,{status:t.status,step:t.step,steps:to,children:[t.step==="Detect Repo"&&K(le,{flexDirection:"column",paddingX:2,borderStyle:"round",borderColor:x,children:[D(V,{bold:!0,children:"Detecting GAIA Repository"}),D(le,{marginTop:1,children:D(oi,{label:"Searching for repository..."})}),t.data.repoPath&&D(le,{marginTop:1,children:K(V,{color:"green",children:["Found: ",t.data.repoPath]})})]}),t.step==="Prerequisites"&&t.data.checks&&D(nt,{checks:t.data.checks}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&D(at,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="setup_mode"&&D($t,{onSelect:o=>e.submitInput(o)}),t.inputRequest?.id==="env_method"&&D(Gt,{onSelect:o=>e.submitInput(o)}),t.inputRequest?.id==="env_infisical"&&D(jt,{onSubmit:o=>e.submitInput(o)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&D(Ht,{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(qt,{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(Ut,{alternatives:t.data.alternativeGroups,onSubmit:(o,n)=>e.submitInput({selectedGroups:o,values:n})}),t.step==="Environment Setup"&&!t.inputRequest&&D(it,{status:t.status}),t.step==="Project Setup"&&D(Ft,{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(si,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,onConfirm:()=>e.submitInput("exit")}),t.error&&D(st,{message:t.error.message})]})},si=({setupMode:e,portOverrides:t,onConfirm:r})=>{lo((a,s)=>{s.return&&r()});let o=t?.[3e3]??3e3,n=t?.[8e3]??8e3,i=e==="selfhost";return K(le,{flexDirection:"column",marginTop:2,borderStyle:"round",borderColor:x,padding:1,children:[D(V,{color:x,bold:!0,children:"Setup Complete!"}),K(le,{marginTop:1,children:[D(V,{bold:!0,children:"Run: "}),D(V,{color:"cyan",children:i?"$ gaia start":"$ gaia dev"})]}),K(le,{marginTop:1,flexDirection:"column",children:[K(V,{children:["Web:"," ",K(V,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),K(V,{children:["API:"," ",K(V,{color:"cyan",bold:!0,children:["http://localhost:",n]})]})]}),D(le,{marginTop:1,children:D(V,{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"})}),D(le,{marginTop:1,children:K(V,{dimColor:!0,children:[D(V,{bold:!0,children:"Enter"})," to exit"]})})]})};import{Spinner as ai}from"@inkjs/ui";import{Box as O,Text as k,useInput as ci}from"ink";import{useEffect as uo,useState as Vt}from"react";import{jsx as I,jsxs as L}from"react/jsx-runtime";var mo=({store:e})=>{let[t,r]=Vt(e.currentState),[o,n]=Vt(!1),[i,a]=Vt(null);return uo(()=>{let s=()=>r({...e.currentState});return e.on("change",s),()=>{e.off("change",s)}},[e]),uo(()=>{n(!1),a(new Date().toLocaleTimeString())},[t.data.services]),ci((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"))}),L(O,{flexDirection:"column",width:"100%",children:[I(Pe,{}),t.step==="Checking"&&I(O,{marginTop:1,children:I(ai,{label:t.data.services?"Refreshing service health...":"Checking service health..."})}),t.step==="Results"&&t.data.services&&L(O,{flexDirection:"column",children:[L(O,{flexDirection:"column",borderStyle:"round",borderColor:x,paddingX:2,paddingY:1,children:[L(O,{justifyContent:"space-between",children:[I(k,{bold:!0,color:x,children:"GAIA Service Status"}),i&&L(k,{color:"gray",dimColor:!0,children:["checked ",i," \xB7 ",I(k,{bold:!0,children:"r"})," refresh"]})]}),L(O,{marginTop:1,flexDirection:"column",children:[L(O,{children:[I(O,{width:22,children:I(k,{bold:!0,children:"Service"})}),I(O,{width:10,children:I(k,{bold:!0,children:"Status"})}),I(O,{width:10,children:I(k,{bold:!0,children:"Latency"})})]}),I(k,{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=>L(O,{children:[I(O,{width:22,children:L(k,{children:[s.name," (:",s.port,")"]})}),I(O,{width:10,children:I(k,{color:s.status==="up"?"green":"red",bold:!0,children:s.status==="up"?"\u2713 UP":"\u2717 DOWN"})}),I(O,{width:10,children:I(k,{color:"gray",children:s.latency?`${s.latency}ms`:"--"})})]},s.name))]})]}),t.data.docker&&L(O,{flexDirection:"column",borderStyle:"round",borderColor:"gray",paddingX:2,paddingY:1,marginTop:1,children:[I(k,{bold:!0,children:"Docker Containers"}),L(k,{color:"gray",children:["Docker:"," ",t.data.docker.running?I(k,{color:"green",children:"Running"}):I(k,{color:"red",children:"Not running"})]}),t.data.docker.containers?.length>0&&I(O,{marginTop:1,flexDirection:"column",children:t.data.docker.containers.map(s=>L(O,{children:[L(k,{color:s.status==="running"?"green":"red",children:[s.status==="running"?"\u2713":"\u2717"," "]}),I(k,{children:s.name}),s.health&&L(k,{color:"gray",children:[" (",s.health,")"]})]},s.name))})]}),I(O,{marginTop:1,children:L(k,{dimColor:!0,children:[I(k,{bold:!0,children:"Enter"})," exit \xB7 ",I(k,{bold:!0,children:"r"})," refresh"]})})]}),t.error&&I(O,{borderStyle:"single",borderColor:"red",padding:1,marginTop:2,children:L(k,{color:"red",children:["Error: ",t.error.message]})})]})};import{jsx as Y,jsxs as Fe}from"react/jsx-runtime";var pi=["init","setup","status","start","stop"],Yt=class extends li.Component{constructor(t){super(t),this.state={error:null}}static getDerivedStateFromError(t){return{error:t}}render(){return this.state.error?Fe(ct,{flexDirection:"column",padding:1,children:[Y(ve,{color:"red",bold:!0,children:"An unexpected error occurred:"}),Y(ve,{color:"red",children:this.state.error.message}),this.state.error.stack&&Y(ct,{marginTop:1,children:Y(ve,{color:"gray",dimColor:!0,children:this.state.error.stack})})]}):this.props.children}},ui=({store:e,command:t})=>{switch(t){case"init":return Y(no,{store:e});case"setup":return Y(po,{store:e});case"status":return Y(mo,{store:e});case"start":case"stop":return Y(co,{store:e,command:t});default:return Fe(ct,{flexDirection:"column",padding:1,children:[Fe(ve,{color:"red",children:["Unknown command: ",t]}),Fe(ct,{marginTop:1,flexDirection:"column",children:[Y(ve,{bold:!0,children:"Available commands:"}),pi.map(r=>Fe(ve,{children:[" ",Y(ve,{color:"cyan",children:r})]},r))]})]})}},fo=({store:e,command:t})=>Y(Yt,{children:Y(ui,{store:e,command:t})});import{EventEmitter as di}from"events";var mi=150,Xt=class extends di{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))},mi))}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())}},go=()=>new Xt;function Jt(){return process.stdin.isTTY===!0&&process.stdout.isTTY===!0}function ho(e){if(Jt())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 vo(e){let t="",r="",o="";e.on("change",n=>{n.step&&n.step!==t&&(t=n.step,console.info(`
|
|
34
|
+
[${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 hi=50,vi=130;async function z(e){let t=go();if(e.whenNonInteractive==="fail"){ho(e.command),await So(t,e);return}Jt()?await So(t,e):await Si(t,e)}async function Si(e,t){vo(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)}yo(e)}async function So(e,t){let{unmount:r}=fi(gi.createElement(fo,{store:e,command:t.command})),o=()=>{r(),process.exit(vi)};process.once("SIGINT",o),process.once("SIGTERM",o),await new Promise(n=>setTimeout(n,hi));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(),yo(e)}function yo(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 ne from"fs";import*as Po from"os";import*as ue from"path";import*as xo from"path";var yi=e=>new Promise(t=>setTimeout(t,e));async function lt(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 pt(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=At();for(let c of a){let p=_t(c,r);p&&(i[c]=p)}let s=jr(r);for(let[c,p]of Object.entries(s))i[c]=p;if(n==="infisical")await xi(e,i),e.setStatus("Infisical credentials saved. Ensure your Infisical project contains all required variables.");else try{await wi(e,t,i,r)}catch(c){e.setError(c);return}o&&$r(i,o,r);try{await bi(e,t,i,r,o)}catch(c){e.setError(c);return}await yi(1e3)}async function xi(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 wi(e,t,r,o){e.setStatus("Parsing environment variables...");let n;try{n=await Lr(t),n=Gr(n,o)}catch(v){throw o==="selfhost"?new Error(`Manual environment setup requires Python to parse config schema.
|
|
9
35
|
For self-host mode, we recommend using Infisical for secret management.
|
|
10
36
|
Alternatively, install Python 3.11+ and try again.
|
|
11
37
|
|
|
12
|
-
Original error: ${
|
|
13
|
-
`);for(let
|
|
14
|
-
`);if(n.length>1)return n[1]?.split(/\s+/)?.[0]||void 0}catch{}}async function
|
|
15
|
-
`).filter(
|
|
16
|
-
Installation guides:`),t==="error"&&
|
|
17
|
-
`))),null}return{gitStatus:t,dockerStatus:o,dockerInfo:r
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
$
|
|
23
|
-
`)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
`).
|
|
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();
|
|
38
|
+
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)),p=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,b]of Object.entries(y.values))b&&(r[w]=b)}let f=At(),m=[...c.flatMap(v=>v.variables).filter(v=>!f.includes(v.name))].sort((v,y)=>v.required&&!y.required?-1:!v.required&&y.required?1:0);e.updateData("envVarTotal",m.length);for(let v=0;v<m.length;v++){let y=m[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=[...p].filter(v=>!v.variables.every(y=>f.includes(y.name))).sort((v,y)=>{let w=v.variables.some(E=>E.required),b=y.variables.some(E=>E.required);return w&&!b?-1:!w&&b?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[b,E]of Object.entries(w)){let P=y.variables.find(Z=>Z.name===b);(E||P?.required||P?.defaultValue)&&(r[b]=E||P?.defaultValue||"")}}}async function bi(e,t,r,o,n){e.setStatus("Writing API environment file...");try{let a=xo.join(t,"apps","api");Ur(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{Hr(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&&Yr(t),Vr(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 oe}from"execa";var pe={git:"https://git-scm.com/downloads",docker:"https://docs.docker.com/get-docker/",mise:"https://mise.jdx.dev/getting-started.html"},Ti={8e3:"API Server",5432:"PostgreSQL",6379:"Redis",27017:"MongoDB",5672:"RabbitMQ",3e3:"Web Frontend",8080:"ChromaDB",8083:"Mongo Express"};async function wo(){try{return await oe("git",["--version"]),"success"}catch{return"error"}}async function ut(){let e=!1,t=!1,r;try{await oe("docker",["--version"]),e=!0}catch{return{name:"Docker",installUrl:pe.docker,installed:!1,working:!1,errorMessage:"Docker is not installed"}}try{await oe("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:pe.docker,installed:e,working:t,errorMessage:r}}async function bo(){try{return await oe("mise",["--version"]),"success"}catch{return"missing"}}async function To(){if((await import("node:os")).platform()==="win32")try{return await oe("powershell",["-Command","irm https://mise.jdx.dev/install.ps1 | iex"]),!0}catch{return!1}try{return await oe("sh",["-c","curl https://mise.jdx.dev/install.sh | sh"]),!0}catch{return!1}}async function Co(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=Ti[n]||`Port ${n}`;if(await o(n))r.push({port:n,service:i,available:!0});else{let s=await Ci(n),c=await Ii(n+1,n+100,o);r.push({port:n,service:i,available:!1,usedBy:s,alternative:c||void 0})}}return r}async function Ci(e){if((await import("node:os")).platform()==="win32"){try{let{stdout:o}=await oe("netstat",["-ano","-p","TCP"]),n=o.trim().split(`
|
|
39
|
+
`);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 oe("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 oe("lsof",["-i",`:${e}`,"-sTCP:LISTEN","-P","-n"]),n=o.trim().split(`
|
|
40
|
+
`);if(n.length>1)return n[1]?.split(/\s+/)?.[0]||void 0}catch{}}async function Ii(e,t,r){for(let o=e;o<=t;o++)if(await r(o))return o;return null}var X=e=>new Promise(t=>setTimeout(t,e)),dt=(e,t="dependencyLogs")=>r=>{let o=e.currentState.data[t]||[],n=r.split(`
|
|
41
|
+
`).filter(i=>i.trim()!=="");e.updateData(t,[...o,...n].slice(-30))};async function mt(e){e.updateData("checks",{git:"pending",docker:"pending"}),await X(500);let t=await wo();e.updateData("checks",{...e.currentState.data.checks,git:t});let r=await ut(),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(`
|
|
42
|
+
Installation guides:`),t==="error"&&i.push(` \u2022 Git: ${pe.git}`),o==="error"&&(r.installed?i.push(" \u2022 Docker: Start Docker Desktop or run 'sudo systemctl start docker'"):i.push(` \u2022 Docker: ${pe.docker}`)),e.setError(new Error(i.join(`
|
|
43
|
+
`))),null}return{gitStatus:t,dockerStatus:o,dockerInfo:r}}async function ft(e){e.updateData("checks",{...e.currentState.data.checks,mise:"pending"});let t=await bo();return e.updateData("checks",{...e.currentState.data.checks,mise:t}),t==="missing"&&(e.setStatus("Installing Mise..."),t=await To()?"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.
|
|
44
|
+
\u2022 Mise: ${pe.mise}`)),null):"success"}async function gt(e){e.setStatus("Checking Ports...");let r=await Co([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 X(1e3),o}async function Io(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 U("mise",["trust"],t,void 0,o),e.updateData("dependencyProgress",20),e.updateData("dependencyPhase","Installing tools..."),await U("mise",["install"],t,i=>{e.updateData("dependencyProgress",20+i*.3)},o),e.updateData("dependencyPhase","Running mise setup...");let n=Object.keys(r).length>0?se(r):void 0;return await U("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 Pi}from"execa";import ht from"fs";import Ri from"simple-git";async function Eo(e,t,r,o){if(ht.existsSync(e)){let n=`${e}/.git`;if(!ht.existsSync(n))throw new Error(`Directory ${e} exists but is not a git repository`);await Ri().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=Pi("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 f=Math.min(100,parseInt(c[1],10)),d=c[2],m=c[3];r(10+Math.floor(f*.5),`Receiving objects: ${d}/${m}`)}let p=s.match(/Resolving deltas:\s+(\d+)%\s+\((\d+)\/(\d+)\)/);if(p?.[1]){let f=Math.min(100,parseInt(p[1],10)),d=p[2],m=p[3];r(60+Math.floor(f*.4),`Resolving deltas: ${d}/${m}`)}}),await i,r(100,"Clone complete")}catch(n){throw ht.existsSync(e)&&ht.rmSync(e,{recursive:!0,force:!0}),n}}var ki=process.env.GAIA_CLI_DEV==="true",_i=new RegExp("\x1B\\[[0-9;]*m","g");async function Ro(e,t){e.setStep("Welcome"),e.setStatus("Waiting for user input..."),await e.waitForInput("welcome");let r=dt(e);if(e.setStep("Prerequisites"),e.setStatus("Checking system requirements..."),!await mt(e))return;let o=await gt(e);if(o===null)return;let n=await lt(e);if(n==="developer"&&!await ft(e))return;let i="";if(ki){if(i=$()||"",!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 X(500),e.setStatus("Repository ready!")}else{e.setStep("Repository Setup");let s=n==="selfhost"?ue.join(Po.homedir(),"gaia"):ue.resolve("gaia"),c=!0;for(i=s;;){if(i=await e.waitForInput("repo_path",{default:s}),ue.isAbsolute(i)||(i=ue.resolve(i)),ne.existsSync(i)){if(!ne.statSync(i).isDirectory()){e.setError(new Error(`Path ${i} exists and is not a directory.`)),await X(2e3),e.setError(null);continue}if(ne.existsSync(ue.join(i,"apps/api/app/config/settings_validator.py"))){e.updateData("existingRepoPath",i);let m=await e.waitForInput("existing_repo");if(m==="use_existing"){c=!1;break}else if(m==="delete_reclone"){e.setStatus("Removing existing installation...");try{ne.rmSync(i,{recursive:!0,force:!0})}catch(S){e.setError(new Error(`Failed to remove directory: ${S.message}
|
|
45
|
+
Try removing it manually: rm -rf "${i}"`));return}break}else{if(m==="different_path")continue;e.setError(new Error("Setup cancelled by user."));return}}if(ne.readdirSync(i).length>0){e.setError(new Error(`Directory ${i} is not empty and is not a GAIA installation. Please choose another path.`)),await X(2e3),e.setError(null);continue}}break}if(c){e.setStep("Repository Setup"),e.setStatus("Preparing repository..."),e.updateData("repoProgress",0),e.updateData("repoPhase","");try{await Eo(i,"https://github.com/theexperiencecompany/gaia.git",(p,f)=>{e.updateData("repoProgress",p),f?(e.updateData("repoPhase",f),e.setStatus(`${f}...`)):e.setStatus(`Cloning repository to ${i}... ${p}%`)},t),e.setStatus("Repository ready!")}catch(p){e.setError(p);return}}else e.setStatus("Using existing repository!")}if(await X(1e3),await pt(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=f=>{let d=f.split(`
|
|
46
|
+
`).map(S=>S.replace(_i,"").trim()).filter(S=>S.length>0);if(d.length===0)return;let m=e.currentState.data.dependencyLogs||[];e.updateData("dependencyLogs",[...m,...d].slice(-30))},c=!1;try{e.setStatus("Pulling pre-built images from registry..."),await Oe(i,"selfhost",f=>e.setStatus(f),o,s,{pull:!0}),c=!0}catch(f){let d=f.message?.split(`
|
|
47
|
+
`)[0]??"unknown error";e.setStatus(`Registry pull failed (${d}) \u2014 building images locally (this takes a few minutes)...`)}if(!c)try{await Oe(i,"selfhost",f=>e.setStatus(f),o,s,{build:!0})}catch(f){e.setError(new Error(`Failed to start services: ${f.message}`));return}e.updateData("dependencyProgress",100),e.updateData("dependencyComplete",!0);let p=e.currentState.data.envMethod||"manual";ze({version:ee,setupComplete:!0,setupMethod:p,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 U("mise",["trust"],i,void 0,r),e.updateData("dependencyProgress",50),e.updateData("dependencyPhase","Installing tools (node, python, uv, nx)..."),await U("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 X(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?se(o):void 0;await U("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 X(1e3);let a=e.currentState.data.envMethod||"manual";ze({version:ee,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 Do(e={}){await z({command:"init",whenNonInteractive:"fail",runFlow:t=>Ro(t,e.branch)})}async function ko(e){e.setStep("Detect Repo"),e.setStatus("Looking for GAIA repository...");let t=$();if(!t){e.setError(new Error("Could not find GAIA repository. Run this command from within a cloned gaia repo, or use 'gaia init' to set up from scratch."));return}if(e.updateData("repoPath",t),e.setStatus(`Found repository at ${t}`),await X(1e3),e.setStep("Prerequisites"),e.setStatus("Checking system requirements..."),!await mt(e))return;let r=await gt(e);if(r===null)return;let o=await lt(e);if(o==="developer"&&!await ft(e)||(await pt(e,t,o,r),e.currentState.error))return;if(o==="selfhost"){let s=e.currentState.data.envMethod||"manual";Ae({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=dt(e);if(!await Io(e,t,r,n))return;await X(1e3);let a=e.currentState.data.envMethod||"manual";Ae({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 _o(){await z({command:"setup",whenNonInteractive:"fail",runFlow:ko})}var Ai=new RegExp("\x1B\\[[0-9;]*m","g");async function Ao(e,t){e.setStep("Starting"),e.setStatus("Locating GAIA repository...");let r=$();if(!r){e.setError(new Error("Could not find GAIA repository. Run from within a cloned gaia repo."));return}e.updateData("repoPath",r);let o=await ge(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 ut();if(!c.working){e.setError(new Error(c.errorMessage||`Docker is not running. Please start Docker and try again.
|
|
48
|
+
${pe.docker}`));return}}let n=ae(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 p=c.split(`
|
|
49
|
+
`).map(d=>d.replace(Ai,"").trim()).filter(d=>d.length>0);if(p.length===0)return;let f=e.currentState.data.dockerLogs||[];e.updateData("dockerLogs",[...f,...p].slice(-30))};try{await Oe(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 Oo(e){await z({command:"start",whenNonInteractive:"plain",autoResolve:[["exit"]],runFlow:t=>Ao(t,e)})}import{execa as Qt}from"execa";var Kt=["gaia-backend","gaia-web","chromadb","postgres","redis","mongo","rabbitmq","arq_worker"];async function Mo(){try{let{stdout:e}=await Qt("docker",["inspect","--format","{{.Name}}|{{.State.Status}}|{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}",...Kt]),t=new Map;for(let r of e.trim().split(`
|
|
50
|
+
`)){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 Kt.map(r=>t.get(r)??{name:r,status:"not_found"})}catch{let e=Kt.map(async t=>{try{let{stdout:r}=await Qt("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 No(){try{return await Qt("docker",["info"]),!0}catch{return!1}}var Oi=[{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 Lo(e){let r=Oi.map(o=>({...o,port:e?.[o.port]??o.port})).map(o=>o.type==="http"?Mi(o.name,o.port,o.path):Ni(o.name,o.port));return Promise.all(r)}async function Mi(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 Ni(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 Bo(){return await No()?{running:!0,containers:await Mo()}:{running:!1,containers:[]}}async function Li(e){e.setStep("Checking"),e.setStatus("Checking service health..."),e.updateData("refreshable",!1);let t=$(),r=t?ae(t):void 0,[o,n]=await Promise.all([Lo(r),Bo()]);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 Fo(e){for(;await Li(e),await e.waitForInput("exit_or_refresh")==="refresh";);}async function $o(){await z({command:"status",whenNonInteractive:"plain",autoResolve:[["exit_or_refresh","exit"]],runFlow:Fo,onPlainComplete:Bi})}function Bi(e){let t=e.currentState.data.services??[],r=e.currentState.data.docker;$i(t),Gi(r)}function Fi(e){return e==="up"?"UP":e==="down"?"DOWN":"UNKNOWN"}function $i(e){if(e.length!==0){console.log(`
|
|
51
|
+
Services:`);for(let t of e){let r=Fi(t.status),o=t.latency===void 0?"--":`${t.latency}ms`,n=t.name.padEnd(12);console.log(` ${n} :${t.port} ${r} ${o}`)}}}function Gi(e){if(e){console.log(`
|
|
52
|
+
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 Go(e,t){e.setStep("Stopping"),e.setStatus("Locating GAIA repository...");let r=$();if(!r){e.setError(new Error("Could not find GAIA repository. Run from within a cloned gaia repo."));return}e.updateData("repoPath",r),e.updateData("stopMode",t?.forcePorts?"force-ports":"safe");let o=ae(r);try{await Kr(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 jo(e){await z({command:"stop",whenNonInteractive:"plain",autoResolve:[["exit"]],runFlow:t=>Go(t,e)})}import*as vt from"fs";import*as St from"path";function ji(e){let t=St.join(e,".env");return vt.existsSync(t)?["--env-file",".env"]:[]}async function qo(){let e=$();if(!e)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let t=await ge(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=St.join(e,"infra","docker"),o=ji(r),n=ae(e),i=Object.keys(n).length>0?se(n):void 0;if(t==="selfhost"){await Te("docker",["compose","-f","docker-compose.selfhost.yml",...o,"logs","-f","--tail","200"],r,i);return}let a=["compose",...o,"logs","-f","--tail","200"],s=St.join(e,Xr),c=Mt(e),p=typeof c=="number"&&Ze(c);if(vt.existsSync(s)&&p){console.log("Streaming app and infrastructure logs..."),process.platform==="win32"?await Qe([{cmd:"powershell",args:["-Command",`Get-Content -Path '${s.replace(/'/g,"''")}' -Wait -Tail 200`],cwd:e},{cmd:"docker",args:a,cwd:r,env:i}]):await Qe([{cmd:"tail",args:["-n","200","-f",s],cwd:e},{cmd:"docker",args:a,cwd:r,env:i}]);return}vt.existsSync(s)&&!p?(console.log("Detected stale developer app logs from a previous run. Streaming Docker logs only."),await Te("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 Te("docker",a,r,i))}var Q=new qi;Q.name("gaia").description("CLI tool for setting up and managing GAIA").version(ee);Q.addCommand(te);Q.command("init").description(ie.init).option("--branch <branch>","Git branch to clone").action(async e=>{await Do({branch:e.branch})});Q.command("setup").description(ie.setup).action(async()=>{await _o()});Q.command("status").description(ie.status).action(async()=>{await $o()});Q.command("start").description(ie.start).option("-b, --build","Rebuild Docker images before starting").option("--pull","Pull latest base images before starting").action(async e=>{await Oo({build:e.build,pull:e.pull})});Q.command("dev [profile]").description(ie.dev).action(async e=>{try{await zr(e)}catch(t){console.error(t instanceof Error?t.message:String(t)),process.exit(1)}});Q.command("logs").description(ie.logs).action(async()=>{try{await qo()}catch(e){console.error(e instanceof Error?e.message:String(e)),process.exit(1)}});Q.command("stop").description(ie.stop).option("--force-ports","Aggressively stop processes listening on API/Web ports (may affect non-GAIA processes)").action(async e=>{await jo({forcePorts:e.forcePorts})});process.argv.slice(2).length||(Q.outputHelp(),process.exit(0));Q.parse();
|
package/package.json
CHANGED
|
@@ -1,67 +1,70 @@
|
|
|
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.5.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
11
|
"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",
|
|
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
|
-
"
|
|
23
|
-
"
|
|
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.
|
|
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": "
|
|
54
|
-
"react-dom": "
|
|
55
|
-
"
|
|
56
|
-
"
|
|
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.
|
|
60
|
-
"@types/node": "^
|
|
61
|
-
"@types/react": "^19",
|
|
62
|
-
"@types/react-dom": "^19",
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
38
|
+
"@biomejs/biome": "^2.5.7",
|
|
39
|
+
"@types/node": "^24.13.3",
|
|
40
|
+
"@types/react": "^19.2.17",
|
|
41
|
+
"@types/react-dom": "^19.2.3",
|
|
42
|
+
"@types/ws": "^8.18.1",
|
|
43
|
+
"esbuild": "^0.25.12",
|
|
44
|
+
"tsx": "^4.23.11",
|
|
45
|
+
"typescript": "^7.0.2",
|
|
46
|
+
"vite": "^7.3.6",
|
|
47
|
+
"vitest": "^4.1.10"
|
|
48
|
+
},
|
|
49
|
+
"bin": {
|
|
50
|
+
"gaia": "./dist/index.js"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=20"
|
|
54
|
+
},
|
|
55
|
+
"keywords": [
|
|
56
|
+
"ai-assistant",
|
|
57
|
+
"cli",
|
|
58
|
+
"gaia",
|
|
59
|
+
"setup"
|
|
60
|
+
],
|
|
61
|
+
"license": "MIT",
|
|
62
|
+
"publishConfig": {
|
|
63
|
+
"access": "public"
|
|
64
|
+
},
|
|
65
|
+
"repository": {
|
|
66
|
+
"type": "git",
|
|
67
|
+
"url": "git+https://github.com/theexperiencecompany/gaia.git",
|
|
68
|
+
"directory": "packages/cli"
|
|
66
69
|
}
|
|
67
70
|
}
|