@appchy/jarvis 0.1.108 → 0.1.110

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/dist/bin.js CHANGED
@@ -1387,10 +1387,78 @@ async function ensureGraphify(options = {}) {
1387
1387
  );
1388
1388
  }
1389
1389
 
1390
+ // src/graph/hook.ts
1391
+ import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync, chmodSync } from "fs";
1392
+ import path7 from "path";
1393
+ var SIGNATURE = "# managed by jarvis";
1394
+ var SCRIPT = `#!/bin/sh
1395
+ ${SIGNATURE} \u2014 keeps this repo's map current, so what an agent plans against is what is here.
1396
+ # Detached and silenced: git waits for a hook's output streams to close, so a build left on stdout
1397
+ # would hold up every commit by the length of a build. Never fails a commit.
1398
+ #
1399
+ # Run at the lowest priority the machine offers. A code commit still costs a real extract, and one
1400
+ # arriving at normal priority the instant you commit is felt as the machine going away for half a
1401
+ # minute \u2014 which is how a background job becomes something people turn off. Borrowed from the
1402
+ # docdoc-era hook in crispy, which had this right first.
1403
+ command -v jarvis >/dev/null 2>&1 || exit 0
1404
+ NICE=""
1405
+ command -v nice >/dev/null 2>&1 && NICE="nice -n 19"
1406
+ command -v taskpolicy >/dev/null 2>&1 && NICE="taskpolicy -b $NICE"
1407
+ ( $NICE jarvis build graph >/dev/null 2>&1 & ) >/dev/null 2>&1
1408
+ exit 0
1409
+ `;
1410
+ function findRepoRoot(from) {
1411
+ let dir = path7.resolve(from);
1412
+ for (; ; ) {
1413
+ if (existsSync(path7.join(dir, ".git"))) return dir;
1414
+ const parent = path7.dirname(dir);
1415
+ if (parent === dir) return null;
1416
+ dir = parent;
1417
+ }
1418
+ }
1419
+ function installCommitHook(repoRoot) {
1420
+ const git4 = path7.join(repoRoot, ".git");
1421
+ const dir = path7.join(git4, "hooks");
1422
+ const file = path7.join(dir, "post-commit");
1423
+ if (!existsSync(git4)) return { installed: false, reason: "not-a-repo" };
1424
+ if (!statSync(git4).isDirectory()) return { installed: false, reason: "worktree" };
1425
+ if (!existsSync(path7.join(git4, "HEAD"))) return { installed: false, reason: "not-a-repo" };
1426
+ if (existsSync(file)) {
1427
+ try {
1428
+ if (!readFileSync(file, "utf8").includes(SIGNATURE))
1429
+ return { installed: false, reason: "foreign-hook", path: file };
1430
+ } catch {
1431
+ return { installed: false, reason: "unwritable", path: file };
1432
+ }
1433
+ }
1434
+ try {
1435
+ mkdirSync(dir, { recursive: true });
1436
+ writeFileSync(file, SCRIPT, "utf8");
1437
+ chmodSync(file, 493);
1438
+ return { installed: true, path: file };
1439
+ } catch {
1440
+ return { installed: false, reason: "unwritable", path: file };
1441
+ }
1442
+ }
1443
+ function describeCommitHook(outcome, repoRoot) {
1444
+ if (outcome.installed)
1445
+ return ` the map rebuilds itself on every commit here \u2713 (${path7.relative(repoRoot, outcome.path) || outcome.path})`;
1446
+ if (outcome.reason === "not-a-repo")
1447
+ return ` not a git repo, so there is no commit to rebuild on.
1448
+ Run this inside one, or rebuild by hand with 'jarvis build graph'.`;
1449
+ if (outcome.reason === "worktree")
1450
+ return ` this is a worktree or a submodule, and it shares the hooks of the checkout it
1451
+ was made from. Wire that one instead, or rebuild by hand with 'jarvis build graph'.`;
1452
+ if (outcome.reason === "foreign-hook")
1453
+ return ` a post-commit hook is already here and it is not ours \u2014 left untouched.
1454
+ Add this line to it to keep the map current: jarvis build graph >/dev/null 2>&1 &`;
1455
+ return ` could not write the hook \u2014 the map still builds, by hand, with 'jarvis build graph'.`;
1456
+ }
1457
+
1390
1458
  // src/machine.ts
1391
1459
  import crypto2 from "crypto";
1392
1460
  import fs8 from "fs";
1393
- import path7 from "path";
1461
+ import path8 from "path";
1394
1462
  var cached = null;
1395
1463
  function getMachine() {
1396
1464
  if (cached) return cached;
@@ -1405,7 +1473,7 @@ function getMachine() {
1405
1473
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1406
1474
  schemaVersion: 1
1407
1475
  };
1408
- fs8.mkdirSync(path7.dirname(file), { recursive: true });
1476
+ fs8.mkdirSync(path8.dirname(file), { recursive: true });
1409
1477
  fs8.writeFileSync(file, JSON.stringify(fresh, null, 2));
1410
1478
  return cached = fresh;
1411
1479
  }
@@ -1413,13 +1481,13 @@ function getMachine() {
1413
1481
  // src/service.ts
1414
1482
  import { execSync as execSync3, spawn } from "child_process";
1415
1483
  import fs9 from "fs";
1416
- import path8 from "path";
1484
+ import path9 from "path";
1417
1485
  import os4 from "os";
1418
1486
  function serviceSuffix() {
1419
1487
  const dir = getConfigDir();
1420
- const base = path8.join(os4.homedir(), ".jarvis");
1488
+ const base = path9.join(os4.homedir(), ".jarvis");
1421
1489
  if (dir === base) return "";
1422
- const name = dir.startsWith(base + path8.sep) ? dir.slice(base.length + 1) : path8.basename(dir);
1490
+ const name = dir.startsWith(base + path9.sep) ? dir.slice(base.length + 1) : path9.basename(dir);
1423
1491
  return name.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-|-$/g, "");
1424
1492
  }
1425
1493
  var SERVICE_SUFFIX = serviceSuffix();
@@ -1430,8 +1498,8 @@ function createServiceManager() {
1430
1498
  return new FallbackService();
1431
1499
  }
1432
1500
  var PLIST_LABEL = `com.appchy.jarvis${SERVICE_SUFFIX ? `.${SERVICE_SUFFIX}` : ""}`;
1433
- var PLIST_DIR = path8.join(os4.homedir(), "Library", "LaunchAgents");
1434
- var PLIST_PATH = path8.join(PLIST_DIR, `${PLIST_LABEL}.plist`);
1501
+ var PLIST_DIR = path9.join(os4.homedir(), "Library", "LaunchAgents");
1502
+ var PLIST_PATH = path9.join(PLIST_DIR, `${PLIST_LABEL}.plist`);
1435
1503
  function escapeXml(s) {
1436
1504
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
1437
1505
  }
@@ -1585,7 +1653,7 @@ ${Object.entries(opts.env ?? {}).map(([k, v]) => ` <key>${escapeXml(k)}</key>
1585
1653
  </plist>
1586
1654
  `;
1587
1655
  fs9.mkdirSync(PLIST_DIR, { recursive: true });
1588
- fs9.mkdirSync(path8.dirname(logFile), { recursive: true });
1656
+ fs9.mkdirSync(path9.dirname(logFile), { recursive: true });
1589
1657
  unloadAgent();
1590
1658
  fs9.writeFileSync(PLIST_PATH, plist);
1591
1659
  loadAgent();
@@ -1687,7 +1755,7 @@ var WindowsService = class {
1687
1755
  </Task>
1688
1756
  `;
1689
1757
  const tmpDir = os4.tmpdir();
1690
- const tmpFile = path8.join(tmpDir, `jarvis-task-${Date.now()}.xml`);
1758
+ const tmpFile = path9.join(tmpDir, `jarvis-task-${Date.now()}.xml`);
1691
1759
  fs9.writeFileSync(tmpFile, xml, { encoding: "utf-16le" });
1692
1760
  try {
1693
1761
  execSync3(`schtasks /Create /TN "${TASK_NAME}" /XML "${tmpFile}" /F`, {
@@ -1733,9 +1801,9 @@ var WindowsService = class {
1733
1801
  }
1734
1802
  }
1735
1803
  };
1736
- var SYSTEMD_DIR = path8.join(os4.homedir(), ".config", "systemd", "user");
1804
+ var SYSTEMD_DIR = path9.join(os4.homedir(), ".config", "systemd", "user");
1737
1805
  var UNIT_NAME = `jarvis${SERVICE_SUFFIX ? `-${SERVICE_SUFFIX}` : ""}.service`;
1738
- var UNIT_PATH = path8.join(SYSTEMD_DIR, UNIT_NAME);
1806
+ var UNIT_PATH = path9.join(SYSTEMD_DIR, UNIT_NAME);
1739
1807
  var LinuxService = class {
1740
1808
  install(opts) {
1741
1809
  const args = [opts.entryPath, "start", "--foreground", "--workspace", opts.workspacePath];
@@ -1764,7 +1832,7 @@ StandardError=append:${logFile}
1764
1832
  WantedBy=default.target
1765
1833
  `;
1766
1834
  fs9.mkdirSync(SYSTEMD_DIR, { recursive: true });
1767
- fs9.mkdirSync(path8.dirname(logFile), { recursive: true });
1835
+ fs9.mkdirSync(path9.dirname(logFile), { recursive: true });
1768
1836
  if (this.isInstalled()) {
1769
1837
  try {
1770
1838
  execSync3(`systemctl --user stop ${UNIT_NAME}`, { stdio: "ignore" });
@@ -1844,9 +1912,9 @@ WantedBy=default.target
1844
1912
  };
1845
1913
  var FallbackService = class {
1846
1914
  baseDir = getJarvisDir();
1847
- pidFile = path8.join(this.baseDir, "agent.pid");
1848
- logFile = path8.join(this.baseDir, "agent.log");
1849
- markerFile = path8.join(this.baseDir, "service-installed");
1915
+ pidFile = path9.join(this.baseDir, "agent.pid");
1916
+ logFile = path9.join(this.baseDir, "agent.log");
1917
+ markerFile = path9.join(this.baseDir, "service-installed");
1850
1918
  install(opts) {
1851
1919
  fs9.mkdirSync(this.baseDir, { recursive: true });
1852
1920
  this.stop();
@@ -1921,11 +1989,11 @@ var FallbackService = class {
1921
1989
  };
1922
1990
 
1923
1991
  // src/hooks/install.ts
1924
- import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from "fs";
1992
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, realpathSync, writeFileSync as writeFileSync2 } from "fs";
1925
1993
  import os5 from "os";
1926
- import path9 from "path";
1927
- var SETTINGS_DIR = path9.join(os5.homedir(), ".claude");
1928
- var SETTINGS_FILE = path9.join(SETTINGS_DIR, "settings.json");
1994
+ import path10 from "path";
1995
+ var SETTINGS_DIR = path10.join(os5.homedir(), ".claude");
1996
+ var SETTINGS_FILE = path10.join(SETTINGS_DIR, "settings.json");
1929
1997
  var HOOK_STEMS = [
1930
1998
  "pre-tool-use",
1931
1999
  "session-start",
@@ -1943,7 +2011,7 @@ function jarvisHooks() {
1943
2011
  ];
1944
2012
  }
1945
2013
  function isJarvisCommand(command) {
1946
- const name = path9.basename(command);
2014
+ const name = path10.basename(command);
1947
2015
  return HOOK_STEMS.some((stem) => name === `${stem}.mjs` || name === `${stem}.dev.mjs`);
1948
2016
  }
1949
2017
  function getCliRoot() {
@@ -1956,22 +2024,22 @@ function getCliRoot() {
1956
2024
  entry = realpathSync(binPath);
1957
2025
  } catch {
1958
2026
  }
1959
- return path9.resolve(path9.dirname(entry), "..");
2027
+ return path10.resolve(path10.dirname(entry), "..");
1960
2028
  }
1961
2029
  function resolveHooks() {
1962
2030
  const cliRoot = getCliRoot();
1963
2031
  return jarvisHooks().map((h) => ({
1964
2032
  ...h,
1965
- binAbsPath: path9.join(cliRoot, "bin", h.binBasename)
2033
+ binAbsPath: path10.join(cliRoot, "bin", h.binBasename)
1966
2034
  }));
1967
2035
  }
1968
2036
  function ownsClaudeCode() {
1969
- return getConfigDir() === path9.join(os5.homedir(), ".jarvis");
2037
+ return getConfigDir() === path10.join(os5.homedir(), ".jarvis");
1970
2038
  }
1971
2039
  function readSettings() {
1972
- if (!existsSync(SETTINGS_FILE)) return {};
2040
+ if (!existsSync2(SETTINGS_FILE)) return {};
1973
2041
  try {
1974
- const raw = readFileSync(SETTINGS_FILE, "utf-8");
2042
+ const raw = readFileSync2(SETTINGS_FILE, "utf-8");
1975
2043
  return raw.trim() ? JSON.parse(raw) : {};
1976
2044
  } catch (err) {
1977
2045
  logger.sys.warn("[hooks.install] settings.json unreadable", {
@@ -1982,8 +2050,8 @@ function readSettings() {
1982
2050
  }
1983
2051
  function writeSettings(s) {
1984
2052
  try {
1985
- mkdirSync(SETTINGS_DIR, { recursive: true });
1986
- writeFileSync(SETTINGS_FILE, JSON.stringify(s, null, 2) + "\n");
2053
+ mkdirSync2(SETTINGS_DIR, { recursive: true });
2054
+ writeFileSync2(SETTINGS_FILE, JSON.stringify(s, null, 2) + "\n");
1987
2055
  return true;
1988
2056
  } catch (err) {
1989
2057
  logger.sys.warn("[hooks.install] settings.json unwritable", {
@@ -2028,7 +2096,7 @@ function claudeCodeHooksState() {
2028
2096
  return {
2029
2097
  type: hook.type,
2030
2098
  bin: hook.binAbsPath,
2031
- exists: existsSync(hook.binAbsPath),
2099
+ exists: existsSync2(hook.binAbsPath),
2032
2100
  ...command ? { command } : {}
2033
2101
  };
2034
2102
  });
@@ -2050,10 +2118,10 @@ function installClaudeCodeHooks() {
2050
2118
  expected: resolved.map((h) => ({
2051
2119
  type: h.type,
2052
2120
  bin: h.binAbsPath,
2053
- exists: existsSync(h.binAbsPath)
2121
+ exists: existsSync2(h.binAbsPath)
2054
2122
  }))
2055
2123
  });
2056
- const missing = resolved.filter((h) => !existsSync(h.binAbsPath));
2124
+ const missing = resolved.filter((h) => !existsSync2(h.binAbsPath));
2057
2125
  if (missing.length === resolved.length) {
2058
2126
  logger.sys.warn("[hooks.install] no bin shims found, skipping", {
2059
2127
  configDir: configDir2,
@@ -2064,7 +2132,7 @@ function installClaudeCodeHooks() {
2064
2132
  let settings = readSettings();
2065
2133
  const installed = [];
2066
2134
  for (const hook of resolved) {
2067
- if (!existsSync(hook.binAbsPath)) {
2135
+ if (!existsSync2(hook.binAbsPath)) {
2068
2136
  logger.sys.warn("[hooks.install] bin shim missing, skipping hook", {
2069
2137
  configDir: configDir2,
2070
2138
  type: hook.type,
@@ -2232,89 +2300,8 @@ Open Claude Code in a repo that has a work/ tree to see them.`);
2232
2300
  });
2233
2301
  }
2234
2302
 
2235
- // src/graph/hook.ts
2236
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, chmodSync } from "fs";
2237
- import path10 from "path";
2238
- var SIGNATURE = "# managed by jarvis";
2239
- var SCRIPT = `#!/bin/sh
2240
- ${SIGNATURE} \u2014 keeps this repo's map current, so what an agent plans against is what is here.
2241
- # Detached and silenced: git waits for a hook's output streams to close, so a build left on stdout
2242
- # would hold up every commit by the length of a build. Never fails a commit.
2243
- #
2244
- # Run at the lowest priority the machine offers. A code commit still costs a real extract, and one
2245
- # arriving at normal priority the instant you commit is felt as the machine going away for half a
2246
- # minute \u2014 which is how a background job becomes something people turn off. Borrowed from the
2247
- # docdoc-era hook in crispy, which had this right first.
2248
- command -v jarvis >/dev/null 2>&1 || exit 0
2249
- NICE=""
2250
- command -v nice >/dev/null 2>&1 && NICE="nice -n 19"
2251
- command -v taskpolicy >/dev/null 2>&1 && NICE="taskpolicy -b $NICE"
2252
- ( $NICE jarvis build graph >/dev/null 2>&1 & ) >/dev/null 2>&1
2253
- exit 0
2254
- `;
2255
- function findRepoRoot(from) {
2256
- let dir = path10.resolve(from);
2257
- for (; ; ) {
2258
- if (existsSync2(path10.join(dir, ".git"))) return dir;
2259
- const parent = path10.dirname(dir);
2260
- if (parent === dir) return null;
2261
- dir = parent;
2262
- }
2263
- }
2264
- function installCommitHook(repoRoot) {
2265
- const dir = path10.join(repoRoot, ".git", "hooks");
2266
- const file = path10.join(dir, "post-commit");
2267
- if (!existsSync2(path10.join(repoRoot, ".git")) || !existsSync2(path10.join(repoRoot, ".git", "HEAD"))) {
2268
- return { installed: false, reason: "not-a-repo" };
2269
- }
2270
- if (existsSync2(file)) {
2271
- try {
2272
- if (!readFileSync2(file, "utf8").includes(SIGNATURE))
2273
- return { installed: false, reason: "foreign-hook", path: file };
2274
- } catch {
2275
- return { installed: false, reason: "unwritable", path: file };
2276
- }
2277
- }
2278
- try {
2279
- mkdirSync2(dir, { recursive: true });
2280
- writeFileSync2(file, SCRIPT, "utf8");
2281
- chmodSync(file, 493);
2282
- return { installed: true, path: file };
2283
- } catch {
2284
- return { installed: false, reason: "unwritable", path: file };
2285
- }
2286
- }
2287
- function describeCommitHook(outcome, repoRoot) {
2288
- if (outcome.installed)
2289
- return ` the map rebuilds itself on every commit here \u2713 (${path10.relative(repoRoot, outcome.path) || outcome.path})`;
2290
- if (outcome.reason === "not-a-repo")
2291
- return ` not a git repo, so there is no commit to rebuild on.
2292
- Run this inside one, or rebuild by hand with 'jarvis build graph'.`;
2293
- if (outcome.reason === "foreign-hook")
2294
- return ` a post-commit hook is already here and it is not ours \u2014 left untouched.
2295
- Add this line to it to keep the map current: jarvis build graph >/dev/null 2>&1 &`;
2296
- return ` could not write the hook \u2014 the map still builds, by hand, with 'jarvis build graph'.`;
2297
- }
2298
-
2299
- // src/commands/repo.ts
2300
- function register3(program) {
2301
- const repo = program.command("repo").description("Set up the repo you are standing in \u2014 no pairing, no daemon, no network");
2302
- repo.command("init").description("Keep this repo's map current by rebuilding it on every commit").action(() => {
2303
- if (!setUpThisRepo()) process.exit(1);
2304
- console.log(" It rebuilds from your next commit. To build one now: jarvis build graph\n");
2305
- });
2306
- }
2307
- function setUpThisRepo() {
2308
- const root = findRepoRoot(process.cwd()) ?? process.cwd();
2309
- console.log(" \u25B8 Keeping this repo's map current");
2310
- const outcome = installCommitHook(root);
2311
- console.log(`${describeCommitHook(outcome, root)}
2312
- `);
2313
- return outcome.installed;
2314
- }
2315
-
2316
2303
  // src/commands/init.ts
2317
- function register4(program) {
2304
+ function register3(program) {
2318
2305
  program.command("init").description("Set this machine up to work in repos, and join an instance if you name one").option("--url <url>", "Also join the jarvis instance at this address").option("--skip-daemon", "Skip the background daemon install step").option("--force", "Re-ask all prompts even when config already has answers").action(async (opts) => {
2319
2306
  const ok = await runInit({
2320
2307
  url: opts.url,
@@ -2410,6 +2397,14 @@ async function setUpThisMachine(prompts) {
2410
2397
  `
2411
2398
  );
2412
2399
  }
2400
+ function setUpThisRepo() {
2401
+ const root = findRepoRoot(process.cwd()) ?? process.cwd();
2402
+ console.log(" \u25B8 Keeping this repo's map current");
2403
+ const outcome = installCommitHook(root);
2404
+ console.log(`${describeCommitHook(outcome, root)}
2405
+ `);
2406
+ return outcome.installed;
2407
+ }
2413
2408
  async function setUpMapTool(prompts) {
2414
2409
  console.log(" \u25B8 The tool the map's code half is built from");
2415
2410
  const state2 = resolveGraphify();
@@ -2472,7 +2467,7 @@ function reportSetUp(joined) {
2472
2467
  console.log(" \u2714 Done. This machine works in any repo that has a work/ tree:");
2473
2468
  console.log(" the board, the map, the session block, the rules that arrive on edit,");
2474
2469
  console.log(" and 'jarvis serve' for any agent that speaks MCP.\n");
2475
- console.log(" In a repo you have cloned: jarvis repo init");
2470
+ console.log(" In a repo you have cloned: jarvis init");
2476
2471
  console.log(" jarvis build graph");
2477
2472
  console.log(" jarvis work list\n");
2478
2473
  if (joined) {
@@ -2691,7 +2686,7 @@ async function promptList(question, fallback) {
2691
2686
  }
2692
2687
 
2693
2688
  // src/commands/pair.ts
2694
- function register5(program) {
2689
+ function register4(program) {
2695
2690
  program.command("pair").description("Re-pair this machine (when token expired)").action(async () => {
2696
2691
  try {
2697
2692
  await runPair();
@@ -2805,7 +2800,7 @@ async function unpair() {
2805
2800
  clearConfig();
2806
2801
  return { attempted: true, serverStatus };
2807
2802
  }
2808
- function register6(program) {
2803
+ function register5(program) {
2809
2804
  program.command("unpair").description("Unregister this env from cloud and wipe local config").option("-y, --yes", "Skip confirmation prompt").action(async (opts) => {
2810
2805
  try {
2811
2806
  const config2 = loadConfig();
@@ -2860,7 +2855,7 @@ function getRoots() {
2860
2855
  const cfg = readConfig();
2861
2856
  return Array.isArray(cfg.roots) ? cfg.roots : [];
2862
2857
  }
2863
- function register7(program) {
2858
+ function register6(program) {
2864
2859
  const cmd = program.command("roots").description("Manage code-root directories");
2865
2860
  cmd.command("list", { isDefault: true }).description("List current roots").action(() => {
2866
2861
  const roots = getRoots();
@@ -2905,7 +2900,7 @@ function readLocalConfig() {
2905
2900
  return {};
2906
2901
  }
2907
2902
  }
2908
- function register8(program) {
2903
+ function register7(program) {
2909
2904
  program.command("settings").description("Show this env's settings (roots, repos map)").action(async () => {
2910
2905
  try {
2911
2906
  const config2 = loadConfig();
@@ -3033,7 +3028,7 @@ function loadEnvFile(path23) {
3033
3028
 
3034
3029
  // ../../providers/anthropic/src/anthropic.agent.provider.ts
3035
3030
  import { execFile as execFile2 } from "child_process";
3036
- import { chmodSync as chmodSync2, existsSync as existsSync4, readFileSync as readFileSync3, readdirSync as readdirSync2, statSync } from "fs";
3031
+ import { chmodSync as chmodSync2, existsSync as existsSync4, readFileSync as readFileSync3, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
3037
3032
  import { createRequire } from "module";
3038
3033
  import { randomUUID } from "crypto";
3039
3034
  import { homedir as homedir3 } from "os";
@@ -3093,7 +3088,7 @@ function ensureSpawnHelperIsExecutable() {
3093
3088
  "spawn-helper"
3094
3089
  );
3095
3090
  if (!existsSync4(helper)) return;
3096
- const mode = statSync(helper).mode;
3091
+ const mode = statSync2(helper).mode;
3097
3092
  if (mode & 73) return;
3098
3093
  chmodSync2(helper, mode | 493);
3099
3094
  } catch {
@@ -7596,7 +7591,7 @@ function leavesOf(ladder) {
7596
7591
  }
7597
7592
 
7598
7593
  // ../../packages/data/src/mcp/tools/cache.ts
7599
- import { statSync as statSync2 } from "fs";
7594
+ import { statSync as statSync3 } from "fs";
7600
7595
  import { resolve as resolve6 } from "path";
7601
7596
  var cache = /* @__PURE__ */ new WeakMap();
7602
7597
  async function cachedEnforcerDiags(ctx, freshPaths) {
@@ -7617,7 +7612,7 @@ function isFresh(snapshot, repoRoot, freshPaths) {
7617
7612
  for (const path23 of freshPaths) {
7618
7613
  let mtimeMs;
7619
7614
  try {
7620
- mtimeMs = statSync2(resolve6(repoRoot, path23)).mtimeMs;
7615
+ mtimeMs = statSync3(resolve6(repoRoot, path23)).mtimeMs;
7621
7616
  } catch {
7622
7617
  return false;
7623
7618
  }
@@ -10287,7 +10282,7 @@ import { createRequire as createRequire2 } from "module";
10287
10282
  var _require = createRequire2(import.meta.url);
10288
10283
  var VERSION2 = _require("../package.json").version ?? "0.0.0";
10289
10284
  var IS_DEV = String(_require("../package.json").name ?? "").endsWith("-dev");
10290
- var SHA = "80c44b6";
10285
+ var SHA = "497a5e2";
10291
10286
  var BUILT = "2026-09-12";
10292
10287
  var BUILD = SHA ?? "source";
10293
10288
  var BUILD_LABEL = `${SHA ? `${VERSION2} (${SHA}${BUILT ? ` ${BUILT}` : ""})` : `${VERSION2} (source)`}${IS_DEV ? " \u2014 development build" : ""}`;
@@ -10806,7 +10801,7 @@ async function fetchRoots(hubUrl, envId, token) {
10806
10801
  }
10807
10802
 
10808
10803
  // src/commands/start.ts
10809
- function register9(program) {
10804
+ function register8(program) {
10810
10805
  program.command("start").description("Start the local agent (authenticates, cleans up stale processes, starts fresh)").option("-w, --workspace <path>", "Workspace root path").option("--api-key <key>", "Anthropic API key (for local-only use)").option("--no-upstream", "Don't connect to cloud (local-only mode)").option("--foreground", "Run in foreground (don't daemonize)").option("--force", "Re-ask all prompts even when config has them").action(async (opts) => {
10811
10806
  if (refuseWithoutInstance()) process.exit(1);
10812
10807
  const config2 = loadConfig();
@@ -10943,7 +10938,7 @@ function buildUpstreamConfig(req) {
10943
10938
  }
10944
10939
 
10945
10940
  // src/commands/stop.ts
10946
- function register10(program) {
10941
+ function register9(program) {
10947
10942
  program.command("stop").description("Stop the running agent").action(() => {
10948
10943
  uninstallClaudeCodeHooks();
10949
10944
  const service = createServiceManager();
@@ -10970,7 +10965,7 @@ function register10(program) {
10970
10965
  }
10971
10966
 
10972
10967
  // src/commands/restart.ts
10973
- function register11(program) {
10968
+ function register10(program) {
10974
10969
  program.command("restart").description("Restart the agent (alias for start \u2014 start always does a clean restart)").action(async () => {
10975
10970
  await program.parseAsync(["node", "jarvis", "start"]);
10976
10971
  });
@@ -10979,7 +10974,7 @@ function register11(program) {
10979
10974
  // src/commands/logs.ts
10980
10975
  import { spawn as spawn2, execSync as execSync6 } from "child_process";
10981
10976
  import fs16 from "fs";
10982
- function register12(program) {
10977
+ function register11(program) {
10983
10978
  program.command("logs").description("View agent logs").option("-f, --follow", "Follow log output (like tail -f)", true).option("-n, --lines <n>", "Number of lines to show", "50").action((opts) => {
10984
10979
  const logFile = getLogFile();
10985
10980
  if (!fs16.existsSync(logFile)) {
@@ -11054,7 +11049,7 @@ function portOf(url) {
11054
11049
  // src/commands/status.ts
11055
11050
  var GREEN2 = (text) => `\x1B[32m${text}\x1B[0m`;
11056
11051
  var RED2 = (text) => `\x1B[31m${text}\x1B[0m`;
11057
- function register13(program) {
11052
+ function register12(program) {
11058
11053
  program.command("status").description("Show agent configuration and connection status").action(async () => {
11059
11054
  const config2 = loadConfig();
11060
11055
  const health = await getHealth();
@@ -11093,7 +11088,7 @@ function endpoint(probed) {
11093
11088
  }
11094
11089
 
11095
11090
  // src/commands/install.ts
11096
- function register14(program) {
11091
+ function register13(program) {
11097
11092
  program.command("install").description("Install as OS service for auto-start on login and crash recovery").option("-w, --workspace <path>", "Workspace root path").option("--no-upstream", "Don't connect to cloud").action(async (opts) => {
11098
11093
  if (refuseWithoutInstance()) process.exit(1);
11099
11094
  const config2 = loadConfig();
@@ -11142,7 +11137,7 @@ function register14(program) {
11142
11137
  import fs17 from "fs";
11143
11138
  import path19 from "path";
11144
11139
  import { createInterface as createInterface5 } from "readline";
11145
- function register15(program) {
11140
+ function register14(program) {
11146
11141
  program.command("uninstall").description("Stop the agent, remove the OS service, and wipe local config + identity").option("--keep-data", "Skip the data-wipe prompt; preserve skills/prompts/cache/settings").option("--purge", "Skip the prompt and wipe ALL local data (skills, prompts, cache, settings)").action(async (opts) => {
11147
11142
  try {
11148
11143
  await runUninstall(opts);
@@ -11204,7 +11199,7 @@ function confirm2(prompt) {
11204
11199
  }
11205
11200
 
11206
11201
  // src/commands/logout.ts
11207
- function register16(program) {
11202
+ function register15(program) {
11208
11203
  program.command("logout").description("Clear saved configuration").action(() => {
11209
11204
  clearConfig();
11210
11205
  console.log("Configuration cleared.");
@@ -11235,7 +11230,7 @@ async function call(path23, method, body) {
11235
11230
  }
11236
11231
  return await resp.json();
11237
11232
  }
11238
- function register17(program) {
11233
+ function register16(program) {
11239
11234
  const mcp = program.command("mcp").description("Connect an agent to this workspace's board");
11240
11235
  mcp.command("token").description("Mint a personal token for the Jarvis MCP server").option("--name <name>", "Which machine this token is for, e.g. 'laptop'").option("--scopes <list>", "read | write | read,write", "read,write").option("--show", "Show the current token's details instead of minting").option("--revoke", "Revoke the current token").action(async (opts) => {
11241
11236
  try {
@@ -11289,7 +11284,7 @@ function register17(program) {
11289
11284
  }
11290
11285
 
11291
11286
  // src/commands/model.ts
11292
- function register18(program) {
11287
+ function register17(program) {
11293
11288
  const model = program.command("model").description("Model access for the map's semantic search, on this machine");
11294
11289
  model.command("key").argument("[key]", "The OpenAI key to store. Omit it to see what is set.").option("--show", "Say whether a key is set, without printing it").option("--clear", "Forget the stored key").description("Set the OpenAI key the map embeds with").action((key, opts) => {
11295
11290
  const config2 = loadConfig();
@@ -11316,7 +11311,7 @@ function register18(program) {
11316
11311
  }
11317
11312
 
11318
11313
  // src/graph/build.ts
11319
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync7, rmSync, statSync as statSync3, writeFileSync as writeFileSync4 } from "fs";
11314
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync7, rmSync, statSync as statSync4, writeFileSync as writeFileSync4 } from "fs";
11320
11315
  import { dirname as dirname6, resolve as resolve8 } from "path";
11321
11316
 
11322
11317
  // src/graph/ratchet.ts
@@ -11541,14 +11536,14 @@ function acquireBuildLock(repoRoot, options = {}) {
11541
11536
  }
11542
11537
  function isStale(lockPath, staleMs) {
11543
11538
  try {
11544
- return Math.max(0, Date.now() - statSync3(lockPath).mtimeMs) >= staleMs;
11539
+ return Math.max(0, Date.now() - statSync4(lockPath).mtimeMs) >= staleMs;
11545
11540
  } catch {
11546
11541
  return true;
11547
11542
  }
11548
11543
  }
11549
11544
 
11550
11545
  // src/commands/build.ts
11551
- function register19(program) {
11546
+ function register18(program) {
11552
11547
  const build2 = program.command("build").description("Build an artifact from this repo");
11553
11548
  build2.command("graph").description("Read the repo's jarvis.config.ts, build the graph, and say what is wrong with it").option("--repo <path>", "The repo to map. Default: the working directory").option("--rebuild", "LAST RESORT: throw the graph away and re-extract from scratch").option("--label", "Re-name the detected communities through the configured labeler").option("--gate", "Fail when a governance class has more findings than this repo carries").action(async (opts) => {
11554
11549
  const argv = [
@@ -11608,7 +11603,7 @@ function isRedirected(req) {
11608
11603
  }
11609
11604
 
11610
11605
  // src/commands/dev.ts
11611
- function register20(program) {
11606
+ function register19(program) {
11612
11607
  const dev = program.command("dev").description("Run a development build in a repo, without replacing the installed jarvis");
11613
11608
  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) => {
11614
11609
  const current = readDevRedirect();
@@ -12325,7 +12320,7 @@ async function brief2(repo) {
12325
12320
  }
12326
12321
 
12327
12322
  // src/commands/serve.ts
12328
- function register21(program) {
12323
+ function register20(program) {
12329
12324
  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) => {
12330
12325
  const repo = resolveRepo(opts.repo);
12331
12326
  const problem = harnessProblem();
@@ -12630,7 +12625,7 @@ function whenRebuilt(dir, reload) {
12630
12625
  }
12631
12626
 
12632
12627
  // src/commands/ui.ts
12633
- function register22(program) {
12628
+ function register21(program) {
12634
12629
  program.command("ui").description("Open this repo's board in a browser \u2014 nothing to configure, nothing to join").option("--repo <path>", "The repo to show. Default: the working directory").option("--port <number>", "The port to listen on. Default: 3402").option("--no-open", "Print the address instead of opening a browser").option("--packaged", "Serve the page this build shipped with, never a checkout's").action(async (opts) => {
12635
12630
  const repo = resolveRepo(opts.repo);
12636
12631
  const port = opts.port ? Number.parseInt(opts.port, 10) : 3402;
@@ -12700,7 +12695,7 @@ async function openWhenUp(port) {
12700
12695
 
12701
12696
  // src/commands/work.ts
12702
12697
  import { spawnSync as spawnSync3 } from "child_process";
12703
- function register23(program) {
12698
+ function register22(program) {
12704
12699
  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) => {
12705
12700
  const problem = harnessProblem();
12706
12701
  if (problem) {
@@ -12723,11 +12718,11 @@ function register23(program) {
12723
12718
  // src/cli.ts
12724
12719
  function createCli() {
12725
12720
  const program = new Command().enablePositionalOptions().name("jarvis").description("Jarvis local agent \u2014 watches Claude Code sessions on your machine").version(BUILD_LABEL);
12726
- register4(program);
12727
12721
  register3(program);
12722
+ register4(program);
12728
12723
  register5(program);
12729
- register6(program);
12730
12724
  register(program);
12725
+ register6(program);
12731
12726
  register7(program);
12732
12727
  register8(program);
12733
12728
  register9(program);
@@ -12742,10 +12737,9 @@ function createCli() {
12742
12737
  register18(program);
12743
12738
  register19(program);
12744
12739
  register20(program);
12745
- register21(program);
12746
12740
  register2(program);
12741
+ register21(program);
12747
12742
  register22(program);
12748
- register23(program);
12749
12743
  return program;
12750
12744
  }
12751
12745