Something went wrong. Try again.
the tangled network observatory ◈ every knot, its health, its version, in your terminal
tangled cli tui knot monitoring observability atproto federation
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142#!/usr/bin/env nodeimport { readFileSync } from "node:fs";import { styleText } from "node:util";import { parse } from "@bomb.sh/args";import { animateBanner } from "./banner.js";
// completion calls answer before anything else — no banner, no arg parsingif (process.argv[2] === "complete") { const { runComplete } = await import("./completions.js"); runComplete(process.argv.slice(3)); process.exit(0);}
const args = parse(process.argv.slice(2), { // note: args parses `--no-repos` as minimist-style negation → `repos: false` boolean: [ "json", "all", "fresh", "help", "version", "mine", "repos", "down", "stale", "managed", "self-hosted", ], string: ["as"], alias: { h: "help", v: "version" },});
const usage = `usage: fid list every knot on the network --json machine-readable output --all include localhost/dev junk knots --fresh skip the 5-minute cache --no-repos skip the slow repo sweep (no counts, knots-only) --down only unreachable knots --stale only pre-v1.15 knots (the silent-data-loss cohort) --managed only tangled-hosted knots --self-hosted only self-hosted knots fid check <host> health-check one knot (exit 0 ok / 1 stale / 2 down) --mine check every knot you own instead --as <handle> who you are (or {"handle":"..."} in ~/.config/fid/config.json) fid stats network aggregates: versions, hosting, top knots fid repos <host> what repos live on a knot fid spindles the ci runner fleet fid find <query> search repos across the network fid watch live network board (q to quit) fid complete <shell> print completion script (zsh/bash/fish/powershell) fid --version print the version`;
// colors go in after the columns are padded, so alignment math never sees ansiconst colorUsage = (s: string) => s .split("\n") .map((line) => { if (line === "usage:") return styleText("dim", line); const m = /^(\s+)(\S.*?)(\s{2,})(.*)$/.exec(line); if (!m) return line; const [, indent, left, gap, desc] = m; const colored = left .replace( /^fid (?!--)(\S+)/, (_, cmd: string) => `fid ${styleText(["green", "bold"], cmd)}`, ) .replace(/--[\w-]+/g, (f) => styleText("cyan", f)) .replace(/<[^>]+>/g, (a) => styleText("magenta", a)); return indent + colored + gap + styleText("dim", desc); }) .join("\n");
if (args.version) { const pkg = JSON.parse( readFileSync(new URL("../package.json", import.meta.url), "utf8"), ); console.log(`fid ${pkg.version}`); process.exit(0);}
const [command] = args._;// keep --json pipe-cleanif (!args.json) await animateBanner();
if (args.help) { console.log(colorUsage(usage)); process.exit(0);}if (!command) { console.log( styleText("dim", "run ") + styleText("cyan", "fid -h") + styleText("dim", " to see what fid can do"), ); process.exit(1);}
switch (command) { case "list": await ( await import("./commands/list.js") ).run({ ...args, noRepos: args.repos === false, selfHosted: args["self-hosted"], }); break; case "check": await (await import("./commands/check.js")).run( args, args._[1] === undefined ? undefined : String(args._[1]), ); break; case "stats": await (await import("./commands/stats.js")).run(args); break; case "repos": await (await import("./commands/repos.js")).run( args, args._[1] === undefined ? undefined : String(args._[1]), ); break; case "spindles": await (await import("./commands/spindles.js")).run(args); break; case "find": await (await import("./commands/find.js")).run( args, args._.slice(1).map(String).join(" "), ); break; case "watch": await (await import("./commands/watch.js")).run(args); break; default: console.error(`unknown command: ${command}\n`); console.log(colorUsage(usage)); process.exit(1);}