atlas-hq 0.1.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 +52 -0
- package/bin/cli.mjs +5 -0
- package/docker-compose.yml +85 -0
- package/lib/index.mjs +211 -0
- package/package.json +30 -0
package/README.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# atlas-hq
|
|
2
|
+
|
|
3
|
+
CLI launcher for [Atlas HQ](https://github.com/nord-initiatives/atlas_hq) — task management for AI agent teams.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx atlas-hq start
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
That's it. Atlas HQ will be running at [http://localhost:3500](http://localhost:3500).
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
- [Docker Desktop](https://docs.docker.com/get-docker/) (with Docker Compose V2)
|
|
16
|
+
- Node.js ≥ 18
|
|
17
|
+
|
|
18
|
+
## Commands
|
|
19
|
+
|
|
20
|
+
| Command | Description |
|
|
21
|
+
| ----------------- | ------------------------------------ |
|
|
22
|
+
| `atlas-hq start` | Pull images and start the stack |
|
|
23
|
+
| `atlas-hq stop` | Stop the stack |
|
|
24
|
+
| `atlas-hq status` | Show running container status |
|
|
25
|
+
| `atlas-hq open` | Open the UI in your browser |
|
|
26
|
+
| `atlas-hq help` | Show help |
|
|
27
|
+
|
|
28
|
+
## Options
|
|
29
|
+
|
|
30
|
+
| Flag | Description | Default |
|
|
31
|
+
| ----------------- | ------------------------------------ | ------- |
|
|
32
|
+
| `--port-api` | Host port for the API | 3501 |
|
|
33
|
+
| `--port-ui` | Host port for the UI | 3500 |
|
|
34
|
+
|
|
35
|
+
Environment variables `ATLAS_HQ_API_PORT` and `ATLAS_HQ_UI_PORT` also work.
|
|
36
|
+
|
|
37
|
+
## Examples
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Start with custom ports
|
|
41
|
+
npx atlas-hq start --port-ui 8080 --port-api 8081
|
|
42
|
+
|
|
43
|
+
# Check status
|
|
44
|
+
npx atlas-hq status
|
|
45
|
+
|
|
46
|
+
# Stop
|
|
47
|
+
npx atlas-hq stop
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## License
|
|
51
|
+
|
|
52
|
+
MIT
|
package/bin/cli.mjs
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
###############################################################################
|
|
2
|
+
# docker-compose.yml — Atlas HQ full-stack one-command local install
|
|
3
|
+
#
|
|
4
|
+
# Spins up:
|
|
5
|
+
# atlas-hq-api Atlas HQ API → http://localhost:3501
|
|
6
|
+
# atlas-hq-ui Atlas HQ UI → http://localhost:3500
|
|
7
|
+
#
|
|
8
|
+
# Named volume:
|
|
9
|
+
# atlas-hq-data SQLite database persistence (/data inside the API container)
|
|
10
|
+
#
|
|
11
|
+
# ── Quick start ───────────────────────────────────────────────────────────────
|
|
12
|
+
# docker compose up # build images and start everything (foreground)
|
|
13
|
+
# docker compose up -d # same, detached
|
|
14
|
+
# docker compose down # stop and remove containers (data volume kept)
|
|
15
|
+
# docker compose down -v # ⚠️ also removes the data volume (wipes DB)
|
|
16
|
+
#
|
|
17
|
+
# ── Local overrides ───────────────────────────────────────────────────────────
|
|
18
|
+
# Copy docker-compose.override.yml.example to docker-compose.override.yml
|
|
19
|
+
# and edit it. Docker Compose merges it automatically — no extra flags needed.
|
|
20
|
+
#
|
|
21
|
+
# ── Environment variables ─────────────────────────────────────────────────────
|
|
22
|
+
# ATLAS_HQ_API_PORT Host port for the API (default: 3501)
|
|
23
|
+
# ATLAS_HQ_UI_PORT Host port for the UI (default: 3500)
|
|
24
|
+
# NEXT_PUBLIC_API_URL API URL baked into the UI build
|
|
25
|
+
# (default: http://localhost:3501)
|
|
26
|
+
###############################################################################
|
|
27
|
+
|
|
28
|
+
name: atlas-hq
|
|
29
|
+
|
|
30
|
+
# ── Named volume for SQLite persistence ───────────────────────────────────────
|
|
31
|
+
volumes:
|
|
32
|
+
atlas-hq-data:
|
|
33
|
+
driver: local
|
|
34
|
+
|
|
35
|
+
# ── Services ──────────────────────────────────────────────────────────────────
|
|
36
|
+
services:
|
|
37
|
+
|
|
38
|
+
# ── API ─────────────────────────────────────────────────────────────────────
|
|
39
|
+
atlas-hq-api:
|
|
40
|
+
build:
|
|
41
|
+
context: .
|
|
42
|
+
dockerfile: docker/Dockerfile.api
|
|
43
|
+
image: atlas-hq-api:local
|
|
44
|
+
container_name: atlas-hq-api
|
|
45
|
+
restart: unless-stopped
|
|
46
|
+
ports:
|
|
47
|
+
- "${ATLAS_HQ_API_PORT:-3501}:3501"
|
|
48
|
+
volumes:
|
|
49
|
+
- atlas-hq-data:/data
|
|
50
|
+
environment:
|
|
51
|
+
NODE_ENV: production
|
|
52
|
+
PORT: "3501"
|
|
53
|
+
ATLAS_HQ_DB_PATH: /data/atlas.db
|
|
54
|
+
ATLAS_HQ_DATA_DIR: /data
|
|
55
|
+
healthcheck:
|
|
56
|
+
test: ["CMD", "wget", "-qO-", "http://localhost:3501/health"]
|
|
57
|
+
interval: 30s
|
|
58
|
+
timeout: 10s
|
|
59
|
+
retries: 5
|
|
60
|
+
start_period: 15s
|
|
61
|
+
|
|
62
|
+
# ── UI ──────────────────────────────────────────────────────────────────────
|
|
63
|
+
atlas-hq-ui:
|
|
64
|
+
build:
|
|
65
|
+
context: .
|
|
66
|
+
dockerfile: docker/Dockerfile.ui
|
|
67
|
+
args:
|
|
68
|
+
NEXT_PUBLIC_API_URL: "${NEXT_PUBLIC_API_URL:-http://localhost:3501}"
|
|
69
|
+
image: atlas-hq-ui:local
|
|
70
|
+
container_name: atlas-hq-ui
|
|
71
|
+
restart: unless-stopped
|
|
72
|
+
ports:
|
|
73
|
+
- "${ATLAS_HQ_UI_PORT:-3500}:3500"
|
|
74
|
+
environment:
|
|
75
|
+
NODE_ENV: production
|
|
76
|
+
PORT: "3500"
|
|
77
|
+
depends_on:
|
|
78
|
+
atlas-hq-api:
|
|
79
|
+
condition: service_healthy
|
|
80
|
+
healthcheck:
|
|
81
|
+
test: ["CMD", "wget", "-qO-", "http://localhost:3500"]
|
|
82
|
+
interval: 30s
|
|
83
|
+
timeout: 10s
|
|
84
|
+
retries: 5
|
|
85
|
+
start_period: 20s
|
package/lib/index.mjs
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { execSync, execFileSync } from 'node:child_process';
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
|
|
7
|
+
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
8
|
+
const COMPOSE_SOURCE = join(__dirname, '..', 'docker-compose.yml');
|
|
9
|
+
|
|
10
|
+
// Data directory where we keep the compose file and any local config
|
|
11
|
+
const DATA_DIR = join(homedir(), '.atlas-hq');
|
|
12
|
+
|
|
13
|
+
const HELP = `
|
|
14
|
+
atlas-hq — CLI launcher for Atlas HQ
|
|
15
|
+
|
|
16
|
+
Usage:
|
|
17
|
+
atlas-hq <command> [options]
|
|
18
|
+
|
|
19
|
+
Commands:
|
|
20
|
+
start Pull images and start the Atlas HQ stack
|
|
21
|
+
stop Stop the Atlas HQ stack
|
|
22
|
+
status Show running container status
|
|
23
|
+
open Open the Atlas HQ UI in a browser
|
|
24
|
+
help Show this help message
|
|
25
|
+
|
|
26
|
+
Options:
|
|
27
|
+
--port-api <port> Host port for the API (default: 3501, env: ATLAS_HQ_API_PORT)
|
|
28
|
+
--port-ui <port> Host port for the UI (default: 3500, env: ATLAS_HQ_UI_PORT)
|
|
29
|
+
|
|
30
|
+
Examples:
|
|
31
|
+
npx atlas-hq start
|
|
32
|
+
npx atlas-hq start --port-ui 8080
|
|
33
|
+
npx atlas-hq stop
|
|
34
|
+
`.trim();
|
|
35
|
+
|
|
36
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
function die(msg) {
|
|
39
|
+
console.error(`\x1b[31m✗\x1b[0m ${msg}`);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function info(msg) {
|
|
44
|
+
console.log(`\x1b[36mℹ\x1b[0m ${msg}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function success(msg) {
|
|
48
|
+
console.log(`\x1b[32m✓\x1b[0m ${msg}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function checkDocker() {
|
|
52
|
+
try {
|
|
53
|
+
execFileSync('docker', ['--version'], { stdio: 'pipe' });
|
|
54
|
+
} catch {
|
|
55
|
+
die(
|
|
56
|
+
'Docker is not installed or not in PATH.\n' +
|
|
57
|
+
' Install Docker Desktop: https://docs.docker.com/get-docker/\n' +
|
|
58
|
+
' Then run this command again.'
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Check Docker daemon is running
|
|
63
|
+
try {
|
|
64
|
+
execFileSync('docker', ['info'], { stdio: 'pipe' });
|
|
65
|
+
} catch {
|
|
66
|
+
die(
|
|
67
|
+
'Docker daemon is not running.\n' +
|
|
68
|
+
' Start Docker Desktop and try again.'
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Check docker compose is available
|
|
73
|
+
try {
|
|
74
|
+
execFileSync('docker', ['compose', 'version'], { stdio: 'pipe' });
|
|
75
|
+
} catch {
|
|
76
|
+
die(
|
|
77
|
+
'Docker Compose (V2) is not available.\n' +
|
|
78
|
+
' Update Docker Desktop or install the compose plugin:\n' +
|
|
79
|
+
' https://docs.docker.com/compose/install/'
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function ensureDataDir() {
|
|
85
|
+
if (!existsSync(DATA_DIR)) {
|
|
86
|
+
mkdirSync(DATA_DIR, { recursive: true });
|
|
87
|
+
}
|
|
88
|
+
// Copy compose file into data dir so Docker Compose has a stable project dir
|
|
89
|
+
const dest = join(DATA_DIR, 'docker-compose.yml');
|
|
90
|
+
writeFileSync(dest, readFileSync(COMPOSE_SOURCE));
|
|
91
|
+
return DATA_DIR;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function compose(args, opts = {}) {
|
|
95
|
+
const cwd = ensureDataDir();
|
|
96
|
+
const cmd = ['docker', 'compose', ...args].join(' ');
|
|
97
|
+
try {
|
|
98
|
+
execSync(cmd, { cwd, stdio: 'inherit', ...opts });
|
|
99
|
+
} catch (e) {
|
|
100
|
+
if (!opts.ignoreError) {
|
|
101
|
+
die(`Command failed: ${cmd}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function parseFlags(argv) {
|
|
107
|
+
const flags = {};
|
|
108
|
+
for (let i = 0; i < argv.length; i++) {
|
|
109
|
+
if (argv[i] === '--port-api' && argv[i + 1]) {
|
|
110
|
+
flags.apiPort = argv[++i];
|
|
111
|
+
} else if (argv[i] === '--port-ui' && argv[i + 1]) {
|
|
112
|
+
flags.uiPort = argv[++i];
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return flags;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function setPortEnv(flags) {
|
|
119
|
+
if (flags.apiPort) process.env.ATLAS_HQ_API_PORT = flags.apiPort;
|
|
120
|
+
if (flags.uiPort) process.env.ATLAS_HQ_UI_PORT = flags.uiPort;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function getUiPort() {
|
|
124
|
+
return process.env.ATLAS_HQ_UI_PORT || '3500';
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function openBrowser(url) {
|
|
128
|
+
const platform = process.platform;
|
|
129
|
+
try {
|
|
130
|
+
if (platform === 'darwin') {
|
|
131
|
+
execFileSync('open', [url], { stdio: 'pipe' });
|
|
132
|
+
} else if (platform === 'win32') {
|
|
133
|
+
execFileSync('cmd', ['/c', 'start', url], { stdio: 'pipe' });
|
|
134
|
+
} else {
|
|
135
|
+
execFileSync('xdg-open', [url], { stdio: 'pipe' });
|
|
136
|
+
}
|
|
137
|
+
} catch {
|
|
138
|
+
info(`Could not open browser automatically. Visit: ${url}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ── Commands ─────────────────────────────────────────────────────────────────
|
|
143
|
+
|
|
144
|
+
function cmdStart(flags) {
|
|
145
|
+
checkDocker();
|
|
146
|
+
setPortEnv(flags);
|
|
147
|
+
const uiPort = getUiPort();
|
|
148
|
+
const apiPort = process.env.ATLAS_HQ_API_PORT || '3501';
|
|
149
|
+
|
|
150
|
+
info('Pulling latest Atlas HQ images…');
|
|
151
|
+
compose(['pull']);
|
|
152
|
+
|
|
153
|
+
info('Starting Atlas HQ…');
|
|
154
|
+
compose(['up', '-d', '--remove-orphans']);
|
|
155
|
+
|
|
156
|
+
success(`Atlas HQ is starting!`);
|
|
157
|
+
console.log(` UI: http://localhost:${uiPort}`);
|
|
158
|
+
console.log(` API: http://localhost:${apiPort}`);
|
|
159
|
+
console.log(`\n Run \x1b[1matlas-hq open\x1b[0m to open the UI in your browser.`);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function cmdStop() {
|
|
163
|
+
checkDocker();
|
|
164
|
+
info('Stopping Atlas HQ…');
|
|
165
|
+
compose(['down']);
|
|
166
|
+
success('Atlas HQ stopped.');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function cmdStatus() {
|
|
170
|
+
checkDocker();
|
|
171
|
+
ensureDataDir();
|
|
172
|
+
compose(['ps'], { ignoreError: true });
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function cmdOpen(flags) {
|
|
176
|
+
setPortEnv(flags);
|
|
177
|
+
const uiPort = getUiPort();
|
|
178
|
+
const url = `http://localhost:${uiPort}`;
|
|
179
|
+
info(`Opening ${url}…`);
|
|
180
|
+
openBrowser(url);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ── Main ─────────────────────────────────────────────────────────────────────
|
|
184
|
+
|
|
185
|
+
export function run(argv) {
|
|
186
|
+
const command = argv[0];
|
|
187
|
+
const flags = parseFlags(argv.slice(1));
|
|
188
|
+
|
|
189
|
+
switch (command) {
|
|
190
|
+
case 'start':
|
|
191
|
+
cmdStart(flags);
|
|
192
|
+
break;
|
|
193
|
+
case 'stop':
|
|
194
|
+
cmdStop();
|
|
195
|
+
break;
|
|
196
|
+
case 'status':
|
|
197
|
+
cmdStatus();
|
|
198
|
+
break;
|
|
199
|
+
case 'open':
|
|
200
|
+
cmdOpen(flags);
|
|
201
|
+
break;
|
|
202
|
+
case 'help':
|
|
203
|
+
case '--help':
|
|
204
|
+
case '-h':
|
|
205
|
+
case undefined:
|
|
206
|
+
console.log(HELP);
|
|
207
|
+
break;
|
|
208
|
+
default:
|
|
209
|
+
die(`Unknown command: ${command}\n\nRun \x1b[1matlas-hq help\x1b[0m for usage.`);
|
|
210
|
+
}
|
|
211
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "atlas-hq",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI launcher for Atlas HQ — task management for AI agent teams",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"bin": {
|
|
7
|
+
"atlas-hq": "./bin/cli.mjs"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": ">=18"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"bin/",
|
|
15
|
+
"lib/",
|
|
16
|
+
"docker-compose.yml",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"keywords": [
|
|
20
|
+
"atlas-hq",
|
|
21
|
+
"task-management",
|
|
22
|
+
"ai-agents",
|
|
23
|
+
"docker",
|
|
24
|
+
"cli"
|
|
25
|
+
],
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/nord-initiatives/atlas_hq"
|
|
29
|
+
}
|
|
30
|
+
}
|