create-urateam 0.1.8 → 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/scaffold.test.js +167 -2
- package/dist/__tests__/scaffold.test.js.map +1 -1
- package/dist/index.d.ts +73 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +395 -63
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/template/.urateam/.env.example +71 -15
- package/template/.urateam/Caddyfile +36 -0
- package/template/.urateam/Dockerfile +10 -1
- package/template/.urateam/README.md +90 -7
- package/template/.urateam/docker-compose.yml +50 -11
|
@@ -1,39 +1,95 @@
|
|
|
1
|
-
#
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# urateam .env — copy to .env and fill in. NEVER commit .env to git.
|
|
3
|
+
# =============================================================================
|
|
4
|
+
|
|
5
|
+
# === Linear (REQUIRED) ===
|
|
2
6
|
LINEAR_API_KEY=
|
|
3
7
|
LINEAR_WEBHOOK_SECRET=
|
|
4
8
|
LINEAR_TEAM_ID=
|
|
5
9
|
|
|
6
|
-
# Repository
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
# every inbound Linear event with "no repo mapping". In the common
|
|
10
|
-
# single-team setup, REPO_TEAM_ID is the same UUID as LINEAR_TEAM_ID.
|
|
10
|
+
# === Repository (REQUIRED) ===
|
|
11
|
+
# `ura dev` and `ura start` exit with an error if these are missing.
|
|
12
|
+
# In a single-team setup, REPO_TEAM_ID == LINEAR_TEAM_ID.
|
|
11
13
|
REPO_URL=
|
|
12
14
|
REPO_DEFAULT_BRANCH=main
|
|
13
15
|
REPO_TEAM_ID=
|
|
14
16
|
|
|
15
|
-
#
|
|
16
|
-
|
|
17
|
+
# === Anthropic auth (REQUIRED for production / headless) ===
|
|
18
|
+
# Use ANTHROPIC_API_KEY for any deployment without an interactive shell
|
|
19
|
+
# (VPS, containerized, CI). The OSS-tier `claude` CLI session flow only
|
|
20
|
+
# works when you can `claude login` interactively on the host.
|
|
21
|
+
ANTHROPIC_API_KEY=
|
|
22
|
+
|
|
23
|
+
# === Pro license (REQUIRED for Pro features: Slack, multi-repo, deep-review, etc.) ===
|
|
24
|
+
URATEAM_LICENSE_KEY=
|
|
25
|
+
|
|
26
|
+
# === GitHub (REQUIRED for PR creation in production) ===
|
|
27
|
+
# Two paths: GitHub App credentials (production) OR `gh` CLI session
|
|
28
|
+
# inside the container (`docker compose exec agent gh auth login` after
|
|
29
|
+
# bringing the stack up — fine for solo / single-repo).
|
|
30
|
+
#
|
|
31
|
+
# Production path — GitHub App:
|
|
32
|
+
# 1. Create at github.com/settings/apps/new with Contents:Write,
|
|
33
|
+
# Pull requests:Write, Metadata:Read scopes
|
|
34
|
+
# 2. Install the app on the target repo
|
|
35
|
+
# 3. Download the private key .pem and bind-mount it into the container
|
|
36
|
+
# (e.g. add a volume map in docker-compose.yml: ./gh-app.pem:/run/gh-app.pem:ro)
|
|
37
|
+
# GITHUB_APP_ID=
|
|
38
|
+
# GITHUB_PRIVATE_KEY_PATH=/run/gh-app.pem
|
|
39
|
+
# GITHUB_INSTALLATION_ID=
|
|
40
|
+
# Optional: only needed if PR-comment-driven re-runs are enabled
|
|
41
|
+
# GITHUB_WEBHOOK_SECRET=
|
|
17
42
|
|
|
18
|
-
#
|
|
43
|
+
# === Database ===
|
|
44
|
+
# Generate POSTGRES_PASSWORD with: openssl rand -base64 32
|
|
45
|
+
# DATABASE_URL is assembled in docker-compose.yml from this password —
|
|
46
|
+
# do NOT set it here (env_file does not interpolate variables).
|
|
47
|
+
POSTGRES_PASSWORD=
|
|
48
|
+
|
|
49
|
+
# === Domain (REQUIRED for production deploy with the Caddy reverse proxy) ===
|
|
50
|
+
# Public hostname Caddy will request a Let's Encrypt cert for. Must resolve
|
|
51
|
+
# to this host before bringing the stack up; ports 80 + 443 must be open.
|
|
52
|
+
DOMAIN=
|
|
53
|
+
# Email for ACME / Let's Encrypt expiry warnings. Strongly recommended.
|
|
54
|
+
CADDY_EMAIL=
|
|
55
|
+
|
|
56
|
+
# === Dashboard auth (REQUIRED) ===
|
|
57
|
+
# Generate a strong DASHBOARD_PASSWORD. Production refuses to start without one.
|
|
19
58
|
DASHBOARD_USER=admin
|
|
20
59
|
DASHBOARD_PASSWORD=
|
|
60
|
+
# Set DASHBOARD_BASE_PATH if mounting under a path prefix (no trailing slash).
|
|
61
|
+
# DASHBOARD_BASE_PATH=
|
|
62
|
+
|
|
63
|
+
# === Workspace (defaults inside the container) ===
|
|
64
|
+
# AGENT_RUN_DIR=/var/agent-runs
|
|
65
|
+
# REPO_CLONE_DIR=/var/agent-repos
|
|
66
|
+
# WORKTREE_TTL_HOURS=24
|
|
67
|
+
|
|
68
|
+
# === Concurrency ===
|
|
69
|
+
# MAX_CONCURRENT_RUNS=3
|
|
70
|
+
|
|
71
|
+
# =============================================================================
|
|
72
|
+
# Optional features below
|
|
73
|
+
# =============================================================================
|
|
21
74
|
|
|
22
|
-
# === Optional ===
|
|
23
75
|
# Override per-stage agent budget (maxTurns / maxInputTokens / model / tools).
|
|
24
|
-
# Useful when the test stage has to bootstrap test infra
|
|
25
|
-
#
|
|
76
|
+
# Useful when the test stage has to bootstrap test infra and burns the
|
|
77
|
+
# default 25-turn cap. See urateam#38.
|
|
26
78
|
# URATEAM_AGENT_PROFILES='{"test":{"maxTurns":50,"maxInputTokens":80000}}'
|
|
27
79
|
|
|
80
|
+
# Slack notifier — basic incoming-webhook (no Pro license needed)
|
|
28
81
|
# SLACK_WEBHOOK_URL=
|
|
29
82
|
# DISCORD_WEBHOOK_URL=
|
|
30
|
-
|
|
83
|
+
|
|
84
|
+
# PM Agent + Slack interface (Pro feature: slack-interface)
|
|
31
85
|
# PM_AGENT_ENABLED=false
|
|
32
86
|
# PM_AGENT_TEAM_IDS=
|
|
33
87
|
# PM_AGENT_SLACK_CHANNEL_ID=
|
|
34
88
|
# PM_AGENT_DAILY_TOKEN_BUDGET=5000000
|
|
35
89
|
# PM_AGENT_MAX_IN_FLIGHT=3
|
|
90
|
+
# PM_AGENT_CRON_INTERVAL_MS=1800000
|
|
36
91
|
# SLACK_BOT_TOKEN=
|
|
92
|
+
# SLACK_SIGNING_SECRET=
|
|
93
|
+
|
|
94
|
+
# Logging
|
|
37
95
|
# LOG_LEVEL=info
|
|
38
|
-
# MAX_CONCURRENT_RUNS=3
|
|
39
|
-
# URATEAM_LICENSE_KEY=
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# urateam reverse proxy + auto-HTTPS via Let's Encrypt.
|
|
2
|
+
#
|
|
3
|
+
# Caddy routes:
|
|
4
|
+
# - /webhooks/* → agent:3000 (Linear, GitHub webhook receivers)
|
|
5
|
+
# - /slack/* → agent:3000 (Slack events + slash commands, optional PM agent)
|
|
6
|
+
# - /health → agent:3000 (liveness probe)
|
|
7
|
+
# - everything else → agent:3001 (the ops dashboard)
|
|
8
|
+
#
|
|
9
|
+
# DOMAIN is read from .env; required for cert issuance.
|
|
10
|
+
# Ports 80 and 443 must be reachable from the public internet for ACME.
|
|
11
|
+
|
|
12
|
+
{
|
|
13
|
+
email {$CADDY_EMAIL}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
{$DOMAIN} {
|
|
17
|
+
encode zstd gzip
|
|
18
|
+
|
|
19
|
+
handle /webhooks/* {
|
|
20
|
+
reverse_proxy agent:3000
|
|
21
|
+
}
|
|
22
|
+
handle /slack/* {
|
|
23
|
+
reverse_proxy agent:3000
|
|
24
|
+
}
|
|
25
|
+
handle /health {
|
|
26
|
+
reverse_proxy agent:3000
|
|
27
|
+
}
|
|
28
|
+
handle {
|
|
29
|
+
reverse_proxy agent:3001
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
log {
|
|
33
|
+
output stdout
|
|
34
|
+
format console
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
FROM node:22-slim
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# git + gh: needed by the agent for cloning, branch operations, PR creation.
|
|
4
|
+
# Claude Code CLI: required for OSS-tier subscription auth and as a fallback
|
|
5
|
+
# for Pro-tier deployments that don't set ANTHROPIC_API_KEY. Persisted auth
|
|
6
|
+
# lives at /root/.config/claude — bind-mounted via a docker volume below
|
|
7
|
+
# so `claude login` only has to run once.
|
|
8
|
+
RUN apt-get update \
|
|
9
|
+
&& apt-get install -y --no-install-recommends git gh ca-certificates \
|
|
10
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
11
|
+
|
|
4
12
|
RUN corepack enable
|
|
13
|
+
RUN npm install -g @anthropic-ai/claude-code
|
|
5
14
|
|
|
6
15
|
WORKDIR /app
|
|
7
16
|
COPY package.json pnpm-lock.yaml* ./
|
|
@@ -7,10 +7,18 @@ to implement features, fix bugs, and create PRs automatically.
|
|
|
7
7
|
|
|
8
8
|
## Setup
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Two paths: pick one.
|
|
11
|
+
|
|
12
|
+
### Local dev (your laptop)
|
|
13
|
+
|
|
14
|
+
1. Copy `.env.example` to `.env` and fill in. NEVER commit `.env`.
|
|
11
15
|
2. Install dependencies: `pnpm install`
|
|
12
|
-
3. **Authenticate Claude** (OSS path only — see [Claude auth lifecycle](#claude-auth-lifecycle-oss-tier) below): `claude login`
|
|
13
|
-
4. Start the agent: `pnpm dev`
|
|
16
|
+
3. **Authenticate Claude** (OSS path only — see [Claude auth lifecycle](#claude-auth-lifecycle-oss-tier) below): `claude login`. Skip if you set `ANTHROPIC_API_KEY`.
|
|
17
|
+
4. Start the agent: `pnpm dev`
|
|
18
|
+
|
|
19
|
+
### Production VPS
|
|
20
|
+
|
|
21
|
+
Skip the `pnpm install` / `pnpm dev` steps and jump straight to [Production deploy](#production-deploy-via-docker-compose) — Docker Compose handles everything.
|
|
14
22
|
|
|
15
23
|
## Claude auth lifecycle (OSS tier)
|
|
16
24
|
|
|
@@ -44,23 +52,98 @@ Use that variant when re-authing inside a running container.
|
|
|
44
52
|
have session-lifetime semantics, so this whole concern goes away. See the
|
|
45
53
|
[urateam docs](https://github.com/JonB32/urateam) for upgrade paths.
|
|
46
54
|
|
|
47
|
-
## Expose the webhook
|
|
55
|
+
## Expose the webhook (local dev only)
|
|
48
56
|
|
|
49
|
-
The agent listens on `http://localhost:3000/webhooks/linear`.
|
|
50
|
-
|
|
57
|
+
The agent listens on `http://localhost:3000/webhooks/linear`. For local
|
|
58
|
+
development, expose via ngrok:
|
|
51
59
|
|
|
52
60
|
```bash
|
|
53
61
|
ngrok http 3000
|
|
54
62
|
```
|
|
55
63
|
|
|
56
64
|
Configure the ngrok URL as a webhook in Linear settings with the
|
|
57
|
-
`LINEAR_WEBHOOK_SECRET` from your `.env`.
|
|
65
|
+
`LINEAR_WEBHOOK_SECRET` from your `.env`. For production, see
|
|
66
|
+
[Production deploy](#production-deploy-via-docker-compose) — Caddy
|
|
67
|
+
handles HTTPS termination directly and you wire Linear to your real domain.
|
|
58
68
|
|
|
59
69
|
## Dashboard
|
|
60
70
|
|
|
61
71
|
The ops dashboard runs on `http://localhost:3001`. Credentials from
|
|
62
72
|
`DASHBOARD_USER` / `DASHBOARD_PASSWORD` in `.env`.
|
|
63
73
|
|
|
74
|
+
## Production deploy via docker compose
|
|
75
|
+
|
|
76
|
+
Compose template ships a hardened three-service stack:
|
|
77
|
+
|
|
78
|
+
- **caddy** — reverse proxy on :80/:443 with automatic Let's Encrypt certs.
|
|
79
|
+
Routes `/webhooks/*` and `/slack/*` to the agent (:3000), everything else
|
|
80
|
+
to the dashboard (:3001).
|
|
81
|
+
- **agent** — `ura start`. No public ports; reachable only via Caddy.
|
|
82
|
+
- **postgres** — internal-only network, no published ports. Password from
|
|
83
|
+
`POSTGRES_PASSWORD` (compose refuses to start without it).
|
|
84
|
+
|
|
85
|
+
### Pre-flight
|
|
86
|
+
|
|
87
|
+
1. **Provision a VPS** (Hetzner, DigitalOcean, Linode, Fly, etc.). 4 GB RAM
|
|
88
|
+
minimum for `MAX_CONCURRENT_RUNS=3`.
|
|
89
|
+
2. **Point a domain** (e.g. `urateam.your-domain.com`) at the VPS IP. Caddy needs
|
|
90
|
+
ports 80 + 443 open for ACME challenges.
|
|
91
|
+
3. **Install Docker** and the Compose plugin on the box.
|
|
92
|
+
|
|
93
|
+
### Deploy
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# 1. On the VPS, clone or scp this project
|
|
97
|
+
cd /opt/<project>/.urateam
|
|
98
|
+
|
|
99
|
+
# 2. Copy and fill in env
|
|
100
|
+
cp .env.example .env
|
|
101
|
+
# At minimum set: DOMAIN, CADDY_EMAIL, POSTGRES_PASSWORD (openssl rand -base64 32),
|
|
102
|
+
# ANTHROPIC_API_KEY, URATEAM_LICENSE_KEY (for Pro), LINEAR_*, REPO_*,
|
|
103
|
+
# DASHBOARD_PASSWORD.
|
|
104
|
+
|
|
105
|
+
# 3. Bring up the stack
|
|
106
|
+
docker compose up -d --build
|
|
107
|
+
|
|
108
|
+
# 4. Authenticate Claude Code CLI inside the container (skip if you set
|
|
109
|
+
# ANTHROPIC_API_KEY in .env). Login is persisted in a docker volume,
|
|
110
|
+
# so this only has to run once per deployment.
|
|
111
|
+
docker compose exec agent claude login
|
|
112
|
+
|
|
113
|
+
# 5. Authenticate gh CLI inside the container (required for PR creation
|
|
114
|
+
# unless you wired GITHUB_APP_ID / GITHUB_PRIVATE_KEY_PATH /
|
|
115
|
+
# GITHUB_INSTALLATION_ID in .env). Also persisted across rebuilds.
|
|
116
|
+
docker compose exec agent gh auth login
|
|
117
|
+
|
|
118
|
+
# 4. Tail logs to verify license, webhooks, dashboard
|
|
119
|
+
docker compose logs -f agent
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
After the first run, Caddy will request and store a Let's Encrypt cert for
|
|
123
|
+
`$DOMAIN`. The dashboard is reachable at `https://$DOMAIN`, webhooks at
|
|
124
|
+
`https://$DOMAIN/webhooks/linear`.
|
|
125
|
+
|
|
126
|
+
### Wiring Linear
|
|
127
|
+
|
|
128
|
+
In Linear → Workspace settings → API → Webhooks → Create:
|
|
129
|
+
|
|
130
|
+
- URL: `https://$DOMAIN/webhooks/linear`
|
|
131
|
+
- Secret: paste `LINEAR_WEBHOOK_SECRET` from `.env`
|
|
132
|
+
- Subscribe to: Issue state changes (and any others your pipelines key off of).
|
|
133
|
+
|
|
134
|
+
### Re-deploy
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
git pull && docker compose up -d --build
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Backups
|
|
141
|
+
|
|
142
|
+
`pgdata` and `agent-runs` are named docker volumes. For backups, snapshot the
|
|
143
|
+
host volume directory or use `docker run --rm -v pgdata:/data … pg_dump` style
|
|
144
|
+
sidecars. Workspace dirs (`/var/agent-runs`, `/var/agent-repos`) auto-clean
|
|
145
|
+
older than `WORKTREE_TTL_HOURS` (default 24h).
|
|
146
|
+
|
|
64
147
|
## How it works
|
|
65
148
|
|
|
66
149
|
1. Move a Linear issue to the `Todo` state with an appropriate pipeline label
|
|
@@ -1,28 +1,67 @@
|
|
|
1
1
|
services:
|
|
2
|
-
|
|
3
|
-
image:
|
|
2
|
+
caddy:
|
|
3
|
+
image: caddy:2
|
|
4
|
+
restart: unless-stopped
|
|
5
|
+
ports:
|
|
6
|
+
- "80:80"
|
|
7
|
+
- "443:443"
|
|
4
8
|
environment:
|
|
5
|
-
|
|
6
|
-
POSTGRES_PASSWORD: password
|
|
7
|
-
POSTGRES_DB: urateam
|
|
9
|
+
DOMAIN: ${DOMAIN}
|
|
8
10
|
volumes:
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
-
|
|
11
|
+
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
|
12
|
+
- caddy-data:/data
|
|
13
|
+
- caddy-config:/config
|
|
14
|
+
depends_on:
|
|
15
|
+
- agent
|
|
16
|
+
networks:
|
|
17
|
+
- frontend
|
|
12
18
|
|
|
13
19
|
agent:
|
|
14
20
|
build: .
|
|
21
|
+
restart: unless-stopped
|
|
15
22
|
env_file: .env
|
|
23
|
+
environment:
|
|
24
|
+
# Compose interpolates ${POSTGRES_PASSWORD} from .env here. It does NOT
|
|
25
|
+
# interpolate inside .env itself, so DATABASE_URL must be assembled
|
|
26
|
+
# at the compose layer rather than the env-file layer.
|
|
27
|
+
DATABASE_URL: "postgres://urateam:${POSTGRES_PASSWORD}@postgres:5432/urateam"
|
|
16
28
|
depends_on:
|
|
17
29
|
- postgres
|
|
18
|
-
|
|
19
|
-
- "3000
|
|
20
|
-
- "3001
|
|
30
|
+
expose:
|
|
31
|
+
- "3000"
|
|
32
|
+
- "3001"
|
|
21
33
|
volumes:
|
|
22
34
|
- agent-runs:/var/agent-runs
|
|
23
35
|
- agent-repos:/var/agent-repos
|
|
36
|
+
# Persist the `claude` and `gh` CLI login state across rebuilds so
|
|
37
|
+
# operators don't have to re-auth every `docker compose up --build`.
|
|
38
|
+
- claude-config:/root/.config/claude
|
|
39
|
+
- gh-config:/root/.config/gh
|
|
40
|
+
networks:
|
|
41
|
+
- frontend
|
|
42
|
+
- backend
|
|
43
|
+
|
|
44
|
+
postgres:
|
|
45
|
+
image: postgres:16
|
|
46
|
+
restart: unless-stopped
|
|
47
|
+
environment:
|
|
48
|
+
POSTGRES_USER: urateam
|
|
49
|
+
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set in .env}
|
|
50
|
+
POSTGRES_DB: urateam
|
|
51
|
+
volumes:
|
|
52
|
+
- pgdata:/var/lib/postgresql/data
|
|
53
|
+
networks:
|
|
54
|
+
- backend
|
|
55
|
+
|
|
56
|
+
networks:
|
|
57
|
+
frontend:
|
|
58
|
+
backend:
|
|
24
59
|
|
|
25
60
|
volumes:
|
|
26
61
|
pgdata:
|
|
27
62
|
agent-runs:
|
|
28
63
|
agent-repos:
|
|
64
|
+
caddy-data:
|
|
65
|
+
caddy-config:
|
|
66
|
+
claude-config:
|
|
67
|
+
gh-config:
|