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.
- package/dist/cli.mjs +407 -124
- 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
|
|
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) =>
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
2396
|
-
import { join as
|
|
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"] ||
|
|
2402
|
-
const wasmFile =
|
|
2403
|
-
const pkgsFile =
|
|
2404
|
-
if (!
|
|
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 (!
|
|
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
|
|
3515
|
-
import { join as
|
|
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 =
|
|
3537
|
-
if (!
|
|
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 =
|
|
3597
|
-
const name = isDir ? (
|
|
3598
|
-
out11(`scene \u2014 ${name} (${isDir ?
|
|
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 =
|
|
3976
|
+
const outDir = resolve3(opts.out ?? join13("scene", name));
|
|
3617
3977
|
mkdirSync5(outDir, { recursive: true });
|
|
3618
|
-
const usdaPath =
|
|
3619
|
-
const usdzPath =
|
|
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
|
|
3649
|
-
import { spawnSync as
|
|
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
|
|
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 =
|
|
5251
|
-
if (!
|
|
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 =
|
|
5254
|
-
if (!
|
|
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 =
|
|
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
|
|
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
|
|
5563
|
+
return dirname7(createRequire2(pathToFileURL4(join14(process.cwd(), "noop.js"))).resolve("@githolon/dsl/package.json"));
|
|
5285
5564
|
} catch {
|
|
5286
5565
|
try {
|
|
5287
|
-
return
|
|
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(
|
|
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 =
|
|
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 =
|
|
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.
|
|
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.
|
|
33
|
-
"@githolon/dsl": "^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": {
|