githolon 0.52.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 +407 -124
  2. package/package.json +3 -3
package/dist/cli.mjs CHANGED
@@ -1276,6 +1276,98 @@ var init_editor = __esm({
1276
1276
  }
1277
1277
  });
1278
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
+
1279
1371
  // vendor/engine/git-fs.mjs
1280
1372
  function fsErr(code, p) {
1281
1373
  const e = new Error(`${code}: ${p}`);
@@ -1291,7 +1383,7 @@ function makeGitFs(preopen, mount, { File: File3, Directory: Directory3 }) {
1291
1383
  const rel = p.slice(mount.length + 1).replace(/\/+$/, "");
1292
1384
  return rel === "" ? [] : rel.split("/");
1293
1385
  }
1294
- function resolve4(ps) {
1386
+ function resolve5(ps) {
1295
1387
  let cur = root;
1296
1388
  for (const part of ps) {
1297
1389
  if (!isDir(cur)) return null;
@@ -1301,11 +1393,11 @@ function makeGitFs(preopen, mount, { File: File3, Directory: Directory3 }) {
1301
1393
  }
1302
1394
  return cur;
1303
1395
  }
1304
- const parent = (ps) => resolve4(ps.slice(0, -1));
1396
+ const parent = (ps) => resolve5(ps.slice(0, -1));
1305
1397
  const leaf = (ps) => ps[ps.length - 1];
1306
1398
  const promises = {
1307
1399
  async readFile(p, opts) {
1308
- const n = resolve4(parts(p));
1400
+ const n = resolve5(parts(p));
1309
1401
  if (n === null) throw fsErr("ENOENT", p);
1310
1402
  if (isDir(n)) throw fsErr("EISDIR", p);
1311
1403
  const data = n.data ?? new Uint8Array(0);
@@ -1324,7 +1416,7 @@ function makeGitFs(preopen, mount, { File: File3, Directory: Directory3 }) {
1324
1416
  if (!isDir(par) || !par.contents.delete(leaf(ps))) throw fsErr("ENOENT", p);
1325
1417
  },
1326
1418
  async readdir(p) {
1327
- const n = resolve4(parts(p));
1419
+ const n = resolve5(parts(p));
1328
1420
  if (n === null) throw fsErr("ENOENT", p);
1329
1421
  if (!isDir(n)) throw fsErr("ENOTDIR", p);
1330
1422
  return [...n.contents.keys()];
@@ -1344,7 +1436,7 @@ function makeGitFs(preopen, mount, { File: File3, Directory: Directory3 }) {
1344
1436
  return promises.lstat(p);
1345
1437
  },
1346
1438
  async lstat(p) {
1347
- const n = resolve4(parts(p));
1439
+ const n = resolve5(parts(p));
1348
1440
  if (n === null) throw fsErr("ENOENT", p);
1349
1441
  const dir = isDir(n);
1350
1442
  return {
@@ -2387,21 +2479,289 @@ var init_proof_offline = __esm({
2387
2479
  }
2388
2480
  });
2389
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
+
2390
2750
  // src/harness.ts
2391
2751
  var harness_exports = {};
2392
2752
  __export(harness_exports, {
2393
2753
  harnessInstall: () => harnessInstall
2394
2754
  });
2395
- import { existsSync as existsSync10, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "node:fs";
2396
- import { join as join11 } 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";
2397
2757
  import { randomBytes as randomBytes3 } from "node:crypto";
2398
2758
  async function harnessInstall(opts) {
2399
2759
  const { deploy: deployPaths, workspace, out: outPath } = opts;
2400
2760
  if (deployPaths.length === 0) die("no --deploy JSON path(s) given");
2401
- const runtimeDir = opts.runtime || process.env["NOMOS_OFFLINE_RUNTIME"] || join11(configDir(), "runtime");
2402
- const wasmFile = join11(runtimeDir, "holon.wasm");
2403
- const pkgsFile = join11(runtimeDir, "packages.json");
2404
- if (!existsSync10(wasmFile) || !existsSync10(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)) {
2405
2765
  die(
2406
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.`
2407
2767
  );
@@ -2420,7 +2780,7 @@ async function harnessInstall(opts) {
2420
2780
  author(eng, workspace, "bootstrap", "installDomain", installPayload(eng.hashes.nomos, eng.nomosPkg, "nomos-test-harness"), "");
2421
2781
  const lawHashes = [];
2422
2782
  for (const p of deployPaths) {
2423
- if (!existsSync10(p)) die(`deploy JSON not found: ${p} \u2014 run \`npx githolon compile\` first`);
2783
+ if (!existsSync11(p)) die(`deploy JSON not found: ${p} \u2014 run \`npx githolon compile\` first`);
2424
2784
  const deploy2 = JSON.parse(readFileSync12(p, "utf8"));
2425
2785
  const usda = deploy2.packageUsda;
2426
2786
  if (typeof usda !== "string" || !usda.startsWith("#usda")) die(`${p} has no #usda packageUsda`);
@@ -3511,8 +3871,8 @@ var scene_exports = {};
3511
3871
  __export(scene_exports, {
3512
3872
  scene: () => scene
3513
3873
  });
3514
- import { existsSync as existsSync11, mkdirSync as mkdirSync5, writeFileSync as writeFileSync8 } from "node:fs";
3515
- import { join as join12, 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";
3516
3876
  import { createHash as createHash5 } from "node:crypto";
3517
3877
  import git3 from "isomorphic-git";
3518
3878
  async function walkChain2(eng, ws) {
@@ -3533,8 +3893,8 @@ async function projectOnce(cloud, target, isDir, name) {
3533
3893
  const { eng } = await holonEngine(cloud, void 0, "githolon-scene");
3534
3894
  const SOURCE3 = "source";
3535
3895
  if (isDir) {
3536
- const gitDir = existsSync11(join12(target, ".git")) ? join12(target, ".git") : target;
3537
- if (!existsSync11(join12(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)`);
3538
3898
  await mountFresh(eng, SOURCE3);
3539
3899
  eng.preopen.dir.contents.get("ws").contents.get(SOURCE3).contents.set("nomos.git", readTreeFromDisk(gitDir));
3540
3900
  } else {
@@ -3593,9 +3953,9 @@ async function projectOnce(cloud, target, isDir, name) {
3593
3953
  }
3594
3954
  async function scene(target, opts) {
3595
3955
  const cloud = cloudBase(opts.cloud);
3596
- const isDir = existsSync11(target) || target.includes("/") || target.startsWith(".");
3597
- const name = isDir ? (resolve2(target).split("/").filter(Boolean).pop() ?? "scene").replace(/\.git$/, "") : target;
3598
- 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}`})`);
3599
3959
  let first, second;
3600
3960
  try {
3601
3961
  first = await projectOnce(cloud, target, isDir, name);
@@ -3613,10 +3973,10 @@ async function scene(target, opts) {
3613
3973
  err11(`the emitted stage violates the portable profile: ${violations.join("; ")}`);
3614
3974
  return 1;
3615
3975
  }
3616
- const outDir = resolve2(opts.out ?? join12("scene", name));
3976
+ const outDir = resolve3(opts.out ?? join13("scene", name));
3617
3977
  mkdirSync5(outDir, { recursive: true });
3618
- const usdaPath = join12(outDir, `${name}.usda`);
3619
- const usdzPath = join12(outDir, `${name}.usdz`);
3978
+ const usdaPath = join13(outDir, `${name}.usda`);
3979
+ const usdzPath = join13(outDir, `${name}.usdz`);
3620
3980
  const usdaBytes = new TextEncoder().encode(first.usda);
3621
3981
  writeFileSync8(usdaPath, usdaBytes);
3622
3982
  writeFileSync8(usdzPath, usdzPack([[`${name}.usda`, usdaBytes]]));
@@ -3645,10 +4005,10 @@ var init_scene = __esm({
3645
4005
  });
3646
4006
 
3647
4007
  // src/cli.ts
3648
- import { existsSync as existsSync12, readdirSync as readdirSync4, readFileSync as readFileSync13 } from "node:fs";
3649
- 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";
3650
4010
  import { createRequire as createRequire2 } from "node:module";
3651
- import { dirname as dirname6, join as join13, resolve as resolve3 } from "node:path";
4011
+ import { dirname as dirname7, join as join14, resolve as resolve4 } from "node:path";
3652
4012
  import { pathToFileURL as pathToFileURL4 } from "node:url";
3653
4013
 
3654
4014
  // src/generate.ts
@@ -3831,101 +4191,17 @@ Re-run with --force to replace it.`
3831
4191
 
3832
4192
  // src/cli.ts
3833
4193
  init_cloud();
3834
-
3835
- // src/compile.ts
3836
- init_editor();
3837
- import { spawn, spawnSync } from "node:child_process";
3838
- import { createRequire } from "node:module";
3839
- import { dirname as dirname2, join as join4 } from "node:path";
3840
- import { pathToFileURL } from "node:url";
3841
- function resolveCompileLauncher(cwd) {
3842
- const resolveDslPkg = (fromDir) => {
3843
- try {
3844
- const req = fromDir === void 0 ? createRequire(import.meta.url) : createRequire(pathToFileURL(join4(fromDir, "noop.js")));
3845
- return req.resolve("@githolon/dsl/package.json");
3846
- } catch {
3847
- return void 0;
3848
- }
3849
- };
3850
- const dslPkg = resolveDslPkg(cwd) ?? resolveDslPkg(void 0);
3851
- return dslPkg === void 0 ? void 0 : join4(dirname2(dslPkg), "compile_package.mjs");
3852
- }
3853
- var NO_DSL_REMEDY = "@githolon/dsl not found \u2014 add it to your project's dependencies";
3854
- function runCompile(args) {
3855
- const launcher = resolveCompileLauncher(process.cwd());
3856
- if (launcher === void 0) {
3857
- process.stderr.write(`error: ${NO_DSL_REMEDY}
3858
- `);
3859
- return 1;
3860
- }
3861
- const r = spawnSync(process.execPath, [launcher, ...args], { stdio: "inherit", cwd: process.cwd() });
3862
- const status2 = r.status ?? 1;
3863
- if (status2 === 0 && process.stdout.isTTY) {
3864
- try {
3865
- if (!hasEditorRecommendation(process.cwd())) process.stdout.write(`
3866
- ${INIT_EDITOR_HINT}
3867
- `);
3868
- } catch {
3869
- }
3870
- }
3871
- return status2;
3872
- }
3873
- function resolveCheckLauncher(cwd) {
3874
- const launcher = resolveCompileLauncher(cwd);
3875
- return launcher === void 0 ? void 0 : join4(dirname2(launcher), "check_package.mjs");
3876
- }
3877
- function runCheck(args) {
3878
- const launcher = resolveCheckLauncher(process.cwd());
3879
- if (launcher === void 0) {
3880
- process.stderr.write(`error: ${NO_DSL_REMEDY}
3881
- `);
3882
- return 1;
3883
- }
3884
- const r = spawnSync(process.execPath, [launcher, ...args], { stdio: "inherit", cwd: process.cwd() });
3885
- return r.status ?? 1;
3886
- }
3887
- function resolveLspLauncher(cwd) {
3888
- const launcher = resolveCompileLauncher(cwd);
3889
- return launcher === void 0 ? void 0 : join4(dirname2(launcher), "lsp_server.mjs");
3890
- }
3891
- function runLsp(args) {
3892
- const launcher = resolveLspLauncher(process.cwd());
3893
- if (launcher === void 0) {
3894
- process.stderr.write(`error: ${NO_DSL_REMEDY}
3895
- `);
3896
- return 1;
3897
- }
3898
- const r = spawnSync(process.execPath, [launcher, ...args], { stdio: "inherit", cwd: process.cwd() });
3899
- return r.status ?? 1;
3900
- }
3901
- function compileAsync(cwd, args = []) {
3902
- const launcher = resolveCompileLauncher(cwd);
3903
- const t0 = performance.now();
3904
- if (launcher === void 0) {
3905
- return Promise.resolve({ ok: false, ms: 0, output: NO_DSL_REMEDY });
3906
- }
3907
- return new Promise((resolveRun) => {
3908
- const chunks = [];
3909
- const dec4 = new TextDecoder();
3910
- const child = spawn(process.execPath, [launcher, ...args], { cwd, stdio: ["ignore", "pipe", "pipe"] });
3911
- child.stdout?.on("data", (c) => chunks.push(dec4.decode(c)));
3912
- child.stderr?.on("data", (c) => chunks.push(dec4.decode(c)));
3913
- child.on("error", (e) => resolveRun({ ok: false, ms: performance.now() - t0, output: String(e) }));
3914
- child.on(
3915
- "close",
3916
- (code) => resolveRun({ ok: code === 0, ms: performance.now() - t0, output: chunks.join("") })
3917
- );
3918
- });
3919
- }
4194
+ init_compile();
3920
4195
 
3921
4196
  // src/dev.ts
3922
4197
  init_engine();
3923
4198
  init_cloud();
4199
+ init_compile();
4200
+ init_local_holon();
3924
4201
  import { existsSync as existsSync7, readFileSync as readFileSync7, watch } from "node:fs";
3925
4202
  import { createServer } from "node:http";
3926
4203
  import { dirname as dirname5, join as join8, resolve } from "node:path";
3927
4204
  import { pathToFileURL as pathToFileURL3 } from "node:url";
3928
- init_local_holon();
3929
4205
 
3930
4206
  // src/project.ts
3931
4207
  import { existsSync as existsSync5, statSync as statSync2 } from "node:fs";
@@ -5059,6 +5335,9 @@ Authoring:
5059
5335
  --json emits the findings (with file:line) as an array
5060
5336
  githolon lsp the author-time gate as a stdio Language Server:
5061
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
5062
5341
  githolon compile [compiler args] compile the package by ./nomos.package.mjs
5063
5342
  githolon init-editor write .vscode/extensions.json recommending the
5064
5343
  Nomos Law extension \u2014 the check gate as red
@@ -5247,11 +5526,11 @@ async function runProof(args) {
5247
5526
  const explicit = args.find((a, i) => !a.startsWith("--") && i !== domainValueIdx);
5248
5527
  let proofPath;
5249
5528
  if (explicit !== void 0) {
5250
- proofPath = resolve3(process.cwd(), explicit);
5251
- if (!existsSync12(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`);
5252
5531
  } else {
5253
- const buildDir = join13(process.cwd(), "build");
5254
- if (!existsSync12(buildDir)) {
5532
+ const buildDir = join14(process.cwd(), "build");
5533
+ if (!existsSync13(buildDir)) {
5255
5534
  return refuse("no build/ directory here \u2014 run `githolon compile` first (every compile generates build/<name>.proof.mts from your law)");
5256
5535
  }
5257
5536
  const proofs = readdirSync4(buildDir).filter((f) => f.endsWith(".proof.mts"));
@@ -5261,7 +5540,7 @@ async function runProof(args) {
5261
5540
  if (proofs.length > 1) {
5262
5541
  return refuse(`found ${proofs.length} proofs (${proofs.join(", ")}) \u2014 name one: githolon proof build/<name>.proof.mts`);
5263
5542
  }
5264
- proofPath = join13(buildDir, proofs[0]);
5543
+ proofPath = join14(buildDir, proofs[0]);
5265
5544
  }
5266
5545
  if (!live) {
5267
5546
  try {
@@ -5274,17 +5553,17 @@ async function runProof(args) {
5274
5553
  }
5275
5554
  const resolvePkgDir = (name, fromDir) => {
5276
5555
  try {
5277
- return dirname6(createRequire2(pathToFileURL4(join13(fromDir, "noop.js"))).resolve(`${name}/package.json`));
5556
+ return dirname7(createRequire2(pathToFileURL4(join14(fromDir, "noop.js"))).resolve(`${name}/package.json`));
5278
5557
  } catch {
5279
5558
  return void 0;
5280
5559
  }
5281
5560
  };
5282
5561
  const dslDir = (() => {
5283
5562
  try {
5284
- return dirname6(createRequire2(pathToFileURL4(join13(process.cwd(), "noop.js"))).resolve("@githolon/dsl/package.json"));
5563
+ return dirname7(createRequire2(pathToFileURL4(join14(process.cwd(), "noop.js"))).resolve("@githolon/dsl/package.json"));
5285
5564
  } catch {
5286
5565
  try {
5287
- return dirname6(createRequire2(import.meta.url).resolve("@githolon/dsl/package.json"));
5566
+ return dirname7(createRequire2(import.meta.url).resolve("@githolon/dsl/package.json"));
5288
5567
  } catch {
5289
5568
  return void 0;
5290
5569
  }
@@ -5294,9 +5573,9 @@ async function runProof(args) {
5294
5573
  if (tsxDir === void 0) {
5295
5574
  return refuse("tsx not found \u2014 add @githolon/dsl to your project's dependencies (tsx rides along) and npm install");
5296
5575
  }
5297
- const tsxPkg = JSON.parse(readFileSync13(join13(tsxDir, "package.json"), "utf8"));
5576
+ const tsxPkg = JSON.parse(readFileSync13(join14(tsxDir, "package.json"), "utf8"));
5298
5577
  const tsxBinRel = typeof tsxPkg.bin === "string" ? tsxPkg.bin : tsxPkg.bin?.["tsx"];
5299
- const tsxCli = join13(tsxDir, tsxBinRel ?? "dist/cli.mjs");
5578
+ const tsxCli = join14(tsxDir, tsxBinRel ?? "dist/cli.mjs");
5300
5579
  console.log("githolon proof --live \u2014 the full cloud loop (throwaway workspace, retired on exit" + (keep ? "; --keep: kept" : "") + ")");
5301
5580
  const { wsCreate: wsCreate2, wsRetire: wsRetire2 } = await Promise.resolve().then(() => (init_cloud(), cloud_exports));
5302
5581
  const { resolveGovernancePrincipal: resolveGovernancePrincipal2 } = await Promise.resolve().then(() => (init_governance(), governance_exports));
@@ -5325,7 +5604,7 @@ async function runProof(args) {
5325
5604
  );
5326
5605
  }
5327
5606
  }
5328
- const r = spawnSync4(process.execPath, [tsxCli, proofPath], {
5607
+ const r = spawnSync5(process.execPath, [tsxCli, proofPath], {
5329
5608
  stdio: "inherit",
5330
5609
  cwd: process.cwd(),
5331
5610
  env: {
@@ -5354,7 +5633,7 @@ function parseArgs(argv) {
5354
5633
  const [command, ...rest] = argv;
5355
5634
  if (command !== "generate" && command !== "g") {
5356
5635
  throw new Error(
5357
- `Unknown command '${command ?? "(none)"}'. Expected dev | compile | check | init-editor | 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.`
5358
5637
  );
5359
5638
  }
5360
5639
  let outDir = DEFAULT_OUT;
@@ -5410,6 +5689,10 @@ async function main(argv) {
5410
5689
  if (argv[0] === "lsp") {
5411
5690
  return runLsp(argv.slice(1));
5412
5691
  }
5692
+ if (argv[0] === "mcp") {
5693
+ const { runMcpServer: runMcpServer2 } = await Promise.resolve().then(() => (init_mcp(), mcp_exports));
5694
+ return runMcpServer2();
5695
+ }
5413
5696
  if (argv[0] === "init-editor") {
5414
5697
  const { initEditor: initEditor2 } = await Promise.resolve().then(() => (init_editor(), editor_exports));
5415
5698
  return initEditor2(process.cwd());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "githolon",
3
- "version": "0.52.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.52.0",
33
- "@githolon/dsl": "^0.52.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": {