constella 0.1.0 → 0.1.1

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/CHANGELOG.md CHANGED
@@ -33,6 +33,23 @@ may still introduce breaking changes while the platform stabilises.
33
33
 
34
34
  ---
35
35
 
36
+ ## [0.1.1] — 2026-06-22 — "Remote / VPS login fix"
37
+
38
+ ### Fixed
39
+ - **Login over a remote host (VPS / Tailscale) now works.** The auth client baked a hardcoded
40
+ `localhost:3000` base URL at build time, so a published build always POSTed sign-in to the *user's
41
+ own* machine (`ERR_CONNECTION_REFUSED`); it now uses the live page origin (`window.location.origin`).
42
+ - The auth server now trusts the origin each request was actually served on, so better-auth's
43
+ CSRF/origin check no longer rejects a login from a Tailscale IP or LAN host. Cross-site forgery is
44
+ still blocked, and an explicit `BETTER_AUTH_URL` is always trusted.
45
+
46
+ ### Changed
47
+ - The VPS Docker image installs the published npm package (compiled `.next`) instead of building from
48
+ source — the public tree ships no `src/`. `Dockerfile`, `docker-compose.yml` and `vps-install.sh`
49
+ updated accordingly; reach the dashboard at the sidecar's Tailscale IP.
50
+
51
+ ---
52
+
36
53
  ## [0.1.0] — 2026-06-22 — "First consolidated release"
37
54
 
38
55
  The first end-to-end release: every previously deferred capability wired into the live system, the full
@@ -295,7 +312,8 @@ bilingual documentation portal, and the release/hardware paths staged for valida
295
312
 
296
313
  ---
297
314
 
298
- [Unreleased]: https://github.com/gabriel7silva/constella/compare/v0.1.0...HEAD
315
+ [Unreleased]: https://github.com/gabriel7silva/constella/compare/v0.1.1...HEAD
316
+ [0.1.1]: https://github.com/gabriel7silva/constella/compare/v0.1.0...v0.1.1
299
317
  [0.1.0]: https://github.com/gabriel7silva/constella/releases/tag/v0.1.0
300
318
  [0.0.13]: https://github.com/gabriel7silva/constella/compare/v0.0.12...v0.0.13
301
319
  [0.0.12]: https://github.com/gabriel7silva/constella/compare/v0.0.11...v0.0.12
@@ -59,8 +59,8 @@ flowchart TD
59
59
  C --> D["TS_AUTHKEY written to .env"]
60
60
  D --> E["docker compose up -d --build"]
61
61
  E --> F["tailscale sidecar joins tailnet"]
62
- E --> G["constella container builds + boots"]
63
- G --> H["bin/constella.mjs --vps --host 0.0.0.0 --port 3000"]
62
+ E --> G["constella image installs constella@npm + boots"]
63
+ G --> H["constella --vps --host 0.0.0.0 --port 3000"]
64
64
  H --> I["generate/persist secrets in /data/.env (chmod 600)"]
65
65
  H --> J["drizzle migrate against /data/constella.db"]
66
66
  H --> K["supervise: next start + worker"]
@@ -76,7 +76,7 @@ flowchart TD
76
76
  `docker-compose.yml` runs **two services that share one network namespace**:
77
77
 
78
78
  - **`tailscale`** — the official `tailscale/tailscale` image, acting as a sidecar. It owns `/dev/net/tun`, holds `net_admin` + `sys_module` caps, joins the tailnet headlessly with `TS_AUTHKEY`, and persists node state in the `tailscale-state` volume.
79
- - **`constella`** — built from the `Dockerfile`, joined to the sidecar's network with `network_mode: service:tailscale`. Because they share the namespace, Constella is reachable **only at the Tailscale IP** on port 3000 — never on the host's public interfaces.
79
+ - **`constella`** — built from the `Dockerfile`, which **installs the published `constella` npm package** (the compiled, prebuilt `.next`) — there is **no source build**, because the public tree ships no `src/`. Joined to the sidecar's network with `network_mode: service:tailscale`; because they share the namespace, Constella is reachable **only at the Tailscale IP** on port 3000 — never on the host's public interfaces. Pin a version with `CONSTELLA_VERSION=0.1.0` in `.env` (default `latest`).
80
80
 
81
81
  ### Runtime root on a volume
82
82
 
@@ -148,7 +148,7 @@ The launcher prints only `• Secrets ready (stored in <HOME>/.env, never printe
148
148
  | Service | Image / build | Network | Volumes | Notable caps |
149
149
  | --- | --- | --- | --- | --- |
150
150
  | `tailscale` | `tailscale/tailscale:latest` | own namespace | `tailscale-state:/var/lib/tailscale` | `net_admin`, `sys_module`, `/dev/net/tun` |
151
- | `constella` | `build: .` (Dockerfile) | `service:tailscale` | `constella-data:/data` | runs as unprivileged `node` (uid 1000) |
151
+ | `constella` | `build: .` (Dockerfile installs `constella@npm`) | `service:tailscale` | `constella-data:/data` | runs as unprivileged `node` (uid 1000) |
152
152
 
153
153
  ---
154
154
 
@@ -187,9 +187,15 @@ flowchart LR
187
187
 
188
188
  ## Step-by-step 🚀
189
189
 
190
- ### 1. Provision a VPS
190
+ ### 1. Provision a VPS and clone the public repo
191
191
 
192
- A fresh Ubuntu Server is the assumed target (the bootstrap installs Docker via `get.docker.com` and Tailscale via `tailscale.com/install.sh`).
192
+ A fresh **Ubuntu Server** (24.04 / 26.04 LTS) is the assumed target. Get the product tree (it carries the `Dockerfile`, `docker-compose.yml` and `scripts/vps-install.sh` — no source needed):
193
+
194
+ ```bash
195
+ apt-get update && apt-get install -y git # if git is missing
196
+ git clone https://github.com/gabriel7silva/constella.git
197
+ cd constella
198
+ ```
193
199
 
194
200
  ### 2. Run the bootstrap
195
201
 
@@ -197,14 +203,13 @@ A fresh Ubuntu Server is the assumed target (the bootstrap installs Docker via `
197
203
  bash scripts/vps-install.sh
198
204
  ```
199
205
 
200
- `scripts/vps-install.sh` does, in order:
206
+ `scripts/vps-install.sh` does, in order (it uses `sudo` only when you're not already `root`):
201
207
 
202
208
  1. **Install Docker** if `docker` is not on `PATH` (`curl -fsSL https://get.docker.com | sh`).
203
- 2. **Install Tailscale** if absent (`curl -fsSL https://tailscale.com/install.sh | sh`).
204
- 3. **Join the tailnet** with `sudo tailscale up` (prints a browser auth URL if needed).
205
- 4. **Ask for a `TS_AUTHKEY`** (so the *container* sidecar can join headlessly) and append it to `.env`.
206
- 5. **Build + start** the stack: `sudo docker compose up -d --build`.
207
- 6. **Print the reach URL**: `http://<tailscale-ip>:3000`.
209
+ 2. **Install Tailscale** on the host if absent (`curl -fsSL https://tailscale.com/install.sh | sh`); `tailscale up` is a **no-op if the host is already joined**.
210
+ 3. **Ask for a `TS_AUTHKEY`** for the *container sidecar* — a **separate tailnet node**, needed **even when the host already runs Tailscale** and append it to `.env`.
211
+ 4. **Build + start** the stack: `docker compose up -d --build` (the image installs `constella` from npm).
212
+ 5. **Print the reach URL** read from the sidecar: `http://<constella-tailnet-ip>:3000`.
208
213
 
209
214
  ### 3. Create the Tailscale auth key
210
215
 
@@ -218,16 +223,34 @@ From **any device on the same tailnet**, open:
218
223
  http://<this-node's-tailscale-ip>:3000
219
224
  ```
220
225
 
221
- Find the IP with `tailscale ip -4` on the VPS. First load lands on `/login` (login is enforced); after sign-in, complete [ONBOARDING](./ONBOARDING.md) if it's the first run.
226
+ Find the IP from the **sidecar** (the device named `constella` in your tailnet), not the host:
227
+
228
+ ```bash
229
+ docker compose exec tailscale tailscale ip -4
230
+ ```
231
+
232
+ First load lands on `/login` (login is enforced); after sign-in, complete [ONBOARDING](./ONBOARDING.md) if it's the first run.
222
233
 
223
234
  ### 5. Manual compose path (no bootstrap)
224
235
 
225
236
  ```bash
226
- echo "TS_AUTHKEY=tskey-auth-..." > .env
237
+ echo "TS_AUTHKEY=tskey-auth-..." > .env # optional: add CONSTELLA_VERSION=0.1.0 to pin the version
227
238
  docker compose up -d --build
228
- # then: http://<tailscale-ip>:3000
239
+ docker compose exec tailscale tailscale ip -4 # -> http://<that-ip>:3000
229
240
  ```
230
241
 
242
+ ### 6. Direct path (no Docker, no sidecar)
243
+
244
+ If the host already runs Tailscale (or you firewall port 3000 yourself), you can skip Docker entirely and run the published package straight on the host — it binds `0.0.0.0`, reachable at the **host's** tailnet IP:
245
+
246
+ ```bash
247
+ curl -fsSL https://deb.nodesource.com/setup_22.x | bash - # Node 20+ if missing
248
+ apt-get install -y nodejs
249
+ npx constella@latest --vps --host 0.0.0.0 --port 3000 # reach: http://<host-tailscale-ip>:3000
250
+ ```
251
+
252
+ > ⚠️ Without the sidecar, `0.0.0.0` is **not** tailnet-private by itself. Only use this when the host has no public route to port 3000 (firewall / security group), or stay on the Docker path, which keeps the bind inside the Tailscale namespace.
253
+
231
254
  ---
232
255
 
233
256
  ## Examples 🪐
@@ -238,10 +261,10 @@ docker compose up -d --build
238
261
  node bin/constella.mjs --vps --host 0.0.0.0 --port 3000
239
262
  ```
240
263
 
241
- **The exact container command (from the `Dockerfile`):**
264
+ **The exact container command (from the `Dockerfile`, after it installs `constella` from npm):**
242
265
 
243
266
  ```dockerfile
244
- CMD ["node", "bin/constella.mjs", "--vps", "--host", "0.0.0.0", "--port", "3000"]
267
+ CMD ["constella", "--vps", "--host", "0.0.0.0", "--port", "3000"]
245
268
  ```
246
269
 
247
270
  **Confirm the run context the app sees:**
@@ -59,8 +59,8 @@ flowchart TD
59
59
  C --> D["TS_AUTHKEY gravado em .env"]
60
60
  D --> E["docker compose up -d --build"]
61
61
  E --> F["sidecar tailscale entra na tailnet"]
62
- E --> G["contêiner constella compila + inicia"]
63
- G --> H["bin/constella.mjs --vps --host 0.0.0.0 --port 3000"]
62
+ E --> G["imagem constella instala constella@npm + inicia"]
63
+ G --> H["constella --vps --host 0.0.0.0 --port 3000"]
64
64
  H --> I["gera/persiste segredos em /data/.env (chmod 600)"]
65
65
  H --> J["drizzle migrate contra /data/constella.db"]
66
66
  H --> K["supervisiona: next start + worker"]
@@ -76,7 +76,7 @@ flowchart TD
76
76
  O `docker-compose.yml` roda **dois serviços que compartilham um único namespace de rede**:
77
77
 
78
78
  - **`tailscale`** — a imagem oficial `tailscale/tailscale`, atuando como sidecar. Ela controla `/dev/net/tun`, possui as capabilities `net_admin` + `sys_module`, entra na tailnet de forma headless com `TS_AUTHKEY` e persiste o estado do nó no volume `tailscale-state`.
79
- - **`constella`** — construída a partir do `Dockerfile`, ligada à rede do sidecar com `network_mode: service:tailscale`. Como compartilham o namespace, o Constella fica acessível **apenas no IP do Tailscale** na porta 3000 — nunca nas interfaces públicas do host.
79
+ - **`constella`** — construída a partir do `Dockerfile`, que **instala o pacote npm publicado `constella`** (o `.next` compilado e pré-buildado) — **não há build de fonte**, porque a árvore pública não inclui `src/`. Ligada à rede do sidecar com `network_mode: service:tailscale`; como compartilham o namespace, o Constella fica acessível **apenas no IP do Tailscale** na porta 3000 — nunca nas interfaces públicas do host. Fixe uma versão com `CONSTELLA_VERSION=0.1.0` no `.env` (padrão `latest`).
80
80
 
81
81
  ### Raiz de runtime em um volume
82
82
 
@@ -148,7 +148,7 @@ O launcher imprime apenas `• Secrets ready (stored in <HOME>/.env, never print
148
148
  | Serviço | Imagem / build | Rede | Volumes | Capabilities notáveis |
149
149
  | --- | --- | --- | --- | --- |
150
150
  | `tailscale` | `tailscale/tailscale:latest` | namespace próprio | `tailscale-state:/var/lib/tailscale` | `net_admin`, `sys_module`, `/dev/net/tun` |
151
- | `constella` | `build: .` (Dockerfile) | `service:tailscale` | `constella-data:/data` | roda como `node` sem privilégios (uid 1000) |
151
+ | `constella` | `build: .` (Dockerfile instala `constella@npm`) | `service:tailscale` | `constella-data:/data` | roda como `node` sem privilégios (uid 1000) |
152
152
 
153
153
  ---
154
154
 
@@ -187,9 +187,15 @@ flowchart LR
187
187
 
188
188
  ## Passo a passo 🚀
189
189
 
190
- ### 1. Provisione uma VPS
190
+ ### 1. Provisione uma VPS e clone o repo público
191
191
 
192
- Um Ubuntu Server novo é o alvo assumido (o bootstrap instala o Docker via `get.docker.com` e o Tailscale via `tailscale.com/install.sh`).
192
+ Um **Ubuntu Server** novo (24.04 / 26.04 LTS) é o alvo assumido. Pegue a árvore do produto (ela carrega o `Dockerfile`, o `docker-compose.yml` e o `scripts/vps-install.sh` — sem precisar de fonte):
193
+
194
+ ```bash
195
+ apt-get update && apt-get install -y git # se o git faltar
196
+ git clone https://github.com/gabriel7silva/constella.git
197
+ cd constella
198
+ ```
193
199
 
194
200
  ### 2. Rode o bootstrap
195
201
 
@@ -197,14 +203,13 @@ Um Ubuntu Server novo é o alvo assumido (o bootstrap instala o Docker via `get.
197
203
  bash scripts/vps-install.sh
198
204
  ```
199
205
 
200
- O `scripts/vps-install.sh` faz, em ordem:
206
+ O `scripts/vps-install.sh` faz, em ordem (usa `sudo` só quando você não é `root`):
201
207
 
202
208
  1. **Instala o Docker** se `docker` não estiver no `PATH` (`curl -fsSL https://get.docker.com | sh`).
203
- 2. **Instala o Tailscale** se ausente (`curl -fsSL https://tailscale.com/install.sh | sh`).
204
- 3. **Entra na tailnet** com `sudo tailscale up` (imprime uma URL de auth no navegador se necessário).
205
- 4. **Pede um `TS_AUTHKEY`** (para que o sidecar do *contêiner* entre de forma headless) e o anexa ao `.env`.
206
- 5. **Constrói + inicia** a stack: `sudo docker compose up -d --build`.
207
- 6. **Imprime a URL de acesso**: `http://<tailscale-ip>:3000`.
209
+ 2. **Instala o Tailscale** no host se ausente (`curl -fsSL https://tailscale.com/install.sh | sh`); `tailscale up` é **no-op se o host já está na tailnet**.
210
+ 3. **Pede um `TS_AUTHKEY`** para o *sidecar do contêiner* — um **nó de tailnet separado**, necessário **mesmo quando o host roda Tailscale** e o anexa ao `.env`.
211
+ 4. **Constrói + inicia** a stack: `docker compose up -d --build` (a imagem instala o `constella` do npm).
212
+ 5. **Imprime a URL de acesso** lida do sidecar: `http://<ip-tailnet-do-constella>:3000`.
208
213
 
209
214
  ### 3. Crie a auth key do Tailscale
210
215
 
@@ -218,16 +223,34 @@ De **qualquer dispositivo na mesma tailnet**, abra:
218
223
  http://<ip-tailscale-deste-nó>:3000
219
224
  ```
220
225
 
221
- Encontre o IP com `tailscale ip -4` na VPS. O primeiro carregamento cai em `/login` (login é obrigatório); após entrar, complete o [ONBOARDING](./ONBOARDING.md) se for o primeiro boot.
226
+ Encontre o IP no **sidecar** (o dispositivo chamado `constella` na sua tailnet), não no host:
227
+
228
+ ```bash
229
+ docker compose exec tailscale tailscale ip -4
230
+ ```
231
+
232
+ O primeiro carregamento cai em `/login` (login é obrigatório); após entrar, complete o [ONBOARDING](./ONBOARDING.md) se for o primeiro boot.
222
233
 
223
234
  ### 5. Caminho manual com compose (sem o bootstrap)
224
235
 
225
236
  ```bash
226
- echo "TS_AUTHKEY=tskey-auth-..." > .env
237
+ echo "TS_AUTHKEY=tskey-auth-..." > .env # opcional: adicione CONSTELLA_VERSION=0.1.0 para fixar a versão
227
238
  docker compose up -d --build
228
- # depois: http://<tailscale-ip>:3000
239
+ docker compose exec tailscale tailscale ip -4 # -> http://<esse-ip>:3000
229
240
  ```
230
241
 
242
+ ### 6. Caminho direto (sem Docker, sem sidecar)
243
+
244
+ Se o host já roda Tailscale (ou você mesmo bloqueia a porta 3000 no firewall), dá para pular o Docker inteiro e rodar o pacote publicado direto no host — ele vincula `0.0.0.0`, acessível no IP de tailnet **do host**:
245
+
246
+ ```bash
247
+ curl -fsSL https://deb.nodesource.com/setup_22.x | bash - # Node 20+ se faltar
248
+ apt-get install -y nodejs
249
+ npx constella@latest --vps --host 0.0.0.0 --port 3000 # acesso: http://<ip-tailscale-do-host>:3000
250
+ ```
251
+
252
+ > ⚠️ Sem o sidecar, `0.0.0.0` **não** é privado por tailnet sozinho. Só use isto quando o host não tiver rota pública para a porta 3000 (firewall / security group), ou fique no caminho Docker, que mantém o bind dentro do namespace do Tailscale.
253
+
231
254
  ---
232
255
 
233
256
  ## Exemplos 🪐
@@ -238,10 +261,10 @@ docker compose up -d --build
238
261
  node bin/constella.mjs --vps --host 0.0.0.0 --port 3000
239
262
  ```
240
263
 
241
- **O comando exato do contêiner (do `Dockerfile`):**
264
+ **O comando exato do contêiner (do `Dockerfile`, depois que ele instala o `constella` do npm):**
242
265
 
243
266
  ```dockerfile
244
- CMD ["node", "bin/constella.mjs", "--vps", "--host", "0.0.0.0", "--port", "3000"]
267
+ CMD ["constella", "--vps", "--host", "0.0.0.0", "--port", "3000"]
245
268
  ```
246
269
 
247
270
  **Confirmar o contexto de execução que o app enxerga:**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "constella",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Constella — run autonomous AI agent-companies locally: real claude/codex agents, Goals → Specs → Issues → Plans, local models, GitHub & Telegram, all from one cosmic control plane.",
5
5
  "//name": "Unscoped so `npx constella` works. If the name is taken on npm, fall back to `@constella/cli` (then commands become `npx @constella/cli`).",
6
6
  "license": "MIT",
@@ -1,26 +1,35 @@
1
1
  #!/usr/bin/env bash
2
- # Constella VPS bootstrap (Ubuntu Server). Installs Docker + Tailscale, joins the tailnet, and brings
3
- # up Constella over Tailscale. Run on a fresh VPS: curl ... | bash — or bash scripts/vps-install.sh
2
+ # Constella VPS bootstrap (Ubuntu Server). Installs Docker + Tailscale (skips either if already
3
+ # present), then builds + runs Constella over Tailscale. The image installs the PUBLISHED npm package
4
+ # (compiled, prebuilt .next) — there is no source build. Run from a clone of the public repo:
5
+ # git clone https://github.com/gabriel7silva/constella.git && cd constella && bash scripts/vps-install.sh
4
6
  set -euo pipefail
5
7
 
6
8
  echo "✦ Constella VPS install — Docker + Tailscale"
7
9
 
10
+ # Use sudo only when not already root (minimal Ubuntu images often have no `sudo`).
11
+ SUDO=""
12
+ if [ "$(id -u)" -ne 0 ]; then SUDO="sudo"; fi
13
+
8
14
  # 1) Docker
9
15
  if ! command -v docker >/dev/null 2>&1; then
10
16
  echo "• Installing Docker…"
11
- curl -fsSL https://get.docker.com | sh
17
+ curl -fsSL https://get.docker.com | $SUDO sh
18
+ else
19
+ echo "• Docker already installed — skipping."
12
20
  fi
13
21
 
14
- # 2) Tailscale
22
+ # 2) Tailscale on the HOST (optional — the container runs its own Tailscale sidecar). Installed only
23
+ # if absent; `tailscale up` is a no-op when the host is already joined.
15
24
  if ! command -v tailscale >/dev/null 2>&1; then
16
25
  echo "• Installing Tailscale…"
17
- curl -fsSL https://tailscale.com/install.sh | sh
26
+ curl -fsSL https://tailscale.com/install.sh | $SUDO sh
18
27
  fi
28
+ echo "• Ensuring the host is on your tailnet (no-op if already joined)…"
29
+ $SUDO tailscale up || true
19
30
 
20
- echo "• Joining your tailnet (a browser auth URL will be printed if needed)…"
21
- sudo tailscale up || true
22
-
23
- # 3) Auth key for the Tailscale container (so the compose sidecar can join headlessly)
31
+ # 3) Auth key for the Tailscale CONTAINER sidecar (a separate tailnet node, even if the host already
32
+ # runs Tailscale) so compose can join it headlessly.
24
33
  if [ ! -f .env ] || ! grep -q '^TS_AUTHKEY=' .env; then
25
34
  echo
26
35
  echo " Create a Tailscale auth key at https://login.tailscale.com/admin/settings/keys"
@@ -28,12 +37,16 @@ if [ ! -f .env ] || ! grep -q '^TS_AUTHKEY=' .env; then
28
37
  echo "TS_AUTHKEY=${TS_KEY}" >> .env
29
38
  fi
30
39
 
31
- # 4) Bring up the stack
40
+ # 4) Build + start the stack (the image pulls constella from npm; pin with CONSTELLA_VERSION in .env).
32
41
  echo "• Building + starting Constella…"
33
- sudo docker compose up -d --build
42
+ $SUDO docker compose up -d --build
34
43
 
35
- IP="$(tailscale ip -4 2>/dev/null | head -1 || true)"
44
+ # 5) Reach URL = the SIDECAR's tailnet IP (device "constella"), not the host's. Read it from the
45
+ # sidecar container; fall back to a hint if it isn't up yet.
46
+ sleep 3
47
+ IP="$($SUDO docker compose exec -T tailscale tailscale ip -4 2>/dev/null | head -1 || true)"
36
48
  echo
37
49
  echo "✓ Constella is starting."
38
- echo " Reach it on your tailnet at: http://${IP:-<tailscale-ip>}:3000"
39
- echo " (Open it from any device on the same tailnet.)"
50
+ echo " Reach it on your tailnet at: http://${IP:-<constella-tailnet-ip>}:3000"
51
+ echo " (If the IP is blank, wait a few seconds and run: docker compose exec tailscale tailscale ip -4)"
52
+ echo " Open it from any device on the same tailnet. First load → /login (login is enforced in VPS mode)."