coxpit 2.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/.env.example ADDED
@@ -0,0 +1,10 @@
1
+ # Coxpit OSS — 설정 예시. 실값은 .env 로 복사(커밋 금지). 시크릿 번들 0.
2
+ COXPIT_HOST=127.0.0.1
3
+ COXPIT_PORT=8210
4
+ COXPIT_DB=./coxpit.db
5
+
6
+ # 인증 게이트(basic). 프로덕션은 앞단에 Cloudflare Access / Tailscale 권장.
7
+ COXPIT_AUTH_USER=admin
8
+ COXPIT_AUTH_PASS=
9
+ # 로컬 개발 시 인증 끄기:
10
+ # COXPIT_AUTH_DISABLED=1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 gc.yang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # Coxpit
2
+
3
+ **Own your agent fleet. Run parallel AI coding agents across your own machines — steer them from any browser.**
4
+
5
+ **[Landing & downloads](https://hanmariyang.github.io/coxpit-oss/)** · [Latest release](https://github.com/hanmariyang/coxpit-oss/releases/latest)
6
+
7
+ ![coxpit fleet board — three agents racing the same task](docs/demo.gif)
8
+
9
+ Coxpit is a self-hosted cockpit for CLI coding agents (Claude Code first). Give it a task and it launches N agents in parallel — each in its own **isolated git worktree**, on its own branch, inside its own tmux session — then streams everything to a live board where you watch, compare diffs side by side, attach a real terminal, and merge the winner.
10
+
11
+ Your machines. Your auth. Your code never leaves your network.
12
+
13
+ ## What it does
14
+
15
+ - **Fleet runs** — one task, N agents. Each run = worktree + branch + tmux window. No agent ever touches your checkout.
16
+ - **Live board** — WebSocket-driven console: status, event timeline (parsed from the agent's stream-json), per-run diff.
17
+ - **Compare & merge** — all runs of a task side by side; pick the winner, merge to the base branch (auto-commits the worktree, guards a clean base, aborts on conflict).
18
+ - **Real terminal** — attach to any run's tmux session in the browser (xterm.js over a server-side PTY; resize propagates, `Ctrl-b d` detaches).
19
+ - **Multi-machine** — register remote machines over SSH (Tailscale/LAN); probe reachability (git·tmux), run fleets there.
20
+ - **Safe stops** — stop kills the whole process group; task close stops and cleans every worktree/branch.
21
+ - **Design Mode** — drag the `⌖ coxpit inspect` bookmarklet to your bar, click it on your running app, click any element: its selector, HTML and computed styles are captured and injected into the agents' prompt as design context.
22
+
23
+ External tools are spawned, never vendored: `git`, `tmux`, your agent CLI. No editor bundled — terminal-first.
24
+
25
+ | Fleet board | Compare & merge |
26
+ |---|---|
27
+ | ![board](docs/shot-board.png) | ![compare](docs/shot-compare.png) |
28
+
29
+ ## Quickstart
30
+
31
+ Requirements: Node 20+, git, tmux, an agent CLI on PATH (e.g. `claude`).
32
+
33
+ ```bash
34
+ npm install
35
+ cp .env.example .env # set COXPIT_AUTH_PASS (or COXPIT_AUTH_DISABLED=1 locally)
36
+ npm run dev # → http://127.0.0.1:8210
37
+ ```
38
+
39
+ Open the board, register a repo (absolute path), write a task, hit **Run fleet**.
40
+
41
+ By default agents run in **dry-run mode** (a mock that exercises the whole pipeline without spending credits). Flip the "real agent" toggle per launch, or set `COXPIT_AGENT_REAL=1` to default to real.
42
+
43
+ ## Configuration
44
+
45
+ | env | default | what |
46
+ |---|---|---|
47
+ | `COXPIT_HOST` / `COXPIT_PORT` | `127.0.0.1` / `8210` | daemon bind |
48
+ | `COXPIT_DB` | `./coxpit.db` | SQLite (libSQL) file |
49
+ | `COXPIT_AUTH_PASS` / `COXPIT_AUTH_USER` | — / `admin` | basic auth (empty pass = open; set it) |
50
+ | `COXPIT_AUTH_DISABLED` | — | `1` disables auth (local dev only) |
51
+ | `COXPIT_SSH_KEY` | — | private key for remote machines (else ssh defaults/agent) |
52
+ | `COXPIT_AGENT_REAL` | — | `1` = real agent CLI by default (credits!) |
53
+ | `COXPIT_AGENT_BIN` | `claude` | agent command |
54
+ | `COXPIT_AGENT_PERM` | `acceptEdits` | headless permission mode passed to the agent |
55
+
56
+ Running on the open internet? Put it behind your own front door (Tailscale, Cloudflare Access, a reverse proxy with TLS) and keep basic auth on — it exposes shells.
57
+
58
+ ## Architecture
59
+
60
+ ```
61
+ browser (board · xterm)
62
+ │ HTTP + WS
63
+ daemon — Node/TS · Fastify · libSQL(Drizzle)
64
+ │ spawn / ssh
65
+ machines — git worktrees · tmux sessions · agent CLIs
66
+ ```
67
+
68
+ One daemon, one SQLite file, zero external services. Machines are reached over SSH; the local machine is just `sh`.
69
+
70
+ ## Status
71
+
72
+ `v2.0` — agent fleet (P1), compare/review + terminal (P2), and Design Mode (P3) are implemented and tested. Roadmap: richer review tooling, more agent providers, packaging (Docker/npm).
73
+
74
+ ## License
75
+
76
+ MIT
package/bin/coxpit.js ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ // coxpit CLI — boots the daemon. Ships TS sources and runs them via tsx
3
+ // (no build step, no ESM extension rewrites).
4
+ import { spawn } from 'node:child_process';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { dirname, join } from 'node:path';
7
+
8
+ const root = dirname(dirname(fileURLToPath(import.meta.url)));
9
+ const entry = join(root, 'src', 'index.ts');
10
+
11
+ const child = spawn(process.execPath, ['--import', 'tsx', entry, ...process.argv.slice(2)], {
12
+ stdio: 'inherit',
13
+ env: process.env,
14
+ });
15
+ child.on('exit', (code, sig) => process.exit(code ?? (sig ? 1 : 0)));
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "coxpit",
3
+ "version": "2.1.0",
4
+ "description": "Self-hosted cockpit for running a fleet of AI coding agents across your own machines — parallel worktree runs, live board, compare & merge, web terminal, design capture.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": { "type": "git", "url": "git+https://github.com/hanmariyang/coxpit-oss.git" },
8
+ "homepage": "https://hanmariyang.github.io/coxpit-oss/",
9
+ "bugs": { "url": "https://github.com/hanmariyang/coxpit-oss/issues" },
10
+ "keywords": ["ai-agents", "claude-code", "git-worktree", "tmux", "self-hosted", "fleet", "coding-agents", "cockpit"],
11
+ "engines": { "node": ">=20" },
12
+ "bin": { "coxpit": "bin/coxpit.js" },
13
+ "files": ["bin", "src", "README.md", "LICENSE", ".env.example"],
14
+ "scripts": {
15
+ "dev": "tsx watch src/index.ts",
16
+ "start": "tsx src/index.ts",
17
+ "typecheck": "tsc --noEmit",
18
+ "build": "tsc"
19
+ },
20
+ "dependencies": {
21
+ "@fastify/websocket": "^11",
22
+ "@libsql/client": "^0.14",
23
+ "@xterm/addon-fit": "^0.11.0",
24
+ "@xterm/xterm": "^6.0.0",
25
+ "dotenv": "^16",
26
+ "drizzle-orm": "^0.38",
27
+ "fastify": "^5",
28
+ "node-pty": "^1.1.0",
29
+ "tsx": "^4"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^22",
33
+ "drizzle-kit": "^0.30",
34
+ "typescript": "^5"
35
+ }
36
+ }
package/src/auth.ts ADDED
@@ -0,0 +1,26 @@
1
+ import type { FastifyRequest, FastifyReply } from 'fastify';
2
+ import { config } from './config';
3
+
4
+ // /api/design/capture · /design/bookmarklet.js 는 외부 앱(북마클릿)에서 오므로
5
+ // basic 헤더를 못 싣는다 — 라우트 자체가 캡처 키(?k=)를 검증한다.
6
+ const EXEMPT = new Set(['/api/health', '/api/design/capture', '/design/bookmarklet.js']);
7
+
8
+ /**
9
+ * 인증 게이트 — 현재 basic. 플러그형 좌석: 배포 시 앞단에 Cloudflare Access / Tailscale 을
10
+ * 두는 것을 권장(그 경우 COXPIT_AUTH_DISABLED=1 로 내부 인증을 끄고 게이트웨이에 위임).
11
+ */
12
+ export async function authGate(req: FastifyRequest, reply: FastifyReply): Promise<void> {
13
+ if (config.auth.disabled) return;
14
+ const path = req.url.split('?')[0] ?? '';
15
+ if (EXEMPT.has(path)) return;
16
+
17
+ const h = req.headers.authorization ?? '';
18
+ if (h.startsWith('Basic ') && config.auth.pass !== '') {
19
+ const decoded = Buffer.from(h.slice(6), 'base64').toString('utf8');
20
+ const idx = decoded.indexOf(':');
21
+ const u = decoded.slice(0, idx);
22
+ const p = decoded.slice(idx + 1);
23
+ if (u === config.auth.user && p === config.auth.pass) return;
24
+ }
25
+ await reply.header('WWW-Authenticate', 'Basic realm="coxpit"').code(401).send({ error: 'unauthorized' });
26
+ }