@chit-run/cli 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 (2) hide show
  1. package/dist/chit.js +214 -21
  2. package/package.json +1 -1
package/dist/chit.js CHANGED
@@ -9965,10 +9965,10 @@ var init_dist = __esm(() => {
9965
9965
  // ../studio/src/server/audit.ts
9966
9966
  import { existsSync as existsSync8, readFileSync as readFileSync9 } from "fs";
9967
9967
  import { homedir as homedir5 } from "os";
9968
- import { join as join7 } from "path";
9968
+ import { join as join8 } from "path";
9969
9969
  function defaultAuditDir2() {
9970
- const xdg = process.env.XDG_STATE_HOME || join7(homedir5(), ".local", "state");
9971
- return join7(xdg, "chit", "audit");
9970
+ const xdg = process.env.XDG_STATE_HOME || join8(homedir5(), ".local", "state");
9971
+ return join8(xdg, "chit", "audit");
9972
9972
  }
9973
9973
  function blobRefs(e) {
9974
9974
  switch (e.type) {
@@ -9987,8 +9987,8 @@ function blobRefs(e) {
9987
9987
  function readAuditRun(auditDir, runId, includeBlobs) {
9988
9988
  if (!SAFE_RUN_ID2.test(runId))
9989
9989
  return { kind: "invalid-id" };
9990
- const runDir = join7(auditDir, "runs", runId);
9991
- const eventsPath = join7(runDir, "events.jsonl");
9990
+ const runDir = join8(auditDir, "runs", runId);
9991
+ const eventsPath = join8(runDir, "events.jsonl");
9992
9992
  if (!existsSync8(eventsPath))
9993
9993
  return { kind: "not-found" };
9994
9994
  let events2;
@@ -10001,13 +10001,13 @@ function readAuditRun(auditDir, runId, includeBlobs) {
10001
10001
  }
10002
10002
  if (!includeBlobs)
10003
10003
  return { kind: "ok", events: events2 };
10004
- const blobsDir = join7(runDir, "blobs");
10004
+ const blobsDir = join8(runDir, "blobs");
10005
10005
  const blobs = {};
10006
10006
  for (const e of events2) {
10007
10007
  for (const ref of blobRefs(e)) {
10008
10008
  if (!SHA256_HEX2.test(ref) || ref in blobs)
10009
10009
  continue;
10010
- const blobPath = join7(blobsDir, ref);
10010
+ const blobPath = join8(blobsDir, ref);
10011
10011
  if (existsSync8(blobPath))
10012
10012
  blobs[ref] = readFileSync9(blobPath, "utf-8");
10013
10013
  }
@@ -10094,7 +10094,7 @@ var init_paths = __esm(() => {
10094
10094
 
10095
10095
  // ../studio/src/server/discovery.ts
10096
10096
  import { readdirSync as readdirSync3, readFileSync as readFileSync10 } from "fs";
10097
- import { basename, join as join8, relative } from "path";
10097
+ import { basename, join as join9, relative } from "path";
10098
10098
  function safeParseChit(absolutePath) {
10099
10099
  try {
10100
10100
  const raw2 = JSON.parse(readFileSync10(absolutePath, "utf-8"));
@@ -10124,7 +10124,7 @@ function discover(opts) {
10124
10124
  continue;
10125
10125
  if (!entry.name.endsWith(".json"))
10126
10126
  continue;
10127
- const absolutePath = join8(opts.cwd, entry.name);
10127
+ const absolutePath = join9(opts.cwd, entry.name);
10128
10128
  if (!safeParseChit(absolutePath))
10129
10129
  continue;
10130
10130
  candidates.push({
@@ -10150,7 +10150,7 @@ var init_discovery = __esm(() => {
10150
10150
 
10151
10151
  // ../studio/src/server/docs.ts
10152
10152
  import { createHash as createHash5 } from "crypto";
10153
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync5 } from "fs";
10153
+ import { readFileSync as readFileSync11, writeFileSync as writeFileSync6 } from "fs";
10154
10154
  import { basename as basename2, relative as relative2 } from "path";
10155
10155
  function canonicalize(draft) {
10156
10156
  return JSON.stringify(draft, null, "\t");
@@ -10293,7 +10293,7 @@ class DocStore {
10293
10293
  const manifest = parseManifest(draft);
10294
10294
  const graphModel = buildGraphModel(manifest, this.registry, surface);
10295
10295
  const canonicalRaw = canonicalize(draft);
10296
- writeFileSync5(entry.absolutePath, canonicalRaw, "utf-8");
10296
+ writeFileSync6(entry.absolutePath, canonicalRaw, "utf-8");
10297
10297
  const newHash = hashRaw(canonicalRaw);
10298
10298
  return {
10299
10299
  kind: "saved",
@@ -10363,9 +10363,9 @@ var init_docs = __esm(() => {
10363
10363
 
10364
10364
  // ../studio/src/server/loops.ts
10365
10365
  import { existsSync as existsSync10, readdirSync as readdirSync4, readFileSync as readFileSync12 } from "fs";
10366
- import { join as join9 } from "path";
10366
+ import { join as join10 } from "path";
10367
10367
  function loopsDir2(cwd) {
10368
- return join9(cwd, ".chit", "loops");
10368
+ return join10(cwd, ".chit", "loops");
10369
10369
  }
10370
10370
  function summarize(loopId, records) {
10371
10371
  const header = records[0];
@@ -10402,7 +10402,7 @@ function listLoops(cwd) {
10402
10402
  function readLoop2(cwd, loopId) {
10403
10403
  if (!SAFE_LOOP_ID2.test(loopId))
10404
10404
  return { kind: "invalid-id" };
10405
- const path = join9(loopsDir2(cwd), `${loopId}.jsonl`);
10405
+ const path = join10(loopsDir2(cwd), `${loopId}.jsonl`);
10406
10406
  if (!existsSync10(path))
10407
10407
  return { kind: "not-found" };
10408
10408
  try {
@@ -10456,7 +10456,7 @@ __export(exports_server, {
10456
10456
  PathError: () => PathError
10457
10457
  });
10458
10458
  import { existsSync as existsSync11 } from "fs";
10459
- import { join as join10 } from "path";
10459
+ import { join as join11 } from "path";
10460
10460
  async function startStudio(opts) {
10461
10461
  const hostname3 = opts.hostname ?? "127.0.0.1";
10462
10462
  const requestedPort = opts.port ?? 0;
@@ -10508,7 +10508,7 @@ function buildApp(opts) {
10508
10508
  const asset = c.req.param("asset");
10509
10509
  if (!CLIENT_ASSETS.has(asset))
10510
10510
  return c.text("not found", 404);
10511
- const path = join10(opts.clientDistDir, asset);
10511
+ const path = join11(opts.clientDistDir, asset);
10512
10512
  if (!existsSync11(path)) {
10513
10513
  return c.text(`client bundle missing at ${path}. Run: bun run studio:build`, 503);
10514
10514
  }
@@ -10684,7 +10684,7 @@ var init_server = __esm(() => {
10684
10684
  init_loops();
10685
10685
  init_token();
10686
10686
  init_paths();
10687
- CLIENT_DIST = join10(import.meta.dir, "..", "..", "dist", "client");
10687
+ CLIENT_DIST = join11(import.meta.dir, "..", "..", "dist", "client");
10688
10688
  CLIENT_ASSETS = new Set(["index.js", "index.css"]);
10689
10689
  });
10690
10690
 
@@ -10692,7 +10692,7 @@ var init_server = __esm(() => {
10692
10692
  init_src();
10693
10693
  import { readFileSync as readFileSync13 } from "fs";
10694
10694
  import { homedir as homedir6 } from "os";
10695
- import { basename as basename3, dirname as dirname2, join as join11 } from "path";
10695
+ import { basename as basename3, dirname as dirname2, join as join12 } from "path";
10696
10696
 
10697
10697
  // src/adapters/sanitize.ts
10698
10698
  var SENSITIVE_KEY = /key|token|secret|password|auth/i;
@@ -36680,10 +36680,200 @@ ${AUDIT_HELP}`);
36680
36680
  });
36681
36681
  }
36682
36682
 
36683
+ // src/cli/doctor.ts
36684
+ import { randomUUID as randomUUID3 } from "crypto";
36685
+ import { mkdirSync as mkdirSync5, rmSync as rmSync5, writeFileSync as writeFileSync5 } from "fs";
36686
+ import { join as join7 } from "path";
36687
+ var defaultIO3 = {
36688
+ out: (s) => process.stdout.write(s),
36689
+ err: (s) => process.stderr.write(s)
36690
+ };
36691
+ var PROBE_TIMEOUT_MS = 5000;
36692
+ function makeDefaultProbe(timeoutMs) {
36693
+ return (cmd, cwd) => {
36694
+ try {
36695
+ const r = Bun.spawnSync(cmd, {
36696
+ cwd,
36697
+ stdout: "pipe",
36698
+ stderr: "pipe",
36699
+ stdin: "ignore",
36700
+ timeout: timeoutMs
36701
+ });
36702
+ const output = `${r.stdout?.toString() ?? ""}${r.stderr?.toString() ?? ""}`.trim();
36703
+ return { ok: r.exitCode === 0, output };
36704
+ } catch {
36705
+ return { ok: false, output: "" };
36706
+ }
36707
+ };
36708
+ }
36709
+ var defaultProbe = makeDefaultProbe(PROBE_TIMEOUT_MS);
36710
+ function defaultDeps() {
36711
+ return {
36712
+ probe: defaultProbe,
36713
+ cwd: process.cwd(),
36714
+ auditDir: defaultAuditDir(),
36715
+ loadReg: () => loadRegistry(),
36716
+ bunVersion: process.versions.bun
36717
+ };
36718
+ }
36719
+ function checkBun(deps) {
36720
+ if (deps.bunVersion) {
36721
+ return { name: "bun", status: "pass", detail: `Bun ${deps.bunVersion}` };
36722
+ }
36723
+ return {
36724
+ name: "bun",
36725
+ status: "fail",
36726
+ detail: "not running under Bun",
36727
+ hint: "chit is Bun-native; install Bun from https://bun.sh and run chit under bun"
36728
+ };
36729
+ }
36730
+ function checkChitOnPath(deps) {
36731
+ if (deps.probe(["which", "chit"]).ok) {
36732
+ return { name: "chit", status: "pass", detail: "on PATH" };
36733
+ }
36734
+ return {
36735
+ name: "chit",
36736
+ status: "warn",
36737
+ detail: "not on PATH (running locally or via bunx)",
36738
+ hint: "install globally so `chit mcp` resolves: bun install -g @chit-run/cli"
36739
+ };
36740
+ }
36741
+ function checkGitRepo(deps) {
36742
+ if (deps.probe(["git", "rev-parse", "--is-inside-work-tree"], deps.cwd).ok) {
36743
+ return { name: "git repo", status: "pass", detail: `cwd is a git repo (${deps.cwd})` };
36744
+ }
36745
+ return {
36746
+ name: "git repo",
36747
+ status: "warn",
36748
+ detail: `cwd is not a git repo (${deps.cwd})`,
36749
+ hint: "converge and worktree-based flows expect a git repo; cd into one or git init"
36750
+ };
36751
+ }
36752
+ function checkAuditDir(deps) {
36753
+ try {
36754
+ mkdirSync5(deps.auditDir, { recursive: true });
36755
+ const probeFile = join7(deps.auditDir, `.doctor-${randomUUID3()}`);
36756
+ writeFileSync5(probeFile, "ok");
36757
+ rmSync5(probeFile);
36758
+ return { name: "audit dir", status: "pass", detail: `writable (${deps.auditDir})` };
36759
+ } catch (e) {
36760
+ return {
36761
+ name: "audit dir",
36762
+ status: "fail",
36763
+ detail: `not writable (${deps.auditDir}): ${e.message}`,
36764
+ hint: "audited runs need this dir; fix its permissions or set XDG_STATE_HOME"
36765
+ };
36766
+ }
36767
+ }
36768
+ function checkRegistry(deps) {
36769
+ let registry3;
36770
+ try {
36771
+ registry3 = deps.loadReg();
36772
+ } catch (e) {
36773
+ if (e instanceof RegistryError) {
36774
+ return {
36775
+ name: "agents",
36776
+ status: "fail",
36777
+ detail: `invalid agent config: ${e.message}`,
36778
+ hint: "fix or remove ~/.config/chit/agents.json"
36779
+ };
36780
+ }
36781
+ throw e;
36782
+ }
36783
+ const ids = Object.keys(registry3.agents).sort().join(", ");
36784
+ const source = registry3.configPath ? `from ${registry3.configPath}` : "built-in defaults (no agents.json)";
36785
+ return { name: "agents", status: "pass", detail: `${ids || "none"} (${source})` };
36786
+ }
36787
+ function checkAgentCli(deps, bin) {
36788
+ if (deps.probe([bin, "--version"]).ok) {
36789
+ return { name: bin, status: "pass", detail: "available (auth confirmed on first run)" };
36790
+ }
36791
+ return {
36792
+ name: bin,
36793
+ status: "warn",
36794
+ detail: `not found on PATH`,
36795
+ hint: `install ${bin} and authenticate it; chit calls it as an agent`
36796
+ };
36797
+ }
36798
+ function checkMcpRegistration(deps) {
36799
+ if (!deps.probe(["claude", "--version"]).ok) {
36800
+ return {
36801
+ name: "mcp register",
36802
+ status: "warn",
36803
+ detail: "skipped (claude CLI not found)",
36804
+ hint: "with claude installed: claude mcp add chit --scope local -- chit mcp"
36805
+ };
36806
+ }
36807
+ if (deps.probe(["claude", "mcp", "get", "chit"]).ok) {
36808
+ return { name: "mcp register", status: "pass", detail: "chit registered as an MCP server" };
36809
+ }
36810
+ return {
36811
+ name: "mcp register",
36812
+ status: "warn",
36813
+ detail: "chit not registered as an MCP server",
36814
+ hint: "register it: claude mcp add chit --scope local -- chit mcp"
36815
+ };
36816
+ }
36817
+ function runChecks(deps) {
36818
+ return [
36819
+ checkBun(deps),
36820
+ checkChitOnPath(deps),
36821
+ checkAgentCli(deps, "codex"),
36822
+ checkAgentCli(deps, "claude"),
36823
+ checkRegistry(deps),
36824
+ checkMcpRegistration(deps),
36825
+ checkAuditDir(deps),
36826
+ checkGitRepo(deps)
36827
+ ];
36828
+ }
36829
+ var SHAPE = { pass: "\u25CF", warn: "\u25CB", fail: "\u25C6" };
36830
+ function render(checks4, io) {
36831
+ io.out(`chit doctor
36832
+
36833
+ `);
36834
+ const width = Math.max(...checks4.map((c) => c.name.length));
36835
+ for (const c of checks4) {
36836
+ io.out(`${SHAPE[c.status]} ${c.name.padEnd(width)} ${c.detail}
36837
+ `);
36838
+ if (c.hint && c.status !== "pass")
36839
+ io.out(`${" ".repeat(width + 4)}\u21B3 ${c.hint}
36840
+ `);
36841
+ }
36842
+ const fails = checks4.filter((c) => c.status === "fail").length;
36843
+ const warns = checks4.filter((c) => c.status === "warn").length;
36844
+ io.out(`
36845
+ ${fails} failure${fails === 1 ? "" : "s"}, ${warns} warning${warns === 1 ? "" : "s"}. Agent authentication is verified on the first real run.
36846
+ `);
36847
+ }
36848
+ var DOCTOR_HELP = `chit doctor
36849
+
36850
+ Preflight check for first-time setup. Runs no agents and changes nothing (it only
36851
+ writes and removes a probe file in the audit dir to confirm it is writable).
36852
+
36853
+ Checks: Bun, the chit binary on PATH, the codex and claude CLIs, the agent
36854
+ registry, MCP registration, the audit dir, and whether the cwd is a git repo.
36855
+ Agent authentication is not checked here; it is confirmed on the first real run.
36856
+ `;
36857
+ function runDoctor(argv, io = defaultIO3, deps = defaultDeps()) {
36858
+ if (argv[0] === "-h" || argv[0] === "--help") {
36859
+ io.out(DOCTOR_HELP);
36860
+ return 0;
36861
+ }
36862
+ if (argv.length > 0) {
36863
+ io.err(`chit doctor: unexpected argument ${JSON.stringify(argv[0])}
36864
+
36865
+ ${DOCTOR_HELP}`);
36866
+ return 2;
36867
+ }
36868
+ const checks4 = runChecks(deps);
36869
+ render(checks4, io);
36870
+ return checks4.some((c) => c.status === "fail") ? 1 : 0;
36871
+ }
36872
+
36683
36873
  // src/cli/loop-log.ts
36684
36874
  init_src();
36685
36875
  import { resolve as resolve4 } from "path";
36686
- var defaultIO3 = {
36876
+ var defaultIO4 = {
36687
36877
  out: (s) => process.stdout.write(s),
36688
36878
  err: (s) => process.stderr.write(s)
36689
36879
  };
@@ -36798,7 +36988,7 @@ function renderLoop(records) {
36798
36988
  `)}
36799
36989
  `;
36800
36990
  }
36801
- function runLoopLog(argv, io = defaultIO3) {
36991
+ function runLoopLog(argv, io = defaultIO4) {
36802
36992
  const verb = argv[0];
36803
36993
  if (!verb || verb === "-h" || verb === "--help") {
36804
36994
  (verb ? io.out : io.err)(LOOP_LOG_HELP);
@@ -37082,6 +37272,7 @@ var HELP = `Usage:
37082
37272
  chit uninstall <name> [--to <dir>]
37083
37273
  chit studio [path]
37084
37274
  chit mcp (run the stdio MCP server)
37275
+ chit doctor (preflight: check setup)
37085
37276
  chit loop-log <start|append|stop|show> [flags] (chit loop-log --help)
37086
37277
  chit converge --task <text> --scope <id> [options] (chit converge --help)
37087
37278
  chit audit <list|show> [options] (chit audit --help)
@@ -37172,6 +37363,8 @@ async function runMain(argv) {
37172
37363
  return runConverge(argv.slice(1));
37173
37364
  if (argv[0] === "audit")
37174
37365
  return runAudit(argv.slice(1));
37366
+ if (argv[0] === "doctor")
37367
+ return runDoctor(argv.slice(1));
37175
37368
  let args;
37176
37369
  try {
37177
37370
  args = parseArgs(argv);
@@ -37423,7 +37616,7 @@ ${HELP}`);
37423
37616
  `);
37424
37617
  return 2;
37425
37618
  }
37426
- const outputDir = args.outputDir ?? join11(homedir6(), ".claude", "skills");
37619
+ const outputDir = args.outputDir ?? join12(homedir6(), ".claude", "skills");
37427
37620
  const runtimePath = args.runtimePath ?? defaultRuntimePath();
37428
37621
  try {
37429
37622
  const result = installClaudeSkill({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chit-run/cli",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "A thin runtime for multi-agent workflows. Stop being the glue between your agents.",
5
5
  "type": "module",
6
6
  "license": "MIT",