@appchy/jarvis 0.1.57 → 0.1.58

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
@@ -1226,6 +1226,126 @@ function sleep(ms) {
1226
1226
  return new Promise((r) => setTimeout(r, ms));
1227
1227
  }
1228
1228
 
1229
+ // src/graph/graphify.ts
1230
+ import { spawnSync } from "child_process";
1231
+ import { homedir } from "os";
1232
+ import { delimiter, dirname, join } from "path";
1233
+ var BIN = "graphify";
1234
+ var PACKAGE = "graphifyy";
1235
+ var UV = "uv";
1236
+ var UV_INSTALLER = "https://astral.sh/uv/install.sh";
1237
+ var TOOL_DIRS = [
1238
+ join(homedir(), ".local", "bin"),
1239
+ join(homedir(), ".cargo", "bin"),
1240
+ "/opt/homebrew/bin",
1241
+ "/usr/local/bin"
1242
+ ];
1243
+ function runnable(bin, spawn3) {
1244
+ const probe = spawn3(bin, ["--help"], { stdio: "ignore" });
1245
+ return probe.error?.code !== "ENOENT";
1246
+ }
1247
+ function locate(bin, spawn3) {
1248
+ if (runnable(bin, spawn3)) return { command: bin, strayDir: null };
1249
+ for (const dir of TOOL_DIRS) {
1250
+ const candidate = join(dir, bin);
1251
+ if (runnable(candidate, spawn3)) return { command: candidate, strayDir: dir };
1252
+ }
1253
+ return { command: null, strayDir: null };
1254
+ }
1255
+ function reachInto(dir) {
1256
+ process.env.PATH = `${dir}${delimiter}${process.env.PATH ?? ""}`;
1257
+ }
1258
+ function resolveGraphify(options = {}) {
1259
+ const spawn3 = options.spawn ?? spawnSync;
1260
+ const tool = locate(BIN, spawn3);
1261
+ const uv = locate(UV, spawn3);
1262
+ return {
1263
+ onPath: tool.command !== null && tool.strayDir === null,
1264
+ strayPath: tool.strayDir ? join(tool.strayDir, BIN) : null,
1265
+ uv: uv.command
1266
+ };
1267
+ }
1268
+ function installGraphify(req, options = {}) {
1269
+ const spawn3 = options.spawn ?? spawnSync;
1270
+ const install = spawn3(req.uv, ["tool", "install", PACKAGE], { stdio: "inherit" });
1271
+ if (install.status !== 0) {
1272
+ return {
1273
+ installed: false,
1274
+ strayPath: null,
1275
+ problem: `\`${req.uv} tool install ${PACKAGE}\` did not succeed. Run it by hand to see why.`
1276
+ };
1277
+ }
1278
+ const after = locate(BIN, spawn3);
1279
+ return {
1280
+ installed: true,
1281
+ strayPath: after.strayDir ? join(after.strayDir, BIN) : null,
1282
+ problem: null
1283
+ };
1284
+ }
1285
+ function installUv(options = {}) {
1286
+ const spawn3 = options.spawn ?? spawnSync;
1287
+ if (!runnable("curl", spawn3)) {
1288
+ return { uv: null, problem: `curl is needed to fetch ${UV_INSTALLER} and is not installed.` };
1289
+ }
1290
+ const script = join(process.env.TMPDIR ?? "/tmp", `uv-install-${process.pid}.sh`);
1291
+ const fetched = spawn3("curl", ["-LsSf", UV_INSTALLER, "-o", script], { stdio: "inherit" });
1292
+ if (fetched.status !== 0) {
1293
+ return { uv: null, problem: `could not download ${UV_INSTALLER}.` };
1294
+ }
1295
+ const ran = spawn3("sh", [script], { stdio: "inherit" });
1296
+ if (ran.status !== 0) {
1297
+ return { uv: null, problem: `the uv installer did not succeed. See ${UV_INSTALLER}.` };
1298
+ }
1299
+ const after = locate(UV, spawn3);
1300
+ if (after.command === null) {
1301
+ return { uv: null, problem: `uv installed but nothing here can run it. See ${UV_INSTALLER}.` };
1302
+ }
1303
+ if (after.strayDir) reachInto(after.strayDir);
1304
+ return { uv: after.command, problem: null };
1305
+ }
1306
+ function ensureGraphify(options = {}) {
1307
+ const state2 = resolveGraphify(options);
1308
+ if (state2.onPath) return;
1309
+ if (state2.strayPath) {
1310
+ const dir = dirname(state2.strayPath);
1311
+ reachInto(dir);
1312
+ process.stderr.write(
1313
+ `[data] found ${BIN} in ${dir} \u2014 using it for this build.
1314
+ [data] add that directory to your PATH to stop this being a surprise.
1315
+ `
1316
+ );
1317
+ return;
1318
+ }
1319
+ if (!state2.uv) {
1320
+ process.stderr.write(
1321
+ `[data] ${BIN} is needed to read this repo's code and is not installed, and neither is \`uv\`,
1322
+ [data] which installs it. Install uv (https://docs.astral.sh/uv/), then re-run this build \u2014
1323
+ [data] or run \`jarvis init\`, which offers to install both. Building the rest of the map anyway.
1324
+ `
1325
+ );
1326
+ return;
1327
+ }
1328
+ process.stderr.write(
1329
+ `[data] ${BIN} is not installed \u2014 installing it with \`uv tool install ${PACKAGE}\`.
1330
+ `
1331
+ );
1332
+ const installed = installGraphify({ uv: state2.uv }, options);
1333
+ if (!installed.installed) {
1334
+ process.stderr.write(
1335
+ `[data] ${installed.problem}
1336
+ [data] Building the rest of the map anyway.
1337
+ `
1338
+ );
1339
+ return;
1340
+ }
1341
+ if (installed.strayPath) reachInto(dirname(installed.strayPath));
1342
+ process.stderr.write(
1343
+ installed.strayPath ? `[data] ${BIN} installed to ${dirname(installed.strayPath)}, which is not on your PATH. Add it there.
1344
+ ` : `[data] ${BIN} installed.
1345
+ `
1346
+ );
1347
+ }
1348
+
1229
1349
  // src/machine.ts
1230
1350
  import crypto2 from "crypto";
1231
1351
  import fs8 from "fs";
@@ -2088,7 +2208,7 @@ async function runInit(options = {}) {
2088
2208
  try {
2089
2209
  console.log("\n Jarvis setup");
2090
2210
  console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n");
2091
- setUpThisMachine();
2211
+ await setUpThisMachine(prompts);
2092
2212
  if (!url) {
2093
2213
  reportLocalOnly();
2094
2214
  return true;
@@ -2153,10 +2273,11 @@ Error: ${err instanceof Error ? err.message : err}`);
2153
2273
  return false;
2154
2274
  }
2155
2275
  }
2156
- function setUpThisMachine() {
2276
+ async function setUpThisMachine(prompts) {
2157
2277
  console.log(" \u25B8 Wiring this machine's Claude Code to jarvis");
2158
2278
  installHooks();
2159
2279
  console.log();
2280
+ await setUpMapTool(prompts);
2160
2281
  console.log(" \u25B8 The model key the map embeds with");
2161
2282
  const key = loadConfig()?.openaiApiKey;
2162
2283
  console.log(
@@ -2166,6 +2287,59 @@ function setUpThisMachine() {
2166
2287
  `
2167
2288
  );
2168
2289
  }
2290
+ async function setUpMapTool(prompts) {
2291
+ console.log(" \u25B8 The tool the map's code half is built from");
2292
+ const state2 = resolveGraphify();
2293
+ if (state2.onPath) {
2294
+ console.log(" graphify is ready \u2713 this machine can build a map\n");
2295
+ return;
2296
+ }
2297
+ if (state2.strayPath) {
2298
+ console.log(
2299
+ ` graphify is INSTALLED but not on PATH \u2014 it is at
2300
+ ${state2.strayPath}, and your shell cannot see it.
2301
+ 'jarvis build graph' finds it anyway; nothing else will. Fix it for good:
2302
+ uv tool update-shell (then open a new shell)
2303
+ or for this shell only:
2304
+ export PATH="${path10.dirname(state2.strayPath)}:$PATH"
2305
+ `
2306
+ );
2307
+ return;
2308
+ }
2309
+ console.log(
2310
+ state2.uv ? " graphify is not installed, so this machine cannot build a map yet." : " graphify is not installed, and neither is uv, which installs it."
2311
+ );
2312
+ if (!await prompts.confirmGraphifyInstall({ needsUv: state2.uv === null })) {
2313
+ console.log(
2314
+ state2.uv ? " left alone. Install it whenever: uv tool install graphifyy\n" : " left alone. Install uv (https://docs.astral.sh/uv/), then:\n uv tool install graphifyy\n"
2315
+ );
2316
+ return;
2317
+ }
2318
+ let uv = state2.uv;
2319
+ if (!uv) {
2320
+ console.log(" installing uv \u2026");
2321
+ const gotUv = installUv();
2322
+ if (!gotUv.uv) {
2323
+ console.log(` ${gotUv.problem}
2324
+ Install it yourself: https://docs.astral.sh/uv/
2325
+ `);
2326
+ return;
2327
+ }
2328
+ uv = gotUv.uv;
2329
+ }
2330
+ console.log(" installing graphify \u2026");
2331
+ const installed = installGraphify({ uv });
2332
+ if (!installed.installed) {
2333
+ console.log(` ${installed.problem}
2334
+ `);
2335
+ return;
2336
+ }
2337
+ console.log(
2338
+ installed.strayPath ? ` installed \u2713 \u2014 at ${installed.strayPath}, which your shell cannot see.
2339
+ Put it where it can: uv tool update-shell (then open a new shell)
2340
+ ` : " installed \u2713 this machine can build a map\n"
2341
+ );
2342
+ }
2169
2343
  function reportLocalOnly() {
2170
2344
  console.log(" \u2714 Done. This machine works in any repo that has a work/ tree:");
2171
2345
  console.log(" the board, the map, the session block, the rules that arrive on edit,");
@@ -2358,6 +2532,15 @@ function readLocalRoots() {
2358
2532
  }
2359
2533
  function defaultPrompts() {
2360
2534
  return {
2535
+ // With nothing at the other end of stdin the answer is no, never a hang and never a silent
2536
+ // yes: a scripted setup must not block on a question, and must not install software on a
2537
+ // machine where nobody was there to agree to it.
2538
+ async confirmGraphifyInstall(req) {
2539
+ if (!process.stdin.isTTY) return false;
2540
+ const question = req.needsUv ? " Install both now? uv comes from https://astral.sh/uv/install.sh [Y/n] " : " Install it now with uv? [Y/n] ";
2541
+ const answer = (await readlineQuestion2(question)).trim().toLowerCase();
2542
+ return answer === "" || answer === "y" || answer === "yes";
2543
+ },
2361
2544
  async pickRoots(candidates) {
2362
2545
  const savedDefaults = candidates.filter((c) => c.saved).map((c) => c.path);
2363
2546
  const defaults = savedDefaults.length > 0 ? savedDefaults : candidates.filter((c) => c.exists).map((c) => c.path);
@@ -2698,18 +2881,18 @@ function publish(ctx, channel, payload2) {
2698
2881
  }
2699
2882
 
2700
2883
  // src/graph/repo.ts
2701
- import { homedir } from "os";
2702
- import { dirname, resolve } from "path";
2884
+ import { homedir as homedir2 } from "os";
2885
+ import { dirname as dirname2, resolve } from "path";
2703
2886
  import { fileURLToPath } from "url";
2704
2887
  function resolveVendor() {
2705
- process.env["JARVIS_DATA_VENDOR"] ??= resolve(dirname(fileURLToPath(import.meta.url)), "data");
2888
+ process.env["JARVIS_DATA_VENDOR"] ??= resolve(dirname2(fileURLToPath(import.meta.url)), "data");
2706
2889
  return process.env["JARVIS_DATA_VENDOR"];
2707
2890
  }
2708
2891
  function resolveRepo(repo) {
2709
2892
  const cwd = repo ? resolve(process.cwd(), repo) : process.cwd();
2710
2893
  resolveVendor();
2711
2894
  loadEnvFile(resolve(cwd, ".env"));
2712
- loadEnvFile(resolve(homedir(), ".jarvis", "data.env"));
2895
+ loadEnvFile(resolve(homedir2(), ".jarvis", "data.env"));
2713
2896
  return cwd;
2714
2897
  }
2715
2898
  function loadEnvFile(path22) {
@@ -2724,8 +2907,8 @@ import { execFile as execFile2 } from "child_process";
2724
2907
  import { chmodSync, existsSync as existsSync3, readFileSync as readFileSync2, readdirSync as readdirSync2, statSync } from "fs";
2725
2908
  import { createRequire } from "module";
2726
2909
  import { randomUUID } from "crypto";
2727
- import { homedir as homedir2 } from "os";
2728
- import { dirname as dirname2, join } from "path";
2910
+ import { homedir as homedir3 } from "os";
2911
+ import { dirname as dirname3, join as join2 } from "path";
2729
2912
  import { promisify as promisify2 } from "util";
2730
2913
  var run2 = promisify2(execFile2);
2731
2914
  var require2 = createRequire(import.meta.url);
@@ -2773,8 +2956,8 @@ function openTerminal(req) {
2773
2956
  function ensureSpawnHelperIsExecutable() {
2774
2957
  try {
2775
2958
  const entry = require2.resolve("node-pty");
2776
- const helper = join(
2777
- dirname2(entry),
2959
+ const helper = join2(
2960
+ dirname3(entry),
2778
2961
  "..",
2779
2962
  "prebuilds",
2780
2963
  `${process.platform}-${process.arch}`,
@@ -2788,7 +2971,7 @@ function ensureSpawnHelperIsExecutable() {
2788
2971
  }
2789
2972
  }
2790
2973
  async function idOf(term) {
2791
- const entry = join(homedir2(), ".claude", "sessions", `${term.pid}.json`);
2974
+ const entry = join2(homedir3(), ".claude", "sessions", `${term.pid}.json`);
2792
2975
  for (let attempt = 0; attempt < 60; attempt++) {
2793
2976
  if (existsSync3(entry)) {
2794
2977
  try {
@@ -2802,19 +2985,19 @@ async function idOf(term) {
2802
2985
  throw new Error("Claude Code started but never registered a session id");
2803
2986
  }
2804
2987
  function candidatePaths2() {
2805
- const home = homedir2();
2988
+ const home = homedir3();
2806
2989
  return [
2807
- join(home, ".local", "bin", "claude"),
2808
- join(home, ".claude", "local", "claude"),
2990
+ join2(home, ".local", "bin", "claude"),
2991
+ join2(home, ".claude", "local", "claude"),
2809
2992
  "/opt/homebrew/bin/claude",
2810
2993
  "/usr/local/bin/claude",
2811
2994
  ...bundledWithEditor2(home)
2812
2995
  ];
2813
2996
  }
2814
2997
  function bundledWithEditor2(home) {
2815
- const extensions = join(home, ".vscode", "extensions");
2998
+ const extensions = join2(home, ".vscode", "extensions");
2816
2999
  try {
2817
- return readdirSync2(extensions).filter((name) => name.startsWith("anthropic.claude-code-")).sort().reverse().map((name) => join(extensions, name, "resources", "native-binary", "claude"));
3000
+ return readdirSync2(extensions).filter((name) => name.startsWith("anthropic.claude-code-")).sort().reverse().map((name) => join2(extensions, name, "resources", "native-binary", "claude"));
2818
3001
  } catch {
2819
3002
  return [];
2820
3003
  }
@@ -2884,10 +3067,10 @@ function endedAs(exitCode, signal) {
2884
3067
  // ../../providers/anthropic/src/anthropic.session.provider.ts
2885
3068
  import { stat as fsStat } from "fs/promises";
2886
3069
  import { createReadStream, readdirSync as readdirSync3, readFileSync as readFileSync3 } from "fs";
2887
- import { homedir as homedir3 } from "os";
2888
- import { join as join2 } from "path";
3070
+ import { homedir as homedir4 } from "os";
3071
+ import { join as join3 } from "path";
2889
3072
  import readline from "readline";
2890
- var LIVE = join2(homedir3(), ".claude", "sessions");
3073
+ var LIVE = join3(homedir4(), ".claude", "sessions");
2891
3074
  var LIVE_TTL_MS = 1e3;
2892
3075
  var live2 = null;
2893
3076
  function listLiveSessions() {
@@ -2898,7 +3081,7 @@ function listLiveSessions() {
2898
3081
  for (const name of readdirSync3(LIVE)) {
2899
3082
  if (!name.endsWith(".json")) continue;
2900
3083
  try {
2901
- const record = JSON.parse(readFileSync3(join2(LIVE, name), "utf-8"));
3084
+ const record = JSON.parse(readFileSync3(join3(LIVE, name), "utf-8"));
2902
3085
  if (typeof record.sessionId === "string") ids.add(record.sessionId);
2903
3086
  } catch {
2904
3087
  }
@@ -4374,7 +4557,7 @@ async function listHolders(root, id) {
4374
4557
  // ../../packages/board/src/board.tree.ts
4375
4558
  import { execFile as execFile5 } from "child_process";
4376
4559
  import { readdir, readFile, stat } from "fs/promises";
4377
- import { join as join3, relative, sep } from "path";
4560
+ import { join as join4, relative, sep } from "path";
4378
4561
  import { promisify as promisify5 } from "util";
4379
4562
 
4380
4563
  // ../../packages/errors/src/errors.ts
@@ -4544,7 +4727,7 @@ async function getWorkItem(ctx, req, options) {
4544
4727
  }
4545
4728
  async function getBrief(_ctx, req, options) {
4546
4729
  try {
4547
- return await readFile(join3(options.root, "work", req.path), "utf-8");
4730
+ return await readFile(join4(options.root, "work", req.path), "utf-8");
4548
4731
  } catch {
4549
4732
  return null;
4550
4733
  }
@@ -4665,10 +4848,10 @@ function harnessMessage(err) {
4665
4848
  return said || e.message || "the work harness failed";
4666
4849
  }
4667
4850
  async function scanTree(root) {
4668
- const work = join3(root, "work");
4851
+ const work = join4(root, "work");
4669
4852
  const items = [];
4670
4853
  for (const base of ["versions", "backlog"]) {
4671
- for (const file of await walk(join3(work, base))) {
4854
+ for (const file of await walk(join4(work, base))) {
4672
4855
  const text = await readFile(file, "utf-8");
4673
4856
  const changedAt = (await stat(file)).mtime.toISOString().slice(0, 10);
4674
4857
  const path22 = relative(work, file).split(sep).join("/");
@@ -4688,7 +4871,7 @@ async function walk(dir, depth = 0) {
4688
4871
  }
4689
4872
  const found = [];
4690
4873
  for (const entry of entries) {
4691
- const full = join3(dir, entry.name);
4874
+ const full = join4(dir, entry.name);
4692
4875
  if (entry.isDirectory()) found.push(...await walk(full, depth + 1));
4693
4876
  else if (entry.name === ITEM_FILE) found.push(full);
4694
4877
  }
@@ -4804,19 +4987,19 @@ async function createWorkItem2(ctx, req, options) {
4804
4987
  }
4805
4988
 
4806
4989
  // src/harness.ts
4807
- import { spawnSync } from "child_process";
4990
+ import { spawnSync as spawnSync2 } from "child_process";
4808
4991
  import { existsSync as existsSync4 } from "fs";
4809
- import { dirname as dirname3, join as join4 } from "path";
4992
+ import { dirname as dirname4, join as join5 } from "path";
4810
4993
  import { fileURLToPath as fileURLToPath2 } from "url";
4811
- var ENTRY = join4("harness", "work.py");
4994
+ var ENTRY = join5("harness", "work.py");
4812
4995
  var INTERPRETERS = ["python3", "python"];
4813
4996
  var OLDEST = [3, 9];
4814
4997
  var INSTALLED = ["jarvis", "work"];
4815
4998
  function payload() {
4816
- let dir = dirname3(fileURLToPath2(import.meta.url));
4999
+ let dir = dirname4(fileURLToPath2(import.meta.url));
4817
5000
  for (let up = 0; up < 6; up++) {
4818
- if (existsSync4(join4(dir, ENTRY))) return join4(dir, ENTRY);
4819
- const parent = dirname3(dir);
5001
+ if (existsSync4(join5(dir, ENTRY))) return join5(dir, ENTRY);
5002
+ const parent = dirname4(dir);
4820
5003
  if (parent === dir) break;
4821
5004
  dir = parent;
4822
5005
  }
@@ -4824,7 +5007,7 @@ function payload() {
4824
5007
  }
4825
5008
  function interpreter() {
4826
5009
  for (const name of INTERPRETERS) {
4827
- const said = spawnSync(name, ["--version"], { encoding: "utf-8" });
5010
+ const said = spawnSync2(name, ["--version"], { encoding: "utf-8" });
4828
5011
  if (said.status !== 0) continue;
4829
5012
  const version = /(\d+)\.(\d+)/.exec(`${said.stdout}${said.stderr}`);
4830
5013
  if (!version) continue;
@@ -4861,7 +5044,7 @@ function say(repo, args, timeout = PATIENCE) {
4861
5044
  try {
4862
5045
  const [command, ...prefix] = harness2();
4863
5046
  const { WORK_DIR: _inherited, ...ambient } = process.env;
4864
- const ran = spawnSync(command, [...prefix, ...args, "--project", repo], {
5047
+ const ran = spawnSync2(command, [...prefix, ...args, "--project", repo], {
4865
5048
  encoding: "utf-8",
4866
5049
  timeout,
4867
5050
  env: { ...ambient, CLAUDE_PROJECT_DIR: repo, PYTHONDONTWRITEBYTECODE: "1" }
@@ -5334,7 +5517,7 @@ async function runEntries(req) {
5334
5517
  await Promise.all(scopes.map((scope2) => shape(run6, scope2)));
5335
5518
  for (const scope2 of scopes) await mint(run6, scope2);
5336
5519
  for (const scope2 of scopes) link(run6, scope2);
5337
- for (const spec of connects) await join5(run6, spec);
5520
+ for (const spec of connects) await join6(run6, spec);
5338
5521
  for (const diagnostic of silence(scopes)) run6.report(diagnostic);
5339
5522
  return scopes.map((scope2) => scope2.ledger);
5340
5523
  }
@@ -5576,7 +5759,7 @@ function emit(run6, scope2, request) {
5576
5759
  );
5577
5760
  scope2.ledger.edges[request.rel] = (scope2.ledger.edges[request.rel] ?? 0) + 1;
5578
5761
  }
5579
- async function join5(run6, spec) {
5762
+ async function join6(run6, spec) {
5580
5763
  const ctx = finderContext(run6, spec.name);
5581
5764
  const graph2 = {
5582
5765
  nodes: (type) => run6.graph.nodes(type),
@@ -5908,13 +6091,13 @@ function edgeMatchesConfidence(edge, backendName, confidence) {
5908
6091
  // ../../packages/data/src/config.ts
5909
6092
  import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
5910
6093
  import { readFile as readFile4 } from "fs/promises";
5911
- import { dirname as dirname5, resolve as resolve4 } from "path";
6094
+ import { dirname as dirname6, resolve as resolve4 } from "path";
5912
6095
  import { fileURLToPath as fileURLToPath3 } from "url";
5913
6096
  import { createJiti } from "jiti";
5914
6097
 
5915
6098
  // ../../packages/data/src/persistences/local.ts
5916
6099
  import { mkdir, readFile as readFile3, writeFile } from "fs/promises";
5917
- import { dirname as dirname4, join as join6, resolve as resolve3 } from "path";
6100
+ import { dirname as dirname5, join as join7, resolve as resolve3 } from "path";
5918
6101
  function localFiles(options = {}) {
5919
6102
  const root = options.root ?? ".data";
5920
6103
  const rel = {
@@ -5927,7 +6110,7 @@ function localFiles(options = {}) {
5927
6110
  const pathOf = (ctx, key) => resolve3(
5928
6111
  ctx.repoRoot,
5929
6112
  root,
5930
- key.startsWith("plugin:") ? join6("plugins", `${key.slice(7)}.json`) : rel[key]
6113
+ key.startsWith("plugin:") ? join7("plugins", `${key.slice(7)}.json`) : rel[key]
5931
6114
  );
5932
6115
  return persistence({
5933
6116
  name: "local-files",
@@ -5940,7 +6123,7 @@ function localFiles(options = {}) {
5940
6123
  },
5941
6124
  save: async (ctx, key, bytes) => {
5942
6125
  const path22 = pathOf(ctx, key);
5943
- await mkdir(dirname4(path22), { recursive: true });
6126
+ await mkdir(dirname5(path22), { recursive: true });
5944
6127
  await writeFile(path22, bytes, "utf8");
5945
6128
  },
5946
6129
  locate: (ctx, key) => pathOf(ctx, key)
@@ -5970,7 +6153,7 @@ async function loadConfig2(cwd) {
5970
6153
  };
5971
6154
  }
5972
6155
  }
5973
- const parent = dirname5(dir);
6156
+ const parent = dirname6(dir);
5974
6157
  if (parent === dir) break;
5975
6158
  dir = parent;
5976
6159
  }
@@ -5986,10 +6169,10 @@ async function importConfig(path22) {
5986
6169
  }
5987
6170
  var PACKAGE_NAME = "@jarvis/data";
5988
6171
  function packageRoot() {
5989
- let dir = dirname5(fileURLToPath3(import.meta.url));
6172
+ let dir = dirname6(fileURLToPath3(import.meta.url));
5990
6173
  for (; ; ) {
5991
6174
  if (existsSync5(resolve4(dir, "package.json"))) return dir;
5992
- const parent = dirname5(dir);
6175
+ const parent = dirname6(dir);
5993
6176
  if (parent === dir) return dir;
5994
6177
  dir = parent;
5995
6178
  }
@@ -9894,7 +10077,7 @@ import { createRequire as createRequire2 } from "module";
9894
10077
  var _require = createRequire2(import.meta.url);
9895
10078
  var VERSION2 = _require("../package.json").version ?? "0.0.0";
9896
10079
  var IS_DEV = String(_require("../package.json").name ?? "").endsWith("-dev");
9897
- var SHA = "5de8b68";
10080
+ var SHA = "7f725ef";
9898
10081
  var BUILT = "2026-09-09";
9899
10082
  var BUILD = SHA ?? "source";
9900
10083
  var BUILD_LABEL = `${SHA ? `${VERSION2} (${SHA}${BUILT ? ` ${BUILT}` : ""})` : `${VERSION2} (source)`}${IS_DEV ? " \u2014 development build" : ""}`;
@@ -10924,60 +11107,7 @@ function register17(program) {
10924
11107
 
10925
11108
  // src/graph/build.ts
10926
11109
  import { mkdirSync as mkdirSync2, readFileSync as readFileSync6, rmSync, statSync as statSync3, writeFileSync as writeFileSync3 } from "fs";
10927
- import { dirname as dirname6, resolve as resolve8 } from "path";
10928
-
10929
- // src/graph/graphify.ts
10930
- import { spawnSync as spawnSync2 } from "child_process";
10931
- import { homedir as homedir4 } from "os";
10932
- import { delimiter, join as join7 } from "path";
10933
- var BIN = "graphify";
10934
- var PACKAGE = "graphifyy";
10935
- var UV_BIN_DIR = join7(homedir4(), ".local", "bin");
10936
- function runnable(bin) {
10937
- const probe = spawnSync2(bin, ["--help"], { stdio: "ignore" });
10938
- return probe.error?.code !== "ENOENT";
10939
- }
10940
- function ensureGraphify() {
10941
- if (runnable(BIN)) return;
10942
- const installed = join7(UV_BIN_DIR, BIN);
10943
- if (runnable(installed)) {
10944
- process.env.PATH = `${UV_BIN_DIR}${delimiter}${process.env.PATH ?? ""}`;
10945
- process.stderr.write(
10946
- `[data] found ${BIN} in ${UV_BIN_DIR} \u2014 using it for this build.
10947
- [data] add that directory to your PATH to stop this being a surprise.
10948
- `
10949
- );
10950
- return;
10951
- }
10952
- if (!runnable("uv")) {
10953
- process.stderr.write(
10954
- `[data] ${BIN} is needed to read this repo's code and is not installed, and neither is \`uv\`,
10955
- [data] which installs it. Install uv (https://docs.astral.sh/uv/), then re-run this build \u2014
10956
- [data] or run \`uv tool install ${PACKAGE}\` yourself. Building the rest of the map anyway.
10957
- `
10958
- );
10959
- return;
10960
- }
10961
- process.stderr.write(
10962
- `[data] ${BIN} is not installed \u2014 installing it with \`uv tool install ${PACKAGE}\`.
10963
- `
10964
- );
10965
- const install = spawnSync2("uv", ["tool", "install", PACKAGE], { stdio: "inherit" });
10966
- if (install.status !== 0) {
10967
- process.stderr.write(
10968
- `[data] that install did not succeed. Run \`uv tool install ${PACKAGE}\` by hand to see why.
10969
- [data] Building the rest of the map anyway.
10970
- `
10971
- );
10972
- return;
10973
- }
10974
- if (!runnable(BIN)) process.env.PATH = `${UV_BIN_DIR}${delimiter}${process.env.PATH ?? ""}`;
10975
- process.stderr.write(
10976
- runnable(BIN) ? `[data] ${BIN} installed.
10977
- ` : `[data] ${BIN} installed to ${UV_BIN_DIR}, which is not on your PATH. Add it there.
10978
- `
10979
- );
10980
- }
11110
+ import { dirname as dirname7, resolve as resolve8 } from "path";
10981
11111
 
10982
11112
  // src/graph/ratchet.ts
10983
11113
  import { execFileSync as execFileSync3 } from "child_process";
@@ -11152,7 +11282,7 @@ var DEFAULT_STALE_MS = 10 * 60 * 1e3;
11152
11282
  function acquireBuildLock(repoRoot, options = {}) {
11153
11283
  const staleMs = options.staleMs ?? DEFAULT_STALE_MS;
11154
11284
  const lockPath = options.lockPath ?? resolve8(repoRoot, ".data", "build.lock");
11155
- mkdirSync2(dirname6(lockPath), { recursive: true });
11285
+ mkdirSync2(dirname7(lockPath), { recursive: true });
11156
11286
  const stamp = () => writeFileSync3(lockPath, `${process.pid}
11157
11287
  `, { flag: "wx" });
11158
11288
  try {
@@ -11983,7 +12113,7 @@ import { basename as basename3 } from "path";
11983
12113
  // src/ui/server.ts
11984
12114
  import { createServer as createServer2 } from "http";
11985
12115
  import { readFile as readFile7 } from "fs/promises";
11986
- import { basename as basename2, dirname as dirname7, extname, join as join9, resolve as resolve9 } from "path";
12116
+ import { basename as basename2, dirname as dirname8, extname, join as join9, resolve as resolve9 } from "path";
11987
12117
  import { fileURLToPath as fileURLToPath4 } from "url";
11988
12118
 
11989
12119
  // src/ui/machine.ts
@@ -12010,7 +12140,7 @@ async function readMachine(req) {
12010
12140
  }
12011
12141
 
12012
12142
  // src/ui/server.ts
12013
- var ASSETS = resolve9(dirname7(fileURLToPath4(import.meta.url)), "ui");
12143
+ var ASSETS = resolve9(dirname8(fileURLToPath4(import.meta.url)), "ui");
12014
12144
  var TYPES = {
12015
12145
  ".html": "text/html; charset=utf-8",
12016
12146
  ".js": "text/javascript; charset=utf-8",