githolon 0.51.0 → 0.53.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/cli.mjs +573 -172
  2. package/package.json +3 -3
package/dist/cli.mjs CHANGED
@@ -1195,6 +1195,179 @@ var init_cloud = __esm({
1195
1195
  }
1196
1196
  });
1197
1197
 
1198
+ // src/editor.ts
1199
+ var editor_exports = {};
1200
+ __export(editor_exports, {
1201
+ INIT_EDITOR_HINT: () => INIT_EDITOR_HINT,
1202
+ NOMOS_LAW_EXTENSION_ID: () => NOMOS_LAW_EXTENSION_ID,
1203
+ hasEditorRecommendation: () => hasEditorRecommendation,
1204
+ initEditor: () => initEditor,
1205
+ writeEditorRecommendation: () => writeEditorRecommendation
1206
+ });
1207
+ import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "node:fs";
1208
+ import { dirname, join as join3 } from "node:path";
1209
+ function hasEditorRecommendation(cwd) {
1210
+ const p = join3(cwd, ".vscode", "extensions.json");
1211
+ if (!existsSync3(p)) return false;
1212
+ try {
1213
+ const json = JSON.parse(readFileSync4(p, "utf8"));
1214
+ return Array.isArray(json.recommendations) && json.recommendations.includes(NOMOS_LAW_EXTENSION_ID);
1215
+ } catch {
1216
+ return true;
1217
+ }
1218
+ }
1219
+ function writeEditorRecommendation(cwd) {
1220
+ const dir = join3(cwd, ".vscode");
1221
+ const path = join3(dir, "extensions.json");
1222
+ let json = {};
1223
+ let existed = false;
1224
+ if (existsSync3(path)) {
1225
+ existed = true;
1226
+ try {
1227
+ const parsed = JSON.parse(readFileSync4(path, "utf8"));
1228
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
1229
+ json = parsed;
1230
+ } else {
1231
+ throw new Error("extensions.json is not a JSON object");
1232
+ }
1233
+ } catch (e) {
1234
+ throw new Error(
1235
+ `${path} exists but could not be parsed as JSON (${e.message}) \u2014 fix or remove it, then rerun`
1236
+ );
1237
+ }
1238
+ }
1239
+ const recs = Array.isArray(json.recommendations) ? [...json.recommendations] : [];
1240
+ if (recs.includes(NOMOS_LAW_EXTENSION_ID)) {
1241
+ return { path, action: "unchanged" };
1242
+ }
1243
+ recs.push(NOMOS_LAW_EXTENSION_ID);
1244
+ json.recommendations = recs;
1245
+ mkdirSync3(dirname(path), { recursive: true });
1246
+ writeFileSync4(path, JSON.stringify(json, null, 2) + "\n", "utf8");
1247
+ return { path, action: existed ? "updated" : "created" };
1248
+ }
1249
+ function initEditor(cwd = process.cwd()) {
1250
+ let res;
1251
+ try {
1252
+ res = writeEditorRecommendation(cwd);
1253
+ } catch (e) {
1254
+ process.stderr.write(`error: ${e.message}
1255
+ `);
1256
+ return 1;
1257
+ }
1258
+ if (res.action === "unchanged") {
1259
+ process.stdout.write(`${res.path} already recommends the Nomos Law extension \u2014 nothing to do
1260
+ `);
1261
+ } else {
1262
+ process.stdout.write(
1263
+ `${res.action} ${res.path} \u2014 VS Code will now suggest the Nomos Law extension when this project is opened
1264
+ (install it from the marketplace, or search "Nomos Law"; it surfaces \`githolon check\` as you type)
1265
+ `
1266
+ );
1267
+ }
1268
+ return 0;
1269
+ }
1270
+ var NOMOS_LAW_EXTENSION_ID, INIT_EDITOR_HINT;
1271
+ var init_editor = __esm({
1272
+ "src/editor.ts"() {
1273
+ "use strict";
1274
+ NOMOS_LAW_EXTENSION_ID = "captain-app.nomos-law";
1275
+ INIT_EDITOR_HINT = "tip: the Nomos Law VS Code extension gives you these checks as you type \u2014 npx githolon init-editor";
1276
+ }
1277
+ });
1278
+
1279
+ // src/compile.ts
1280
+ import { spawn, spawnSync } from "node:child_process";
1281
+ import { createRequire } from "node:module";
1282
+ import { dirname as dirname2, join as join4 } from "node:path";
1283
+ import { pathToFileURL } from "node:url";
1284
+ function resolveCompileLauncher(cwd) {
1285
+ const resolveDslPkg = (fromDir) => {
1286
+ try {
1287
+ const req = fromDir === void 0 ? createRequire(import.meta.url) : createRequire(pathToFileURL(join4(fromDir, "noop.js")));
1288
+ return req.resolve("@githolon/dsl/package.json");
1289
+ } catch {
1290
+ return void 0;
1291
+ }
1292
+ };
1293
+ const dslPkg = resolveDslPkg(cwd) ?? resolveDslPkg(void 0);
1294
+ return dslPkg === void 0 ? void 0 : join4(dirname2(dslPkg), "compile_package.mjs");
1295
+ }
1296
+ function runCompile(args) {
1297
+ const launcher = resolveCompileLauncher(process.cwd());
1298
+ if (launcher === void 0) {
1299
+ process.stderr.write(`error: ${NO_DSL_REMEDY}
1300
+ `);
1301
+ return 1;
1302
+ }
1303
+ const r = spawnSync(process.execPath, [launcher, ...args], { stdio: "inherit", cwd: process.cwd() });
1304
+ const status2 = r.status ?? 1;
1305
+ if (status2 === 0 && process.stdout.isTTY) {
1306
+ try {
1307
+ if (!hasEditorRecommendation(process.cwd())) process.stdout.write(`
1308
+ ${INIT_EDITOR_HINT}
1309
+ `);
1310
+ } catch {
1311
+ }
1312
+ }
1313
+ return status2;
1314
+ }
1315
+ function resolveCheckLauncher(cwd) {
1316
+ const launcher = resolveCompileLauncher(cwd);
1317
+ return launcher === void 0 ? void 0 : join4(dirname2(launcher), "check_package.mjs");
1318
+ }
1319
+ function runCheck(args) {
1320
+ const launcher = resolveCheckLauncher(process.cwd());
1321
+ if (launcher === void 0) {
1322
+ process.stderr.write(`error: ${NO_DSL_REMEDY}
1323
+ `);
1324
+ return 1;
1325
+ }
1326
+ const r = spawnSync(process.execPath, [launcher, ...args], { stdio: "inherit", cwd: process.cwd() });
1327
+ return r.status ?? 1;
1328
+ }
1329
+ function resolveLspLauncher(cwd) {
1330
+ const launcher = resolveCompileLauncher(cwd);
1331
+ return launcher === void 0 ? void 0 : join4(dirname2(launcher), "lsp_server.mjs");
1332
+ }
1333
+ function runLsp(args) {
1334
+ const launcher = resolveLspLauncher(process.cwd());
1335
+ if (launcher === void 0) {
1336
+ process.stderr.write(`error: ${NO_DSL_REMEDY}
1337
+ `);
1338
+ return 1;
1339
+ }
1340
+ const r = spawnSync(process.execPath, [launcher, ...args], { stdio: "inherit", cwd: process.cwd() });
1341
+ return r.status ?? 1;
1342
+ }
1343
+ function compileAsync(cwd, args = []) {
1344
+ const launcher = resolveCompileLauncher(cwd);
1345
+ const t0 = performance.now();
1346
+ if (launcher === void 0) {
1347
+ return Promise.resolve({ ok: false, ms: 0, output: NO_DSL_REMEDY });
1348
+ }
1349
+ return new Promise((resolveRun) => {
1350
+ const chunks = [];
1351
+ const dec4 = new TextDecoder();
1352
+ const child = spawn(process.execPath, [launcher, ...args], { cwd, stdio: ["ignore", "pipe", "pipe"] });
1353
+ child.stdout?.on("data", (c) => chunks.push(dec4.decode(c)));
1354
+ child.stderr?.on("data", (c) => chunks.push(dec4.decode(c)));
1355
+ child.on("error", (e) => resolveRun({ ok: false, ms: performance.now() - t0, output: String(e) }));
1356
+ child.on(
1357
+ "close",
1358
+ (code) => resolveRun({ ok: code === 0, ms: performance.now() - t0, output: chunks.join("") })
1359
+ );
1360
+ });
1361
+ }
1362
+ var NO_DSL_REMEDY;
1363
+ var init_compile = __esm({
1364
+ "src/compile.ts"() {
1365
+ "use strict";
1366
+ init_editor();
1367
+ NO_DSL_REMEDY = "@githolon/dsl not found \u2014 add it to your project's dependencies";
1368
+ }
1369
+ });
1370
+
1198
1371
  // vendor/engine/git-fs.mjs
1199
1372
  function fsErr(code, p) {
1200
1373
  const e = new Error(`${code}: ${p}`);
@@ -1210,7 +1383,7 @@ function makeGitFs(preopen, mount, { File: File3, Directory: Directory3 }) {
1210
1383
  const rel = p.slice(mount.length + 1).replace(/\/+$/, "");
1211
1384
  return rel === "" ? [] : rel.split("/");
1212
1385
  }
1213
- function resolve4(ps) {
1386
+ function resolve5(ps) {
1214
1387
  let cur = root;
1215
1388
  for (const part of ps) {
1216
1389
  if (!isDir(cur)) return null;
@@ -1220,11 +1393,11 @@ function makeGitFs(preopen, mount, { File: File3, Directory: Directory3 }) {
1220
1393
  }
1221
1394
  return cur;
1222
1395
  }
1223
- const parent = (ps) => resolve4(ps.slice(0, -1));
1396
+ const parent = (ps) => resolve5(ps.slice(0, -1));
1224
1397
  const leaf = (ps) => ps[ps.length - 1];
1225
1398
  const promises = {
1226
1399
  async readFile(p, opts) {
1227
- const n = resolve4(parts(p));
1400
+ const n = resolve5(parts(p));
1228
1401
  if (n === null) throw fsErr("ENOENT", p);
1229
1402
  if (isDir(n)) throw fsErr("EISDIR", p);
1230
1403
  const data = n.data ?? new Uint8Array(0);
@@ -1243,7 +1416,7 @@ function makeGitFs(preopen, mount, { File: File3, Directory: Directory3 }) {
1243
1416
  if (!isDir(par) || !par.contents.delete(leaf(ps))) throw fsErr("ENOENT", p);
1244
1417
  },
1245
1418
  async readdir(p) {
1246
- const n = resolve4(parts(p));
1419
+ const n = resolve5(parts(p));
1247
1420
  if (n === null) throw fsErr("ENOENT", p);
1248
1421
  if (!isDir(n)) throw fsErr("ENOTDIR", p);
1249
1422
  return [...n.contents.keys()];
@@ -1263,7 +1436,7 @@ function makeGitFs(preopen, mount, { File: File3, Directory: Directory3 }) {
1263
1436
  return promises.lstat(p);
1264
1437
  },
1265
1438
  async lstat(p) {
1266
- const n = resolve4(parts(p));
1439
+ const n = resolve5(parts(p));
1267
1440
  if (n === null) throw fsErr("ENOENT", p);
1268
1441
  const dir = isDir(n);
1269
1442
  return {
@@ -1776,59 +1949,59 @@ var init_engine = __esm({
1776
1949
 
1777
1950
  // src/local_holon.ts
1778
1951
  import { randomBytes } from "node:crypto";
1779
- import { existsSync as existsSync3, mkdirSync as mkdirSync3, readdirSync as readdirSync2, readFileSync as readFileSync4, statSync, writeFileSync as writeFileSync4 } from "node:fs";
1780
- import { dirname as dirname2, join as join4 } from "node:path";
1952
+ import { existsSync as existsSync4, mkdirSync as mkdirSync4, readdirSync as readdirSync2, readFileSync as readFileSync5, statSync, writeFileSync as writeFileSync5 } from "node:fs";
1953
+ import { dirname as dirname3, join as join5 } from "node:path";
1781
1954
  import { File as File2, Directory as Directory2 } from "@bjorn3/browser_wasi_shim";
1782
1955
  async function fetchJsonCached(url, cacheFile) {
1783
1956
  try {
1784
1957
  const r = await fetch(url);
1785
1958
  if (!r.ok) throw new Error(`${url} \u2192 ${r.status}`);
1786
1959
  const text = await r.text();
1787
- mkdirSync3(dirname2(cacheFile), { recursive: true });
1788
- writeFileSync4(cacheFile, text, "utf8");
1960
+ mkdirSync4(dirname3(cacheFile), { recursive: true });
1961
+ writeFileSync5(cacheFile, text, "utf8");
1789
1962
  return JSON.parse(text);
1790
1963
  } catch (e) {
1791
- if (existsSync3(cacheFile)) return JSON.parse(readFileSync4(cacheFile, "utf8"));
1964
+ if (existsSync4(cacheFile)) return JSON.parse(readFileSync5(cacheFile, "utf8"));
1792
1965
  throw e;
1793
1966
  }
1794
1967
  }
1795
1968
  async function fetchRuntime(cloud) {
1796
- const cache = join4(configDir(), "runtime");
1969
+ const cache = join5(configDir(), "runtime");
1797
1970
  let wasmBytes;
1798
- const wasmCache = join4(cache, "holon.wasm");
1971
+ const wasmCache = join5(cache, "holon.wasm");
1799
1972
  const localWasm = process.env["NOMOS_LOCAL_WASM"];
1800
1973
  if (localWasm) {
1801
- const bytes = readFileSync4(localWasm);
1802
- const packages2 = await fetchJsonCached(`${cloud}/v1/runtime/packages`, join4(cache, "packages.json"));
1974
+ const bytes = readFileSync5(localWasm);
1975
+ const packages2 = await fetchJsonCached(`${cloud}/v1/runtime/packages`, join5(cache, "packages.json"));
1803
1976
  return { wasmBytes: bytes, packages: packages2 };
1804
1977
  }
1805
1978
  try {
1806
1979
  const r = await fetch(`${cloud}/v1/runtime/holon.wasm`);
1807
1980
  if (!r.ok) throw new Error(`runtime wasm \u2192 ${r.status}`);
1808
1981
  wasmBytes = new Uint8Array(await r.arrayBuffer());
1809
- mkdirSync3(cache, { recursive: true });
1810
- writeFileSync4(wasmCache, wasmBytes);
1982
+ mkdirSync4(cache, { recursive: true });
1983
+ writeFileSync5(wasmCache, wasmBytes);
1811
1984
  } catch (e) {
1812
- if (!existsSync3(wasmCache)) throw e;
1813
- wasmBytes = readFileSync4(wasmCache);
1985
+ if (!existsSync4(wasmCache)) throw e;
1986
+ wasmBytes = readFileSync5(wasmCache);
1814
1987
  }
1815
- const packages = await fetchJsonCached(`${cloud}/v1/runtime/packages`, join4(cache, "packages.json"));
1988
+ const packages = await fetchJsonCached(`${cloud}/v1/runtime/packages`, join5(cache, "packages.json"));
1816
1989
  return { wasmBytes, packages };
1817
1990
  }
1818
1991
  function writeTreeToDisk(dir, diskPath) {
1819
- mkdirSync3(diskPath, { recursive: true });
1992
+ mkdirSync4(diskPath, { recursive: true });
1820
1993
  for (const [name, inode] of dir.contents) {
1821
- const p = join4(diskPath, name);
1994
+ const p = join5(diskPath, name);
1822
1995
  if (inode.contents instanceof Map) writeTreeToDisk(inode, p);
1823
- else writeFileSync4(p, inode.data ?? new Uint8Array(0));
1996
+ else writeFileSync5(p, inode.data ?? new Uint8Array(0));
1824
1997
  }
1825
1998
  }
1826
1999
  function readTreeFromDisk(diskPath) {
1827
2000
  const contents = /* @__PURE__ */ new Map();
1828
2001
  for (const name of readdirSync2(diskPath)) {
1829
- const p = join4(diskPath, name);
2002
+ const p = join5(diskPath, name);
1830
2003
  if (statSync(p).isDirectory()) contents.set(name, readTreeFromDisk(p));
1831
- else contents.set(name, new File2(readFileSync4(p)));
2004
+ else contents.set(name, new File2(readFileSync5(p)));
1832
2005
  }
1833
2006
  return new Directory2(contents);
1834
2007
  }
@@ -1886,8 +2059,8 @@ __export(proof_offline_exports, {
1886
2059
  runOfflineProofStandalone: () => runOfflineProofStandalone,
1887
2060
  runRelationBootstrapLeg: () => runRelationBootstrapLeg
1888
2061
  });
1889
- import { existsSync as existsSync5, readFileSync as readFileSync5 } from "node:fs";
1890
- import { basename, dirname as dirname3, join as join6 } from "node:path";
2062
+ import { existsSync as existsSync6, readFileSync as readFileSync6 } from "node:fs";
2063
+ import { basename, dirname as dirname4, join as join7 } from "node:path";
1891
2064
  function parseOfflineLegs(proofSource) {
1892
2065
  if (!proofSource.includes("AUTO-GENERATED by nomos-compile")) {
1893
2066
  throw new Error("not a generated proof (missing the AUTO-GENERATED header) \u2014 run `githolon compile` to (re)generate build/<name>.proof.mts");
@@ -2252,16 +2425,16 @@ function actorFromPayload(payload, field) {
2252
2425
  return typeof value === "string" && value.trim().length > 0 ? value : void 0;
2253
2426
  }
2254
2427
  async function runOfflineProofStandalone(proofPath, cloud, domain) {
2255
- const src = readFileSync5(proofPath, "utf8");
2428
+ const src = readFileSync6(proofPath, "utf8");
2256
2429
  const packageName = basename(proofPath).replace(/\.proof\.mts$/, "");
2257
- const deployFile = join6(dirname3(proofPath), `${packageName}.deploy.json`);
2258
- if (!existsSync5(deployFile)) {
2430
+ const deployFile = join7(dirname4(proofPath), `${packageName}.deploy.json`);
2431
+ if (!existsSync6(deployFile)) {
2259
2432
  throw new Error(`missing ${deployFile} \u2014 run \`githolon compile\` (the proof and the deploy body are built together)`);
2260
2433
  }
2261
2434
  let legs;
2262
- const legsFile = join6(dirname3(proofPath), `${packageName}.proof-legs.json`);
2263
- if (existsSync5(legsFile)) {
2264
- const index = JSON.parse(readFileSync5(legsFile, "utf8"));
2435
+ const legsFile = join7(dirname4(proofPath), `${packageName}.proof-legs.json`);
2436
+ if (existsSync6(legsFile)) {
2437
+ const index = JSON.parse(readFileSync6(legsFile, "utf8"));
2265
2438
  const keys = Object.keys(index.domains);
2266
2439
  const chosen = domain ?? index.default;
2267
2440
  if (index.domains[chosen] === void 0) {
@@ -2279,7 +2452,7 @@ async function runOfflineProofStandalone(proofPath, cloud, domain) {
2279
2452
  if (domain !== void 0) throw new Error(`--domain needs a per-domain legs index (build/${packageName}.proof-legs.json) \u2014 recompile with \`githolon compile\` to emit it`);
2280
2453
  legs = parseOfflineLegs(src);
2281
2454
  }
2282
- const deployBody = JSON.parse(readFileSync5(deployFile, "utf8"));
2455
+ const deployBody = JSON.parse(readFileSync6(deployFile, "utf8"));
2283
2456
  const lawHash = await sha256hex(deployBody.packageUsda);
2284
2457
  console.log(`githolon proof \u2014 OFFLINE legs on a local holon (the cloud loop: githolon proof --live)`);
2285
2458
  const { eng } = await holonEngine(cloud, deployBody, "githolon-proof");
@@ -2306,27 +2479,295 @@ var init_proof_offline = __esm({
2306
2479
  }
2307
2480
  });
2308
2481
 
2482
+ // src/mcp.ts
2483
+ var mcp_exports = {};
2484
+ __export(mcp_exports, {
2485
+ callTool: () => callTool,
2486
+ extractDispositions: () => extractDispositions,
2487
+ handleRequest: () => handleRequest,
2488
+ runMcpServer: () => runMcpServer,
2489
+ summarize: () => summarize,
2490
+ toolCheck: () => toolCheck,
2491
+ toolEvolvePreview: () => toolEvolvePreview
2492
+ });
2493
+ import { spawnSync as spawnSync4 } from "node:child_process";
2494
+ import { existsSync as existsSync10 } from "node:fs";
2495
+ import { dirname as dirname6, isAbsolute, resolve as resolve2 } from "node:path";
2496
+ function resolveConfig(config) {
2497
+ const arg = config ?? "nomos.package.mjs";
2498
+ const configPath = isAbsolute(arg) ? arg : resolve2(process.cwd(), arg);
2499
+ return { configPath, cfgDir: dirname6(configPath) };
2500
+ }
2501
+ function runCheckLauncher(configPath, extraArgs) {
2502
+ const cfgDir = dirname6(configPath);
2503
+ const launcher = resolveCheckLauncher(cfgDir) ?? resolveCheckLauncher(process.cwd());
2504
+ if (launcher === void 0) {
2505
+ return { findings: [], stdout: "", stderr: "", status: 1, error: NO_DSL_REMEDY };
2506
+ }
2507
+ const r = spawnSync4(process.execPath, [launcher, configPath, ...extraArgs], {
2508
+ cwd: cfgDir,
2509
+ encoding: "utf8"
2510
+ });
2511
+ return {
2512
+ findings: [],
2513
+ stdout: r.stdout ?? "",
2514
+ stderr: r.stderr ?? "",
2515
+ status: r.status ?? 1
2516
+ };
2517
+ }
2518
+ function runCheckJson(configPath, extraArgs) {
2519
+ const base = runCheckLauncher(configPath, [...extraArgs, "--json"]);
2520
+ if (base.error !== void 0) return base;
2521
+ const line = base.stdout.trim().split("\n").filter(Boolean).pop() ?? "";
2522
+ let findings;
2523
+ try {
2524
+ const parsed = JSON.parse(line);
2525
+ if (!Array.isArray(parsed)) throw new Error("not an array");
2526
+ findings = parsed;
2527
+ } catch (e) {
2528
+ return {
2529
+ ...base,
2530
+ error: `could not parse check --json output: ${e.message}
2531
+ ${base.stdout}${base.stderr}`
2532
+ };
2533
+ }
2534
+ return { ...base, findings };
2535
+ }
2536
+ function summarize(findings) {
2537
+ const n = { refuse: 0, warn: 0, note: 0 };
2538
+ for (const f of findings) n[f.level]++;
2539
+ if (findings.length === 0) return "githolon check: all clear \u2014 no static twin flagged anything.";
2540
+ const head = `githolon check: ${findings.length} finding(s) \u2014 ${n.refuse} refuse, ${n.warn} warn, ${n.note} note.`;
2541
+ const lines = findings.map((f) => {
2542
+ const where = f.file !== void 0 ? ` (${f.file}:${f.line ?? 1})` : "";
2543
+ const who = f.directiveId !== void 0 ? `${f.domain}/${f.directiveId}` : f.domain;
2544
+ return ` ${f.level.toUpperCase()} ${who}${where}: ${f.what} \u2014 fix: ${f.fix}`;
2545
+ });
2546
+ return [head, ...lines].join("\n");
2547
+ }
2548
+ function extractDispositions(humanReport) {
2549
+ const marker = "add `dispositions` to the domain's deploy JSON:";
2550
+ const at = humanReport.indexOf(marker);
2551
+ if (at < 0) return void 0;
2552
+ const rest = humanReport.slice(at + marker.length);
2553
+ const start = rest.indexOf("{");
2554
+ if (start < 0) return void 0;
2555
+ let depth = 0;
2556
+ for (let i = start; i < rest.length; i++) {
2557
+ if (rest[i] === "{") depth++;
2558
+ else if (rest[i] === "}") {
2559
+ depth--;
2560
+ if (depth === 0) {
2561
+ try {
2562
+ return JSON.parse(rest.slice(start, i + 1));
2563
+ } catch {
2564
+ return void 0;
2565
+ }
2566
+ }
2567
+ }
2568
+ }
2569
+ return void 0;
2570
+ }
2571
+ function toolCheck(args) {
2572
+ const { configPath } = resolveConfig(args.config);
2573
+ if (!existsSync10(configPath)) {
2574
+ return { text: `nomos_check: config not found: ${configPath}`, isError: true };
2575
+ }
2576
+ const extra = args.against !== void 0 ? ["--against", args.against] : [];
2577
+ const run = runCheckJson(configPath, extra);
2578
+ if (run.error !== void 0) {
2579
+ return { text: `nomos_check: ${run.error}${run.stderr ? `
2580
+ ${run.stderr}` : ""}`, isError: true };
2581
+ }
2582
+ const summary = summarize(run.findings);
2583
+ const payload = { summary, findings: run.findings };
2584
+ return { text: `${summary}
2585
+
2586
+ ${JSON.stringify(payload, null, 2)}`, isError: false };
2587
+ }
2588
+ function toolEvolvePreview(args) {
2589
+ const { configPath } = resolveConfig(args.config);
2590
+ if (!existsSync10(configPath)) {
2591
+ return { text: `nomos_evolve_preview: config not found: ${configPath}`, isError: true };
2592
+ }
2593
+ const againstPath = isAbsolute(args.against) ? args.against : resolve2(dirname6(configPath), args.against);
2594
+ const priorArg = existsSync10(againstPath) ? againstPath : args.against;
2595
+ const jsonRun = runCheckJson(configPath, ["--against", priorArg]);
2596
+ if (jsonRun.error !== void 0) {
2597
+ return {
2598
+ text: `nomos_evolve_preview: ${jsonRun.error}${jsonRun.stderr ? `
2599
+ ${jsonRun.stderr}` : ""}`,
2600
+ isError: true
2601
+ };
2602
+ }
2603
+ const humanRun = runCheckLauncher(configPath, ["--against", priorArg]);
2604
+ const dispositions = extractDispositions(humanRun.stdout);
2605
+ const summary = summarize(jsonRun.findings);
2606
+ const dispLine = dispositions !== void 0 ? "A DESTRUCTIVE evolve was detected. Add this `dispositions` block to the domain's deploy JSON before deploying:" : "No destructive evolve \u2014 the diff admits without dispositions.";
2607
+ const payload = { summary, findings: jsonRun.findings, dispositions: dispositions ?? null };
2608
+ return {
2609
+ text: `${summary}
2610
+
2611
+ ${dispLine}
2612
+
2613
+ ${JSON.stringify(payload, null, 2)}`,
2614
+ isError: false
2615
+ };
2616
+ }
2617
+ function callTool(name, argsIn) {
2618
+ const a = argsIn ?? {};
2619
+ const config = typeof a.config === "string" ? a.config : void 0;
2620
+ if (name === "nomos_check") {
2621
+ return toolCheck({
2622
+ ...config !== void 0 ? { config } : {},
2623
+ ...typeof a.against === "string" ? { against: a.against } : {}
2624
+ });
2625
+ }
2626
+ if (name === "nomos_evolve_preview") {
2627
+ if (typeof a.against !== "string" || a.against.length === 0) {
2628
+ return { text: "nomos_evolve_preview: `against` is required (a prior deploy.json / lockfile).", isError: true };
2629
+ }
2630
+ return toolEvolvePreview({ against: a.against, ...config !== void 0 ? { config } : {} });
2631
+ }
2632
+ return { text: `unknown tool: ${name}`, isError: true };
2633
+ }
2634
+ function handleRequest(req) {
2635
+ const reply = (result) => ({ jsonrpc: "2.0", id: req.id ?? null, result });
2636
+ const fail = (code, message) => ({
2637
+ jsonrpc: "2.0",
2638
+ id: req.id ?? null,
2639
+ error: { code, message }
2640
+ });
2641
+ switch (req.method) {
2642
+ case "initialize": {
2643
+ const clientVersion = req.params?.protocolVersion;
2644
+ return reply({
2645
+ protocolVersion: clientVersion ?? PROTOCOL_VERSION,
2646
+ capabilities: { tools: {} },
2647
+ serverInfo: { name: SERVER_NAME, version: SERVER_VERSION }
2648
+ });
2649
+ }
2650
+ case "notifications/initialized":
2651
+ case "initialized":
2652
+ return void 0;
2653
+ // notification — no response
2654
+ case "ping":
2655
+ return reply({});
2656
+ case "tools/list":
2657
+ return reply({ tools: TOOLS });
2658
+ case "tools/call": {
2659
+ const p = req.params ?? {};
2660
+ if (typeof p.name !== "string") return fail(-32602, "tools/call requires a string `name`");
2661
+ const res = callTool(p.name, p.arguments);
2662
+ return reply({ content: [{ type: "text", text: res.text }], isError: res.isError });
2663
+ }
2664
+ default:
2665
+ if (req.id === void 0 || req.id === null) return void 0;
2666
+ return fail(-32601, `method not found: ${req.method}`);
2667
+ }
2668
+ }
2669
+ function runMcpServer() {
2670
+ return new Promise((resolveRun) => {
2671
+ let buf = "";
2672
+ const write = (obj) => {
2673
+ process.stdout.write(JSON.stringify(obj) + "\n");
2674
+ };
2675
+ process.stdin.setEncoding("utf8");
2676
+ process.stdin.on("data", (chunk) => {
2677
+ buf += chunk;
2678
+ let nl;
2679
+ while ((nl = buf.indexOf("\n")) >= 0) {
2680
+ const line = buf.slice(0, nl).trim();
2681
+ buf = buf.slice(nl + 1);
2682
+ if (line.length === 0) continue;
2683
+ let req;
2684
+ try {
2685
+ req = JSON.parse(line);
2686
+ } catch {
2687
+ write({ jsonrpc: "2.0", id: null, error: { code: -32700, message: "parse error" } });
2688
+ continue;
2689
+ }
2690
+ try {
2691
+ const res = handleRequest(req);
2692
+ if (res !== void 0) write(res);
2693
+ } catch (e) {
2694
+ write({ jsonrpc: "2.0", id: req.id ?? null, error: { code: -32603, message: e.message } });
2695
+ }
2696
+ }
2697
+ });
2698
+ process.stdin.on("end", () => resolveRun(0));
2699
+ process.stdin.on("close", () => resolveRun(0));
2700
+ });
2701
+ }
2702
+ var SERVER_NAME, SERVER_VERSION, PROTOCOL_VERSION, TOOLS;
2703
+ var init_mcp = __esm({
2704
+ "src/mcp.ts"() {
2705
+ "use strict";
2706
+ init_compile();
2707
+ SERVER_NAME = "nomos";
2708
+ SERVER_VERSION = "0.1.0";
2709
+ PROTOCOL_VERSION = "2024-11-05";
2710
+ TOOLS = [
2711
+ {
2712
+ name: "nomos_check",
2713
+ description: "Run the Nomos author-time gate (githolon check static twins) over a nomos.package.mjs and return the findings (refuse/warn/note) plus a human summary. Optionally diff against a prior deployed law for evolve-safety. Call before compiling or deploying domain law.",
2714
+ inputSchema: {
2715
+ type: "object",
2716
+ properties: {
2717
+ config: {
2718
+ type: "string",
2719
+ description: "Path to nomos.package.mjs (default: ./nomos.package.mjs, relative to the server working dir)."
2720
+ },
2721
+ against: {
2722
+ type: "string",
2723
+ description: "Optional prior law to diff evolve-safety against: a build/<name>.deploy.json, a build/ dir, or a nomos.stable-ids.json lockfile."
2724
+ }
2725
+ }
2726
+ }
2727
+ },
2728
+ {
2729
+ name: "nomos_evolve_preview",
2730
+ description: "Preview a Nomos LAW EVOLUTION: diff the current build against a prior deployed law and return the evolve findings plus the pasteable `dispositions` block a destructive change (removal/retype) requires. Call before deploying a change to already-deployed law.",
2731
+ inputSchema: {
2732
+ type: "object",
2733
+ properties: {
2734
+ against: {
2735
+ type: "string",
2736
+ description: "REQUIRED prior law: a build/<name>.deploy.json, a build/ dir, or a nomos.stable-ids.json lockfile."
2737
+ },
2738
+ config: {
2739
+ type: "string",
2740
+ description: "Path to nomos.package.mjs (default: ./nomos.package.mjs)."
2741
+ }
2742
+ },
2743
+ required: ["against"]
2744
+ }
2745
+ }
2746
+ ];
2747
+ }
2748
+ });
2749
+
2309
2750
  // src/harness.ts
2310
2751
  var harness_exports = {};
2311
2752
  __export(harness_exports, {
2312
2753
  harnessInstall: () => harnessInstall
2313
2754
  });
2314
- import { existsSync as existsSync9, readFileSync as readFileSync11, writeFileSync as writeFileSync6 } from "node:fs";
2315
- import { join as join10 } from "node:path";
2755
+ import { existsSync as existsSync11, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "node:fs";
2756
+ import { join as join12 } from "node:path";
2316
2757
  import { randomBytes as randomBytes3 } from "node:crypto";
2317
2758
  async function harnessInstall(opts) {
2318
2759
  const { deploy: deployPaths, workspace, out: outPath } = opts;
2319
2760
  if (deployPaths.length === 0) die("no --deploy JSON path(s) given");
2320
- const runtimeDir = opts.runtime || process.env["NOMOS_OFFLINE_RUNTIME"] || join10(configDir(), "runtime");
2321
- const wasmFile = join10(runtimeDir, "holon.wasm");
2322
- const pkgsFile = join10(runtimeDir, "packages.json");
2323
- if (!existsSync9(wasmFile) || !existsSync9(pkgsFile)) {
2761
+ const runtimeDir = opts.runtime || process.env["NOMOS_OFFLINE_RUNTIME"] || join12(configDir(), "runtime");
2762
+ const wasmFile = join12(runtimeDir, "holon.wasm");
2763
+ const pkgsFile = join12(runtimeDir, "packages.json");
2764
+ if (!existsSync11(wasmFile) || !existsSync11(pkgsFile)) {
2324
2765
  die(
2325
2766
  `runtime cache missing at ${runtimeDir} (holon.wasm + packages.json). Warm it once with a \`githolon\` run (it fetches + caches the runtime), then re-run offline.`
2326
2767
  );
2327
2768
  }
2328
- const wasm = readFileSync11(wasmFile);
2329
- const pkgs = JSON.parse(readFileSync11(pkgsFile, "utf8"));
2769
+ const wasm = readFileSync12(wasmFile);
2770
+ const pkgs = JSON.parse(readFileSync12(pkgsFile, "utf8"));
2330
2771
  const replica = BigInt(`0x${randomBytes3(8).toString("hex")}`) & (1n << 63n) - 1n;
2331
2772
  const eng = await createEngine({
2332
2773
  wasmModule: await WebAssembly.compile(wasm),
@@ -2339,8 +2780,8 @@ async function harnessInstall(opts) {
2339
2780
  author(eng, workspace, "bootstrap", "installDomain", installPayload(eng.hashes.nomos, eng.nomosPkg, "nomos-test-harness"), "");
2340
2781
  const lawHashes = [];
2341
2782
  for (const p of deployPaths) {
2342
- if (!existsSync9(p)) die(`deploy JSON not found: ${p} \u2014 run \`npx githolon compile\` first`);
2343
- const deploy2 = JSON.parse(readFileSync11(p, "utf8"));
2783
+ if (!existsSync11(p)) die(`deploy JSON not found: ${p} \u2014 run \`npx githolon compile\` first`);
2784
+ const deploy2 = JSON.parse(readFileSync12(p, "utf8"));
2344
2785
  const usda = deploy2.packageUsda;
2345
2786
  if (typeof usda !== "string" || !usda.startsWith("#usda")) die(`${p} has no #usda packageUsda`);
2346
2787
  const lawHash = await sha256hex(usda);
@@ -2352,7 +2793,7 @@ async function harnessInstall(opts) {
2352
2793
  const wsNode = eng.preopen.dir.contents.get("ws").contents.get(workspace);
2353
2794
  if (!wsNode) die(`internal: workspace tree '${workspace}' not found after install`);
2354
2795
  const treeBytes = serializeTree(wsNode);
2355
- writeFileSync6(outPath, treeBytes);
2796
+ writeFileSync7(outPath, treeBytes);
2356
2797
  process.stderr.write(`harness-install: snapshot written (${treeBytes.length} bytes) \u2192 ${outPath}
2357
2798
  `);
2358
2799
  process.stdout.write(JSON.stringify({ ok: true, snapshot: outPath, workspace, lawHashes }) + "\n");
@@ -3430,8 +3871,8 @@ var scene_exports = {};
3430
3871
  __export(scene_exports, {
3431
3872
  scene: () => scene
3432
3873
  });
3433
- import { existsSync as existsSync10, mkdirSync as mkdirSync4, writeFileSync as writeFileSync7 } from "node:fs";
3434
- import { join as join11, resolve as resolve2 } from "node:path";
3874
+ import { existsSync as existsSync12, mkdirSync as mkdirSync5, writeFileSync as writeFileSync8 } from "node:fs";
3875
+ import { join as join13, resolve as resolve3 } from "node:path";
3435
3876
  import { createHash as createHash5 } from "node:crypto";
3436
3877
  import git3 from "isomorphic-git";
3437
3878
  async function walkChain2(eng, ws) {
@@ -3452,8 +3893,8 @@ async function projectOnce(cloud, target, isDir, name) {
3452
3893
  const { eng } = await holonEngine(cloud, void 0, "githolon-scene");
3453
3894
  const SOURCE3 = "source";
3454
3895
  if (isDir) {
3455
- const gitDir = existsSync10(join11(target, ".git")) ? join11(target, ".git") : target;
3456
- if (!existsSync10(join11(gitDir, "HEAD"))) throw new Error(`${target} is not a git repo (no HEAD)`);
3896
+ const gitDir = existsSync12(join13(target, ".git")) ? join13(target, ".git") : target;
3897
+ if (!existsSync12(join13(gitDir, "HEAD"))) throw new Error(`${target} is not a git repo (no HEAD)`);
3457
3898
  await mountFresh(eng, SOURCE3);
3458
3899
  eng.preopen.dir.contents.get("ws").contents.get(SOURCE3).contents.set("nomos.git", readTreeFromDisk(gitDir));
3459
3900
  } else {
@@ -3512,9 +3953,9 @@ async function projectOnce(cloud, target, isDir, name) {
3512
3953
  }
3513
3954
  async function scene(target, opts) {
3514
3955
  const cloud = cloudBase(opts.cloud);
3515
- const isDir = existsSync10(target) || target.includes("/") || target.startsWith(".");
3516
- const name = isDir ? (resolve2(target).split("/").filter(Boolean).pop() ?? "scene").replace(/\.git$/, "") : target;
3517
- out11(`scene \u2014 ${name} (${isDir ? resolve2(target) : `${cloud} :: ${target}`})`);
3956
+ const isDir = existsSync12(target) || target.includes("/") || target.startsWith(".");
3957
+ const name = isDir ? (resolve3(target).split("/").filter(Boolean).pop() ?? "scene").replace(/\.git$/, "") : target;
3958
+ out11(`scene \u2014 ${name} (${isDir ? resolve3(target) : `${cloud} :: ${target}`})`);
3518
3959
  let first, second;
3519
3960
  try {
3520
3961
  first = await projectOnce(cloud, target, isDir, name);
@@ -3532,13 +3973,13 @@ async function scene(target, opts) {
3532
3973
  err11(`the emitted stage violates the portable profile: ${violations.join("; ")}`);
3533
3974
  return 1;
3534
3975
  }
3535
- const outDir = resolve2(opts.out ?? join11("scene", name));
3536
- mkdirSync4(outDir, { recursive: true });
3537
- const usdaPath = join11(outDir, `${name}.usda`);
3538
- const usdzPath = join11(outDir, `${name}.usdz`);
3976
+ const outDir = resolve3(opts.out ?? join13("scene", name));
3977
+ mkdirSync5(outDir, { recursive: true });
3978
+ const usdaPath = join13(outDir, `${name}.usda`);
3979
+ const usdzPath = join13(outDir, `${name}.usdz`);
3539
3980
  const usdaBytes = new TextEncoder().encode(first.usda);
3540
- writeFileSync7(usdaPath, usdaBytes);
3541
- writeFileSync7(usdzPath, usdzPack([[`${name}.usda`, usdaBytes]]));
3981
+ writeFileSync8(usdaPath, usdaBytes);
3982
+ writeFileSync8(usdzPath, usdzPack([[`${name}.usda`, usdaBytes]]));
3542
3983
  const s = first.stats;
3543
3984
  out11(` verify_chain ${s.verdictLine}`);
3544
3985
  out11(` law canopy ${s.nodes} node(s), ${s.edges} edge(s) \u2014 from the chain's own installed packages`);
@@ -3564,10 +4005,10 @@ var init_scene = __esm({
3564
4005
  });
3565
4006
 
3566
4007
  // src/cli.ts
3567
- import { existsSync as existsSync11, readdirSync as readdirSync4, readFileSync as readFileSync12 } from "node:fs";
3568
- import { spawnSync as spawnSync4 } from "node:child_process";
4008
+ import { existsSync as existsSync13, readdirSync as readdirSync4, readFileSync as readFileSync13 } from "node:fs";
4009
+ import { spawnSync as spawnSync5 } from "node:child_process";
3569
4010
  import { createRequire as createRequire2 } from "node:module";
3570
- import { dirname as dirname5, join as join12, resolve as resolve3 } from "node:path";
4011
+ import { dirname as dirname7, join as join14, resolve as resolve4 } from "node:path";
3571
4012
  import { pathToFileURL as pathToFileURL4 } from "node:url";
3572
4013
 
3573
4014
  // src/generate.ts
@@ -3750,86 +4191,26 @@ Re-run with --force to replace it.`
3750
4191
 
3751
4192
  // src/cli.ts
3752
4193
  init_cloud();
3753
-
3754
- // src/compile.ts
3755
- import { spawn, spawnSync } from "node:child_process";
3756
- import { createRequire } from "node:module";
3757
- import { dirname, join as join3 } from "node:path";
3758
- import { pathToFileURL } from "node:url";
3759
- function resolveCompileLauncher(cwd) {
3760
- const resolveDslPkg = (fromDir) => {
3761
- try {
3762
- const req = fromDir === void 0 ? createRequire(import.meta.url) : createRequire(pathToFileURL(join3(fromDir, "noop.js")));
3763
- return req.resolve("@githolon/dsl/package.json");
3764
- } catch {
3765
- return void 0;
3766
- }
3767
- };
3768
- const dslPkg = resolveDslPkg(cwd) ?? resolveDslPkg(void 0);
3769
- return dslPkg === void 0 ? void 0 : join3(dirname(dslPkg), "compile_package.mjs");
3770
- }
3771
- var NO_DSL_REMEDY = "@githolon/dsl not found \u2014 add it to your project's dependencies";
3772
- function runCompile(args) {
3773
- const launcher = resolveCompileLauncher(process.cwd());
3774
- if (launcher === void 0) {
3775
- process.stderr.write(`error: ${NO_DSL_REMEDY}
3776
- `);
3777
- return 1;
3778
- }
3779
- const r = spawnSync(process.execPath, [launcher, ...args], { stdio: "inherit", cwd: process.cwd() });
3780
- return r.status ?? 1;
3781
- }
3782
- function resolveCheckLauncher(cwd) {
3783
- const launcher = resolveCompileLauncher(cwd);
3784
- return launcher === void 0 ? void 0 : join3(dirname(launcher), "check_package.mjs");
3785
- }
3786
- function runCheck(args) {
3787
- const launcher = resolveCheckLauncher(process.cwd());
3788
- if (launcher === void 0) {
3789
- process.stderr.write(`error: ${NO_DSL_REMEDY}
3790
- `);
3791
- return 1;
3792
- }
3793
- const r = spawnSync(process.execPath, [launcher, ...args], { stdio: "inherit", cwd: process.cwd() });
3794
- return r.status ?? 1;
3795
- }
3796
- function compileAsync(cwd, args = []) {
3797
- const launcher = resolveCompileLauncher(cwd);
3798
- const t0 = performance.now();
3799
- if (launcher === void 0) {
3800
- return Promise.resolve({ ok: false, ms: 0, output: NO_DSL_REMEDY });
3801
- }
3802
- return new Promise((resolveRun) => {
3803
- const chunks = [];
3804
- const dec4 = new TextDecoder();
3805
- const child = spawn(process.execPath, [launcher, ...args], { cwd, stdio: ["ignore", "pipe", "pipe"] });
3806
- child.stdout?.on("data", (c) => chunks.push(dec4.decode(c)));
3807
- child.stderr?.on("data", (c) => chunks.push(dec4.decode(c)));
3808
- child.on("error", (e) => resolveRun({ ok: false, ms: performance.now() - t0, output: String(e) }));
3809
- child.on(
3810
- "close",
3811
- (code) => resolveRun({ ok: code === 0, ms: performance.now() - t0, output: chunks.join("") })
3812
- );
3813
- });
3814
- }
4194
+ init_compile();
3815
4195
 
3816
4196
  // src/dev.ts
3817
4197
  init_engine();
3818
4198
  init_cloud();
3819
- import { existsSync as existsSync6, readFileSync as readFileSync6, watch } from "node:fs";
4199
+ init_compile();
4200
+ init_local_holon();
4201
+ import { existsSync as existsSync7, readFileSync as readFileSync7, watch } from "node:fs";
3820
4202
  import { createServer } from "node:http";
3821
- import { dirname as dirname4, join as join7, resolve } from "node:path";
4203
+ import { dirname as dirname5, join as join8, resolve } from "node:path";
3822
4204
  import { pathToFileURL as pathToFileURL3 } from "node:url";
3823
- init_local_holon();
3824
4205
 
3825
4206
  // src/project.ts
3826
- import { existsSync as existsSync4, statSync as statSync2 } from "node:fs";
3827
- import { join as join5 } from "node:path";
4207
+ import { existsSync as existsSync5, statSync as statSync2 } from "node:fs";
4208
+ import { join as join6 } from "node:path";
3828
4209
  import { pathToFileURL as pathToFileURL2 } from "node:url";
3829
4210
  var CONFIG_FILE = "nomos.package.mjs";
3830
4211
  async function loadProject(cwd, opts = {}) {
3831
- const configPath = join5(cwd, CONFIG_FILE);
3832
- if (!existsSync4(configPath)) return void 0;
4212
+ const configPath = join6(cwd, CONFIG_FILE);
4213
+ if (!existsSync5(configPath)) return void 0;
3833
4214
  const href = pathToFileURL2(configPath).href + (opts.bust === true ? `?v=${statSync2(configPath).mtimeMs}-${Date.now()}` : "");
3834
4215
  const mod = await import(href);
3835
4216
  const cfg = mod.default;
@@ -3994,11 +4375,11 @@ function startServer(s) {
3994
4375
  });
3995
4376
  }
3996
4377
  function readDeployBody2(cwd, packageName) {
3997
- const file = join7(cwd, "build", `${packageName}.deploy.json`);
3998
- if (!existsSync6(file)) {
4378
+ const file = join8(cwd, "build", `${packageName}.deploy.json`);
4379
+ if (!existsSync7(file)) {
3999
4380
  throw new Error(`compile produced no ${file} \u2014 check the compile output above`);
4000
4381
  }
4001
- return JSON.parse(readFileSync6(file, "utf8"));
4382
+ return JSON.parse(readFileSync7(file, "utf8"));
4002
4383
  }
4003
4384
  async function installLaw(s, deployBody, installedBy) {
4004
4385
  const newHash = await sha256hex(deployBody.packageUsda);
@@ -4014,11 +4395,11 @@ async function installLaw(s, deployBody, installedBy) {
4014
4395
  return { ok: true };
4015
4396
  }
4016
4397
  async function runProofCycle(s, cwd, deployBody, installedBy) {
4017
- const proofPath = join7(cwd, "build", `${s.packageName}.proof.mts`);
4018
- if (!existsSync6(proofPath)) return void 0;
4398
+ const proofPath = join8(cwd, "build", `${s.packageName}.proof.mts`);
4399
+ if (!existsSync7(proofPath)) return void 0;
4019
4400
  const scratch = `proof-${s.cycle}`;
4020
4401
  try {
4021
- const legs = parseOfflineLegs(readFileSync6(proofPath, "utf8"));
4402
+ const legs = parseOfflineLegs(readFileSync7(proofPath, "utf8"));
4022
4403
  await mountFresh(s.eng, scratch);
4023
4404
  author(s.eng, scratch, "bootstrap", "installDomain", installPayload(s.eng.hashes.nomos, s.eng.nomosPkg, installedBy), "");
4024
4405
  author(s.eng, scratch, "nomos", "installDomain", installPayload(s.lawHash, deployBody.packageUsda, installedBy), s.eng.hashes.nomos);
@@ -4037,7 +4418,7 @@ async function dev(opts) {
4037
4418
  return void 0;
4038
4419
  });
4039
4420
  if (project === void 0) {
4040
- if (!existsSync6(join7(cwd, CONFIG_FILE))) {
4421
+ if (!existsSync7(join8(cwd, CONFIG_FILE))) {
4041
4422
  err5(`no ${CONFIG_FILE} here (${cwd}) \u2014 \`githolon dev\` runs inside a project; scaffold one from examples/guestbook or \`githolon generate domain <name>\``);
4042
4423
  }
4043
4424
  return 1;
@@ -4104,12 +4485,12 @@ ${firstCompile.output}`);
4104
4485
  try {
4105
4486
  const cfgModule = await import(pathToFileURL3(project.configPath).href);
4106
4487
  for (const d of cfgModule.default?.domains ?? []) {
4107
- for (const m of d.modules ?? []) moduleDirs.add(dirname4(resolve(cwd, m)));
4488
+ for (const m of d.modules ?? []) moduleDirs.add(dirname5(resolve(cwd, m)));
4108
4489
  }
4109
4490
  } catch {
4110
- moduleDirs.add(join7(cwd, "domains"));
4491
+ moduleDirs.add(join8(cwd, "domains"));
4111
4492
  }
4112
- if (moduleDirs.size === 0) moduleDirs.add(join7(cwd, "domains"));
4493
+ if (moduleDirs.size === 0) moduleDirs.add(join8(cwd, "domains"));
4113
4494
  let timer;
4114
4495
  let cycling = false;
4115
4496
  let queued = false;
@@ -4159,7 +4540,7 @@ ${run.output}`);
4159
4540
  };
4160
4541
  const watchers = [];
4161
4542
  for (const d of moduleDirs) {
4162
- if (!existsSync6(d)) continue;
4543
+ if (!existsSync7(d)) continue;
4163
4544
  watchers.push(watch(d, { recursive: true }, (_evt, f) => onChange(f)));
4164
4545
  s.watchRoots.push(d.startsWith(cwd) ? d.slice(cwd.length + 1) + "/" : d);
4165
4546
  }
@@ -4186,7 +4567,7 @@ ${run.output}`);
4186
4567
  init_cloud();
4187
4568
  import { spawnSync as spawnSync2 } from "node:child_process";
4188
4569
  import { randomBytes as randomBytes2 } from "node:crypto";
4189
- import { readFileSync as readFileSync7 } from "node:fs";
4570
+ import { readFileSync as readFileSync8 } from "node:fs";
4190
4571
  var out6 = (s) => void process.stdout.write(s + "\n");
4191
4572
  var err6 = (s) => void process.stderr.write("error: " + s + "\n");
4192
4573
  function git(args, opts = {}) {
@@ -4215,7 +4596,7 @@ function workspaceFromPath(path) {
4215
4596
  }
4216
4597
  async function gitCredential(action) {
4217
4598
  if (action !== "get") return 0;
4218
- const kv = parseCredentialInput(readFileSync7(0, "utf8"));
4599
+ const kv = parseCredentialInput(readFileSync8(0, "utf8"));
4219
4600
  const ws = workspaceFromPath(kv["path"]);
4220
4601
  if (kv["protocol"] !== "https" || ws === void 0) return 0;
4221
4602
  const cloud = `https://${kv["host"]}`;
@@ -4503,14 +4884,14 @@ init_engine();
4503
4884
  init_cloud();
4504
4885
  init_local_holon();
4505
4886
  import { spawnSync as spawnSync3 } from "node:child_process";
4506
- import { existsSync as existsSync7, readdirSync as readdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "node:fs";
4507
- import { join as join8 } from "node:path";
4887
+ import { existsSync as existsSync8, readdirSync as readdirSync3, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
4888
+ import { join as join9 } from "node:path";
4508
4889
  var out7 = (s) => void process.stdout.write(s + "\n");
4509
4890
  var err7 = (s) => void process.stderr.write("error: " + s + "\n");
4510
4891
  var WS2 = "local";
4511
4892
  async function ledgerInit(dir, opts) {
4512
4893
  const cloud = cloudBase(opts.cloud);
4513
- if (existsSync7(dir) && readdirSync3(dir).length > 0) {
4894
+ if (existsSync8(dir) && readdirSync3(dir).length > 0) {
4514
4895
  err7(`refusing to mint into non-empty directory: ${dir}`);
4515
4896
  return 1;
4516
4897
  }
@@ -4521,7 +4902,7 @@ async function ledgerInit(dir, opts) {
4521
4902
  err7(e.message);
4522
4903
  return 1;
4523
4904
  }
4524
- const deployBody = JSON.parse(readFileSync8(deployFile, "utf8"));
4905
+ const deployBody = JSON.parse(readFileSync9(deployFile, "utf8"));
4525
4906
  const domainHash = await sha256hex(deployBody.packageUsda);
4526
4907
  const c = loadCreds();
4527
4908
  const principal = await sessionToken().catch(() => void 0) !== void 0 ? c.session.uid : c.principal;
@@ -4537,10 +4918,10 @@ async function ledgerInit(dir, opts) {
4537
4918
  const verdict = verifyChainLocal(eng, WS2);
4538
4919
  if (!printVerdict(verdict)) return 1;
4539
4920
  const gitTree = eng.preopen.dir.contents.get("ws").contents.get(WS2).contents.get("nomos.git");
4540
- const gitDir = join8(dir, ".git");
4921
+ const gitDir = join9(dir, ".git");
4541
4922
  writeTreeToDisk(gitTree, gitDir);
4542
- const cfgPath = join8(gitDir, "config");
4543
- writeFileSync5(cfgPath, readFileSync8(cfgPath, "utf8").replace(/bare = true/, "bare = false"), "utf8");
4923
+ const cfgPath = join9(gitDir, "config");
4924
+ writeFileSync6(cfgPath, readFileSync9(cfgPath, "utf8").replace(/bare = true/, "bare = false"), "utf8");
4544
4925
  spawnSync3("git", ["-C", dir, "reset", "--hard", "main"], { stdio: "ignore" });
4545
4926
  out7(`\u2713 holon written \u2192 ${dir} (a normal git repo; git log IS the audit trail)`);
4546
4927
  out7(`
@@ -4549,8 +4930,8 @@ Birth it on Nomos Cloud (the cloud re-derives this exact verdict):`);
4549
4930
  return 0;
4550
4931
  }
4551
4932
  async function ledgerVerify(dir, opts) {
4552
- const gitDir = existsSync7(join8(dir, ".git")) ? join8(dir, ".git") : dir;
4553
- if (!existsSync7(join8(gitDir, "HEAD"))) {
4933
+ const gitDir = existsSync8(join9(dir, ".git")) ? join9(dir, ".git") : dir;
4934
+ if (!existsSync8(join9(gitDir, "HEAD"))) {
4554
4935
  err7(`${dir} is not a git repo (no HEAD)`);
4555
4936
  return 1;
4556
4937
  }
@@ -4566,8 +4947,8 @@ init_engine();
4566
4947
  init_engine();
4567
4948
  init_cloud();
4568
4949
  init_local_holon();
4569
- import { existsSync as existsSync8 } from "node:fs";
4570
- import { join as join9 } from "node:path";
4950
+ import { existsSync as existsSync9 } from "node:fs";
4951
+ import { join as join10 } from "node:path";
4571
4952
  import git2 from "isomorphic-git";
4572
4953
  var out8 = (s) => void process.stdout.write(s + "\n");
4573
4954
  var err8 = (s) => void process.stderr.write("error: " + s + "\n");
@@ -4663,10 +5044,10 @@ async function replay(target, opts) {
4663
5044
  the runtime rides ${cloud}/v1/runtime/* (cached in ~/.holon/runtime after one fetch)`);
4664
5045
  return 1;
4665
5046
  }
4666
- const isDir = existsSync8(target) || target.includes("/") || target.startsWith(".");
5047
+ const isDir = existsSync9(target) || target.includes("/") || target.startsWith(".");
4667
5048
  if (isDir) {
4668
- const gitDir = existsSync8(join9(target, ".git")) ? join9(target, ".git") : target;
4669
- if (!existsSync8(join9(gitDir, "HEAD"))) {
5049
+ const gitDir = existsSync9(join10(target, ".git")) ? join10(target, ".git") : target;
5050
+ if (!existsSync9(join10(gitDir, "HEAD"))) {
4670
5051
  err8(`${target} is not a git repo (no HEAD) \u2014 pass a holon directory (githolon ledger init <dir>) or a workspace name`);
4671
5052
  return 1;
4672
5053
  }
@@ -4830,7 +5211,7 @@ async function decrypt(ws, opts) {
4830
5211
  init_engine();
4831
5212
  init_cloud();
4832
5213
  init_lifecycle();
4833
- import { readFileSync as readFileSync10 } from "node:fs";
5214
+ import { readFileSync as readFileSync11 } from "node:fs";
4834
5215
  var out10 = (s) => void process.stdout.write(s + "\n");
4835
5216
  var err10 = (s) => void process.stderr.write("error: " + s + "\n");
4836
5217
  function lawDiffVerdict(localHash, installed, ws, hasCurrencyData) {
@@ -4885,7 +5266,7 @@ async function status(wsArg, opts) {
4885
5266
  }
4886
5267
  let localHash;
4887
5268
  try {
4888
- const body = JSON.parse(readFileSync10(discoverDeployJson(process.cwd(), opts.file), "utf8"));
5269
+ const body = JSON.parse(readFileSync11(discoverDeployJson(process.cwd(), opts.file), "utf8"));
4889
5270
  if (typeof body.packageUsda === "string") localHash = await sha256hex(body.packageUsda);
4890
5271
  } catch {
4891
5272
  localHash = void 0;
@@ -4948,10 +5329,19 @@ The inner loop:
4948
5329
  --query <id> [--param k=v] keys from the chain, read private fields in cleartext
4949
5330
 
4950
5331
  Authoring:
4951
- githolon check [config] run the author-time gate (static twins) on
5332
+ githolon check [config] [--json] [--against <p>] run the author-time gate (static twins) on
4952
5333
  ./nomos.package.mjs \u2014 the unified report; exits
4953
- non-zero on any REFUSE (compile runs it implicitly)
5334
+ non-zero on any REFUSE (compile runs it implicitly).
5335
+ --json emits the findings (with file:line) as an array
5336
+ githolon lsp the author-time gate as a stdio Language Server:
5337
+ red squiggles while you write law (VS Code/Neovim/\u2026)
5338
+ githolon mcp the author-time gate as a stdio MCP server for AI
5339
+ agents (Codex/Claude): tools nomos_check +
5340
+ nomos_evolve_preview. Setup: codex mcp add nomos -- githolon mcp
4954
5341
  githolon compile [compiler args] compile the package by ./nomos.package.mjs
5342
+ githolon init-editor write .vscode/extensions.json recommending the
5343
+ Nomos Law extension \u2014 the check gate as red
5344
+ squiggles while you type (idempotent)
4955
5345
  githolon proof [build/<name>.proof.mts] run the proof GENERATED from your law, live
4956
5346
  (every compile emits it; ALL GREEN or it names the jam)
4957
5347
  githolon harness-install --deploy <deploy.json[,...]> offline install for the headless TEST HARNESS:
@@ -5136,11 +5526,11 @@ async function runProof(args) {
5136
5526
  const explicit = args.find((a, i) => !a.startsWith("--") && i !== domainValueIdx);
5137
5527
  let proofPath;
5138
5528
  if (explicit !== void 0) {
5139
- proofPath = resolve3(process.cwd(), explicit);
5140
- if (!existsSync11(proofPath)) return refuse(`proof not found: ${proofPath} \u2014 run \`githolon compile\` to (re)generate it`);
5529
+ proofPath = resolve4(process.cwd(), explicit);
5530
+ if (!existsSync13(proofPath)) return refuse(`proof not found: ${proofPath} \u2014 run \`githolon compile\` to (re)generate it`);
5141
5531
  } else {
5142
- const buildDir = join12(process.cwd(), "build");
5143
- if (!existsSync11(buildDir)) {
5532
+ const buildDir = join14(process.cwd(), "build");
5533
+ if (!existsSync13(buildDir)) {
5144
5534
  return refuse("no build/ directory here \u2014 run `githolon compile` first (every compile generates build/<name>.proof.mts from your law)");
5145
5535
  }
5146
5536
  const proofs = readdirSync4(buildDir).filter((f) => f.endsWith(".proof.mts"));
@@ -5150,7 +5540,7 @@ async function runProof(args) {
5150
5540
  if (proofs.length > 1) {
5151
5541
  return refuse(`found ${proofs.length} proofs (${proofs.join(", ")}) \u2014 name one: githolon proof build/<name>.proof.mts`);
5152
5542
  }
5153
- proofPath = join12(buildDir, proofs[0]);
5543
+ proofPath = join14(buildDir, proofs[0]);
5154
5544
  }
5155
5545
  if (!live) {
5156
5546
  try {
@@ -5163,17 +5553,17 @@ async function runProof(args) {
5163
5553
  }
5164
5554
  const resolvePkgDir = (name, fromDir) => {
5165
5555
  try {
5166
- return dirname5(createRequire2(pathToFileURL4(join12(fromDir, "noop.js"))).resolve(`${name}/package.json`));
5556
+ return dirname7(createRequire2(pathToFileURL4(join14(fromDir, "noop.js"))).resolve(`${name}/package.json`));
5167
5557
  } catch {
5168
5558
  return void 0;
5169
5559
  }
5170
5560
  };
5171
5561
  const dslDir = (() => {
5172
5562
  try {
5173
- return dirname5(createRequire2(pathToFileURL4(join12(process.cwd(), "noop.js"))).resolve("@githolon/dsl/package.json"));
5563
+ return dirname7(createRequire2(pathToFileURL4(join14(process.cwd(), "noop.js"))).resolve("@githolon/dsl/package.json"));
5174
5564
  } catch {
5175
5565
  try {
5176
- return dirname5(createRequire2(import.meta.url).resolve("@githolon/dsl/package.json"));
5566
+ return dirname7(createRequire2(import.meta.url).resolve("@githolon/dsl/package.json"));
5177
5567
  } catch {
5178
5568
  return void 0;
5179
5569
  }
@@ -5183,9 +5573,9 @@ async function runProof(args) {
5183
5573
  if (tsxDir === void 0) {
5184
5574
  return refuse("tsx not found \u2014 add @githolon/dsl to your project's dependencies (tsx rides along) and npm install");
5185
5575
  }
5186
- const tsxPkg = JSON.parse(readFileSync12(join12(tsxDir, "package.json"), "utf8"));
5576
+ const tsxPkg = JSON.parse(readFileSync13(join14(tsxDir, "package.json"), "utf8"));
5187
5577
  const tsxBinRel = typeof tsxPkg.bin === "string" ? tsxPkg.bin : tsxPkg.bin?.["tsx"];
5188
- const tsxCli = join12(tsxDir, tsxBinRel ?? "dist/cli.mjs");
5578
+ const tsxCli = join14(tsxDir, tsxBinRel ?? "dist/cli.mjs");
5189
5579
  console.log("githolon proof --live \u2014 the full cloud loop (throwaway workspace, retired on exit" + (keep ? "; --keep: kept" : "") + ")");
5190
5580
  const { wsCreate: wsCreate2, wsRetire: wsRetire2 } = await Promise.resolve().then(() => (init_cloud(), cloud_exports));
5191
5581
  const { resolveGovernancePrincipal: resolveGovernancePrincipal2 } = await Promise.resolve().then(() => (init_governance(), governance_exports));
@@ -5214,7 +5604,7 @@ async function runProof(args) {
5214
5604
  );
5215
5605
  }
5216
5606
  }
5217
- const r = spawnSync4(process.execPath, [tsxCli, proofPath], {
5607
+ const r = spawnSync5(process.execPath, [tsxCli, proofPath], {
5218
5608
  stdio: "inherit",
5219
5609
  cwd: process.cwd(),
5220
5610
  env: {
@@ -5243,7 +5633,7 @@ function parseArgs(argv) {
5243
5633
  const [command, ...rest] = argv;
5244
5634
  if (command !== "generate" && command !== "g") {
5245
5635
  throw new Error(
5246
- `Unknown command '${command ?? "(none)"}'. Expected dev | compile | proof | replay | scene | status | generate | ws | deploy | domains | secret.`
5636
+ `Unknown command '${command ?? "(none)"}'. Expected dev | compile | check | lsp | mcp | init-editor | proof | replay | scene | status | generate | ws | deploy | domains | secret.`
5247
5637
  );
5248
5638
  }
5249
5639
  let outDir = DEFAULT_OUT;
@@ -5296,6 +5686,17 @@ async function main(argv) {
5296
5686
  if (argv[0] === "check") {
5297
5687
  return runCheck(argv.slice(1));
5298
5688
  }
5689
+ if (argv[0] === "lsp") {
5690
+ return runLsp(argv.slice(1));
5691
+ }
5692
+ if (argv[0] === "mcp") {
5693
+ const { runMcpServer: runMcpServer2 } = await Promise.resolve().then(() => (init_mcp(), mcp_exports));
5694
+ return runMcpServer2();
5695
+ }
5696
+ if (argv[0] === "init-editor") {
5697
+ const { initEditor: initEditor2 } = await Promise.resolve().then(() => (init_editor(), editor_exports));
5698
+ return initEditor2(process.cwd());
5699
+ }
5299
5700
  if (argv[0] === "proof") {
5300
5701
  return runProof(argv.slice(1));
5301
5702
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "githolon",
3
- "version": "0.51.0",
3
+ "version": "0.53.0",
4
4
  "type": "module",
5
5
  "description": "githolon — the Nomos developer CLI: Rails-style generators for @githolon/dsl domains + the package compiler. Kernel-independent.",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -29,8 +29,8 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "@bjorn3/browser_wasi_shim": "0.4.2",
32
- "@githolon/client": "^0.51.0",
33
- "@githolon/dsl": "^0.51.0",
32
+ "@githolon/client": "^0.53.0",
33
+ "@githolon/dsl": "^0.53.0",
34
34
  "isomorphic-git": "^1.38.4"
35
35
  },
36
36
  "devDependencies": {