githolon 0.69.1 → 0.69.3
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 +387 -258
- package/package.json +3 -3
package/dist/cli.mjs
CHANGED
|
@@ -2828,9 +2828,151 @@ var init_local_holon = __esm({
|
|
|
2828
2828
|
}
|
|
2829
2829
|
});
|
|
2830
2830
|
|
|
2831
|
+
// src/repairs.ts
|
|
2832
|
+
var repairs_exports = {};
|
|
2833
|
+
__export(repairs_exports, {
|
|
2834
|
+
discoverRepairs: () => discoverRepairs,
|
|
2835
|
+
knownRepairBlock: () => knownRepairBlock,
|
|
2836
|
+
matchRepair: () => matchRepair,
|
|
2837
|
+
parseRefusal: () => parseRefusal
|
|
2838
|
+
});
|
|
2839
|
+
import { spawnSync } from "node:child_process";
|
|
2840
|
+
import { createRequire } from "node:module";
|
|
2841
|
+
import { existsSync as existsSync3, mkdtempSync, readdirSync as readdirSync2, readFileSync as readFileSync2, rmSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
2842
|
+
import { tmpdir } from "node:os";
|
|
2843
|
+
import { dirname as dirname2, isAbsolute, join as join3, resolve } from "node:path";
|
|
2844
|
+
import { pathToFileURL } from "node:url";
|
|
2845
|
+
function parseRefusal(verdict) {
|
|
2846
|
+
const check2 = String(verdict["check"] ?? "");
|
|
2847
|
+
const error = String(verdict["error"] ?? "");
|
|
2848
|
+
const raw = `${check2}: ${error}`;
|
|
2849
|
+
const kind = /evolve.?gate/i.test(raw) || /evolve/i.test(check2) ? "evolve-gate" : "other";
|
|
2850
|
+
const sids = /* @__PURE__ */ new Set();
|
|
2851
|
+
const structured = verdict["stableId"] ?? verdict["stableIds"];
|
|
2852
|
+
if (typeof structured === "string" && SID_SHAPE.test(structured)) sids.add(structured.toLowerCase());
|
|
2853
|
+
if (Array.isArray(structured)) {
|
|
2854
|
+
for (const s of structured) if (typeof s === "string" && SID_SHAPE.test(s)) sids.add(s.toLowerCase());
|
|
2855
|
+
}
|
|
2856
|
+
for (const m of raw.matchAll(SID_RE)) sids.add(m[1].toLowerCase());
|
|
2857
|
+
return { kind, stableIds: [...sids], raw };
|
|
2858
|
+
}
|
|
2859
|
+
function matchRepair(refusal, repairs) {
|
|
2860
|
+
if (refusal.kind === "other") return void 0;
|
|
2861
|
+
return repairs.find(
|
|
2862
|
+
(r) => r.matcher.refusal === refusal.kind && refusal.stableIds.includes(r.matcher.stableId.toLowerCase())
|
|
2863
|
+
);
|
|
2864
|
+
}
|
|
2865
|
+
function knownRepairBlock(repair) {
|
|
2866
|
+
return [
|
|
2867
|
+
"",
|
|
2868
|
+
`\u2726 KNOWN REPAIR: '${repair.id}' (${repair.file}) declares a remedy for exactly this refusal.`,
|
|
2869
|
+
` reason: ${repair.reason}`,
|
|
2870
|
+
" Re-run with --repair to execute it."
|
|
2871
|
+
].join("\n");
|
|
2872
|
+
}
|
|
2873
|
+
function resolveTsxCli(cwd) {
|
|
2874
|
+
const pkgDir = (name, fromDir) => {
|
|
2875
|
+
try {
|
|
2876
|
+
return dirname2(createRequire(pathToFileURL(join3(fromDir, "noop.js")).href).resolve(`${name}/package.json`));
|
|
2877
|
+
} catch {
|
|
2878
|
+
return void 0;
|
|
2879
|
+
}
|
|
2880
|
+
};
|
|
2881
|
+
const dslDir = pkgDir("@githolon/dsl", cwd) ?? (() => {
|
|
2882
|
+
try {
|
|
2883
|
+
return dirname2(createRequire(import.meta.url).resolve("@githolon/dsl/package.json"));
|
|
2884
|
+
} catch {
|
|
2885
|
+
return void 0;
|
|
2886
|
+
}
|
|
2887
|
+
})();
|
|
2888
|
+
const tsxDir = pkgDir("tsx", cwd) ?? (dslDir !== void 0 ? pkgDir("tsx", dslDir) : void 0);
|
|
2889
|
+
if (tsxDir === void 0) return void 0;
|
|
2890
|
+
try {
|
|
2891
|
+
const pkg = JSON.parse(
|
|
2892
|
+
readFileSync2(join3(tsxDir, "package.json"), "utf8")
|
|
2893
|
+
);
|
|
2894
|
+
const rel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.["tsx"];
|
|
2895
|
+
return join3(tsxDir, rel ?? "dist/cli.mjs");
|
|
2896
|
+
} catch {
|
|
2897
|
+
return void 0;
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2900
|
+
function resolveDslEntry(cwd) {
|
|
2901
|
+
const tryFrom = (fromUrl) => {
|
|
2902
|
+
try {
|
|
2903
|
+
return createRequire(fromUrl).resolve("@githolon/dsl");
|
|
2904
|
+
} catch {
|
|
2905
|
+
return void 0;
|
|
2906
|
+
}
|
|
2907
|
+
};
|
|
2908
|
+
return tryFrom(pathToFileURL(join3(cwd, "noop.js")).href) ?? tryFrom(import.meta.url);
|
|
2909
|
+
}
|
|
2910
|
+
function discoverRepairs(cwd) {
|
|
2911
|
+
const dir = join3(cwd, "repairs");
|
|
2912
|
+
if (!existsSync3(dir)) return { repairs: [] };
|
|
2913
|
+
let files;
|
|
2914
|
+
try {
|
|
2915
|
+
files = readdirSync2(dir).filter((f) => /\.(ts|mts|cts)$/.test(f) && !/\.d\.ts$/.test(f)).sort().map((f) => resolve(dir, f));
|
|
2916
|
+
} catch (e) {
|
|
2917
|
+
return { error: `could not read the repairs/ folder: ${e.message}` };
|
|
2918
|
+
}
|
|
2919
|
+
if (files.length === 0) return { repairs: [] };
|
|
2920
|
+
const tsxCli = resolveTsxCli(cwd);
|
|
2921
|
+
const dslEntry = resolveDslEntry(cwd);
|
|
2922
|
+
if (tsxCli === void 0 || dslEntry === void 0) {
|
|
2923
|
+
return { error: "repairs/ is present but the toolchain to load it is missing \u2014 add @githolon/dsl (tsx + the DSL ride it) to the project and npm install" };
|
|
2924
|
+
}
|
|
2925
|
+
const scratch = mkdtempSync(join3(tmpdir(), "githolon-repairs-"));
|
|
2926
|
+
const loader = join3(scratch, "discover.mts");
|
|
2927
|
+
const loaderSrc = `
|
|
2928
|
+
import { repairsOf } from ${JSON.stringify(dslEntry)};
|
|
2929
|
+
const files = ${JSON.stringify(files)};
|
|
2930
|
+
const out = [];
|
|
2931
|
+
const seen = new Map();
|
|
2932
|
+
for (const file of files) {
|
|
2933
|
+
const mod = await import(${JSON.stringify("file://")} + file);
|
|
2934
|
+
for (const r of repairsOf(mod)) {
|
|
2935
|
+
if (seen.has(r.id)) {
|
|
2936
|
+
throw new Error("duplicate repair id '" + r.id + "' \u2014 declared in " + seen.get(r.id) + " and " + file);
|
|
2937
|
+
}
|
|
2938
|
+
seen.set(r.id, file);
|
|
2939
|
+
out.push({ id: r.id, matcher: r.matcher, reason: r.reason, verb: r.verb, file });
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
process.stdout.write("\\u0001REPAIRS\\u0001" + JSON.stringify(out) + "\\u0001END\\u0001\\n");
|
|
2943
|
+
`;
|
|
2944
|
+
try {
|
|
2945
|
+
writeFileSync3(loader, loaderSrc, "utf8");
|
|
2946
|
+
const r = spawnSync(process.execPath, [tsxCli, loader], { cwd, encoding: "utf8" });
|
|
2947
|
+
if (r.status !== 0) {
|
|
2948
|
+
const msg = (r.stderr || r.stdout || "").trim().split("\n").filter(Boolean).slice(-4).join("\n");
|
|
2949
|
+
return { error: `loading repairs/ failed:
|
|
2950
|
+
${msg || `tsx exited ${r.status ?? "?"}`}` };
|
|
2951
|
+
}
|
|
2952
|
+
const m = /REPAIRS([\s\S]*?)END/.exec(r.stdout);
|
|
2953
|
+
if (m === null) return { error: "the repairs loader produced no manifest (unexpected \u2014 the DSL/tsx may be too old)" };
|
|
2954
|
+
const parsed = JSON.parse(m[1]);
|
|
2955
|
+
const repairs = parsed.map((p) => ({ ...p, file: isAbsolute(p.file) ? p.file : resolve(cwd, p.file) }));
|
|
2956
|
+
return { repairs };
|
|
2957
|
+
} catch (e) {
|
|
2958
|
+
return { error: `loading repairs/ failed: ${e.message}` };
|
|
2959
|
+
} finally {
|
|
2960
|
+
rmSync(scratch, { recursive: true, force: true });
|
|
2961
|
+
}
|
|
2962
|
+
}
|
|
2963
|
+
var SID_RE, SID_SHAPE;
|
|
2964
|
+
var init_repairs = __esm({
|
|
2965
|
+
"src/repairs.ts"() {
|
|
2966
|
+
"use strict";
|
|
2967
|
+
SID_RE = /stable id ([0-9a-f]{16})/gi;
|
|
2968
|
+
SID_SHAPE = /^[0-9a-f]{16}$/i;
|
|
2969
|
+
}
|
|
2970
|
+
});
|
|
2971
|
+
|
|
2831
2972
|
// src/governance.ts
|
|
2832
2973
|
var governance_exports = {};
|
|
2833
2974
|
__export(governance_exports, {
|
|
2975
|
+
ROOT_CUSTODIAN_SECRET: () => ROOT_CUSTODIAN_SECRET,
|
|
2834
2976
|
buildCertificate: () => buildCertificate,
|
|
2835
2977
|
buildRebirthPlan: () => buildRebirthPlan,
|
|
2836
2978
|
certifyEra: () => certifyEra,
|
|
@@ -2846,6 +2988,7 @@ __export(governance_exports, {
|
|
|
2846
2988
|
rebirthPlanCommand: () => rebirthPlanCommand,
|
|
2847
2989
|
rebirthWorkspace: () => rebirthWorkspace,
|
|
2848
2990
|
renderRebirthImpact: () => renderRebirthImpact,
|
|
2991
|
+
resolveGovernanceHash: () => resolveGovernanceHash,
|
|
2849
2992
|
resolveGovernancePrincipal: () => resolveGovernancePrincipal,
|
|
2850
2993
|
signAndPostGovernance: () => signAndPostGovernance,
|
|
2851
2994
|
signAndPostOffer: () => signAndPostOffer,
|
|
@@ -2853,8 +2996,8 @@ __export(governance_exports, {
|
|
|
2853
2996
|
verifyWorkspaceVerdict: () => verifyWorkspaceVerdict
|
|
2854
2997
|
});
|
|
2855
2998
|
import { createHash, createPrivateKey, createPublicKey } from "node:crypto";
|
|
2856
|
-
import { mkdirSync as mkdirSync3, readFileSync as
|
|
2857
|
-
import { dirname as
|
|
2999
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
3000
|
+
import { dirname as dirname3, join as join4 } from "node:path";
|
|
2858
3001
|
async function clientConnect() {
|
|
2859
3002
|
const mod = await import("@githolon/client");
|
|
2860
3003
|
return mod.connect;
|
|
@@ -3072,7 +3215,7 @@ async function keyExport(opts) {
|
|
|
3072
3215
|
return 0;
|
|
3073
3216
|
}
|
|
3074
3217
|
function buildOfferPayload(opts) {
|
|
3075
|
-
const raw = opts.payloadFile !== void 0 ?
|
|
3218
|
+
const raw = opts.payloadFile !== void 0 ? readFileSync3(opts.payloadFile, "utf8") : opts.payload;
|
|
3076
3219
|
let payload = {};
|
|
3077
3220
|
if (raw !== void 0 && raw.trim() !== "") payload = JSON.parse(raw);
|
|
3078
3221
|
if (typeof payload !== "object" || payload === null || Array.isArray(payload)) {
|
|
@@ -3106,7 +3249,7 @@ async function governanceOffer(ws, directiveId, opts) {
|
|
|
3106
3249
|
const holon = await connectGovernance(cloudBase(opts.cloud), ws);
|
|
3107
3250
|
const device = await ensureDeviceKey(holon, principal);
|
|
3108
3251
|
const sealed = await holon.signGovernanceOffer({ directiveId, payload, authorSecret: device.secret, actor: `user:${principal}` });
|
|
3109
|
-
|
|
3252
|
+
writeFileSync4(opts.save, JSON.stringify({ ws, directiveId, principal, intentBytes: sealed.intentBytes }, null, 2) + "\n");
|
|
3110
3253
|
} catch (e) {
|
|
3111
3254
|
err2(e.message);
|
|
3112
3255
|
return 1;
|
|
@@ -3133,7 +3276,7 @@ async function governanceOffer(ws, directiveId, opts) {
|
|
|
3133
3276
|
async function governanceRelay(ws, file, opts) {
|
|
3134
3277
|
let saved;
|
|
3135
3278
|
try {
|
|
3136
|
-
saved = JSON.parse(
|
|
3279
|
+
saved = JSON.parse(readFileSync3(file, "utf8"));
|
|
3137
3280
|
} catch (e) {
|
|
3138
3281
|
err2(`cannot read offer file ${file}: ${e.message}`);
|
|
3139
3282
|
return 1;
|
|
@@ -3294,6 +3437,15 @@ certify-era ${ws}:`);
|
|
|
3294
3437
|
out2(` verify: githolon ledger verify ${ws} (expect GREEN with certifiedRanges naming the oids)`);
|
|
3295
3438
|
return 0;
|
|
3296
3439
|
}
|
|
3440
|
+
async function resolveGovernanceHash(cloud, domainKey, ws = "root", fetchImpl = fetch) {
|
|
3441
|
+
try {
|
|
3442
|
+
const d = await (await fetchImpl(`${cloud}/v2/workspaces/${ws}/domains`)).json();
|
|
3443
|
+
const h = d && d.currentLaw && d.currentLaw[domainKey];
|
|
3444
|
+
return typeof h === "string" && h.length > 0 ? h : void 0;
|
|
3445
|
+
} catch {
|
|
3446
|
+
return void 0;
|
|
3447
|
+
}
|
|
3448
|
+
}
|
|
3297
3449
|
async function parkedAreAllLawInstalls(engMod, eng, ws, oids) {
|
|
3298
3450
|
try {
|
|
3299
3451
|
const git4 = (await import("isomorphic-git")).default;
|
|
@@ -3351,18 +3503,27 @@ async function buildRebirthPlan(cloud, ws, reason) {
|
|
|
3351
3503
|
} catch {
|
|
3352
3504
|
}
|
|
3353
3505
|
const lawHashes = {};
|
|
3506
|
+
let currentLaw2 = {};
|
|
3354
3507
|
try {
|
|
3355
3508
|
const d = await (await fetch(`${cloud}/v2/workspaces/${ws}/domains`)).json();
|
|
3509
|
+
currentLaw2 = d.currentLaw ?? {};
|
|
3510
|
+
const currentHashes = new Set(Object.values(currentLaw2));
|
|
3356
3511
|
for (const dom of d.domains ?? []) {
|
|
3357
|
-
if (typeof dom.domainHash
|
|
3512
|
+
if (typeof dom.domainHash !== "string") continue;
|
|
3513
|
+
lawHashes[dom.domainHash] = {
|
|
3514
|
+
phase: dom.phase ?? "unknown",
|
|
3515
|
+
current: dom.current === true || currentHashes.has(dom.domainHash)
|
|
3516
|
+
};
|
|
3358
3517
|
}
|
|
3359
3518
|
} catch {
|
|
3360
3519
|
}
|
|
3361
3520
|
let verdict = { replay: "unknown", firstRefusal: null };
|
|
3521
|
+
let rawVerdict = null;
|
|
3362
3522
|
try {
|
|
3363
3523
|
const m = await mountWorkspace2(eng, ws, { remote: `${cloud}/v2/workspaces/${ws}/git`, headers: {} });
|
|
3364
3524
|
if (m.restored === true) {
|
|
3365
3525
|
const v = verifyChainLocal2(eng, ws);
|
|
3526
|
+
rawVerdict = v;
|
|
3366
3527
|
if (v["valid"] === true) verdict = { replay: "green", firstRefusal: null };
|
|
3367
3528
|
else verdict = { replay: "red", firstRefusal: `${String(v["check"] ?? "?")}${v["atIndex"] !== void 0 ? ` @intent ${v["atIndex"]}` : ""}: ${String(v["error"] ?? "").slice(0, 200)}` };
|
|
3368
3529
|
}
|
|
@@ -3384,13 +3545,42 @@ async function buildRebirthPlan(cloud, ws, reason) {
|
|
|
3384
3545
|
} catch {
|
|
3385
3546
|
}
|
|
3386
3547
|
const mode = compaction.scarShape === "mid-chain" && !((compaction.parked ?? 99) <= 2 && parkedAllLawInstalls) ? "state-seed" : "replay-compact";
|
|
3548
|
+
let repairs = [];
|
|
3549
|
+
if (rawVerdict !== null && rawVerdict["valid"] !== true) {
|
|
3550
|
+
try {
|
|
3551
|
+
const { discoverRepairs: discoverRepairs2, parseRefusal: parseRefusal2, matchRepair: matchRepair2 } = await Promise.resolve().then(() => (init_repairs(), repairs_exports));
|
|
3552
|
+
const discovered = discoverRepairs2(process.cwd());
|
|
3553
|
+
if (!("error" in discovered) && discovered.repairs.length > 0) {
|
|
3554
|
+
const refusal = parseRefusal2(rawVerdict);
|
|
3555
|
+
for (const r of discovered.repairs) {
|
|
3556
|
+
if (r.matcher.refusal === refusal.kind && refusal.stableIds.includes(r.matcher.stableId.toLowerCase())) {
|
|
3557
|
+
const v = r.verb;
|
|
3558
|
+
repairs.push({
|
|
3559
|
+
id: r.id,
|
|
3560
|
+
file: r.file,
|
|
3561
|
+
reason: r.reason,
|
|
3562
|
+
matcher: { refusal: r.matcher.refusal, stableId: r.matcher.stableId },
|
|
3563
|
+
verb: {
|
|
3564
|
+
kind: String(v.kind ?? ""),
|
|
3565
|
+
...typeof v.aggregateId === "string" ? { aggregateId: v.aggregateId } : {},
|
|
3566
|
+
...typeof v.field === "string" ? { field: v.field } : {},
|
|
3567
|
+
...typeof v.through === "string" ? { through: v.through } : {}
|
|
3568
|
+
},
|
|
3569
|
+
execution: "recorded"
|
|
3570
|
+
});
|
|
3571
|
+
}
|
|
3572
|
+
}
|
|
3573
|
+
}
|
|
3574
|
+
} catch {
|
|
3575
|
+
}
|
|
3576
|
+
}
|
|
3387
3577
|
const frozenAt = priorSupersessions === 0 ? ws : `${ws}--i${priorSupersessions}`;
|
|
3388
3578
|
const newCustodyAddress = `${ws}--i${priorSupersessions + 1}`;
|
|
3389
3579
|
const plan = {
|
|
3390
3580
|
v: 1,
|
|
3391
3581
|
workspace: ws,
|
|
3392
3582
|
reason: reason ?? null,
|
|
3393
|
-
pinned: { incarnation, lawHashes, parent },
|
|
3583
|
+
pinned: { incarnation, lawHashes, currentLaw: currentLaw2, parent },
|
|
3394
3584
|
will: {
|
|
3395
3585
|
newCustodyAddress,
|
|
3396
3586
|
frozenAt,
|
|
@@ -3400,7 +3590,7 @@ async function buildRebirthPlan(cloud, ws, reason) {
|
|
|
3400
3590
|
verdict,
|
|
3401
3591
|
mode,
|
|
3402
3592
|
compaction,
|
|
3403
|
-
repairs
|
|
3593
|
+
repairs,
|
|
3404
3594
|
clientImpact: CLIENT_IMPACT,
|
|
3405
3595
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3406
3596
|
};
|
|
@@ -3416,8 +3606,15 @@ function renderRebirthImpact(plan, ledgerCommits) {
|
|
|
3416
3606
|
L.push(` incarnation : ${plan.pinned.incarnation ? plan.pinned.incarnation.slice(0, 16) + "\u2026" : "(none recorded \u2014 first incarnation)"}`);
|
|
3417
3607
|
L.push(` verify_chain : ${plan.verdict.replay.toUpperCase()}${plan.verdict.firstRefusal ? ` \u2014 first refusal: ${plan.verdict.firstRefusal}` : ""}`);
|
|
3418
3608
|
L.push(` ledger size : ${ledgerCommits !== null ? `${ledgerCommits} commit(s)` : "(unknown)"}`);
|
|
3419
|
-
const laws = Object.
|
|
3420
|
-
|
|
3609
|
+
const laws = Object.entries(plan.pinned.lawHashes);
|
|
3610
|
+
const currentLaw2 = plan.pinned.currentLaw ?? {};
|
|
3611
|
+
const keysForHash = (hash) => Object.entries(currentLaw2).filter(([, h]) => h === hash).map(([k]) => k);
|
|
3612
|
+
const currentHashes = laws.filter(([, m]) => m.current).map(([h]) => h);
|
|
3613
|
+
const currentDesc = currentHashes.length ? currentHashes.map((h) => {
|
|
3614
|
+
const ks = keysForHash(h);
|
|
3615
|
+
return `${h.slice(0, 8)}\u2026${ks.length ? ` (${ks.join(", ")})` : ""}`;
|
|
3616
|
+
}).join(" \xB7 ") : "(none current)";
|
|
3617
|
+
L.push(` installed law : ${laws.length} historical \xB7 current: ${currentDesc}`);
|
|
3421
3618
|
L.push(` parent : ${plan.pinned.parent || "(root)"}`);
|
|
3422
3619
|
L.push("");
|
|
3423
3620
|
L.push("WHAT A REBIRTH WOULD DO");
|
|
@@ -3450,9 +3647,33 @@ function renderRebirthImpact(plan, ledgerCommits) {
|
|
|
3450
3647
|
L.push(" \u2192 preserved by lineage continuity; their birth-cert chains stay valid (same founding key + self-id).");
|
|
3451
3648
|
}
|
|
3452
3649
|
L.push("");
|
|
3650
|
+
L.push(`REPAIRS (${plan.repairs.length})`);
|
|
3651
|
+
if (plan.repairs.length === 0) L.push(" (none matched \u2014 a plain compaction; no corrective verb declared for this refusal)");
|
|
3652
|
+
else {
|
|
3653
|
+
for (const r of plan.repairs) {
|
|
3654
|
+
const v = r.verb;
|
|
3655
|
+
const verbDesc = `${v.kind}${v.aggregateId ? ` ${v.aggregateId}${v.field ? `.${v.field}` : ""}` : ""}${v.through ? ` through ${v.through}` : ""}`;
|
|
3656
|
+
L.push(` \u2726 ${r.id} [${r.execution}]`);
|
|
3657
|
+
L.push(` matches : ${r.matcher.refusal} \xB7 stable id ${r.matcher.stableId}`);
|
|
3658
|
+
L.push(` verb : ${verbDesc} (${r.file})`);
|
|
3659
|
+
L.push(` reason : ${r.reason}`);
|
|
3660
|
+
}
|
|
3661
|
+
L.push(" \u2192 v1 records the repair as provenance/justification (the certificate + supersession reason name it);");
|
|
3662
|
+
L.push(" state-transform verbs execute at the re-fold seam in a future release.");
|
|
3663
|
+
}
|
|
3664
|
+
L.push("");
|
|
3453
3665
|
L.push("CLIENT IMPACT");
|
|
3454
3666
|
L.push(` ${plan.clientImpact}.`);
|
|
3455
3667
|
L.push(" Recommend tenants DRAIN/SYNC their clients before the rebirth window.");
|
|
3668
|
+
L.push("");
|
|
3669
|
+
L.push("NEXT STEPS \u2014 the blessed golden path");
|
|
3670
|
+
L.push(" 1. plan (this)");
|
|
3671
|
+
L.push(` 2. apply githolon rebirth apply --plan <path> --gcp-secret ${ROOT_CUSTODIAN_SECRET} [--yes]`);
|
|
3672
|
+
L.push(" (apply requires the ROOT CUSTODIAN seed \u2014 --gcp-secret is the blessed path;");
|
|
3673
|
+
L.push(" --seed-secret <b64> is break-glass, env NOMOS_ROOT_SEED is the CI lane)");
|
|
3674
|
+
L.push(` 3. replay githolon replay ${plan.workspace} (expect GREEN from intent 0)`);
|
|
3675
|
+
L.push(` 4. status githolon status ${plan.workspace} (incarnation + supersession history)`);
|
|
3676
|
+
L.push(" 5. compat githolon compat (clients raise CustodyBreak \u2014 choose adopt/reject)");
|
|
3456
3677
|
return L.join("\n");
|
|
3457
3678
|
}
|
|
3458
3679
|
async function rebirthPlanCommand(ws, opts) {
|
|
@@ -3463,19 +3684,22 @@ async function rebirthPlanCommand(ws, opts) {
|
|
|
3463
3684
|
return 1;
|
|
3464
3685
|
}
|
|
3465
3686
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3466
|
-
const dir = opts.out ??
|
|
3687
|
+
const dir = opts.out ?? join4("rebirths", `${date}-${ws}`);
|
|
3467
3688
|
try {
|
|
3468
3689
|
mkdirSync3(dir, { recursive: true });
|
|
3469
|
-
|
|
3470
|
-
|
|
3690
|
+
writeFileSync4(join4(dir, "plan.json"), JSON.stringify(built.plan, null, 2) + "\n");
|
|
3691
|
+
writeFileSync4(join4(dir, "impact.md"), "```\n" + renderRebirthImpact(built.plan, built.ledgerCommits) + "\n```\n");
|
|
3471
3692
|
} catch (e) {
|
|
3472
3693
|
err2(`could not write the plan into ${dir}: ${e.message}`);
|
|
3473
3694
|
return 1;
|
|
3474
3695
|
}
|
|
3475
3696
|
out2(renderRebirthImpact(built.plan, built.ledgerCommits));
|
|
3476
3697
|
out2("");
|
|
3477
|
-
out2(`\u2713 plan written: ${
|
|
3478
|
-
out2(" fill in `reason`
|
|
3698
|
+
out2(`\u2713 plan written: ${join4(dir, "plan.json")} + ${join4(dir, "impact.md")}`);
|
|
3699
|
+
if (built.plan.reason === null) out2(" fill in the plan's `reason` (the mandatory audit justification) before apply.");
|
|
3700
|
+
out2(" apply requires the ROOT CUSTODIAN seed. The blessed command:");
|
|
3701
|
+
out2(` githolon rebirth apply --plan ${join4(dir, "plan.json")} --gcp-secret ${ROOT_CUSTODIAN_SECRET} [--yes]`);
|
|
3702
|
+
out2(" (--seed-secret <b64> is break-glass \u2014 avoid in shell history; env NOMOS_ROOT_SEED is the CI lane.)");
|
|
3479
3703
|
return 0;
|
|
3480
3704
|
}
|
|
3481
3705
|
async function rebirthWorkspace(ws, opts) {
|
|
@@ -3503,9 +3727,12 @@ async function rebirthWorkspace(ws, opts) {
|
|
|
3503
3727
|
err2("the law refuses to rebirth root \u2014 the seat of the authorizing law cannot supersede itself");
|
|
3504
3728
|
return 1;
|
|
3505
3729
|
}
|
|
3506
|
-
if (opts.plan !== void 0 && Array.isArray(opts.plan.repairs)
|
|
3507
|
-
|
|
3508
|
-
|
|
3730
|
+
if (opts.plan !== void 0 && Array.isArray(opts.plan.repairs)) {
|
|
3731
|
+
const unknown = opts.plan.repairs.find((r2) => r2.execution !== "recorded");
|
|
3732
|
+
if (unknown !== void 0) {
|
|
3733
|
+
err2(`the plan carries a repair with an unsupported execution '${String(unknown.execution)}' \u2014 v1 executes only execution:"recorded" (state-transform verbs land in a future release)`);
|
|
3734
|
+
return 1;
|
|
3735
|
+
}
|
|
3509
3736
|
}
|
|
3510
3737
|
let seed = opts.seedSecret ?? process.env["NOMOS_ROOT_SEED"];
|
|
3511
3738
|
if (seed === void 0 && opts.gcpSecret !== void 0) {
|
|
@@ -3518,7 +3745,7 @@ async function rebirthWorkspace(ws, opts) {
|
|
|
3518
3745
|
}
|
|
3519
3746
|
}
|
|
3520
3747
|
if (seed === void 0 || seed.trim() === "") {
|
|
3521
|
-
err2(
|
|
3748
|
+
err2(`gov rebirth needs the ROOT CUSTODIAN seed \u2014 the blessed path is --gcp-secret ${ROOT_CUSTODIAN_SECRET}; --seed-secret <b64> is break-glass (avoid in shell history), env NOMOS_ROOT_SEED is the CI lane`);
|
|
3522
3749
|
return 1;
|
|
3523
3750
|
}
|
|
3524
3751
|
const cloud = cloudBase(opts.cloud);
|
|
@@ -3578,9 +3805,9 @@ gov rebirth ${ws}:`);
|
|
|
3578
3805
|
}
|
|
3579
3806
|
}
|
|
3580
3807
|
const rebornAt = Date.now();
|
|
3581
|
-
const controllerHash = opts.controllerHash ??
|
|
3808
|
+
const controllerHash = opts.controllerHash ?? await resolveGovernanceHash(cloud, "workspaces");
|
|
3582
3809
|
if (typeof controllerHash !== "string") {
|
|
3583
|
-
err2("could not resolve root's governance
|
|
3810
|
+
err2("could not resolve root's governance (workspaces) law hash from root currentLaw (pass --controller-hash)");
|
|
3584
3811
|
return 1;
|
|
3585
3812
|
}
|
|
3586
3813
|
const res = author2(eng, "root", "workspaces", "rebirthWorkspace", { workspaceId, reason, rebornAt }, controllerHash, { authorSecret: seed, actor: "user:root-custodian" });
|
|
@@ -3628,8 +3855,11 @@ function validatePlanForApply(plan, liveIncarnation) {
|
|
|
3628
3855
|
if (plan.reason === null || typeof plan.reason === "string" && plan.reason.trim() === "") {
|
|
3629
3856
|
return { error: "the plan's `reason` is still null \u2014 fill it in (the mandatory audit justification) before apply" };
|
|
3630
3857
|
}
|
|
3631
|
-
if (Array.isArray(plan.repairs)
|
|
3632
|
-
|
|
3858
|
+
if (Array.isArray(plan.repairs)) {
|
|
3859
|
+
const bad = plan.repairs.find((r) => r.execution !== "recorded");
|
|
3860
|
+
if (bad !== void 0) {
|
|
3861
|
+
return { error: `the plan carries a repair with an unsupported execution '${String(bad.execution)}' \u2014 this CLI executes only execution:"recorded" (state-transform verbs land in a future release)` };
|
|
3862
|
+
}
|
|
3633
3863
|
}
|
|
3634
3864
|
if (plan.pinned.incarnation !== null) {
|
|
3635
3865
|
if (liveIncarnation === void 0) {
|
|
@@ -3643,6 +3873,7 @@ function validatePlanForApply(plan, liveIncarnation) {
|
|
|
3643
3873
|
}
|
|
3644
3874
|
function buildCertificate(args) {
|
|
3645
3875
|
const { plan } = args;
|
|
3876
|
+
const childNames = plan.children.map((c) => c.name);
|
|
3646
3877
|
return {
|
|
3647
3878
|
v: 1,
|
|
3648
3879
|
plan,
|
|
@@ -3651,12 +3882,17 @@ function buildCertificate(args) {
|
|
|
3651
3882
|
custodian: args.custodian,
|
|
3652
3883
|
oldIncarnation: args.oldIncarnation,
|
|
3653
3884
|
newIncarnation: args.newIncarnation,
|
|
3885
|
+
oldHead: args.oldHead ?? args.oldIncarnation,
|
|
3886
|
+
newHead: args.newHead ?? args.newIncarnation,
|
|
3887
|
+
oldCustodyAddress: plan.will.frozenAt,
|
|
3654
3888
|
newCustodyAddress: plan.will.newCustodyAddress,
|
|
3655
3889
|
carried: plan.compaction.carried,
|
|
3656
3890
|
parked: plan.compaction.parked,
|
|
3657
3891
|
verdictBefore: args.verdictBefore,
|
|
3658
3892
|
...args.firstRefusal ? { firstRefusal: args.firstRefusal } : {},
|
|
3659
|
-
verdictAfter: args.verdictAfter
|
|
3893
|
+
verdictAfter: args.verdictAfter,
|
|
3894
|
+
activeLawAfter: args.activeLawAfter ?? {},
|
|
3895
|
+
childrenCarried: { count: childNames.length, names: childNames }
|
|
3660
3896
|
},
|
|
3661
3897
|
supersessionFacts: {
|
|
3662
3898
|
supersededBy: plan.will.newCustodyAddress,
|
|
@@ -3665,6 +3901,7 @@ function buildCertificate(args) {
|
|
|
3665
3901
|
custodian: args.custodian,
|
|
3666
3902
|
at: args.at
|
|
3667
3903
|
},
|
|
3904
|
+
repairs: Array.isArray(plan.repairs) ? plan.repairs : [],
|
|
3668
3905
|
...args.repair !== void 0 ? { repair: args.repair } : {}
|
|
3669
3906
|
};
|
|
3670
3907
|
}
|
|
@@ -3684,6 +3921,14 @@ async function verifyWorkspaceVerdict(cloud, ws) {
|
|
|
3684
3921
|
return { replay: "unknown", firstRefusal: null };
|
|
3685
3922
|
}
|
|
3686
3923
|
}
|
|
3924
|
+
async function currentLawOf(cloud, ws) {
|
|
3925
|
+
try {
|
|
3926
|
+
const d = await (await fetch(`${cloud}/v2/workspaces/${ws}/domains`)).json();
|
|
3927
|
+
return d.currentLaw ?? {};
|
|
3928
|
+
} catch {
|
|
3929
|
+
return {};
|
|
3930
|
+
}
|
|
3931
|
+
}
|
|
3687
3932
|
async function liveIncarnationOf(cloud, ws) {
|
|
3688
3933
|
try {
|
|
3689
3934
|
const s = await (await fetch(`${cloud}/v2/workspaces/${ws}`)).json();
|
|
@@ -3695,7 +3940,7 @@ async function liveIncarnationOf(cloud, ws) {
|
|
|
3695
3940
|
async function rebirthApply(planPath, opts) {
|
|
3696
3941
|
let plan;
|
|
3697
3942
|
try {
|
|
3698
|
-
plan = JSON.parse(
|
|
3943
|
+
plan = JSON.parse(readFileSync3(planPath, "utf8"));
|
|
3699
3944
|
} catch (e) {
|
|
3700
3945
|
err2(`cannot read the plan ${planPath}: ${e.message}`);
|
|
3701
3946
|
return 1;
|
|
@@ -3730,9 +3975,11 @@ async function rebirthApply(planPath, opts) {
|
|
|
3730
3975
|
}
|
|
3731
3976
|
const verdictBefore = plan.verdict.replay === "green" ? "green" : "red";
|
|
3732
3977
|
const custodian = opts.principal ?? activePrincipal() ?? "root-custodian";
|
|
3978
|
+
const repairIds = (plan.repairs ?? []).map((r) => r.id);
|
|
3979
|
+
const effectiveReason = repairIds.length ? `${plan.reason ?? ""} ${repairIds.map((id) => `[repair:${id}]`).join(" ")}`.trim() : plan.reason ?? void 0;
|
|
3733
3980
|
const code = await rebirthWorkspace(ws, {
|
|
3734
3981
|
...opts,
|
|
3735
|
-
reason:
|
|
3982
|
+
reason: effectiveReason,
|
|
3736
3983
|
plan,
|
|
3737
3984
|
quiet: true,
|
|
3738
3985
|
yes: true
|
|
@@ -3743,19 +3990,21 @@ async function rebirthApply(planPath, opts) {
|
|
|
3743
3990
|
}
|
|
3744
3991
|
const newIncarnation = await liveIncarnationOf(cloud, ws) ?? null;
|
|
3745
3992
|
const verdictAfter = await verifyWorkspaceVerdict(cloud, ws);
|
|
3993
|
+
const activeLawAfter = await currentLawOf(cloud, ws);
|
|
3746
3994
|
const cert = buildCertificate({
|
|
3747
3995
|
plan,
|
|
3748
3996
|
custodian,
|
|
3749
3997
|
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3750
3998
|
oldIncarnation: plan.pinned.incarnation,
|
|
3751
3999
|
newIncarnation,
|
|
4000
|
+
activeLawAfter,
|
|
3752
4001
|
verdictBefore,
|
|
3753
4002
|
...plan.verdict.firstRefusal ? { firstRefusal: plan.verdict.firstRefusal } : {},
|
|
3754
4003
|
verdictAfter
|
|
3755
4004
|
});
|
|
3756
|
-
const certPath =
|
|
4005
|
+
const certPath = join4(dirname3(planPath), "certificate.json");
|
|
3757
4006
|
try {
|
|
3758
|
-
|
|
4007
|
+
writeFileSync4(certPath, JSON.stringify(cert, null, 2) + "\n");
|
|
3759
4008
|
} catch (e) {
|
|
3760
4009
|
err2(`the rebirth succeeded but the certificate could not be written to ${certPath}: ${e.message}`);
|
|
3761
4010
|
return 1;
|
|
@@ -3806,12 +4055,14 @@ async function executeRepairRebirth(cloud, ws, repair, verdict, opts) {
|
|
|
3806
4055
|
}
|
|
3807
4056
|
const newIncarnation = await liveIncarnationOf(cloudBaseUrl, ws) ?? null;
|
|
3808
4057
|
const verdictAfter = await verifyWorkspaceVerdict(cloudBaseUrl, ws);
|
|
4058
|
+
const activeLawAfter = await currentLawOf(cloudBaseUrl, ws);
|
|
3809
4059
|
const cert = buildCertificate({
|
|
3810
4060
|
plan,
|
|
3811
4061
|
custodian,
|
|
3812
4062
|
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3813
4063
|
oldIncarnation: plan.pinned.incarnation,
|
|
3814
4064
|
newIncarnation,
|
|
4065
|
+
activeLawAfter,
|
|
3815
4066
|
verdictBefore,
|
|
3816
4067
|
firstRefusal,
|
|
3817
4068
|
verdictAfter,
|
|
@@ -3822,9 +4073,9 @@ async function executeRepairRebirth(cloud, ws, repair, verdict, opts) {
|
|
|
3822
4073
|
note: "repair verb recorded; state transform verbs land in a future release (v1 rebirth only)"
|
|
3823
4074
|
}
|
|
3824
4075
|
});
|
|
3825
|
-
const certPath =
|
|
4076
|
+
const certPath = join4(dirname3(repair.file), "certificate.json");
|
|
3826
4077
|
try {
|
|
3827
|
-
|
|
4078
|
+
writeFileSync4(certPath, JSON.stringify(cert, null, 2) + "\n");
|
|
3828
4079
|
} catch (e) {
|
|
3829
4080
|
err2(`the repair rebirth succeeded but the certificate could not be written to ${certPath}: ${e.message}`);
|
|
3830
4081
|
return 1;
|
|
@@ -3844,13 +4095,14 @@ function readSealedIntentBytes(eng, ws, intentOut) {
|
|
|
3844
4095
|
if (f?.data === void 0) return void 0;
|
|
3845
4096
|
return Buffer.from(f.data).toString("base64");
|
|
3846
4097
|
}
|
|
3847
|
-
var out2, err2, CLIENT_IMPACT;
|
|
4098
|
+
var out2, err2, ROOT_CUSTODIAN_SECRET, CLIENT_IMPACT;
|
|
3848
4099
|
var init_governance = __esm({
|
|
3849
4100
|
"src/governance.ts"() {
|
|
3850
4101
|
"use strict";
|
|
3851
4102
|
init_cloud();
|
|
3852
4103
|
out2 = (s) => void process.stdout.write(s + "\n");
|
|
3853
4104
|
err2 = (s) => void process.stderr.write("error: " + s + "\n");
|
|
4105
|
+
ROOT_CUSTODIAN_SECRET = "nomos-root-custodian-key";
|
|
3854
4106
|
CLIENT_IMPACT = "every connected client raises CustodyBreak(superseded); unsynced client work is invisible to the cloud \u2014 drain/sync clients first";
|
|
3855
4107
|
}
|
|
3856
4108
|
});
|
|
@@ -3874,7 +4126,7 @@ __export(lifecycle_exports, {
|
|
|
3874
4126
|
signingAvailable: () => signingAvailable
|
|
3875
4127
|
});
|
|
3876
4128
|
import { createHash as createHash2 } from "node:crypto";
|
|
3877
|
-
import { readFileSync as
|
|
4129
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
3878
4130
|
async function fetchInstalledLaw(cloud, ws) {
|
|
3879
4131
|
try {
|
|
3880
4132
|
const r = await fetch(`${cloud}/v2/workspaces/${ws}/domains`);
|
|
@@ -3897,7 +4149,7 @@ async function fetchInstalledPackage(cloud, ws, hash) {
|
|
|
3897
4149
|
function readDeployBody(file) {
|
|
3898
4150
|
let body;
|
|
3899
4151
|
try {
|
|
3900
|
-
body = JSON.parse(
|
|
4152
|
+
body = JSON.parse(readFileSync4(file, "utf8"));
|
|
3901
4153
|
} catch (e) {
|
|
3902
4154
|
throw new Error(`deploy body ${file} is not valid JSON \u2014 recompile (githolon compile): ${e.message}`);
|
|
3903
4155
|
}
|
|
@@ -4197,9 +4449,9 @@ __export(cloud_exports, {
|
|
|
4197
4449
|
wsRetire: () => wsRetire,
|
|
4198
4450
|
wsStatus: () => wsStatus
|
|
4199
4451
|
});
|
|
4200
|
-
import { chmodSync, existsSync as
|
|
4452
|
+
import { chmodSync, existsSync as existsSync4, mkdirSync as mkdirSync4, readdirSync as readdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
4201
4453
|
import { createHash as createHash3 } from "node:crypto";
|
|
4202
|
-
import { join as
|
|
4454
|
+
import { join as join5 } from "node:path";
|
|
4203
4455
|
import { homedir } from "node:os";
|
|
4204
4456
|
function cloudBase(flag) {
|
|
4205
4457
|
return (flag ?? process.env["NOMOS_CLOUD"] ?? DEFAULT_CLOUD).replace(/\/+$/, "");
|
|
@@ -4211,18 +4463,18 @@ function authAnonKey() {
|
|
|
4211
4463
|
return process.env["HOLON_AUTH_ANON_KEY"] ?? DEFAULT_AUTH_ANON_KEY;
|
|
4212
4464
|
}
|
|
4213
4465
|
function configDir() {
|
|
4214
|
-
return process.env["HOLON_CONFIG_DIR"] ??
|
|
4466
|
+
return process.env["HOLON_CONFIG_DIR"] ?? join5(homedir(), ".holon");
|
|
4215
4467
|
}
|
|
4216
4468
|
function credsPath() {
|
|
4217
|
-
return
|
|
4469
|
+
return join5(configDir(), "credentials.json");
|
|
4218
4470
|
}
|
|
4219
4471
|
function loadCreds() {
|
|
4220
|
-
if (!
|
|
4221
|
-
return JSON.parse(
|
|
4472
|
+
if (!existsSync4(credsPath())) return { version: 1, secrets: {} };
|
|
4473
|
+
return JSON.parse(readFileSync5(credsPath(), "utf8"));
|
|
4222
4474
|
}
|
|
4223
4475
|
function saveCreds(c) {
|
|
4224
4476
|
mkdirSync4(configDir(), { recursive: true });
|
|
4225
|
-
|
|
4477
|
+
writeFileSync5(credsPath(), JSON.stringify(c, null, 2) + "\n", "utf8");
|
|
4226
4478
|
chmodSync(credsPath(), 384);
|
|
4227
4479
|
}
|
|
4228
4480
|
function getSecret(cloud, ws) {
|
|
@@ -4337,21 +4589,21 @@ async function sessionToken() {
|
|
|
4337
4589
|
}
|
|
4338
4590
|
function discoverDeployJson(cwd, explicit) {
|
|
4339
4591
|
if (explicit !== void 0) {
|
|
4340
|
-
if (!
|
|
4592
|
+
if (!existsSync4(explicit)) throw new Error(`deploy body not found: ${explicit}`);
|
|
4341
4593
|
return explicit;
|
|
4342
4594
|
}
|
|
4343
|
-
const buildDir =
|
|
4344
|
-
if (!
|
|
4595
|
+
const buildDir = join5(cwd, "build");
|
|
4596
|
+
if (!existsSync4(buildDir)) {
|
|
4345
4597
|
throw new Error("no build/ directory \u2014 run `githolon compile` first (or pass --file <path>)");
|
|
4346
4598
|
}
|
|
4347
|
-
const bodies =
|
|
4599
|
+
const bodies = readdirSync3(buildDir).filter((f) => f.endsWith(".deploy.json"));
|
|
4348
4600
|
if (bodies.length === 0) {
|
|
4349
4601
|
throw new Error("no build/*.deploy.json \u2014 run `githolon compile` first (or pass --file <path>)");
|
|
4350
4602
|
}
|
|
4351
4603
|
if (bodies.length > 1) {
|
|
4352
4604
|
throw new Error(`multiple deploy bodies in build/ (${bodies.join(", ")}) \u2014 pass --file <path>`);
|
|
4353
4605
|
}
|
|
4354
|
-
return
|
|
4606
|
+
return join5(buildDir, bodies[0]);
|
|
4355
4607
|
}
|
|
4356
4608
|
async function login(opts) {
|
|
4357
4609
|
if (opts.agent !== true && opts.token === void 0) {
|
|
@@ -4578,7 +4830,7 @@ async function deploy2(ws, opts) {
|
|
|
4578
4830
|
if (signed) {
|
|
4579
4831
|
let body;
|
|
4580
4832
|
try {
|
|
4581
|
-
body = JSON.parse(
|
|
4833
|
+
body = JSON.parse(readFileSync5(file, "utf8"));
|
|
4582
4834
|
} catch (e) {
|
|
4583
4835
|
err4(`deploy body ${file} is not valid JSON \u2014 recompile: ${e.message}`);
|
|
4584
4836
|
return 1;
|
|
@@ -4617,7 +4869,7 @@ async function deploy2(ws, opts) {
|
|
|
4617
4869
|
const r = await fetch(`${cloud}/v2/workspaces/${ws}/domains`, {
|
|
4618
4870
|
method: "POST",
|
|
4619
4871
|
headers: { "content-type": "application/json" },
|
|
4620
|
-
body:
|
|
4872
|
+
body: readFileSync5(file, "utf8")
|
|
4621
4873
|
});
|
|
4622
4874
|
const d = await r.json().catch(() => void 0);
|
|
4623
4875
|
if (!r.ok || d?.ok !== true) {
|
|
@@ -4711,27 +4963,27 @@ __export(editor_exports, {
|
|
|
4711
4963
|
initEditor: () => initEditor,
|
|
4712
4964
|
writeEditorRecommendation: () => writeEditorRecommendation
|
|
4713
4965
|
});
|
|
4714
|
-
import { existsSync as
|
|
4715
|
-
import { dirname as
|
|
4966
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "node:fs";
|
|
4967
|
+
import { dirname as dirname4, join as join6 } from "node:path";
|
|
4716
4968
|
function hasEditorRecommendation(cwd) {
|
|
4717
|
-
const p =
|
|
4718
|
-
if (!
|
|
4969
|
+
const p = join6(cwd, ".vscode", "extensions.json");
|
|
4970
|
+
if (!existsSync5(p)) return false;
|
|
4719
4971
|
try {
|
|
4720
|
-
const json = JSON.parse(
|
|
4972
|
+
const json = JSON.parse(readFileSync6(p, "utf8"));
|
|
4721
4973
|
return Array.isArray(json.recommendations) && json.recommendations.includes(NOMOS_LAW_EXTENSION_ID);
|
|
4722
4974
|
} catch {
|
|
4723
4975
|
return true;
|
|
4724
4976
|
}
|
|
4725
4977
|
}
|
|
4726
4978
|
function writeEditorRecommendation(cwd) {
|
|
4727
|
-
const dir =
|
|
4728
|
-
const path =
|
|
4979
|
+
const dir = join6(cwd, ".vscode");
|
|
4980
|
+
const path = join6(dir, "extensions.json");
|
|
4729
4981
|
let json = {};
|
|
4730
4982
|
let existed = false;
|
|
4731
|
-
if (
|
|
4983
|
+
if (existsSync5(path)) {
|
|
4732
4984
|
existed = true;
|
|
4733
4985
|
try {
|
|
4734
|
-
const parsed = JSON.parse(
|
|
4986
|
+
const parsed = JSON.parse(readFileSync6(path, "utf8"));
|
|
4735
4987
|
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
4736
4988
|
json = parsed;
|
|
4737
4989
|
} else {
|
|
@@ -4749,8 +5001,8 @@ function writeEditorRecommendation(cwd) {
|
|
|
4749
5001
|
}
|
|
4750
5002
|
recs.push(NOMOS_LAW_EXTENSION_ID);
|
|
4751
5003
|
json.recommendations = recs;
|
|
4752
|
-
mkdirSync5(
|
|
4753
|
-
|
|
5004
|
+
mkdirSync5(dirname4(path), { recursive: true });
|
|
5005
|
+
writeFileSync6(path, JSON.stringify(json, null, 2) + "\n", "utf8");
|
|
4754
5006
|
return { path, action: existed ? "updated" : "created" };
|
|
4755
5007
|
}
|
|
4756
5008
|
function initEditor(cwd = process.cwd()) {
|
|
@@ -4784,21 +5036,21 @@ var init_editor = __esm({
|
|
|
4784
5036
|
});
|
|
4785
5037
|
|
|
4786
5038
|
// src/compile.ts
|
|
4787
|
-
import { spawn, spawnSync } from "node:child_process";
|
|
4788
|
-
import { createRequire } from "node:module";
|
|
4789
|
-
import { dirname as
|
|
4790
|
-
import { pathToFileURL } from "node:url";
|
|
5039
|
+
import { spawn, spawnSync as spawnSync2 } from "node:child_process";
|
|
5040
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
5041
|
+
import { dirname as dirname5, join as join7 } from "node:path";
|
|
5042
|
+
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
4791
5043
|
function resolveCompileLauncher(cwd) {
|
|
4792
5044
|
const resolveDslPkg = (fromDir) => {
|
|
4793
5045
|
try {
|
|
4794
|
-
const req = fromDir === void 0 ?
|
|
5046
|
+
const req = fromDir === void 0 ? createRequire2(import.meta.url) : createRequire2(pathToFileURL2(join7(fromDir, "noop.js")));
|
|
4795
5047
|
return req.resolve("@githolon/dsl/package.json");
|
|
4796
5048
|
} catch {
|
|
4797
5049
|
return void 0;
|
|
4798
5050
|
}
|
|
4799
5051
|
};
|
|
4800
5052
|
const dslPkg = resolveDslPkg(cwd) ?? resolveDslPkg(void 0);
|
|
4801
|
-
return dslPkg === void 0 ? void 0 :
|
|
5053
|
+
return dslPkg === void 0 ? void 0 : join7(dirname5(dslPkg), "compile_package.mjs");
|
|
4802
5054
|
}
|
|
4803
5055
|
function runCompile(args) {
|
|
4804
5056
|
const launcher = resolveCompileLauncher(process.cwd());
|
|
@@ -4807,7 +5059,7 @@ function runCompile(args) {
|
|
|
4807
5059
|
`);
|
|
4808
5060
|
return 1;
|
|
4809
5061
|
}
|
|
4810
|
-
const r =
|
|
5062
|
+
const r = spawnSync2(process.execPath, [launcher, ...args], { stdio: "inherit", cwd: process.cwd() });
|
|
4811
5063
|
const status2 = r.status ?? 1;
|
|
4812
5064
|
if (status2 === 0 && process.stdout.isTTY) {
|
|
4813
5065
|
try {
|
|
@@ -4821,7 +5073,7 @@ ${INIT_EDITOR_HINT}
|
|
|
4821
5073
|
}
|
|
4822
5074
|
function resolveCheckLauncher(cwd) {
|
|
4823
5075
|
const launcher = resolveCompileLauncher(cwd);
|
|
4824
|
-
return launcher === void 0 ? void 0 :
|
|
5076
|
+
return launcher === void 0 ? void 0 : join7(dirname5(launcher), "check_package.mjs");
|
|
4825
5077
|
}
|
|
4826
5078
|
function runCheck(args) {
|
|
4827
5079
|
const launcher = resolveCheckLauncher(process.cwd());
|
|
@@ -4830,12 +5082,12 @@ function runCheck(args) {
|
|
|
4830
5082
|
`);
|
|
4831
5083
|
return 1;
|
|
4832
5084
|
}
|
|
4833
|
-
const r =
|
|
5085
|
+
const r = spawnSync2(process.execPath, [launcher, ...args], { stdio: "inherit", cwd: process.cwd() });
|
|
4834
5086
|
return r.status ?? 1;
|
|
4835
5087
|
}
|
|
4836
5088
|
function resolveCompatLauncher(cwd) {
|
|
4837
5089
|
const launcher = resolveCompileLauncher(cwd);
|
|
4838
|
-
return launcher === void 0 ? void 0 :
|
|
5090
|
+
return launcher === void 0 ? void 0 : join7(dirname5(launcher), "compat_package.mjs");
|
|
4839
5091
|
}
|
|
4840
5092
|
function runCompat(args) {
|
|
4841
5093
|
const launcher = resolveCompatLauncher(process.cwd());
|
|
@@ -4844,12 +5096,12 @@ function runCompat(args) {
|
|
|
4844
5096
|
`);
|
|
4845
5097
|
return 1;
|
|
4846
5098
|
}
|
|
4847
|
-
const r =
|
|
5099
|
+
const r = spawnSync2(process.execPath, [launcher, ...args], { stdio: "inherit", cwd: process.cwd() });
|
|
4848
5100
|
return r.status ?? 1;
|
|
4849
5101
|
}
|
|
4850
5102
|
function resolveLspLauncher(cwd) {
|
|
4851
5103
|
const launcher = resolveCompileLauncher(cwd);
|
|
4852
|
-
return launcher === void 0 ? void 0 :
|
|
5104
|
+
return launcher === void 0 ? void 0 : join7(dirname5(launcher), "lsp_server.mjs");
|
|
4853
5105
|
}
|
|
4854
5106
|
function runLsp(args) {
|
|
4855
5107
|
const launcher = resolveLspLauncher(process.cwd());
|
|
@@ -4858,7 +5110,7 @@ function runLsp(args) {
|
|
|
4858
5110
|
`);
|
|
4859
5111
|
return 1;
|
|
4860
5112
|
}
|
|
4861
|
-
const r =
|
|
5113
|
+
const r = spawnSync2(process.execPath, [launcher, ...args], { stdio: "inherit", cwd: process.cwd() });
|
|
4862
5114
|
return r.status ?? 1;
|
|
4863
5115
|
}
|
|
4864
5116
|
function compileAsync(cwd, args = []) {
|
|
@@ -4898,8 +5150,8 @@ __export(proof_offline_exports, {
|
|
|
4898
5150
|
runOfflineProofStandalone: () => runOfflineProofStandalone,
|
|
4899
5151
|
runRelationBootstrapLeg: () => runRelationBootstrapLeg
|
|
4900
5152
|
});
|
|
4901
|
-
import { existsSync as
|
|
4902
|
-
import { basename, dirname as
|
|
5153
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
|
|
5154
|
+
import { basename, dirname as dirname6, join as join9 } from "node:path";
|
|
4903
5155
|
function parseOfflineLegs(proofSource) {
|
|
4904
5156
|
if (!proofSource.includes("AUTO-GENERATED by nomos-compile")) {
|
|
4905
5157
|
throw new Error("not a generated proof (missing the AUTO-GENERATED header) \u2014 run `githolon compile` to (re)generate build/<name>.proof.mts");
|
|
@@ -5324,16 +5576,16 @@ function actorFromPayload(payload, field) {
|
|
|
5324
5576
|
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
5325
5577
|
}
|
|
5326
5578
|
async function runOfflineProofStandalone(proofPath, cloud, domain) {
|
|
5327
|
-
const src =
|
|
5579
|
+
const src = readFileSync7(proofPath, "utf8");
|
|
5328
5580
|
const packageName = basename(proofPath).replace(/\.proof\.mts$/, "");
|
|
5329
|
-
const deployFile =
|
|
5330
|
-
if (!
|
|
5581
|
+
const deployFile = join9(dirname6(proofPath), `${packageName}.deploy.json`);
|
|
5582
|
+
if (!existsSync7(deployFile)) {
|
|
5331
5583
|
throw new Error(`missing ${deployFile} \u2014 run \`githolon compile\` (the proof and the deploy body are built together)`);
|
|
5332
5584
|
}
|
|
5333
5585
|
let legs;
|
|
5334
|
-
const legsFile =
|
|
5335
|
-
if (
|
|
5336
|
-
const index = JSON.parse(
|
|
5586
|
+
const legsFile = join9(dirname6(proofPath), `${packageName}.proof-legs.json`);
|
|
5587
|
+
if (existsSync7(legsFile)) {
|
|
5588
|
+
const index = JSON.parse(readFileSync7(legsFile, "utf8"));
|
|
5337
5589
|
const keys = Object.keys(index.domains);
|
|
5338
5590
|
const chosen = domain ?? index.default;
|
|
5339
5591
|
if (index.domains[chosen] === void 0) {
|
|
@@ -5351,7 +5603,7 @@ async function runOfflineProofStandalone(proofPath, cloud, domain) {
|
|
|
5351
5603
|
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`);
|
|
5352
5604
|
legs = parseOfflineLegs(src);
|
|
5353
5605
|
}
|
|
5354
|
-
const deployBody = JSON.parse(
|
|
5606
|
+
const deployBody = JSON.parse(readFileSync7(deployFile, "utf8"));
|
|
5355
5607
|
const lawHash = await sha256hex(deployBody.packageUsda);
|
|
5356
5608
|
console.log(`githolon proof \u2014 OFFLINE legs on a local holon (the cloud loop: githolon proof --live)`);
|
|
5357
5609
|
const { eng } = await holonEngine(cloud, deployBody, "githolon-proof");
|
|
@@ -5378,147 +5630,6 @@ var init_proof_offline = __esm({
|
|
|
5378
5630
|
}
|
|
5379
5631
|
});
|
|
5380
5632
|
|
|
5381
|
-
// src/repairs.ts
|
|
5382
|
-
var repairs_exports = {};
|
|
5383
|
-
__export(repairs_exports, {
|
|
5384
|
-
discoverRepairs: () => discoverRepairs,
|
|
5385
|
-
knownRepairBlock: () => knownRepairBlock,
|
|
5386
|
-
matchRepair: () => matchRepair,
|
|
5387
|
-
parseRefusal: () => parseRefusal
|
|
5388
|
-
});
|
|
5389
|
-
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
5390
|
-
import { createRequire as createRequire2 } from "node:module";
|
|
5391
|
-
import { existsSync as existsSync9, mkdtempSync, readdirSync as readdirSync4, readFileSync as readFileSync10, rmSync, writeFileSync as writeFileSync7 } from "node:fs";
|
|
5392
|
-
import { tmpdir } from "node:os";
|
|
5393
|
-
import { dirname as dirname7, isAbsolute, join as join11, resolve as resolve2 } from "node:path";
|
|
5394
|
-
import { pathToFileURL as pathToFileURL4 } from "node:url";
|
|
5395
|
-
function parseRefusal(verdict) {
|
|
5396
|
-
const check2 = String(verdict["check"] ?? "");
|
|
5397
|
-
const error = String(verdict["error"] ?? "");
|
|
5398
|
-
const raw = `${check2}: ${error}`;
|
|
5399
|
-
const kind = /evolve.?gate/i.test(raw) || /evolve/i.test(check2) ? "evolve-gate" : "other";
|
|
5400
|
-
const sids = /* @__PURE__ */ new Set();
|
|
5401
|
-
const structured = verdict["stableId"] ?? verdict["stableIds"];
|
|
5402
|
-
if (typeof structured === "string" && SID_SHAPE.test(structured)) sids.add(structured.toLowerCase());
|
|
5403
|
-
if (Array.isArray(structured)) {
|
|
5404
|
-
for (const s of structured) if (typeof s === "string" && SID_SHAPE.test(s)) sids.add(s.toLowerCase());
|
|
5405
|
-
}
|
|
5406
|
-
for (const m of raw.matchAll(SID_RE)) sids.add(m[1].toLowerCase());
|
|
5407
|
-
return { kind, stableIds: [...sids], raw };
|
|
5408
|
-
}
|
|
5409
|
-
function matchRepair(refusal, repairs) {
|
|
5410
|
-
if (refusal.kind === "other") return void 0;
|
|
5411
|
-
return repairs.find(
|
|
5412
|
-
(r) => r.matcher.refusal === refusal.kind && refusal.stableIds.includes(r.matcher.stableId.toLowerCase())
|
|
5413
|
-
);
|
|
5414
|
-
}
|
|
5415
|
-
function knownRepairBlock(repair) {
|
|
5416
|
-
return [
|
|
5417
|
-
"",
|
|
5418
|
-
`\u2726 KNOWN REPAIR: '${repair.id}' (${repair.file}) declares a remedy for exactly this refusal.`,
|
|
5419
|
-
` reason: ${repair.reason}`,
|
|
5420
|
-
" Re-run with --repair to execute it."
|
|
5421
|
-
].join("\n");
|
|
5422
|
-
}
|
|
5423
|
-
function resolveTsxCli(cwd) {
|
|
5424
|
-
const pkgDir = (name, fromDir) => {
|
|
5425
|
-
try {
|
|
5426
|
-
return dirname7(createRequire2(pathToFileURL4(join11(fromDir, "noop.js")).href).resolve(`${name}/package.json`));
|
|
5427
|
-
} catch {
|
|
5428
|
-
return void 0;
|
|
5429
|
-
}
|
|
5430
|
-
};
|
|
5431
|
-
const dslDir = pkgDir("@githolon/dsl", cwd) ?? (() => {
|
|
5432
|
-
try {
|
|
5433
|
-
return dirname7(createRequire2(import.meta.url).resolve("@githolon/dsl/package.json"));
|
|
5434
|
-
} catch {
|
|
5435
|
-
return void 0;
|
|
5436
|
-
}
|
|
5437
|
-
})();
|
|
5438
|
-
const tsxDir = pkgDir("tsx", cwd) ?? (dslDir !== void 0 ? pkgDir("tsx", dslDir) : void 0);
|
|
5439
|
-
if (tsxDir === void 0) return void 0;
|
|
5440
|
-
try {
|
|
5441
|
-
const pkg = JSON.parse(
|
|
5442
|
-
readFileSync10(join11(tsxDir, "package.json"), "utf8")
|
|
5443
|
-
);
|
|
5444
|
-
const rel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.["tsx"];
|
|
5445
|
-
return join11(tsxDir, rel ?? "dist/cli.mjs");
|
|
5446
|
-
} catch {
|
|
5447
|
-
return void 0;
|
|
5448
|
-
}
|
|
5449
|
-
}
|
|
5450
|
-
function resolveDslEntry(cwd) {
|
|
5451
|
-
const tryFrom = (fromUrl) => {
|
|
5452
|
-
try {
|
|
5453
|
-
return createRequire2(fromUrl).resolve("@githolon/dsl");
|
|
5454
|
-
} catch {
|
|
5455
|
-
return void 0;
|
|
5456
|
-
}
|
|
5457
|
-
};
|
|
5458
|
-
return tryFrom(pathToFileURL4(join11(cwd, "noop.js")).href) ?? tryFrom(import.meta.url);
|
|
5459
|
-
}
|
|
5460
|
-
function discoverRepairs(cwd) {
|
|
5461
|
-
const dir = join11(cwd, "repairs");
|
|
5462
|
-
if (!existsSync9(dir)) return { repairs: [] };
|
|
5463
|
-
let files;
|
|
5464
|
-
try {
|
|
5465
|
-
files = readdirSync4(dir).filter((f) => /\.(ts|mts|cts)$/.test(f) && !/\.d\.ts$/.test(f)).sort().map((f) => resolve2(dir, f));
|
|
5466
|
-
} catch (e) {
|
|
5467
|
-
return { error: `could not read the repairs/ folder: ${e.message}` };
|
|
5468
|
-
}
|
|
5469
|
-
if (files.length === 0) return { repairs: [] };
|
|
5470
|
-
const tsxCli = resolveTsxCli(cwd);
|
|
5471
|
-
const dslEntry = resolveDslEntry(cwd);
|
|
5472
|
-
if (tsxCli === void 0 || dslEntry === void 0) {
|
|
5473
|
-
return { error: "repairs/ is present but the toolchain to load it is missing \u2014 add @githolon/dsl (tsx + the DSL ride it) to the project and npm install" };
|
|
5474
|
-
}
|
|
5475
|
-
const scratch = mkdtempSync(join11(tmpdir(), "githolon-repairs-"));
|
|
5476
|
-
const loader = join11(scratch, "discover.mts");
|
|
5477
|
-
const loaderSrc = `
|
|
5478
|
-
import { repairsOf } from ${JSON.stringify(dslEntry)};
|
|
5479
|
-
const files = ${JSON.stringify(files)};
|
|
5480
|
-
const out = [];
|
|
5481
|
-
const seen = new Map();
|
|
5482
|
-
for (const file of files) {
|
|
5483
|
-
const mod = await import(${JSON.stringify("file://")} + file);
|
|
5484
|
-
for (const r of repairsOf(mod)) {
|
|
5485
|
-
if (seen.has(r.id)) {
|
|
5486
|
-
throw new Error("duplicate repair id '" + r.id + "' \u2014 declared in " + seen.get(r.id) + " and " + file);
|
|
5487
|
-
}
|
|
5488
|
-
seen.set(r.id, file);
|
|
5489
|
-
out.push({ id: r.id, matcher: r.matcher, reason: r.reason, verb: r.verb, file });
|
|
5490
|
-
}
|
|
5491
|
-
}
|
|
5492
|
-
process.stdout.write("\\u0001REPAIRS\\u0001" + JSON.stringify(out) + "\\u0001END\\u0001\\n");
|
|
5493
|
-
`;
|
|
5494
|
-
try {
|
|
5495
|
-
writeFileSync7(loader, loaderSrc, "utf8");
|
|
5496
|
-
const r = spawnSync4(process.execPath, [tsxCli, loader], { cwd, encoding: "utf8" });
|
|
5497
|
-
if (r.status !== 0) {
|
|
5498
|
-
const msg = (r.stderr || r.stdout || "").trim().split("\n").filter(Boolean).slice(-4).join("\n");
|
|
5499
|
-
return { error: `loading repairs/ failed:
|
|
5500
|
-
${msg || `tsx exited ${r.status ?? "?"}`}` };
|
|
5501
|
-
}
|
|
5502
|
-
const m = /REPAIRS([\s\S]*?)END/.exec(r.stdout);
|
|
5503
|
-
if (m === null) return { error: "the repairs loader produced no manifest (unexpected \u2014 the DSL/tsx may be too old)" };
|
|
5504
|
-
const parsed = JSON.parse(m[1]);
|
|
5505
|
-
const repairs = parsed.map((p) => ({ ...p, file: isAbsolute(p.file) ? p.file : resolve2(cwd, p.file) }));
|
|
5506
|
-
return { repairs };
|
|
5507
|
-
} catch (e) {
|
|
5508
|
-
return { error: `loading repairs/ failed: ${e.message}` };
|
|
5509
|
-
} finally {
|
|
5510
|
-
rmSync(scratch, { recursive: true, force: true });
|
|
5511
|
-
}
|
|
5512
|
-
}
|
|
5513
|
-
var SID_RE, SID_SHAPE;
|
|
5514
|
-
var init_repairs = __esm({
|
|
5515
|
-
"src/repairs.ts"() {
|
|
5516
|
-
"use strict";
|
|
5517
|
-
SID_RE = /stable id ([0-9a-f]{16})/gi;
|
|
5518
|
-
SID_SHAPE = /^[0-9a-f]{16}$/i;
|
|
5519
|
-
}
|
|
5520
|
-
});
|
|
5521
|
-
|
|
5522
5633
|
// src/mcp.ts
|
|
5523
5634
|
var mcp_exports = {};
|
|
5524
5635
|
__export(mcp_exports, {
|
|
@@ -7258,20 +7369,20 @@ init_engine();
|
|
|
7258
7369
|
init_cloud();
|
|
7259
7370
|
init_compile();
|
|
7260
7371
|
init_local_holon();
|
|
7261
|
-
import { existsSync as
|
|
7372
|
+
import { existsSync as existsSync8, readFileSync as readFileSync8, watch } from "node:fs";
|
|
7262
7373
|
import { createServer } from "node:http";
|
|
7263
|
-
import { dirname as
|
|
7264
|
-
import { pathToFileURL as
|
|
7374
|
+
import { dirname as dirname7, join as join10, resolve as resolve2 } from "node:path";
|
|
7375
|
+
import { pathToFileURL as pathToFileURL4 } from "node:url";
|
|
7265
7376
|
|
|
7266
7377
|
// src/project.ts
|
|
7267
|
-
import { existsSync as
|
|
7268
|
-
import { join as
|
|
7269
|
-
import { pathToFileURL as
|
|
7378
|
+
import { existsSync as existsSync6, statSync as statSync2 } from "node:fs";
|
|
7379
|
+
import { join as join8 } from "node:path";
|
|
7380
|
+
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
7270
7381
|
var CONFIG_FILE = "nomos.package.mjs";
|
|
7271
7382
|
async function loadProject(cwd, opts = {}) {
|
|
7272
|
-
const configPath =
|
|
7273
|
-
if (!
|
|
7274
|
-
const href =
|
|
7383
|
+
const configPath = join8(cwd, CONFIG_FILE);
|
|
7384
|
+
if (!existsSync6(configPath)) return void 0;
|
|
7385
|
+
const href = pathToFileURL3(configPath).href + (opts.bust === true ? `?v=${statSync2(configPath).mtimeMs}-${Date.now()}` : "");
|
|
7275
7386
|
const mod = await import(href);
|
|
7276
7387
|
const cfg = mod.default;
|
|
7277
7388
|
if (cfg === void 0 || typeof cfg.name !== "string" || cfg.name.length === 0) {
|
|
@@ -7435,11 +7546,11 @@ function startServer(s) {
|
|
|
7435
7546
|
});
|
|
7436
7547
|
}
|
|
7437
7548
|
function readDeployBody2(cwd, packageName) {
|
|
7438
|
-
const file =
|
|
7439
|
-
if (!
|
|
7549
|
+
const file = join10(cwd, "build", `${packageName}.deploy.json`);
|
|
7550
|
+
if (!existsSync8(file)) {
|
|
7440
7551
|
throw new Error(`compile produced no ${file} \u2014 check the compile output above`);
|
|
7441
7552
|
}
|
|
7442
|
-
return JSON.parse(
|
|
7553
|
+
return JSON.parse(readFileSync8(file, "utf8"));
|
|
7443
7554
|
}
|
|
7444
7555
|
async function installLaw(s, deployBody, installedBy) {
|
|
7445
7556
|
const newHash = await sha256hex(deployBody.packageUsda);
|
|
@@ -7455,11 +7566,11 @@ async function installLaw(s, deployBody, installedBy) {
|
|
|
7455
7566
|
return { ok: true };
|
|
7456
7567
|
}
|
|
7457
7568
|
async function runProofCycle(s, cwd, deployBody, installedBy) {
|
|
7458
|
-
const proofPath =
|
|
7459
|
-
if (!
|
|
7569
|
+
const proofPath = join10(cwd, "build", `${s.packageName}.proof.mts`);
|
|
7570
|
+
if (!existsSync8(proofPath)) return void 0;
|
|
7460
7571
|
const scratch = `proof-${s.cycle}`;
|
|
7461
7572
|
try {
|
|
7462
|
-
const legs = parseOfflineLegs(
|
|
7573
|
+
const legs = parseOfflineLegs(readFileSync8(proofPath, "utf8"));
|
|
7463
7574
|
await mountFresh(s.eng, scratch);
|
|
7464
7575
|
author(s.eng, scratch, "bootstrap", "installDomain", installPayload(s.eng.hashes.nomos, s.eng.nomosPkg, installedBy), "");
|
|
7465
7576
|
author(s.eng, scratch, "nomos", "installDomain", installPayload(s.lawHash, deployBody.packageUsda, installedBy), s.eng.hashes.nomos);
|
|
@@ -7478,7 +7589,7 @@ async function dev(opts) {
|
|
|
7478
7589
|
return void 0;
|
|
7479
7590
|
});
|
|
7480
7591
|
if (project === void 0) {
|
|
7481
|
-
if (!
|
|
7592
|
+
if (!existsSync8(join10(cwd, CONFIG_FILE))) {
|
|
7482
7593
|
err5(`no ${CONFIG_FILE} here (${cwd}) \u2014 \`githolon dev\` runs inside a project; scaffold one from examples/guestbook or \`githolon generate domain <name>\``);
|
|
7483
7594
|
}
|
|
7484
7595
|
return 1;
|
|
@@ -7543,14 +7654,14 @@ ${firstCompile.output}`);
|
|
|
7543
7654
|
}
|
|
7544
7655
|
const moduleDirs = /* @__PURE__ */ new Set();
|
|
7545
7656
|
try {
|
|
7546
|
-
const cfgModule = await import(
|
|
7657
|
+
const cfgModule = await import(pathToFileURL4(project.configPath).href);
|
|
7547
7658
|
for (const d of cfgModule.default?.domains ?? []) {
|
|
7548
|
-
for (const m of d.modules ?? []) moduleDirs.add(
|
|
7659
|
+
for (const m of d.modules ?? []) moduleDirs.add(dirname7(resolve2(cwd, m)));
|
|
7549
7660
|
}
|
|
7550
7661
|
} catch {
|
|
7551
|
-
moduleDirs.add(
|
|
7662
|
+
moduleDirs.add(join10(cwd, "domains"));
|
|
7552
7663
|
}
|
|
7553
|
-
if (moduleDirs.size === 0) moduleDirs.add(
|
|
7664
|
+
if (moduleDirs.size === 0) moduleDirs.add(join10(cwd, "domains"));
|
|
7554
7665
|
let timer;
|
|
7555
7666
|
let cycling = false;
|
|
7556
7667
|
let queued = false;
|
|
@@ -7600,7 +7711,7 @@ ${run.output}`);
|
|
|
7600
7711
|
};
|
|
7601
7712
|
const watchers = [];
|
|
7602
7713
|
for (const d of moduleDirs) {
|
|
7603
|
-
if (!
|
|
7714
|
+
if (!existsSync8(d)) continue;
|
|
7604
7715
|
watchers.push(watch(d, { recursive: true }, (_evt, f) => onChange(f)));
|
|
7605
7716
|
s.watchRoots.push(d.startsWith(cwd) ? d.slice(cwd.length + 1) + "/" : d);
|
|
7606
7717
|
}
|
|
@@ -7625,13 +7736,13 @@ ${run.output}`);
|
|
|
7625
7736
|
|
|
7626
7737
|
// src/git.ts
|
|
7627
7738
|
init_cloud();
|
|
7628
|
-
import { spawnSync as
|
|
7739
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
7629
7740
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
7630
|
-
import { readFileSync as
|
|
7741
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
7631
7742
|
var out6 = (s) => void process.stdout.write(s + "\n");
|
|
7632
7743
|
var err6 = (s) => void process.stderr.write("error: " + s + "\n");
|
|
7633
7744
|
function git(args, opts = {}) {
|
|
7634
|
-
const r =
|
|
7745
|
+
const r = spawnSync3("git", args, { stdio: opts.quiet === true ? "ignore" : "inherit" });
|
|
7635
7746
|
return r.status ?? 1;
|
|
7636
7747
|
}
|
|
7637
7748
|
function ensureSecret(cloud, ws) {
|
|
@@ -7656,7 +7767,7 @@ function workspaceFromPath(path) {
|
|
|
7656
7767
|
}
|
|
7657
7768
|
async function gitCredential(action) {
|
|
7658
7769
|
if (action !== "get") return 0;
|
|
7659
|
-
const kv = parseCredentialInput(
|
|
7770
|
+
const kv = parseCredentialInput(readFileSync9(0, "utf8"));
|
|
7660
7771
|
const ws = workspaceFromPath(kv["path"]);
|
|
7661
7772
|
if (kv["protocol"] !== "https" || ws === void 0) return 0;
|
|
7662
7773
|
const cloud = `https://${kv["host"]}`;
|
|
@@ -7878,6 +7989,23 @@ var HELP = {
|
|
|
7878
7989
|
"githolon gov relay root co2.offer.json"
|
|
7879
7990
|
]
|
|
7880
7991
|
},
|
|
7992
|
+
rebirth: {
|
|
7993
|
+
usage: "githolon rebirth plan <ws> [--reason <text>] [--out <dir>]\n githolon rebirth apply --plan <plan.json> --gcp-secret nomos-root-custodian-key [--yes]",
|
|
7994
|
+
what: "LAWFUL SUPERSESSION as code (the migrations-folder workflow; architecture/rebirth_and_custody_lifecycle.md).\n`plan` writes a read-only, drift-pinned plan.json + impact.md into rebirths/<date>-<ws>/ \u2014 the reviewable\nintent (pinned incarnation, law lifecycle, children, verdict, and any MATCHED repairs from repairs/*.ts).\n`apply` drives the reviewed plan through the signed rebirth path \u2192 certificate.json beside it.\nAPPLY REQUIRES THE ROOT CUSTODIAN SEED \u2014 the blessed path is --gcp-secret nomos-root-custodian-key;\n--seed-secret <b64> is break-glass (avoid in shell history), env NOMOS_ROOT_SEED is the CI lane.\n\nTHE BLESSED GOLDEN PATH:\n 1. githolon rebirth plan <ws>\n 2. githolon rebirth apply --plan <path> --gcp-secret nomos-root-custodian-key [--yes]\n 3. githolon replay <ws> (expect GREEN from intent 0)\n 4. githolon status <ws> (incarnation + supersession history)\n 5. githolon compat (clients raise CustodyBreak \u2014 choose adopt/reject)",
|
|
7995
|
+
flags: [
|
|
7996
|
+
["--reason <text>", "the mandatory audit justification (fill it into the plan before apply)"],
|
|
7997
|
+
["--out <dir>", "plan: an alternate output dir (default: rebirths/<date>-<ws>)"],
|
|
7998
|
+
["--plan <plan.json>", "apply: the reviewed plan file to execute (drift-pinned)"],
|
|
7999
|
+
["--gcp-secret <name>", "apply: read the root custodian seed from this GCP secret (blessed: nomos-root-custodian-key)"],
|
|
8000
|
+
["--seed-secret <b64>", "apply: break-glass \u2014 the seed inline (avoid in shell history)"],
|
|
8001
|
+
["--yes", "apply: skip the interactive confirm"],
|
|
8002
|
+
["--cloud <url>", "target cloud"]
|
|
8003
|
+
],
|
|
8004
|
+
examples: [
|
|
8005
|
+
"githolon rebirth plan co2-platform --reason 'evolve-gate scar at intent 74'",
|
|
8006
|
+
"githolon rebirth apply --plan rebirths/2026-07-09-co2-platform/plan.json --gcp-secret nomos-root-custodian-key --yes"
|
|
8007
|
+
]
|
|
8008
|
+
},
|
|
7881
8009
|
grant: {
|
|
7882
8010
|
usage: "githolon grant <admin|creation|quota> <principal> [--max <N>] [--label <L>] [--parent <ws>] [--cloud <url>]",
|
|
7883
8011
|
what: "Grant authority as a SIGNED governance offer to the parent (default root) \u2014 never a host\nendpoint. The grant is attributed to YOUR signing principal; only an admin's signature is\nadmitted by the far-side gate. `admin`/`creation` grant the principal-centric relation; `quota`\ngrants a per-principal workspace allowance (--max). Enroll a device key first (githolon key enroll).",
|
|
@@ -7958,15 +8086,15 @@ function commandHelp(cmd) {
|
|
|
7958
8086
|
init_engine();
|
|
7959
8087
|
init_cloud();
|
|
7960
8088
|
init_local_holon();
|
|
7961
|
-
import { spawnSync as
|
|
7962
|
-
import { existsSync as
|
|
7963
|
-
import { join as
|
|
8089
|
+
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
8090
|
+
import { existsSync as existsSync9, readdirSync as readdirSync4, readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "node:fs";
|
|
8091
|
+
import { join as join11 } from "node:path";
|
|
7964
8092
|
var out7 = (s) => void process.stdout.write(s + "\n");
|
|
7965
8093
|
var err7 = (s) => void process.stderr.write("error: " + s + "\n");
|
|
7966
8094
|
var WS2 = "local";
|
|
7967
8095
|
async function ledgerInit(dir, opts) {
|
|
7968
8096
|
const cloud = cloudBase(opts.cloud);
|
|
7969
|
-
if (
|
|
8097
|
+
if (existsSync9(dir) && readdirSync4(dir).length > 0) {
|
|
7970
8098
|
err7(`refusing to mint into non-empty directory: ${dir}`);
|
|
7971
8099
|
return 1;
|
|
7972
8100
|
}
|
|
@@ -7977,7 +8105,7 @@ async function ledgerInit(dir, opts) {
|
|
|
7977
8105
|
err7(e.message);
|
|
7978
8106
|
return 1;
|
|
7979
8107
|
}
|
|
7980
|
-
const deployBody = JSON.parse(
|
|
8108
|
+
const deployBody = JSON.parse(readFileSync10(deployFile, "utf8"));
|
|
7981
8109
|
const domainHash = await sha256hex(deployBody.packageUsda);
|
|
7982
8110
|
const c = loadCreds();
|
|
7983
8111
|
const principal = await sessionToken().catch(() => void 0) !== void 0 ? c.session.uid : c.principal;
|
|
@@ -7993,11 +8121,11 @@ async function ledgerInit(dir, opts) {
|
|
|
7993
8121
|
const verdict = verifyChainLocal(eng, WS2);
|
|
7994
8122
|
if (!printVerdict(verdict)) return 1;
|
|
7995
8123
|
const gitTree = eng.preopen.dir.contents.get("ws").contents.get(WS2).contents.get("nomos.git");
|
|
7996
|
-
const gitDir =
|
|
8124
|
+
const gitDir = join11(dir, ".git");
|
|
7997
8125
|
writeTreeToDisk(gitTree, gitDir);
|
|
7998
|
-
const cfgPath =
|
|
7999
|
-
|
|
8000
|
-
|
|
8126
|
+
const cfgPath = join11(gitDir, "config");
|
|
8127
|
+
writeFileSync7(cfgPath, readFileSync10(cfgPath, "utf8").replace(/bare = true/, "bare = false"), "utf8");
|
|
8128
|
+
spawnSync4("git", ["-C", dir, "reset", "--hard", "main"], { stdio: "ignore" });
|
|
8001
8129
|
out7(`\u2713 holon written \u2192 ${dir} (a normal git repo; git log IS the audit trail)`);
|
|
8002
8130
|
out7(`
|
|
8003
8131
|
Birth it on Nomos Cloud (the cloud re-derives this exact verdict):`);
|
|
@@ -8005,8 +8133,8 @@ Birth it on Nomos Cloud (the cloud re-derives this exact verdict):`);
|
|
|
8005
8133
|
return 0;
|
|
8006
8134
|
}
|
|
8007
8135
|
async function ledgerVerify(dir, opts) {
|
|
8008
|
-
const gitDir =
|
|
8009
|
-
if (!
|
|
8136
|
+
const gitDir = existsSync9(join11(dir, ".git")) ? join11(dir, ".git") : dir;
|
|
8137
|
+
if (!existsSync9(join11(gitDir, "HEAD"))) {
|
|
8010
8138
|
err7(`${dir} is not a git repo (no HEAD)`);
|
|
8011
8139
|
return 1;
|
|
8012
8140
|
}
|
|
@@ -8480,7 +8608,8 @@ Governance (SIGNED client-side, relayed as {intentBytes} \u2014 never a host-aut
|
|
|
8480
8608
|
githolon gov rebirth <ws> --reason <text> LAWFUL SUPERSESSION (recovery verb 3): supersede a
|
|
8481
8609
|
[--dry-run [--json]] [--yes] scarred chain; --dry-run = READ-ONLY impact report
|
|
8482
8610
|
githolon rebirth plan <ws> [--reason <text>] [--out D] write a stable plan.json + impact.md (rebirths-as-code)
|
|
8483
|
-
githolon rebirth apply --plan <plan.json>
|
|
8611
|
+
githolon rebirth apply --plan <plan.json> drift-pinned apply of a reviewed plan \u2192 certificate.json
|
|
8612
|
+
--gcp-secret nomos-root-custodian-key [--yes] (apply needs the ROOT CUSTODIAN seed; --gcp-secret is blessed)
|
|
8484
8613
|
githolon replay <ws> --repair execute the repair matching a red verify (\u2192 certificate)
|
|
8485
8614
|
githolon grant <admin|creation> <principal> [--label L] grant authority at the parent (default root)
|
|
8486
8615
|
githolon grant quota <principal> --max <N> grant a per-principal workspace allowance
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "githolon",
|
|
3
|
-
"version": "0.69.
|
|
3
|
+
"version": "0.69.3",
|
|
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.69.
|
|
33
|
-
"@githolon/dsl": "^0.69.
|
|
32
|
+
"@githolon/client": "^0.69.3",
|
|
33
|
+
"@githolon/dsl": "^0.69.3",
|
|
34
34
|
"isomorphic-git": "^1.38.4"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|