tono 0.2.0 → 0.3.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.
Files changed (59) hide show
  1. package/README.md +95 -3
  2. package/dist/cli/checks.js +504 -0
  3. package/dist/cli/checks.js.map +1 -0
  4. package/dist/cli/commands/config.js +20 -3
  5. package/dist/cli/commands/config.js.map +1 -1
  6. package/dist/cli/commands/configure.js +1 -1
  7. package/dist/cli/commands/configure.js.map +1 -1
  8. package/dist/cli/commands/doctor.js +22 -0
  9. package/dist/cli/commands/doctor.js.map +1 -0
  10. package/dist/cli/commands/gateway.js +23 -10
  11. package/dist/cli/commands/gateway.js.map +1 -1
  12. package/dist/cli/commands/init.js +22 -3
  13. package/dist/cli/commands/init.js.map +1 -1
  14. package/dist/cli/commands/start.js +72 -18
  15. package/dist/cli/commands/start.js.map +1 -1
  16. package/dist/cli/commands/worker.js +458 -0
  17. package/dist/cli/commands/worker.js.map +1 -0
  18. package/dist/cli/index.js +28 -9
  19. package/dist/cli/index.js.map +1 -1
  20. package/dist/cli/launchd.js +5 -5
  21. package/dist/cli/launchd.js.map +1 -1
  22. package/dist/server/app.js +90 -14
  23. package/dist/server/app.js.map +1 -1
  24. package/dist/server/config/load.js +19 -1
  25. package/dist/server/config/load.js.map +1 -1
  26. package/dist/server/config/schema.json +19 -0
  27. package/dist/server/db/client.js +50 -1
  28. package/dist/server/db/client.js.map +1 -1
  29. package/dist/server/db/queries.js +126 -3
  30. package/dist/server/db/queries.js.map +1 -1
  31. package/dist/server/db/schema.sql +36 -21
  32. package/dist/server/events.js.map +1 -1
  33. package/dist/server/server.js +28 -11
  34. package/dist/server/server.js.map +1 -1
  35. package/dist/server/worker/agent.js +396 -0
  36. package/dist/server/worker/agent.js.map +1 -0
  37. package/dist/server/worker/pty-bridge.js +27 -0
  38. package/dist/server/worker/pty-bridge.js.map +1 -0
  39. package/dist/server/workers/github-poller.js +26 -8
  40. package/dist/server/workers/github-poller.js.map +1 -1
  41. package/dist/server/workers/reaper.js +44 -0
  42. package/dist/server/workers/reaper.js.map +1 -0
  43. package/dist/server/workers/registry.js +166 -0
  44. package/dist/server/workers/registry.js.map +1 -0
  45. package/dist/server/workers/scheduler.js +79 -130
  46. package/dist/server/workers/scheduler.js.map +1 -1
  47. package/dist/server/ws/pty.js +66 -54
  48. package/dist/server/ws/pty.js.map +1 -1
  49. package/dist/server/ws/workers.js +206 -0
  50. package/dist/server/ws/workers.js.map +1 -0
  51. package/dist/shared/types.js +4 -1
  52. package/dist/shared/types.js.map +1 -1
  53. package/dist/shared/version.js +18 -0
  54. package/dist/shared/version.js.map +1 -0
  55. package/dist/shared/worker-protocol.js +28 -0
  56. package/dist/shared/worker-protocol.js.map +1 -0
  57. package/dist/web/assets/{index-5VFn-lxF.js → index-DPB0x7SX.js} +21 -21
  58. package/dist/web/index.html +1 -1
  59. package/package.json +18 -26
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # tono
2
2
 
3
- A self-hosted gateway that turns labeled GitHub issues and PRs into running CLI agents.
3
+ Self-hosted orchestrator for CLI agent tools (Claude Code, Codex CLI, OpenCode) triggered by GitHub issue labels.
4
4
 
5
- > *The name is the middle of **au·tono·mous** — fitting for a tool whose whole job is letting agents run unattended.*
5
+ > *Etymology: **tono** is the middle of **au·tono·mous** — fitting for a tool whose whole job is letting agents run unattended.*
6
6
 
7
7
  > **Heads up: this project was entirely vibe-coded by AI.** Every line of code, every commit, every README revision (including this one). Read accordingly — there are no human-reviewed parts. Use at your own risk.
8
8
 
@@ -291,10 +291,102 @@ What's next:
291
291
 
292
292
  - **Webhook triggers** to drop polling latency from ~60s to sub-second (Tailscale Funnel or smee.io).
293
293
  - **Manual review-task trigger** in the UI (today: label the PR).
294
- - **Distributed workers.** Designed but unbuilt. The gateway becomes a coordinator; workers connect over WebSocket and run agents on their own filesystems. Tailscale required, no app-level auth.
295
294
  - **Cost / token tracking.**
296
295
  - **Inline review comments** posted by tono itself rather than asking the agent to call `gh api`.
297
296
 
297
+ ## Distributed workers
298
+
299
+ Tono can be split across multiple machines: one **gateway** (always-on box —
300
+ e.g. your Mac mini) plus any number of **workers** (your MacBook, a Windows
301
+ laptop, …) that connect outbound over a tailnet and execute agent runs on
302
+ their own filesystem. Each connected worker adds capacity for the
303
+ `(agent, kind)` partitions it advertises.
304
+
305
+ **Topology.** The gateway owns the SQLite state, GitHub poller, PR watcher,
306
+ scheduler, browser UI, and config. Workers own a local `node-pty` and a
307
+ local `.bare/` clone cache. Tasks flow:
308
+
309
+ ```
310
+ poller (gateway) → scheduler picks an eligible worker
311
+ → task.assign over WS → worker creates worktree, spawns agent
312
+ → PTY data streams back to gateway → browser UI
313
+ ```
314
+
315
+ `tono start` continues to work unchanged on a single box: it launches an
316
+ **embedded local worker** in the same process that connects to its own
317
+ gateway over `127.0.0.1`. The embedded worker is fungible with remote ones —
318
+ the scheduler just sees more capacity once a remote worker connects.
319
+
320
+ **Prerequisites (per worker machine):**
321
+
322
+ - [Tailscale](https://tailscale.com) with the worker on the same tailnet as
323
+ the gateway. There is no app-level auth — reachability over the tailnet IS
324
+ the trust boundary. The gateway should bind on its tailnet IP (or
325
+ `0.0.0.0` if the LAN is also trusted).
326
+ - `gh` CLI, authenticated (`gh auth login`). The worker bare-clones repos
327
+ itself; it does not pull git data through the gateway.
328
+ - The agent CLIs you want this worker to run (`claude`, `codex`,
329
+ `opencode`). The worker auto-detects which are on PATH and advertises
330
+ those as its capabilities.
331
+
332
+ **Run a remote worker (foreground):**
333
+
334
+ ```bash
335
+ tono worker run --gateway <gateway-host>:7040
336
+ # advertise specific agent commands and concurrency:
337
+ tono worker run \
338
+ --gateway my-mac-mini:7040 \
339
+ --agent claude-code=claude \
340
+ --concurrency claude-code=3/2
341
+ ```
342
+
343
+ **Run a remote worker as a background daemon (macOS):**
344
+
345
+ ```bash
346
+ # first time: install + load the LaunchAgent (com.tono.worker)
347
+ tono worker start --gateway my-mac-mini:7040
348
+
349
+ # later: lifecycle commands mirror `tono gateway`
350
+ tono worker stop
351
+ tono worker restart # reload after settings changes
352
+ tono worker status # plist state + connection
353
+ tono worker logs # tail ~/.tono/logs/worker.out.log
354
+ tono worker uninstall # remove the LaunchAgent
355
+ ```
356
+
357
+ Settings persist in `~/.tono/worker.json` (gateway URL, agent commands,
358
+ concurrency, paths). The first `start` / `run` writes them; later
359
+ invocations don't need flags. Pass new flags to override and re-persist
360
+ (`tono worker restart --concurrency claude-code=4/2` updates the JSON and
361
+ reloads the daemon). The same file holds a stable worker UUID so reconnects
362
+ pick up the same identity.
363
+
364
+ Workers reconnect with exponential backoff; if the gateway is offline the
365
+ worker sits idle until it returns.
366
+
367
+ **Disconnect handling.** When a worker drops mid-run (laptop sleeps, Wi-Fi
368
+ blip), the gateway holds the task as `running` for `workers.graceMs`
369
+ (default 60 000 ms). Reconnect within the window resumes the live stream.
370
+ After the grace expires the task is marked `failed` with `exit_code = -3`
371
+ and you can retry it. The setting lives in `~/.tono/config.json` under
372
+ the optional `workers` block:
373
+
374
+ ```json
375
+ {
376
+ "workers": { "graceMs": 60000 }
377
+ }
378
+ ```
379
+
380
+ **Caveats (v1):**
381
+
382
+ - No worker affinity / pinning yet — workers are fungible by capability.
383
+ - Worktree cleanup runs on the gateway's filesystem only. For tasks that
384
+ ran on a remote worker, the worktree under that worker's
385
+ `~/.tono/workspaces/` is left in place; clean it up there manually with
386
+ `git worktree remove`.
387
+ - Free-form shells in the UI are gateway-local (they always run in the
388
+ gateway process, not on workers).
389
+
298
390
  ## License
299
391
 
300
392
  [MIT](./LICENSE).
@@ -0,0 +1,504 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { accessSync, constants, existsSync, statSync } from "node:fs";
3
+ import * as gh from "../server/github/gh.js";
4
+ import { ConfigError, configPath, expandHome, loadConfig, } from "../server/config/load.js";
5
+ import { dbPath, openDb } from "../server/db/client.js";
6
+ import { GATEWAY_LABEL, plistPath } from "./launchd.js";
7
+ /** Run every check in a sensible order, returning a flat list of results. */
8
+ export async function runChecks(opts = {}) {
9
+ const out = [];
10
+ // External tools — always required.
11
+ out.push(await checkGitInstalled());
12
+ out.push(await checkGhInstalled());
13
+ // Config — try to load. If we can't, downstream checks (agents, repos) are skipped.
14
+ const cfgResult = await checkConfig();
15
+ out.push(cfgResult.result);
16
+ const cfg = cfgResult.cfg;
17
+ // gh auth — only meaningful if gh is installed. We still attempt the check
18
+ // (it'll just report the same error) so the user sees a clear "log in" hint.
19
+ out.push(await checkGhAuth());
20
+ if (cfg) {
21
+ out.push(await checkAgentsDeclared(cfg));
22
+ for (const agent of Object.keys(cfg.agents)) {
23
+ out.push(await checkAgentInstalled(cfg, agent));
24
+ }
25
+ out.push(checkWorkspaces(cfg));
26
+ out.push(checkRepoPaths(cfg));
27
+ }
28
+ out.push(checkSchemaVersion());
29
+ if (!opts.skipGateway) {
30
+ out.push(checkGatewayPlist());
31
+ if (cfg)
32
+ out.push(await checkGatewayHealthy(cfg));
33
+ }
34
+ return out;
35
+ }
36
+ function which(cmd) {
37
+ const r = spawnSync("/usr/bin/env", ["sh", "-c", `command -v ${cmd}`], { encoding: "utf8" });
38
+ if (r.status === 0)
39
+ return r.stdout.trim() || null;
40
+ return null;
41
+ }
42
+ function tryRun(cmd, args, timeoutMs = 5000) {
43
+ const r = spawnSync(cmd, args, { encoding: "utf8", timeout: timeoutMs });
44
+ return {
45
+ ok: r.status === 0,
46
+ stdout: (r.stdout ?? "").trim(),
47
+ stderr: (r.stderr ?? "").trim(),
48
+ };
49
+ }
50
+ // — Individual checks —————————————————————————————————————————————————————
51
+ async function checkGitInstalled() {
52
+ const path = which("git");
53
+ if (!path) {
54
+ return {
55
+ id: "git.installed",
56
+ category: "required",
57
+ status: "fail",
58
+ title: "git",
59
+ detail: "not found on $PATH",
60
+ hint: "install git via Xcode Command Line Tools (`xcode-select --install`) or Homebrew (`brew install git`).",
61
+ };
62
+ }
63
+ const v = tryRun("git", ["--version"]);
64
+ return {
65
+ id: "git.installed",
66
+ category: "required",
67
+ status: "ok",
68
+ title: "git",
69
+ detail: v.stdout || path,
70
+ };
71
+ }
72
+ async function checkGhInstalled() {
73
+ const path = which("gh");
74
+ if (!path) {
75
+ return {
76
+ id: "gh.installed",
77
+ category: "required",
78
+ status: "fail",
79
+ title: "gh (GitHub CLI)",
80
+ detail: "not found on $PATH",
81
+ hint: "install via Homebrew (`brew install gh`) or from https://cli.github.com.",
82
+ };
83
+ }
84
+ const v = tryRun("gh", ["--version"]);
85
+ // First line of `gh --version` is "gh version X.Y.Z (...)". Keep only that.
86
+ const firstLine = v.stdout.split("\n")[0] ?? path;
87
+ return {
88
+ id: "gh.installed",
89
+ category: "required",
90
+ status: "ok",
91
+ title: "gh (GitHub CLI)",
92
+ detail: firstLine,
93
+ };
94
+ }
95
+ async function checkGhAuth() {
96
+ if (!which("gh")) {
97
+ return {
98
+ id: "gh.authenticated",
99
+ category: "required",
100
+ status: "fail",
101
+ title: "gh authentication",
102
+ detail: "skipped — gh is not installed",
103
+ };
104
+ }
105
+ try {
106
+ const r = await gh.authStatus();
107
+ if (r.ok) {
108
+ // `gh auth status` lists each host; keep it concise — first non-empty line.
109
+ const summary = r.detail.split("\n").map((l) => l.trim()).find((l) => l.length > 0) ?? "authenticated";
110
+ return {
111
+ id: "gh.authenticated",
112
+ category: "required",
113
+ status: "ok",
114
+ title: "gh authentication",
115
+ detail: summary.length > 80 ? summary.slice(0, 77) + "…" : summary,
116
+ };
117
+ }
118
+ return {
119
+ id: "gh.authenticated",
120
+ category: "required",
121
+ status: "fail",
122
+ title: "gh authentication",
123
+ detail: "not authenticated",
124
+ hint: "run `gh auth login` and grant access to your repos.",
125
+ };
126
+ }
127
+ catch (err) {
128
+ return {
129
+ id: "gh.authenticated",
130
+ category: "required",
131
+ status: "fail",
132
+ title: "gh authentication",
133
+ detail: err.message,
134
+ };
135
+ }
136
+ }
137
+ async function checkConfig() {
138
+ const path = configPath();
139
+ if (!existsSync(path)) {
140
+ return {
141
+ cfg: null,
142
+ result: {
143
+ id: "config.exists",
144
+ category: "required",
145
+ status: "fail",
146
+ title: "config",
147
+ detail: `not found at ${path}`,
148
+ hint: "run `tono init` (or `tono configure`) to create one.",
149
+ },
150
+ };
151
+ }
152
+ try {
153
+ const cfg = loadConfig();
154
+ return {
155
+ cfg,
156
+ result: {
157
+ id: "config.exists",
158
+ category: "required",
159
+ status: "ok",
160
+ title: "config",
161
+ detail: `valid · ${path}`,
162
+ },
163
+ };
164
+ }
165
+ catch (err) {
166
+ const message = err instanceof ConfigError ? err.message.split("\n")[0] : err.message;
167
+ return {
168
+ cfg: null,
169
+ result: {
170
+ id: "config.exists",
171
+ category: "required",
172
+ status: "fail",
173
+ title: "config",
174
+ detail: message,
175
+ hint: "fix the config file or re-run `tono configure`.",
176
+ },
177
+ };
178
+ }
179
+ }
180
+ async function checkAgentsDeclared(cfg) {
181
+ const declared = Object.keys(cfg.agents);
182
+ if (declared.length === 0) {
183
+ return {
184
+ id: "agents.declared",
185
+ category: "required",
186
+ status: "fail",
187
+ title: "agents declared",
188
+ detail: "no agents declared in config",
189
+ hint: "declare at least one of claude-code, codex, opencode in `agents` (or run `tono configure`).",
190
+ };
191
+ }
192
+ return {
193
+ id: "agents.declared",
194
+ category: "required",
195
+ status: "ok",
196
+ title: "agents declared",
197
+ detail: declared.join(", "),
198
+ };
199
+ }
200
+ async function checkAgentInstalled(cfg, agent) {
201
+ const a = cfg.agents[agent];
202
+ if (!a) {
203
+ // Shouldn't happen — checkAgentsDeclared already filters — but defensive.
204
+ return {
205
+ id: `agent.${agent}.installed`,
206
+ category: "required",
207
+ status: "fail",
208
+ title: `agent: ${agent}`,
209
+ detail: "no config block",
210
+ };
211
+ }
212
+ const path = which(a.command);
213
+ if (!path) {
214
+ return {
215
+ id: `agent.${agent}.installed`,
216
+ category: "required",
217
+ status: "fail",
218
+ title: `agent: ${agent}`,
219
+ detail: `\`${a.command}\` not found on $PATH`,
220
+ hint: hintForAgent(agent),
221
+ };
222
+ }
223
+ const v = tryRun(a.command, ["--version"]);
224
+ const firstLine = v.stdout.split("\n")[0] ?? path;
225
+ return {
226
+ id: `agent.${agent}.installed`,
227
+ category: "required",
228
+ status: "ok",
229
+ title: `agent: ${agent}`,
230
+ detail: firstLine,
231
+ };
232
+ }
233
+ function hintForAgent(agent) {
234
+ switch (agent) {
235
+ case "claude-code":
236
+ return "install Claude Code: https://docs.claude.com/en/docs/claude-code/quickstart";
237
+ case "codex":
238
+ return "install Codex CLI: `npm install -g @openai/codex` or https://github.com/openai/codex";
239
+ case "opencode":
240
+ return "install OpenCode: https://opencode.ai";
241
+ }
242
+ }
243
+ function checkWorkspaces(cfg) {
244
+ const root = cfg.workspaces.root;
245
+ if (!existsSync(root)) {
246
+ return {
247
+ id: "workspaces.exists",
248
+ category: "required",
249
+ status: "warn",
250
+ title: "workspaces root",
251
+ detail: `${root} does not exist (will be created on first task)`,
252
+ };
253
+ }
254
+ try {
255
+ accessSync(root, constants.W_OK);
256
+ }
257
+ catch {
258
+ return {
259
+ id: "workspaces.exists",
260
+ category: "required",
261
+ status: "fail",
262
+ title: "workspaces root",
263
+ detail: `${root} is not writable`,
264
+ hint: "fix the directory permissions or change `workspaces.root` in the config.",
265
+ };
266
+ }
267
+ return {
268
+ id: "workspaces.exists",
269
+ category: "required",
270
+ status: "ok",
271
+ title: "workspaces root",
272
+ detail: root,
273
+ };
274
+ }
275
+ function checkRepoPaths(cfg) {
276
+ const withPaths = cfg.repos.filter((r) => r.path && r.path.trim().length > 0);
277
+ if (withPaths.length === 0) {
278
+ return {
279
+ id: "repos.paths",
280
+ category: "optional",
281
+ status: "ok",
282
+ title: "repo paths",
283
+ detail: cfg.repos.length === 0
284
+ ? "no repos configured"
285
+ : `${cfg.repos.length} repo(s); none use a custom path (tono will bare-clone via gh)`,
286
+ };
287
+ }
288
+ const broken = [];
289
+ for (const r of withPaths) {
290
+ const p = expandHome(r.path);
291
+ if (!existsSync(p)) {
292
+ broken.push(`${r.slug} → ${p} (missing)`);
293
+ continue;
294
+ }
295
+ try {
296
+ if (!statSync(p).isDirectory())
297
+ broken.push(`${r.slug} → ${p} (not a directory)`);
298
+ }
299
+ catch {
300
+ broken.push(`${r.slug} → ${p} (unreadable)`);
301
+ }
302
+ }
303
+ if (broken.length > 0) {
304
+ return {
305
+ id: "repos.paths",
306
+ category: "required",
307
+ status: "fail",
308
+ title: "repo paths",
309
+ detail: broken.join("; "),
310
+ hint: "either fix the path on disk, set `path` to a valid clone, or remove the field to bare-clone via gh.",
311
+ };
312
+ }
313
+ return {
314
+ id: "repos.paths",
315
+ category: "required",
316
+ status: "ok",
317
+ title: "repo paths",
318
+ detail: `${withPaths.length}/${cfg.repos.length} repo(s) use a custom path; all valid`,
319
+ };
320
+ }
321
+ function checkSchemaVersion() {
322
+ const path = dbPath();
323
+ if (!existsSync(path)) {
324
+ return {
325
+ id: "db.schema",
326
+ category: "optional",
327
+ status: "ok",
328
+ title: "database schema",
329
+ detail: "database not yet created (will be on first run)",
330
+ };
331
+ }
332
+ try {
333
+ const db = openDb(path);
334
+ const row = db.prepare("SELECT version FROM schema_version LIMIT 1").get();
335
+ db.close();
336
+ return {
337
+ id: "db.schema",
338
+ category: "optional",
339
+ status: "ok",
340
+ title: "database schema",
341
+ detail: row ? `v${row.version}` : "uninitialized (will be set on next run)",
342
+ };
343
+ }
344
+ catch (err) {
345
+ return {
346
+ id: "db.schema",
347
+ category: "required",
348
+ status: "fail",
349
+ title: "database schema",
350
+ detail: err.message,
351
+ hint: "if the DB is corrupted, remove ~/.tono/tono.db* and re-run; tasks history will be lost.",
352
+ };
353
+ }
354
+ }
355
+ function checkGatewayPlist() {
356
+ const file = plistPath();
357
+ const r = spawnSync("launchctl", ["list", GATEWAY_LABEL], { encoding: "utf8" });
358
+ const loaded = r.status === 0;
359
+ if (!existsSync(file) && !loaded) {
360
+ return {
361
+ id: "gateway.plist",
362
+ category: "optional",
363
+ status: "ok",
364
+ title: "gateway",
365
+ detail: "not installed (run `tono gateway start` to install)",
366
+ };
367
+ }
368
+ if (!existsSync(file)) {
369
+ return {
370
+ id: "gateway.plist",
371
+ category: "optional",
372
+ status: "warn",
373
+ title: "gateway",
374
+ detail: "loaded by launchctl but plist file missing — re-run `tono gateway start` to fix",
375
+ };
376
+ }
377
+ if (!loaded) {
378
+ return {
379
+ id: "gateway.plist",
380
+ category: "optional",
381
+ status: "warn",
382
+ title: "gateway",
383
+ detail: "plist exists but is not loaded",
384
+ hint: "run `tono gateway start` (or `restart`) to load it.",
385
+ };
386
+ }
387
+ return {
388
+ id: "gateway.plist",
389
+ category: "optional",
390
+ status: "ok",
391
+ title: "gateway",
392
+ detail: "installed and loaded",
393
+ };
394
+ }
395
+ async function checkGatewayHealthy(cfg) {
396
+ const host = cfg.server.host === "0.0.0.0" ? "127.0.0.1" : cfg.server.host;
397
+ const url = `http://${host}:${cfg.server.port}/api/health`;
398
+ try {
399
+ const res = await fetch(url, { signal: AbortSignal.timeout(2000) });
400
+ if (!res.ok) {
401
+ return {
402
+ id: "gateway.healthy",
403
+ category: "optional",
404
+ status: "warn",
405
+ title: "gateway HTTP",
406
+ detail: `${url} → HTTP ${res.status}`,
407
+ };
408
+ }
409
+ const j = (await res.json());
410
+ return {
411
+ id: "gateway.healthy",
412
+ category: "optional",
413
+ status: "ok",
414
+ title: "gateway HTTP",
415
+ detail: `${url} OK${j.version ? ` (v${j.version})` : ""}`,
416
+ };
417
+ }
418
+ catch (err) {
419
+ return {
420
+ id: "gateway.healthy",
421
+ category: "optional",
422
+ status: "warn",
423
+ title: "gateway HTTP",
424
+ detail: `${url} unreachable`,
425
+ hint: (err.name === "AbortError" || err.message.includes("ECONNREFUSED"))
426
+ ? "if you expect tono to be running, check `tono gateway status` and `tono gateway logs err`."
427
+ : err.message,
428
+ };
429
+ }
430
+ }
431
+ // — Formatting helpers ————————————————————————————————————————————————————
432
+ const COLOR = {
433
+ reset: "\x1b[0m",
434
+ dim: "\x1b[2m",
435
+ bold: "\x1b[1m",
436
+ green: "\x1b[32m",
437
+ yellow: "\x1b[33m",
438
+ red: "\x1b[31m",
439
+ blue: "\x1b[34m",
440
+ };
441
+ function symbolFor(status) {
442
+ switch (status) {
443
+ case "ok":
444
+ return `${COLOR.green}✓${COLOR.reset}`;
445
+ case "warn":
446
+ return `${COLOR.yellow}⚠${COLOR.reset}`;
447
+ case "fail":
448
+ return `${COLOR.red}✗${COLOR.reset}`;
449
+ }
450
+ }
451
+ function categoryTag(c) {
452
+ return c === "required"
453
+ ? `${COLOR.dim}[required]${COLOR.reset}`
454
+ : `${COLOR.dim}[optional]${COLOR.reset}`;
455
+ }
456
+ /** Format a list of check results as a human-readable report (with ANSI colors). */
457
+ export function formatReport(results) {
458
+ const lines = [];
459
+ for (const r of results) {
460
+ lines.push(`${symbolFor(r.status)} ${r.title.padEnd(20)} ${categoryTag(r.category)} ${COLOR.dim}${r.detail}${COLOR.reset}`);
461
+ if (r.status !== "ok" && r.hint) {
462
+ lines.push(` ${COLOR.dim}↳ ${r.hint}${COLOR.reset}`);
463
+ }
464
+ }
465
+ return lines.join("\n");
466
+ }
467
+ export function tally(results) {
468
+ const t = { total: results.length, ok: 0, warnings: 0, failures: 0, requiredFailures: 0 };
469
+ for (const r of results) {
470
+ if (r.status === "ok")
471
+ t.ok++;
472
+ else if (r.status === "warn")
473
+ t.warnings++;
474
+ else {
475
+ t.failures++;
476
+ if (r.category === "required")
477
+ t.requiredFailures++;
478
+ }
479
+ }
480
+ return t;
481
+ }
482
+ export function summarize(t) {
483
+ const parts = [`${t.ok} ok`];
484
+ if (t.warnings)
485
+ parts.push(`${COLOR.yellow}${t.warnings} warning${t.warnings === 1 ? "" : "s"}${COLOR.reset}`);
486
+ if (t.failures)
487
+ parts.push(`${COLOR.red}${t.failures} failure${t.failures === 1 ? "" : "s"}${COLOR.reset}`);
488
+ if (t.requiredFailures)
489
+ parts.push(`${COLOR.bold}${COLOR.red}${t.requiredFailures} required${COLOR.reset}`);
490
+ return parts.join(", ");
491
+ }
492
+ /** Hint string for the requirements section that init/doctor both print. */
493
+ export function requirementsBanner() {
494
+ return [
495
+ `${COLOR.bold}Required tools:${COLOR.reset}`,
496
+ ` • ${COLOR.bold}gh${COLOR.reset} (GitHub CLI, authenticated)`,
497
+ ` • ${COLOR.bold}git${COLOR.reset}`,
498
+ ` • At least one of these agent CLIs (configure the ones you have):`,
499
+ ` - ${COLOR.bold}claude${COLOR.reset} — Claude Code (https://docs.claude.com/en/docs/claude-code/quickstart)`,
500
+ ` - ${COLOR.bold}codex${COLOR.reset} — Codex CLI (\`npm install -g @openai/codex\`)`,
501
+ ` - ${COLOR.bold}opencode${COLOR.reset} — OpenCode (https://opencode.ai)`,
502
+ ].join("\n");
503
+ }
504
+ //# sourceMappingURL=checks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checks.js","sourceRoot":"","sources":["../../src/cli/checks.ts"],"names":[],"mappings":"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"}