@appchy/jarvis 0.1.43 → 0.1.44

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/bin/jarvis.mjs CHANGED
@@ -8,25 +8,91 @@
8
8
  * pairs, so one binary serves our cloud, a self-hosted instance and a laptop
9
9
  * alike. For source-tree iteration with hot reload, run
10
10
  * `pnpm -C apps/cli dev` — that runs `tsx src/bin.ts` directly.
11
+ *
12
+ * It does decide WHICH BUILD, for the two commands a repo reaches jarvis with.
13
+ * A repo names jarvis by `command: "jarvis"` in a checked-in `.mcp.json`, so the
14
+ * only place a machine-specific answer can live is here.
11
15
  */
12
16
 
13
17
  import { fileURLToPath } from "url";
14
- import { dirname, join } from "path";
15
- import { existsSync } from "fs";
18
+ import { dirname, isAbsolute, join, relative } from "path";
19
+ import { existsSync, readFileSync, realpathSync } from "fs";
20
+ import { homedir } from "os";
16
21
 
17
22
  const __dirname = dirname(fileURLToPath(import.meta.url));
18
23
  const distEntry = join(__dirname, "..", "dist", "bin.js");
19
24
 
20
- if (!existsSync(distEntry)) {
21
- const isSourceCheckout = existsSync(join(__dirname, "..", "src", "bin.ts"));
22
- console.error("Error: dist/bin.js not found.");
23
- if (isSourceCheckout) {
24
- console.error(" This is a source checkout. Run `pnpm -C apps/cli dev` for dev work,");
25
- console.error(" or `pnpm -C apps/cli build` to produce a bundle.");
26
- } else {
27
- console.error(" The package may be corrupted. Reinstall with `pnpm i -g @appchy/jarvis`.");
25
+ /** The commands a repo reaches jarvis with. Machine lifecycle — `start`, `init`, `pair` —
26
+ * is deliberately absent: a redirect meant for an MCP server must never move the daemon,
27
+ * which owns this machine's Claude Code and is identified by its config dir, not its build. */
28
+ const REDIRECTED = new Set(["serve", "work"]);
29
+
30
+ /** The development build to run here, or null for the one this launcher ships with.
31
+ * `src/dev.ts` answers the same question for `jarvis dev status`; it cannot be imported,
32
+ * because this has to decide before any bundle is loaded. Keep the two answers identical. */
33
+ function devBuild() {
34
+ const command = process.argv[2];
35
+ if (!REDIRECTED.has(command)) return null;
36
+
37
+ const configDir = process.env.JARVIS_CONFIG_DIR ?? join(homedir(), ".jarvis");
38
+ let redirect;
39
+ try {
40
+ redirect = JSON.parse(readFileSync(join(configDir, "dev.json"), "utf-8"));
41
+ } catch {
42
+ return null;
28
43
  }
29
- process.exit(1);
44
+ if (typeof redirect?.root !== "string") return null;
45
+
46
+ // Every symlink resolved on both sides: an unresolved comparison fails wherever a home
47
+ // or temp directory is a link, and that failure is indistinguishable from being switched off.
48
+ const real = (target) => {
49
+ try {
50
+ return realpathSync(target);
51
+ } catch {
52
+ return target;
53
+ }
54
+ };
55
+ const cwd = real(process.cwd());
56
+ const here =
57
+ redirect.all === true ||
58
+ (Array.isArray(redirect.repos) &&
59
+ redirect.repos.some((repo) => {
60
+ if (typeof repo !== "string") return false;
61
+ const rel = relative(real(repo), cwd);
62
+ return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
63
+ }));
64
+ if (!here) return null;
65
+
66
+ const entry = join(redirect.root, "apps", "cli", "dist", "bin.js");
67
+ if (!existsSync(entry)) {
68
+ // Falling back silently would serve the installed build under the name of the one
69
+ // being tested, which is the shape of this bug nobody catches: the half you look at
70
+ // is right. stderr, because stdout is the MCP transport.
71
+ process.stderr.write(
72
+ `jarvis: ${redirect.root} has no build to run — using the installed one.\n` +
73
+ ` Build it with \`pnpm --filter @appchy/jarvis build\`.\n`,
74
+ );
75
+ return null;
76
+ }
77
+ return entry;
30
78
  }
31
79
 
32
- await import(distEntry);
80
+ const dev = devBuild();
81
+ if (dev) {
82
+ process.stderr.write(`jarvis: development build, from ${dev}\n`);
83
+ await import(dev);
84
+ } else {
85
+ if (!existsSync(distEntry)) {
86
+ const isSourceCheckout = existsSync(join(__dirname, "..", "src", "bin.ts"));
87
+ console.error("Error: dist/bin.js not found.");
88
+ if (isSourceCheckout) {
89
+ console.error(" This is a source checkout. Run `pnpm -C apps/cli dev` for dev work,");
90
+ console.error(" or `pnpm -C apps/cli build` to produce a bundle.");
91
+ } else {
92
+ console.error(" The package may be corrupted. Reinstall with `pnpm i -g @appchy/jarvis`.");
93
+ }
94
+ process.exit(1);
95
+ }
96
+
97
+ await import(distEntry);
98
+ }
package/dist/bin.js CHANGED
@@ -4433,8 +4433,8 @@ async function scanTree(root) {
4433
4433
  for (const file of await walk(join3(work, base))) {
4434
4434
  const text = await readFile(file, "utf-8");
4435
4435
  const changedAt = (await stat(file)).mtime.toISOString().slice(0, 10);
4436
- const path20 = relative(work, file).split(sep).join("/");
4437
- const item = toWorkItem({ path: path20, text, changedAt });
4436
+ const path22 = relative(work, file).split(sep).join("/");
4437
+ const item = toWorkItem({ path: path22, text, changedAt });
4438
4438
  if (item) items.push(item);
4439
4439
  }
4440
4440
  }
@@ -5400,8 +5400,8 @@ function reason(err) {
5400
5400
  }
5401
5401
  function issueText(issues) {
5402
5402
  return issues.slice(0, 3).map((issue) => {
5403
- const path20 = (issue.path ?? []).map((step) => String(typeof step === "object" ? step.key : step)).join(".");
5404
- return path20 ? `${path20}: ${issue.message}` : issue.message;
5403
+ const path22 = (issue.path ?? []).map((step) => String(typeof step === "object" ? step.key : step)).join(".");
5404
+ return path22 ? `${path22}: ${issue.message}` : issue.message;
5405
5405
  }).join("; ");
5406
5406
  }
5407
5407
  function keyText(data) {
@@ -5689,9 +5689,9 @@ function localFiles(options = {}) {
5689
5689
  }
5690
5690
  },
5691
5691
  save: async (ctx, key, bytes) => {
5692
- const path20 = pathOf(ctx, key);
5693
- await mkdir(dirname3(path20), { recursive: true });
5694
- await writeFile(path20, bytes, "utf8");
5692
+ const path22 = pathOf(ctx, key);
5693
+ await mkdir(dirname3(path22), { recursive: true });
5694
+ await writeFile(path22, bytes, "utf8");
5695
5695
  },
5696
5696
  locate: (ctx, key) => pathOf(ctx, key)
5697
5697
  });
@@ -5709,10 +5709,10 @@ async function loadConfig2(cwd) {
5709
5709
  let dir = resolve3(cwd);
5710
5710
  for (; ; ) {
5711
5711
  for (const name of CONFIG_NAMES) {
5712
- const path20 = resolve3(dir, name);
5713
- if (existsSync5(path20)) {
5714
- const config2 = await importConfig(path20);
5715
- validateConfig(config2, path20);
5712
+ const path22 = resolve3(dir, name);
5713
+ if (existsSync5(path22)) {
5714
+ const config2 = await importConfig(path22);
5715
+ validateConfig(config2, path22);
5716
5716
  return {
5717
5717
  ...config2,
5718
5718
  persistence: config2.persistence ?? localFiles(),
@@ -5728,9 +5728,9 @@ async function loadConfig2(cwd) {
5728
5728
  `No jarvis.config.{ts,js,mjs} found from ${cwd}. A repo maps its world in one, at its root.`
5729
5729
  );
5730
5730
  }
5731
- async function importConfig(path20) {
5731
+ async function importConfig(path22) {
5732
5732
  const jiti = createJiti(import.meta.url, { moduleCache: false, alias: selfAlias() });
5733
- const mod = await jiti.import(path20);
5733
+ const mod = await jiti.import(path22);
5734
5734
  const config2 = mod.default ?? mod;
5735
5735
  return config2;
5736
5736
  }
@@ -5783,9 +5783,9 @@ function toVendorAlias(dir) {
5783
5783
  function toSpecifier(subpath) {
5784
5784
  return subpath === "." ? PACKAGE_NAME : `${PACKAGE_NAME}/${subpath.replace(/^\.\//, "")}`;
5785
5785
  }
5786
- function validateConfig(value, path20) {
5786
+ function validateConfig(value, path22) {
5787
5787
  const fail = (msg) => {
5788
- throw new Error(`${path20}: ${msg}`);
5788
+ throw new Error(`${path22}: ${msg}`);
5789
5789
  };
5790
5790
  if (typeof value !== "object" || value === null) fail("config must export an object");
5791
5791
  const c = value;
@@ -6491,10 +6491,10 @@ async function git3(root, argv, timeout = 5e3) {
6491
6491
  }
6492
6492
  }
6493
6493
  async function fetchHeadIso(root) {
6494
- const path20 = await git3(root, ["rev-parse", "--git-path", "FETCH_HEAD"]);
6495
- if (!path20) return void 0;
6494
+ const path22 = await git3(root, ["rev-parse", "--git-path", "FETCH_HEAD"]);
6495
+ if (!path22) return void 0;
6496
6496
  try {
6497
- return (await stat2(resolve4(root, path20))).mtime.toISOString();
6497
+ return (await stat2(resolve4(root, path22))).mtime.toISOString();
6498
6498
  } catch {
6499
6499
  return void 0;
6500
6500
  }
@@ -6571,10 +6571,10 @@ async function freshness(ctx) {
6571
6571
  };
6572
6572
  }
6573
6573
  async function snapshotMtimeMs(ctx) {
6574
- const path20 = ctx.config.persistence?.locate?.({ repoRoot: ctx.config.repoRoot }, "snapshot");
6575
- if (!path20) return void 0;
6574
+ const path22 = ctx.config.persistence?.locate?.({ repoRoot: ctx.config.repoRoot }, "snapshot");
6575
+ if (!path22) return void 0;
6576
6576
  try {
6577
- return (await stat2(path20)).mtimeMs;
6577
+ return (await stat2(path22)).mtimeMs;
6578
6578
  } catch {
6579
6579
  return void 0;
6580
6580
  }
@@ -6996,10 +6996,10 @@ async function cachedEnforcerDiags(ctx, freshPaths) {
6996
6996
  }
6997
6997
  function isFresh(snapshot, repoRoot, freshPaths) {
6998
6998
  if (!freshPaths || freshPaths.length === 0) return true;
6999
- for (const path20 of freshPaths) {
6999
+ for (const path22 of freshPaths) {
7000
7000
  let mtimeMs;
7001
7001
  try {
7002
- mtimeMs = statSync2(resolve5(repoRoot, path20)).mtimeMs;
7002
+ mtimeMs = statSync2(resolve5(repoRoot, path22)).mtimeMs;
7003
7003
  } catch {
7004
7004
  return false;
7005
7005
  }
@@ -7652,15 +7652,15 @@ import { readFile as readFile5 } from "fs/promises";
7652
7652
  import { resolve as resolve6 } from "path";
7653
7653
 
7654
7654
  // ../../packages/data/src/meta.ts
7655
- function stringMeta(metadata, path20) {
7656
- const value = metaValue(metadata, path20);
7655
+ function stringMeta(metadata, path22) {
7656
+ const value = metaValue(metadata, path22);
7657
7657
  return typeof value === "string" ? value : void 0;
7658
7658
  }
7659
- function metaValue(metadata, path20) {
7659
+ function metaValue(metadata, path22) {
7660
7660
  if (!metadata) return void 0;
7661
- if (Object.prototype.hasOwnProperty.call(metadata, path20)) return metadata[path20];
7661
+ if (Object.prototype.hasOwnProperty.call(metadata, path22)) return metadata[path22];
7662
7662
  let current = metadata;
7663
- for (const part of path20.split(".")) {
7663
+ for (const part of path22.split(".")) {
7664
7664
  if (!current || typeof current !== "object" || !Object.prototype.hasOwnProperty.call(current, part))
7665
7665
  return void 0;
7666
7666
  current = current[part];
@@ -7771,8 +7771,8 @@ function resolveScopeGovernance(ctx, members, codeNodes) {
7771
7771
  }
7772
7772
  return [...out.values()];
7773
7773
  }
7774
- function resolveDirectoryGovernance(ctx, path20) {
7775
- let dir = path20.includes("/") ? path20.slice(0, path20.lastIndexOf("/")) : "";
7774
+ function resolveDirectoryGovernance(ctx, path22) {
7775
+ let dir = path22.includes("/") ? path22.slice(0, path22.lastIndexOf("/")) : "";
7776
7776
  for (; ; ) {
7777
7777
  const siblings = codeNodesInDir(ctx, dir);
7778
7778
  if (siblings.length > 0) return resolveScopeGovernance(ctx, [], siblings);
@@ -8333,15 +8333,15 @@ async function review(ctx, req) {
8333
8333
  cites: []
8334
8334
  });
8335
8335
  }
8336
- for (const path20 of unresolved) {
8337
- const dirGov = resolveDirectoryGovernance(ctx, path20).filter((n) => !isWorkItem(n)).map((g) => g.id).filter((id) => !cites.has(id)).slice(0, 3);
8336
+ for (const path22 of unresolved) {
8337
+ const dirGov = resolveDirectoryGovernance(ctx, path22).filter((n) => !isWorkItem(n)).map((g) => g.id).filter((id) => !cites.has(id)).slice(0, 3);
8338
8338
  const hint = dirGov.length ? ` Files in its directory are governed by ${dirGov.join(", ")} \u2014 cite if it applies.` : "";
8339
8339
  findings.push({
8340
8340
  code: "unresolved-edit",
8341
8341
  severity: "info",
8342
8342
  confidence: "precise",
8343
- subject: path20,
8344
- message: `${path20} isn't in the graph yet (a new file, or a path that doesn't match).${hint || " No governed siblings to assess it by."}`,
8343
+ subject: path22,
8344
+ message: `${path22} isn't in the graph yet (a new file, or a path that doesn't match).${hint || " No governed siblings to assess it by."}`,
8345
8345
  cites: dirGov
8346
8346
  });
8347
8347
  }
@@ -9192,8 +9192,8 @@ async function readFileContent(workdir, relPath) {
9192
9192
 
9193
9193
  // src/workspace.ts
9194
9194
  var workspacePath = null;
9195
- function setWorkspacePath(path20) {
9196
- workspacePath = path20;
9195
+ function setWorkspacePath(path22) {
9196
+ workspacePath = path22;
9197
9197
  }
9198
9198
  function getWorkspacePath() {
9199
9199
  if (!workspacePath) {
@@ -9612,10 +9612,11 @@ import WebSocket from "ws";
9612
9612
  import { createRequire as createRequire2 } from "module";
9613
9613
  var _require = createRequire2(import.meta.url);
9614
9614
  var VERSION2 = _require("../package.json").version ?? "0.0.0";
9615
- var SHA = "c87ba61";
9615
+ var IS_DEV = String(_require("../package.json").name ?? "").endsWith("-dev");
9616
+ var SHA = "d64996d";
9616
9617
  var BUILT = "2026-09-07";
9617
9618
  var BUILD = SHA ?? "source";
9618
- var BUILD_LABEL = SHA ? `${VERSION2} (${SHA}${BUILT ? ` ${BUILT}` : ""})` : `${VERSION2} (source)`;
9619
+ var BUILD_LABEL = `${SHA ? `${VERSION2} (${SHA}${BUILT ? ` ${BUILT}` : ""})` : `${VERSION2} (source)`}${IS_DEV ? " \u2014 development build" : ""}`;
9619
9620
 
9620
9621
  // src/upstream.ts
9621
9622
  function createUpstreamClient(config2) {
@@ -10542,12 +10543,12 @@ function register14(program) {
10542
10543
  }
10543
10544
 
10544
10545
  // src/commands/mcp.ts
10545
- async function call(path20, method, body) {
10546
+ async function call(path22, method, body) {
10546
10547
  const config2 = loadConfig();
10547
10548
  if (!config2?.token) {
10548
10549
  throw new Error("not connected \u2014 run `jarvis connect` first");
10549
10550
  }
10550
- const resp = await fetch(new URL(path20, config2.url ?? getJarvisUrl()), {
10551
+ const resp = await fetch(new URL(path22, config2.url ?? getJarvisUrl()), {
10551
10552
  method,
10552
10553
  headers: {
10553
10554
  authorization: `Bearer ${config2.token}`,
@@ -10556,7 +10557,7 @@ async function call(path20, method, body) {
10556
10557
  ...body === void 0 ? {} : { body: JSON.stringify(body) }
10557
10558
  });
10558
10559
  if (!resp.ok) {
10559
- throw new Error(`${method} ${path20} failed: ${resp.status} ${await resp.text()}`);
10560
+ throw new Error(`${method} ${path22} failed: ${resp.status} ${await resp.text()}`);
10560
10561
  }
10561
10562
  return await resp.json();
10562
10563
  }
@@ -10904,9 +10905,9 @@ function resolveRepo(repo) {
10904
10905
  loadEnvFile(resolve8(homedir4(), ".jarvis", "data.env"));
10905
10906
  return cwd;
10906
10907
  }
10907
- function loadEnvFile(path20) {
10908
+ function loadEnvFile(path22) {
10908
10909
  try {
10909
- process.loadEnvFile(path20);
10910
+ process.loadEnvFile(path22);
10910
10911
  } catch {
10911
10912
  }
10912
10913
  }
@@ -10927,6 +10928,102 @@ function register16(program) {
10927
10928
  });
10928
10929
  }
10929
10930
 
10931
+ // src/commands/dev.ts
10932
+ import path20 from "path";
10933
+
10934
+ // src/dev.ts
10935
+ import fs18 from "fs";
10936
+ import path19 from "path";
10937
+ function redirectFile() {
10938
+ return path19.join(getConfigDir(), "dev.json");
10939
+ }
10940
+ function readDevRedirect() {
10941
+ try {
10942
+ const raw = JSON.parse(fs18.readFileSync(redirectFile(), "utf-8"));
10943
+ if (typeof raw.root !== "string" || raw.root.length === 0) return null;
10944
+ return {
10945
+ root: raw.root,
10946
+ repos: Array.isArray(raw.repos) ? raw.repos.filter((r) => typeof r === "string") : [],
10947
+ all: raw.all === true
10948
+ };
10949
+ } catch {
10950
+ return null;
10951
+ }
10952
+ }
10953
+ function saveDevRedirect(req) {
10954
+ const dir = getConfigDir();
10955
+ fs18.mkdirSync(dir, { recursive: true });
10956
+ fs18.writeFileSync(redirectFile(), `${JSON.stringify(req, null, 2)}
10957
+ `);
10958
+ }
10959
+ function clearDevRedirect() {
10960
+ fs18.rmSync(redirectFile(), { force: true });
10961
+ }
10962
+ function realPath(target) {
10963
+ try {
10964
+ return fs18.realpathSync(target);
10965
+ } catch {
10966
+ return target;
10967
+ }
10968
+ }
10969
+ function isRedirected(req) {
10970
+ if (req.redirect.all) return true;
10971
+ const cwd = realPath(req.cwd);
10972
+ return req.redirect.repos.some((repo) => {
10973
+ const rel = path19.relative(realPath(repo), cwd);
10974
+ return rel === "" || !rel.startsWith("..") && !path19.isAbsolute(rel);
10975
+ });
10976
+ }
10977
+
10978
+ // src/commands/dev.ts
10979
+ function register17(program) {
10980
+ const dev = program.command("dev").description("Run a development build in a repo, without replacing the installed jarvis");
10981
+ dev.command("use").argument("[where]", "'here' for the working directory, 'all' for every repo", "here").option("--root <path>", "The checkout to run. Default: the one already recorded").description("Point a repo at the development build").action((where, opts) => {
10982
+ const current = readDevRedirect();
10983
+ const root = path20.resolve(opts.root ?? current?.root ?? process.cwd());
10984
+ if (where !== "here" && where !== "all") {
10985
+ console.error(`Unknown target '${where}' \u2014 say 'here' or 'all'.`);
10986
+ process.exitCode = 1;
10987
+ return;
10988
+ }
10989
+ const repos = new Set(current?.repos ?? []);
10990
+ if (where === "here") repos.add(realPath(process.cwd()));
10991
+ saveDevRedirect({ root, repos: [...repos], all: where === "all" || (current?.all ?? false) });
10992
+ console.log(
10993
+ where === "all" ? `Every repo on this machine now serves the development build in ${root}.` : `${process.cwd()} now serves the development build in ${root}.`
10994
+ );
10995
+ console.log("The installed jarvis is untouched. Undo with `jarvis dev off`.");
10996
+ });
10997
+ dev.command("off").argument("[where]", "'here' for the working directory, 'all' to stop everywhere", "all").description("Stop serving the development build").action((where) => {
10998
+ const current = readDevRedirect();
10999
+ if (!current) {
11000
+ console.log("No repo is on a development build.");
11001
+ return;
11002
+ }
11003
+ if (where === "here") {
11004
+ const repos = current.repos.filter((repo) => realPath(repo) !== realPath(process.cwd()));
11005
+ saveDevRedirect({ ...current, repos, all: false });
11006
+ console.log(`${process.cwd()} is back on the installed jarvis.`);
11007
+ return;
11008
+ }
11009
+ clearDevRedirect();
11010
+ console.log("Every repo is back on the installed jarvis.");
11011
+ });
11012
+ dev.command("status").description("Say which repos are on a development build").action(() => {
11013
+ const current = readDevRedirect();
11014
+ if (!current) {
11015
+ console.log("No repo is on a development build.");
11016
+ return;
11017
+ }
11018
+ console.log(`development build ${current.root}`);
11019
+ console.log(current.all ? " every repo on this machine" : "");
11020
+ for (const repo of current.repos) console.log(` ${repo}`);
11021
+ console.log(
11022
+ isRedirected({ cwd: process.cwd(), redirect: current }) ? "\nHere: the development build." : "\nHere: the installed jarvis."
11023
+ );
11024
+ });
11025
+ }
11026
+
10930
11027
  // src/graph/mcp.ts
10931
11028
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
10932
11029
  async function runMcp(cwd, hosted = [], prompts = []) {
@@ -11464,7 +11561,7 @@ function describeStart(response) {
11464
11561
  // src/serve/approvals.ts
11465
11562
  import { readFileSync as readFileSync7 } from "fs";
11466
11563
  import os10 from "os";
11467
- import path19 from "path";
11564
+ import path21 from "path";
11468
11565
  function pendingApproval(cwd) {
11469
11566
  const unapproved = unapprovedServers(cwd);
11470
11567
  const reasons = [
@@ -11475,15 +11572,15 @@ function pendingApproval(cwd) {
11475
11572
  return `it will HOLD at a prompt and take no turn, because ${reasons.join(" and ")}. Nothing will appear in Claude Code's history or in the app until somebody opens ${cwd} in Claude Code once and answers. This is a one-time gate per folder.`;
11476
11573
  }
11477
11574
  function untrustedFolder(cwd) {
11478
- const state2 = readJson2(path19.join(os10.homedir(), ".claude.json"));
11575
+ const state2 = readJson2(path21.join(os10.homedir(), ".claude.json"));
11479
11576
  const project = state2?.projects?.[cwd];
11480
11577
  if (!state2) return false;
11481
11578
  return project?.hasTrustDialogAccepted !== true;
11482
11579
  }
11483
11580
  function unapprovedServers(cwd) {
11484
- const declared = readJson2(path19.join(cwd, ".mcp.json"));
11581
+ const declared = readJson2(path21.join(cwd, ".mcp.json"));
11485
11582
  if (!declared?.mcpServers) return [];
11486
- const settings = readJson2(path19.join(cwd, ".claude", "settings.local.json"));
11583
+ const settings = readJson2(path21.join(cwd, ".claude", "settings.local.json"));
11487
11584
  if (settings?.enableAllProjectMcpServers === true) return [];
11488
11585
  const answered = /* @__PURE__ */ new Set([
11489
11586
  ...settings?.enabledMcpjsonServers ?? [],
@@ -11593,7 +11690,7 @@ async function brief2(repo) {
11593
11690
  }
11594
11691
 
11595
11692
  // src/commands/serve.ts
11596
- function register17(program) {
11693
+ function register18(program) {
11597
11694
  program.command("serve").description("Serve this repo to an agent over stdio \u2014 what an .mcp.json launches").option("--repo <path>", "The repo to serve. Default: the working directory").action(async (opts) => {
11598
11695
  const repo = resolveRepo(opts.repo);
11599
11696
  const problem = harnessProblem();
@@ -11655,7 +11752,7 @@ function refuseNamedConfigDir() {
11655
11752
  );
11656
11753
  return true;
11657
11754
  }
11658
- function register18(program) {
11755
+ function register19(program) {
11659
11756
  const hooks = program.command("hooks").description("Wire this machine's Claude Code to jarvis \u2014 no pairing, no daemon");
11660
11757
  hooks.command("install").description("Install the Claude Code hooks (the session block and the rules on edit)").action(() => {
11661
11758
  if (refuseNamedConfigDir()) process.exit(1);
@@ -11710,7 +11807,7 @@ Open Claude Code in a repo that has a work/ tree to see them.`);
11710
11807
 
11711
11808
  // src/commands/work.ts
11712
11809
  import { spawnSync as spawnSync3 } from "child_process";
11713
- function register19(program) {
11810
+ function register20(program) {
11714
11811
  program.command("work").description("The board \u2014 take work, prove it, finish it").argument("[args...]", "Passed to the harness untouched").allowUnknownOption().passThroughOptions().helpOption(false).action((passed) => {
11715
11812
  const problem = harnessProblem();
11716
11813
  if (problem) {
@@ -11752,22 +11849,23 @@ function createCli() {
11752
11849
  register17(program);
11753
11850
  register18(program);
11754
11851
  register19(program);
11852
+ register20(program);
11755
11853
  return program;
11756
11854
  }
11757
11855
 
11758
11856
  // src/bin.ts
11759
11857
  if (isRunningFromSource()) {
11760
11858
  const dotenv = await import("dotenv");
11761
- const fs18 = await import("fs");
11762
- const path20 = await import("path");
11859
+ const fs19 = await import("fs");
11860
+ const path22 = await import("path");
11763
11861
  let dir = process.cwd();
11764
- while (dir !== path20.dirname(dir)) {
11765
- const envPath = path20.join(dir, ".env");
11766
- if (fs18.existsSync(envPath)) {
11862
+ while (dir !== path22.dirname(dir)) {
11863
+ const envPath = path22.join(dir, ".env");
11864
+ if (fs19.existsSync(envPath)) {
11767
11865
  dotenv.config({ path: envPath });
11768
11866
  break;
11769
11867
  }
11770
- dir = path20.dirname(dir);
11868
+ dir = path22.dirname(dir);
11771
11869
  }
11772
11870
  }
11773
11871
  createCli().parse();