githolon 0.69.1 → 0.69.2
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 +375 -256
- 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,
|
|
@@ -2853,8 +2995,8 @@ __export(governance_exports, {
|
|
|
2853
2995
|
verifyWorkspaceVerdict: () => verifyWorkspaceVerdict
|
|
2854
2996
|
});
|
|
2855
2997
|
import { createHash, createPrivateKey, createPublicKey } from "node:crypto";
|
|
2856
|
-
import { mkdirSync as mkdirSync3, readFileSync as
|
|
2857
|
-
import { dirname as
|
|
2998
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
2999
|
+
import { dirname as dirname3, join as join4 } from "node:path";
|
|
2858
3000
|
async function clientConnect() {
|
|
2859
3001
|
const mod = await import("@githolon/client");
|
|
2860
3002
|
return mod.connect;
|
|
@@ -3072,7 +3214,7 @@ async function keyExport(opts) {
|
|
|
3072
3214
|
return 0;
|
|
3073
3215
|
}
|
|
3074
3216
|
function buildOfferPayload(opts) {
|
|
3075
|
-
const raw = opts.payloadFile !== void 0 ?
|
|
3217
|
+
const raw = opts.payloadFile !== void 0 ? readFileSync3(opts.payloadFile, "utf8") : opts.payload;
|
|
3076
3218
|
let payload = {};
|
|
3077
3219
|
if (raw !== void 0 && raw.trim() !== "") payload = JSON.parse(raw);
|
|
3078
3220
|
if (typeof payload !== "object" || payload === null || Array.isArray(payload)) {
|
|
@@ -3106,7 +3248,7 @@ async function governanceOffer(ws, directiveId, opts) {
|
|
|
3106
3248
|
const holon = await connectGovernance(cloudBase(opts.cloud), ws);
|
|
3107
3249
|
const device = await ensureDeviceKey(holon, principal);
|
|
3108
3250
|
const sealed = await holon.signGovernanceOffer({ directiveId, payload, authorSecret: device.secret, actor: `user:${principal}` });
|
|
3109
|
-
|
|
3251
|
+
writeFileSync4(opts.save, JSON.stringify({ ws, directiveId, principal, intentBytes: sealed.intentBytes }, null, 2) + "\n");
|
|
3110
3252
|
} catch (e) {
|
|
3111
3253
|
err2(e.message);
|
|
3112
3254
|
return 1;
|
|
@@ -3133,7 +3275,7 @@ async function governanceOffer(ws, directiveId, opts) {
|
|
|
3133
3275
|
async function governanceRelay(ws, file, opts) {
|
|
3134
3276
|
let saved;
|
|
3135
3277
|
try {
|
|
3136
|
-
saved = JSON.parse(
|
|
3278
|
+
saved = JSON.parse(readFileSync3(file, "utf8"));
|
|
3137
3279
|
} catch (e) {
|
|
3138
3280
|
err2(`cannot read offer file ${file}: ${e.message}`);
|
|
3139
3281
|
return 1;
|
|
@@ -3351,18 +3493,27 @@ async function buildRebirthPlan(cloud, ws, reason) {
|
|
|
3351
3493
|
} catch {
|
|
3352
3494
|
}
|
|
3353
3495
|
const lawHashes = {};
|
|
3496
|
+
let currentLaw2 = {};
|
|
3354
3497
|
try {
|
|
3355
3498
|
const d = await (await fetch(`${cloud}/v2/workspaces/${ws}/domains`)).json();
|
|
3499
|
+
currentLaw2 = d.currentLaw ?? {};
|
|
3500
|
+
const currentHashes = new Set(Object.values(currentLaw2));
|
|
3356
3501
|
for (const dom of d.domains ?? []) {
|
|
3357
|
-
if (typeof dom.domainHash
|
|
3502
|
+
if (typeof dom.domainHash !== "string") continue;
|
|
3503
|
+
lawHashes[dom.domainHash] = {
|
|
3504
|
+
phase: dom.phase ?? "unknown",
|
|
3505
|
+
current: dom.current === true || currentHashes.has(dom.domainHash)
|
|
3506
|
+
};
|
|
3358
3507
|
}
|
|
3359
3508
|
} catch {
|
|
3360
3509
|
}
|
|
3361
3510
|
let verdict = { replay: "unknown", firstRefusal: null };
|
|
3511
|
+
let rawVerdict = null;
|
|
3362
3512
|
try {
|
|
3363
3513
|
const m = await mountWorkspace2(eng, ws, { remote: `${cloud}/v2/workspaces/${ws}/git`, headers: {} });
|
|
3364
3514
|
if (m.restored === true) {
|
|
3365
3515
|
const v = verifyChainLocal2(eng, ws);
|
|
3516
|
+
rawVerdict = v;
|
|
3366
3517
|
if (v["valid"] === true) verdict = { replay: "green", firstRefusal: null };
|
|
3367
3518
|
else verdict = { replay: "red", firstRefusal: `${String(v["check"] ?? "?")}${v["atIndex"] !== void 0 ? ` @intent ${v["atIndex"]}` : ""}: ${String(v["error"] ?? "").slice(0, 200)}` };
|
|
3368
3519
|
}
|
|
@@ -3384,13 +3535,42 @@ async function buildRebirthPlan(cloud, ws, reason) {
|
|
|
3384
3535
|
} catch {
|
|
3385
3536
|
}
|
|
3386
3537
|
const mode = compaction.scarShape === "mid-chain" && !((compaction.parked ?? 99) <= 2 && parkedAllLawInstalls) ? "state-seed" : "replay-compact";
|
|
3538
|
+
let repairs = [];
|
|
3539
|
+
if (rawVerdict !== null && rawVerdict["valid"] !== true) {
|
|
3540
|
+
try {
|
|
3541
|
+
const { discoverRepairs: discoverRepairs2, parseRefusal: parseRefusal2, matchRepair: matchRepair2 } = await Promise.resolve().then(() => (init_repairs(), repairs_exports));
|
|
3542
|
+
const discovered = discoverRepairs2(process.cwd());
|
|
3543
|
+
if (!("error" in discovered) && discovered.repairs.length > 0) {
|
|
3544
|
+
const refusal = parseRefusal2(rawVerdict);
|
|
3545
|
+
for (const r of discovered.repairs) {
|
|
3546
|
+
if (r.matcher.refusal === refusal.kind && refusal.stableIds.includes(r.matcher.stableId.toLowerCase())) {
|
|
3547
|
+
const v = r.verb;
|
|
3548
|
+
repairs.push({
|
|
3549
|
+
id: r.id,
|
|
3550
|
+
file: r.file,
|
|
3551
|
+
reason: r.reason,
|
|
3552
|
+
matcher: { refusal: r.matcher.refusal, stableId: r.matcher.stableId },
|
|
3553
|
+
verb: {
|
|
3554
|
+
kind: String(v.kind ?? ""),
|
|
3555
|
+
...typeof v.aggregateId === "string" ? { aggregateId: v.aggregateId } : {},
|
|
3556
|
+
...typeof v.field === "string" ? { field: v.field } : {},
|
|
3557
|
+
...typeof v.through === "string" ? { through: v.through } : {}
|
|
3558
|
+
},
|
|
3559
|
+
execution: "recorded"
|
|
3560
|
+
});
|
|
3561
|
+
}
|
|
3562
|
+
}
|
|
3563
|
+
}
|
|
3564
|
+
} catch {
|
|
3565
|
+
}
|
|
3566
|
+
}
|
|
3387
3567
|
const frozenAt = priorSupersessions === 0 ? ws : `${ws}--i${priorSupersessions}`;
|
|
3388
3568
|
const newCustodyAddress = `${ws}--i${priorSupersessions + 1}`;
|
|
3389
3569
|
const plan = {
|
|
3390
3570
|
v: 1,
|
|
3391
3571
|
workspace: ws,
|
|
3392
3572
|
reason: reason ?? null,
|
|
3393
|
-
pinned: { incarnation, lawHashes, parent },
|
|
3573
|
+
pinned: { incarnation, lawHashes, currentLaw: currentLaw2, parent },
|
|
3394
3574
|
will: {
|
|
3395
3575
|
newCustodyAddress,
|
|
3396
3576
|
frozenAt,
|
|
@@ -3400,7 +3580,7 @@ async function buildRebirthPlan(cloud, ws, reason) {
|
|
|
3400
3580
|
verdict,
|
|
3401
3581
|
mode,
|
|
3402
3582
|
compaction,
|
|
3403
|
-
repairs
|
|
3583
|
+
repairs,
|
|
3404
3584
|
clientImpact: CLIENT_IMPACT,
|
|
3405
3585
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3406
3586
|
};
|
|
@@ -3416,8 +3596,15 @@ function renderRebirthImpact(plan, ledgerCommits) {
|
|
|
3416
3596
|
L.push(` incarnation : ${plan.pinned.incarnation ? plan.pinned.incarnation.slice(0, 16) + "\u2026" : "(none recorded \u2014 first incarnation)"}`);
|
|
3417
3597
|
L.push(` verify_chain : ${plan.verdict.replay.toUpperCase()}${plan.verdict.firstRefusal ? ` \u2014 first refusal: ${plan.verdict.firstRefusal}` : ""}`);
|
|
3418
3598
|
L.push(` ledger size : ${ledgerCommits !== null ? `${ledgerCommits} commit(s)` : "(unknown)"}`);
|
|
3419
|
-
const laws = Object.
|
|
3420
|
-
|
|
3599
|
+
const laws = Object.entries(plan.pinned.lawHashes);
|
|
3600
|
+
const currentLaw2 = plan.pinned.currentLaw ?? {};
|
|
3601
|
+
const keysForHash = (hash) => Object.entries(currentLaw2).filter(([, h]) => h === hash).map(([k]) => k);
|
|
3602
|
+
const currentHashes = laws.filter(([, m]) => m.current).map(([h]) => h);
|
|
3603
|
+
const currentDesc = currentHashes.length ? currentHashes.map((h) => {
|
|
3604
|
+
const ks = keysForHash(h);
|
|
3605
|
+
return `${h.slice(0, 8)}\u2026${ks.length ? ` (${ks.join(", ")})` : ""}`;
|
|
3606
|
+
}).join(" \xB7 ") : "(none current)";
|
|
3607
|
+
L.push(` installed law : ${laws.length} historical \xB7 current: ${currentDesc}`);
|
|
3421
3608
|
L.push(` parent : ${plan.pinned.parent || "(root)"}`);
|
|
3422
3609
|
L.push("");
|
|
3423
3610
|
L.push("WHAT A REBIRTH WOULD DO");
|
|
@@ -3450,9 +3637,33 @@ function renderRebirthImpact(plan, ledgerCommits) {
|
|
|
3450
3637
|
L.push(" \u2192 preserved by lineage continuity; their birth-cert chains stay valid (same founding key + self-id).");
|
|
3451
3638
|
}
|
|
3452
3639
|
L.push("");
|
|
3640
|
+
L.push(`REPAIRS (${plan.repairs.length})`);
|
|
3641
|
+
if (plan.repairs.length === 0) L.push(" (none matched \u2014 a plain compaction; no corrective verb declared for this refusal)");
|
|
3642
|
+
else {
|
|
3643
|
+
for (const r of plan.repairs) {
|
|
3644
|
+
const v = r.verb;
|
|
3645
|
+
const verbDesc = `${v.kind}${v.aggregateId ? ` ${v.aggregateId}${v.field ? `.${v.field}` : ""}` : ""}${v.through ? ` through ${v.through}` : ""}`;
|
|
3646
|
+
L.push(` \u2726 ${r.id} [${r.execution}]`);
|
|
3647
|
+
L.push(` matches : ${r.matcher.refusal} \xB7 stable id ${r.matcher.stableId}`);
|
|
3648
|
+
L.push(` verb : ${verbDesc} (${r.file})`);
|
|
3649
|
+
L.push(` reason : ${r.reason}`);
|
|
3650
|
+
}
|
|
3651
|
+
L.push(" \u2192 v1 records the repair as provenance/justification (the certificate + supersession reason name it);");
|
|
3652
|
+
L.push(" state-transform verbs execute at the re-fold seam in a future release.");
|
|
3653
|
+
}
|
|
3654
|
+
L.push("");
|
|
3453
3655
|
L.push("CLIENT IMPACT");
|
|
3454
3656
|
L.push(` ${plan.clientImpact}.`);
|
|
3455
3657
|
L.push(" Recommend tenants DRAIN/SYNC their clients before the rebirth window.");
|
|
3658
|
+
L.push("");
|
|
3659
|
+
L.push("NEXT STEPS \u2014 the blessed golden path");
|
|
3660
|
+
L.push(" 1. plan (this)");
|
|
3661
|
+
L.push(` 2. apply githolon rebirth apply --plan <path> --gcp-secret ${ROOT_CUSTODIAN_SECRET} [--yes]`);
|
|
3662
|
+
L.push(" (apply requires the ROOT CUSTODIAN seed \u2014 --gcp-secret is the blessed path;");
|
|
3663
|
+
L.push(" --seed-secret <b64> is break-glass, env NOMOS_ROOT_SEED is the CI lane)");
|
|
3664
|
+
L.push(` 3. replay githolon replay ${plan.workspace} (expect GREEN from intent 0)`);
|
|
3665
|
+
L.push(` 4. status githolon status ${plan.workspace} (incarnation + supersession history)`);
|
|
3666
|
+
L.push(" 5. compat githolon compat (clients raise CustodyBreak \u2014 choose adopt/reject)");
|
|
3456
3667
|
return L.join("\n");
|
|
3457
3668
|
}
|
|
3458
3669
|
async function rebirthPlanCommand(ws, opts) {
|
|
@@ -3463,19 +3674,22 @@ async function rebirthPlanCommand(ws, opts) {
|
|
|
3463
3674
|
return 1;
|
|
3464
3675
|
}
|
|
3465
3676
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3466
|
-
const dir = opts.out ??
|
|
3677
|
+
const dir = opts.out ?? join4("rebirths", `${date}-${ws}`);
|
|
3467
3678
|
try {
|
|
3468
3679
|
mkdirSync3(dir, { recursive: true });
|
|
3469
|
-
|
|
3470
|
-
|
|
3680
|
+
writeFileSync4(join4(dir, "plan.json"), JSON.stringify(built.plan, null, 2) + "\n");
|
|
3681
|
+
writeFileSync4(join4(dir, "impact.md"), "```\n" + renderRebirthImpact(built.plan, built.ledgerCommits) + "\n```\n");
|
|
3471
3682
|
} catch (e) {
|
|
3472
3683
|
err2(`could not write the plan into ${dir}: ${e.message}`);
|
|
3473
3684
|
return 1;
|
|
3474
3685
|
}
|
|
3475
3686
|
out2(renderRebirthImpact(built.plan, built.ledgerCommits));
|
|
3476
3687
|
out2("");
|
|
3477
|
-
out2(`\u2713 plan written: ${
|
|
3478
|
-
out2(" fill in `reason`
|
|
3688
|
+
out2(`\u2713 plan written: ${join4(dir, "plan.json")} + ${join4(dir, "impact.md")}`);
|
|
3689
|
+
if (built.plan.reason === null) out2(" fill in the plan's `reason` (the mandatory audit justification) before apply.");
|
|
3690
|
+
out2(" apply requires the ROOT CUSTODIAN seed. The blessed command:");
|
|
3691
|
+
out2(` githolon rebirth apply --plan ${join4(dir, "plan.json")} --gcp-secret ${ROOT_CUSTODIAN_SECRET} [--yes]`);
|
|
3692
|
+
out2(" (--seed-secret <b64> is break-glass \u2014 avoid in shell history; env NOMOS_ROOT_SEED is the CI lane.)");
|
|
3479
3693
|
return 0;
|
|
3480
3694
|
}
|
|
3481
3695
|
async function rebirthWorkspace(ws, opts) {
|
|
@@ -3503,9 +3717,12 @@ async function rebirthWorkspace(ws, opts) {
|
|
|
3503
3717
|
err2("the law refuses to rebirth root \u2014 the seat of the authorizing law cannot supersede itself");
|
|
3504
3718
|
return 1;
|
|
3505
3719
|
}
|
|
3506
|
-
if (opts.plan !== void 0 && Array.isArray(opts.plan.repairs)
|
|
3507
|
-
|
|
3508
|
-
|
|
3720
|
+
if (opts.plan !== void 0 && Array.isArray(opts.plan.repairs)) {
|
|
3721
|
+
const unknown = opts.plan.repairs.find((r2) => r2.execution !== "recorded");
|
|
3722
|
+
if (unknown !== void 0) {
|
|
3723
|
+
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)`);
|
|
3724
|
+
return 1;
|
|
3725
|
+
}
|
|
3509
3726
|
}
|
|
3510
3727
|
let seed = opts.seedSecret ?? process.env["NOMOS_ROOT_SEED"];
|
|
3511
3728
|
if (seed === void 0 && opts.gcpSecret !== void 0) {
|
|
@@ -3518,7 +3735,7 @@ async function rebirthWorkspace(ws, opts) {
|
|
|
3518
3735
|
}
|
|
3519
3736
|
}
|
|
3520
3737
|
if (seed === void 0 || seed.trim() === "") {
|
|
3521
|
-
err2(
|
|
3738
|
+
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
3739
|
return 1;
|
|
3523
3740
|
}
|
|
3524
3741
|
const cloud = cloudBase(opts.cloud);
|
|
@@ -3628,8 +3845,11 @@ function validatePlanForApply(plan, liveIncarnation) {
|
|
|
3628
3845
|
if (plan.reason === null || typeof plan.reason === "string" && plan.reason.trim() === "") {
|
|
3629
3846
|
return { error: "the plan's `reason` is still null \u2014 fill it in (the mandatory audit justification) before apply" };
|
|
3630
3847
|
}
|
|
3631
|
-
if (Array.isArray(plan.repairs)
|
|
3632
|
-
|
|
3848
|
+
if (Array.isArray(plan.repairs)) {
|
|
3849
|
+
const bad = plan.repairs.find((r) => r.execution !== "recorded");
|
|
3850
|
+
if (bad !== void 0) {
|
|
3851
|
+
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)` };
|
|
3852
|
+
}
|
|
3633
3853
|
}
|
|
3634
3854
|
if (plan.pinned.incarnation !== null) {
|
|
3635
3855
|
if (liveIncarnation === void 0) {
|
|
@@ -3643,6 +3863,7 @@ function validatePlanForApply(plan, liveIncarnation) {
|
|
|
3643
3863
|
}
|
|
3644
3864
|
function buildCertificate(args) {
|
|
3645
3865
|
const { plan } = args;
|
|
3866
|
+
const childNames = plan.children.map((c) => c.name);
|
|
3646
3867
|
return {
|
|
3647
3868
|
v: 1,
|
|
3648
3869
|
plan,
|
|
@@ -3651,12 +3872,17 @@ function buildCertificate(args) {
|
|
|
3651
3872
|
custodian: args.custodian,
|
|
3652
3873
|
oldIncarnation: args.oldIncarnation,
|
|
3653
3874
|
newIncarnation: args.newIncarnation,
|
|
3875
|
+
oldHead: args.oldHead ?? args.oldIncarnation,
|
|
3876
|
+
newHead: args.newHead ?? args.newIncarnation,
|
|
3877
|
+
oldCustodyAddress: plan.will.frozenAt,
|
|
3654
3878
|
newCustodyAddress: plan.will.newCustodyAddress,
|
|
3655
3879
|
carried: plan.compaction.carried,
|
|
3656
3880
|
parked: plan.compaction.parked,
|
|
3657
3881
|
verdictBefore: args.verdictBefore,
|
|
3658
3882
|
...args.firstRefusal ? { firstRefusal: args.firstRefusal } : {},
|
|
3659
|
-
verdictAfter: args.verdictAfter
|
|
3883
|
+
verdictAfter: args.verdictAfter,
|
|
3884
|
+
activeLawAfter: args.activeLawAfter ?? {},
|
|
3885
|
+
childrenCarried: { count: childNames.length, names: childNames }
|
|
3660
3886
|
},
|
|
3661
3887
|
supersessionFacts: {
|
|
3662
3888
|
supersededBy: plan.will.newCustodyAddress,
|
|
@@ -3665,6 +3891,7 @@ function buildCertificate(args) {
|
|
|
3665
3891
|
custodian: args.custodian,
|
|
3666
3892
|
at: args.at
|
|
3667
3893
|
},
|
|
3894
|
+
repairs: Array.isArray(plan.repairs) ? plan.repairs : [],
|
|
3668
3895
|
...args.repair !== void 0 ? { repair: args.repair } : {}
|
|
3669
3896
|
};
|
|
3670
3897
|
}
|
|
@@ -3684,6 +3911,14 @@ async function verifyWorkspaceVerdict(cloud, ws) {
|
|
|
3684
3911
|
return { replay: "unknown", firstRefusal: null };
|
|
3685
3912
|
}
|
|
3686
3913
|
}
|
|
3914
|
+
async function currentLawOf(cloud, ws) {
|
|
3915
|
+
try {
|
|
3916
|
+
const d = await (await fetch(`${cloud}/v2/workspaces/${ws}/domains`)).json();
|
|
3917
|
+
return d.currentLaw ?? {};
|
|
3918
|
+
} catch {
|
|
3919
|
+
return {};
|
|
3920
|
+
}
|
|
3921
|
+
}
|
|
3687
3922
|
async function liveIncarnationOf(cloud, ws) {
|
|
3688
3923
|
try {
|
|
3689
3924
|
const s = await (await fetch(`${cloud}/v2/workspaces/${ws}`)).json();
|
|
@@ -3695,7 +3930,7 @@ async function liveIncarnationOf(cloud, ws) {
|
|
|
3695
3930
|
async function rebirthApply(planPath, opts) {
|
|
3696
3931
|
let plan;
|
|
3697
3932
|
try {
|
|
3698
|
-
plan = JSON.parse(
|
|
3933
|
+
plan = JSON.parse(readFileSync3(planPath, "utf8"));
|
|
3699
3934
|
} catch (e) {
|
|
3700
3935
|
err2(`cannot read the plan ${planPath}: ${e.message}`);
|
|
3701
3936
|
return 1;
|
|
@@ -3730,9 +3965,11 @@ async function rebirthApply(planPath, opts) {
|
|
|
3730
3965
|
}
|
|
3731
3966
|
const verdictBefore = plan.verdict.replay === "green" ? "green" : "red";
|
|
3732
3967
|
const custodian = opts.principal ?? activePrincipal() ?? "root-custodian";
|
|
3968
|
+
const repairIds = (plan.repairs ?? []).map((r) => r.id);
|
|
3969
|
+
const effectiveReason = repairIds.length ? `${plan.reason ?? ""} ${repairIds.map((id) => `[repair:${id}]`).join(" ")}`.trim() : plan.reason ?? void 0;
|
|
3733
3970
|
const code = await rebirthWorkspace(ws, {
|
|
3734
3971
|
...opts,
|
|
3735
|
-
reason:
|
|
3972
|
+
reason: effectiveReason,
|
|
3736
3973
|
plan,
|
|
3737
3974
|
quiet: true,
|
|
3738
3975
|
yes: true
|
|
@@ -3743,19 +3980,21 @@ async function rebirthApply(planPath, opts) {
|
|
|
3743
3980
|
}
|
|
3744
3981
|
const newIncarnation = await liveIncarnationOf(cloud, ws) ?? null;
|
|
3745
3982
|
const verdictAfter = await verifyWorkspaceVerdict(cloud, ws);
|
|
3983
|
+
const activeLawAfter = await currentLawOf(cloud, ws);
|
|
3746
3984
|
const cert = buildCertificate({
|
|
3747
3985
|
plan,
|
|
3748
3986
|
custodian,
|
|
3749
3987
|
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3750
3988
|
oldIncarnation: plan.pinned.incarnation,
|
|
3751
3989
|
newIncarnation,
|
|
3990
|
+
activeLawAfter,
|
|
3752
3991
|
verdictBefore,
|
|
3753
3992
|
...plan.verdict.firstRefusal ? { firstRefusal: plan.verdict.firstRefusal } : {},
|
|
3754
3993
|
verdictAfter
|
|
3755
3994
|
});
|
|
3756
|
-
const certPath =
|
|
3995
|
+
const certPath = join4(dirname3(planPath), "certificate.json");
|
|
3757
3996
|
try {
|
|
3758
|
-
|
|
3997
|
+
writeFileSync4(certPath, JSON.stringify(cert, null, 2) + "\n");
|
|
3759
3998
|
} catch (e) {
|
|
3760
3999
|
err2(`the rebirth succeeded but the certificate could not be written to ${certPath}: ${e.message}`);
|
|
3761
4000
|
return 1;
|
|
@@ -3806,12 +4045,14 @@ async function executeRepairRebirth(cloud, ws, repair, verdict, opts) {
|
|
|
3806
4045
|
}
|
|
3807
4046
|
const newIncarnation = await liveIncarnationOf(cloudBaseUrl, ws) ?? null;
|
|
3808
4047
|
const verdictAfter = await verifyWorkspaceVerdict(cloudBaseUrl, ws);
|
|
4048
|
+
const activeLawAfter = await currentLawOf(cloudBaseUrl, ws);
|
|
3809
4049
|
const cert = buildCertificate({
|
|
3810
4050
|
plan,
|
|
3811
4051
|
custodian,
|
|
3812
4052
|
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3813
4053
|
oldIncarnation: plan.pinned.incarnation,
|
|
3814
4054
|
newIncarnation,
|
|
4055
|
+
activeLawAfter,
|
|
3815
4056
|
verdictBefore,
|
|
3816
4057
|
firstRefusal,
|
|
3817
4058
|
verdictAfter,
|
|
@@ -3822,9 +4063,9 @@ async function executeRepairRebirth(cloud, ws, repair, verdict, opts) {
|
|
|
3822
4063
|
note: "repair verb recorded; state transform verbs land in a future release (v1 rebirth only)"
|
|
3823
4064
|
}
|
|
3824
4065
|
});
|
|
3825
|
-
const certPath =
|
|
4066
|
+
const certPath = join4(dirname3(repair.file), "certificate.json");
|
|
3826
4067
|
try {
|
|
3827
|
-
|
|
4068
|
+
writeFileSync4(certPath, JSON.stringify(cert, null, 2) + "\n");
|
|
3828
4069
|
} catch (e) {
|
|
3829
4070
|
err2(`the repair rebirth succeeded but the certificate could not be written to ${certPath}: ${e.message}`);
|
|
3830
4071
|
return 1;
|
|
@@ -3844,13 +4085,14 @@ function readSealedIntentBytes(eng, ws, intentOut) {
|
|
|
3844
4085
|
if (f?.data === void 0) return void 0;
|
|
3845
4086
|
return Buffer.from(f.data).toString("base64");
|
|
3846
4087
|
}
|
|
3847
|
-
var out2, err2, CLIENT_IMPACT;
|
|
4088
|
+
var out2, err2, ROOT_CUSTODIAN_SECRET, CLIENT_IMPACT;
|
|
3848
4089
|
var init_governance = __esm({
|
|
3849
4090
|
"src/governance.ts"() {
|
|
3850
4091
|
"use strict";
|
|
3851
4092
|
init_cloud();
|
|
3852
4093
|
out2 = (s) => void process.stdout.write(s + "\n");
|
|
3853
4094
|
err2 = (s) => void process.stderr.write("error: " + s + "\n");
|
|
4095
|
+
ROOT_CUSTODIAN_SECRET = "nomos-root-custodian-key";
|
|
3854
4096
|
CLIENT_IMPACT = "every connected client raises CustodyBreak(superseded); unsynced client work is invisible to the cloud \u2014 drain/sync clients first";
|
|
3855
4097
|
}
|
|
3856
4098
|
});
|
|
@@ -3874,7 +4116,7 @@ __export(lifecycle_exports, {
|
|
|
3874
4116
|
signingAvailable: () => signingAvailable
|
|
3875
4117
|
});
|
|
3876
4118
|
import { createHash as createHash2 } from "node:crypto";
|
|
3877
|
-
import { readFileSync as
|
|
4119
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
3878
4120
|
async function fetchInstalledLaw(cloud, ws) {
|
|
3879
4121
|
try {
|
|
3880
4122
|
const r = await fetch(`${cloud}/v2/workspaces/${ws}/domains`);
|
|
@@ -3897,7 +4139,7 @@ async function fetchInstalledPackage(cloud, ws, hash) {
|
|
|
3897
4139
|
function readDeployBody(file) {
|
|
3898
4140
|
let body;
|
|
3899
4141
|
try {
|
|
3900
|
-
body = JSON.parse(
|
|
4142
|
+
body = JSON.parse(readFileSync4(file, "utf8"));
|
|
3901
4143
|
} catch (e) {
|
|
3902
4144
|
throw new Error(`deploy body ${file} is not valid JSON \u2014 recompile (githolon compile): ${e.message}`);
|
|
3903
4145
|
}
|
|
@@ -4197,9 +4439,9 @@ __export(cloud_exports, {
|
|
|
4197
4439
|
wsRetire: () => wsRetire,
|
|
4198
4440
|
wsStatus: () => wsStatus
|
|
4199
4441
|
});
|
|
4200
|
-
import { chmodSync, existsSync as
|
|
4442
|
+
import { chmodSync, existsSync as existsSync4, mkdirSync as mkdirSync4, readdirSync as readdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
4201
4443
|
import { createHash as createHash3 } from "node:crypto";
|
|
4202
|
-
import { join as
|
|
4444
|
+
import { join as join5 } from "node:path";
|
|
4203
4445
|
import { homedir } from "node:os";
|
|
4204
4446
|
function cloudBase(flag) {
|
|
4205
4447
|
return (flag ?? process.env["NOMOS_CLOUD"] ?? DEFAULT_CLOUD).replace(/\/+$/, "");
|
|
@@ -4211,18 +4453,18 @@ function authAnonKey() {
|
|
|
4211
4453
|
return process.env["HOLON_AUTH_ANON_KEY"] ?? DEFAULT_AUTH_ANON_KEY;
|
|
4212
4454
|
}
|
|
4213
4455
|
function configDir() {
|
|
4214
|
-
return process.env["HOLON_CONFIG_DIR"] ??
|
|
4456
|
+
return process.env["HOLON_CONFIG_DIR"] ?? join5(homedir(), ".holon");
|
|
4215
4457
|
}
|
|
4216
4458
|
function credsPath() {
|
|
4217
|
-
return
|
|
4459
|
+
return join5(configDir(), "credentials.json");
|
|
4218
4460
|
}
|
|
4219
4461
|
function loadCreds() {
|
|
4220
|
-
if (!
|
|
4221
|
-
return JSON.parse(
|
|
4462
|
+
if (!existsSync4(credsPath())) return { version: 1, secrets: {} };
|
|
4463
|
+
return JSON.parse(readFileSync5(credsPath(), "utf8"));
|
|
4222
4464
|
}
|
|
4223
4465
|
function saveCreds(c) {
|
|
4224
4466
|
mkdirSync4(configDir(), { recursive: true });
|
|
4225
|
-
|
|
4467
|
+
writeFileSync5(credsPath(), JSON.stringify(c, null, 2) + "\n", "utf8");
|
|
4226
4468
|
chmodSync(credsPath(), 384);
|
|
4227
4469
|
}
|
|
4228
4470
|
function getSecret(cloud, ws) {
|
|
@@ -4337,21 +4579,21 @@ async function sessionToken() {
|
|
|
4337
4579
|
}
|
|
4338
4580
|
function discoverDeployJson(cwd, explicit) {
|
|
4339
4581
|
if (explicit !== void 0) {
|
|
4340
|
-
if (!
|
|
4582
|
+
if (!existsSync4(explicit)) throw new Error(`deploy body not found: ${explicit}`);
|
|
4341
4583
|
return explicit;
|
|
4342
4584
|
}
|
|
4343
|
-
const buildDir =
|
|
4344
|
-
if (!
|
|
4585
|
+
const buildDir = join5(cwd, "build");
|
|
4586
|
+
if (!existsSync4(buildDir)) {
|
|
4345
4587
|
throw new Error("no build/ directory \u2014 run `githolon compile` first (or pass --file <path>)");
|
|
4346
4588
|
}
|
|
4347
|
-
const bodies =
|
|
4589
|
+
const bodies = readdirSync3(buildDir).filter((f) => f.endsWith(".deploy.json"));
|
|
4348
4590
|
if (bodies.length === 0) {
|
|
4349
4591
|
throw new Error("no build/*.deploy.json \u2014 run `githolon compile` first (or pass --file <path>)");
|
|
4350
4592
|
}
|
|
4351
4593
|
if (bodies.length > 1) {
|
|
4352
4594
|
throw new Error(`multiple deploy bodies in build/ (${bodies.join(", ")}) \u2014 pass --file <path>`);
|
|
4353
4595
|
}
|
|
4354
|
-
return
|
|
4596
|
+
return join5(buildDir, bodies[0]);
|
|
4355
4597
|
}
|
|
4356
4598
|
async function login(opts) {
|
|
4357
4599
|
if (opts.agent !== true && opts.token === void 0) {
|
|
@@ -4578,7 +4820,7 @@ async function deploy2(ws, opts) {
|
|
|
4578
4820
|
if (signed) {
|
|
4579
4821
|
let body;
|
|
4580
4822
|
try {
|
|
4581
|
-
body = JSON.parse(
|
|
4823
|
+
body = JSON.parse(readFileSync5(file, "utf8"));
|
|
4582
4824
|
} catch (e) {
|
|
4583
4825
|
err4(`deploy body ${file} is not valid JSON \u2014 recompile: ${e.message}`);
|
|
4584
4826
|
return 1;
|
|
@@ -4617,7 +4859,7 @@ async function deploy2(ws, opts) {
|
|
|
4617
4859
|
const r = await fetch(`${cloud}/v2/workspaces/${ws}/domains`, {
|
|
4618
4860
|
method: "POST",
|
|
4619
4861
|
headers: { "content-type": "application/json" },
|
|
4620
|
-
body:
|
|
4862
|
+
body: readFileSync5(file, "utf8")
|
|
4621
4863
|
});
|
|
4622
4864
|
const d = await r.json().catch(() => void 0);
|
|
4623
4865
|
if (!r.ok || d?.ok !== true) {
|
|
@@ -4711,27 +4953,27 @@ __export(editor_exports, {
|
|
|
4711
4953
|
initEditor: () => initEditor,
|
|
4712
4954
|
writeEditorRecommendation: () => writeEditorRecommendation
|
|
4713
4955
|
});
|
|
4714
|
-
import { existsSync as
|
|
4715
|
-
import { dirname as
|
|
4956
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "node:fs";
|
|
4957
|
+
import { dirname as dirname4, join as join6 } from "node:path";
|
|
4716
4958
|
function hasEditorRecommendation(cwd) {
|
|
4717
|
-
const p =
|
|
4718
|
-
if (!
|
|
4959
|
+
const p = join6(cwd, ".vscode", "extensions.json");
|
|
4960
|
+
if (!existsSync5(p)) return false;
|
|
4719
4961
|
try {
|
|
4720
|
-
const json = JSON.parse(
|
|
4962
|
+
const json = JSON.parse(readFileSync6(p, "utf8"));
|
|
4721
4963
|
return Array.isArray(json.recommendations) && json.recommendations.includes(NOMOS_LAW_EXTENSION_ID);
|
|
4722
4964
|
} catch {
|
|
4723
4965
|
return true;
|
|
4724
4966
|
}
|
|
4725
4967
|
}
|
|
4726
4968
|
function writeEditorRecommendation(cwd) {
|
|
4727
|
-
const dir =
|
|
4728
|
-
const path =
|
|
4969
|
+
const dir = join6(cwd, ".vscode");
|
|
4970
|
+
const path = join6(dir, "extensions.json");
|
|
4729
4971
|
let json = {};
|
|
4730
4972
|
let existed = false;
|
|
4731
|
-
if (
|
|
4973
|
+
if (existsSync5(path)) {
|
|
4732
4974
|
existed = true;
|
|
4733
4975
|
try {
|
|
4734
|
-
const parsed = JSON.parse(
|
|
4976
|
+
const parsed = JSON.parse(readFileSync6(path, "utf8"));
|
|
4735
4977
|
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
4736
4978
|
json = parsed;
|
|
4737
4979
|
} else {
|
|
@@ -4749,8 +4991,8 @@ function writeEditorRecommendation(cwd) {
|
|
|
4749
4991
|
}
|
|
4750
4992
|
recs.push(NOMOS_LAW_EXTENSION_ID);
|
|
4751
4993
|
json.recommendations = recs;
|
|
4752
|
-
mkdirSync5(
|
|
4753
|
-
|
|
4994
|
+
mkdirSync5(dirname4(path), { recursive: true });
|
|
4995
|
+
writeFileSync6(path, JSON.stringify(json, null, 2) + "\n", "utf8");
|
|
4754
4996
|
return { path, action: existed ? "updated" : "created" };
|
|
4755
4997
|
}
|
|
4756
4998
|
function initEditor(cwd = process.cwd()) {
|
|
@@ -4784,21 +5026,21 @@ var init_editor = __esm({
|
|
|
4784
5026
|
});
|
|
4785
5027
|
|
|
4786
5028
|
// 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";
|
|
5029
|
+
import { spawn, spawnSync as spawnSync2 } from "node:child_process";
|
|
5030
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
5031
|
+
import { dirname as dirname5, join as join7 } from "node:path";
|
|
5032
|
+
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
4791
5033
|
function resolveCompileLauncher(cwd) {
|
|
4792
5034
|
const resolveDslPkg = (fromDir) => {
|
|
4793
5035
|
try {
|
|
4794
|
-
const req = fromDir === void 0 ?
|
|
5036
|
+
const req = fromDir === void 0 ? createRequire2(import.meta.url) : createRequire2(pathToFileURL2(join7(fromDir, "noop.js")));
|
|
4795
5037
|
return req.resolve("@githolon/dsl/package.json");
|
|
4796
5038
|
} catch {
|
|
4797
5039
|
return void 0;
|
|
4798
5040
|
}
|
|
4799
5041
|
};
|
|
4800
5042
|
const dslPkg = resolveDslPkg(cwd) ?? resolveDslPkg(void 0);
|
|
4801
|
-
return dslPkg === void 0 ? void 0 :
|
|
5043
|
+
return dslPkg === void 0 ? void 0 : join7(dirname5(dslPkg), "compile_package.mjs");
|
|
4802
5044
|
}
|
|
4803
5045
|
function runCompile(args) {
|
|
4804
5046
|
const launcher = resolveCompileLauncher(process.cwd());
|
|
@@ -4807,7 +5049,7 @@ function runCompile(args) {
|
|
|
4807
5049
|
`);
|
|
4808
5050
|
return 1;
|
|
4809
5051
|
}
|
|
4810
|
-
const r =
|
|
5052
|
+
const r = spawnSync2(process.execPath, [launcher, ...args], { stdio: "inherit", cwd: process.cwd() });
|
|
4811
5053
|
const status2 = r.status ?? 1;
|
|
4812
5054
|
if (status2 === 0 && process.stdout.isTTY) {
|
|
4813
5055
|
try {
|
|
@@ -4821,7 +5063,7 @@ ${INIT_EDITOR_HINT}
|
|
|
4821
5063
|
}
|
|
4822
5064
|
function resolveCheckLauncher(cwd) {
|
|
4823
5065
|
const launcher = resolveCompileLauncher(cwd);
|
|
4824
|
-
return launcher === void 0 ? void 0 :
|
|
5066
|
+
return launcher === void 0 ? void 0 : join7(dirname5(launcher), "check_package.mjs");
|
|
4825
5067
|
}
|
|
4826
5068
|
function runCheck(args) {
|
|
4827
5069
|
const launcher = resolveCheckLauncher(process.cwd());
|
|
@@ -4830,12 +5072,12 @@ function runCheck(args) {
|
|
|
4830
5072
|
`);
|
|
4831
5073
|
return 1;
|
|
4832
5074
|
}
|
|
4833
|
-
const r =
|
|
5075
|
+
const r = spawnSync2(process.execPath, [launcher, ...args], { stdio: "inherit", cwd: process.cwd() });
|
|
4834
5076
|
return r.status ?? 1;
|
|
4835
5077
|
}
|
|
4836
5078
|
function resolveCompatLauncher(cwd) {
|
|
4837
5079
|
const launcher = resolveCompileLauncher(cwd);
|
|
4838
|
-
return launcher === void 0 ? void 0 :
|
|
5080
|
+
return launcher === void 0 ? void 0 : join7(dirname5(launcher), "compat_package.mjs");
|
|
4839
5081
|
}
|
|
4840
5082
|
function runCompat(args) {
|
|
4841
5083
|
const launcher = resolveCompatLauncher(process.cwd());
|
|
@@ -4844,12 +5086,12 @@ function runCompat(args) {
|
|
|
4844
5086
|
`);
|
|
4845
5087
|
return 1;
|
|
4846
5088
|
}
|
|
4847
|
-
const r =
|
|
5089
|
+
const r = spawnSync2(process.execPath, [launcher, ...args], { stdio: "inherit", cwd: process.cwd() });
|
|
4848
5090
|
return r.status ?? 1;
|
|
4849
5091
|
}
|
|
4850
5092
|
function resolveLspLauncher(cwd) {
|
|
4851
5093
|
const launcher = resolveCompileLauncher(cwd);
|
|
4852
|
-
return launcher === void 0 ? void 0 :
|
|
5094
|
+
return launcher === void 0 ? void 0 : join7(dirname5(launcher), "lsp_server.mjs");
|
|
4853
5095
|
}
|
|
4854
5096
|
function runLsp(args) {
|
|
4855
5097
|
const launcher = resolveLspLauncher(process.cwd());
|
|
@@ -4858,7 +5100,7 @@ function runLsp(args) {
|
|
|
4858
5100
|
`);
|
|
4859
5101
|
return 1;
|
|
4860
5102
|
}
|
|
4861
|
-
const r =
|
|
5103
|
+
const r = spawnSync2(process.execPath, [launcher, ...args], { stdio: "inherit", cwd: process.cwd() });
|
|
4862
5104
|
return r.status ?? 1;
|
|
4863
5105
|
}
|
|
4864
5106
|
function compileAsync(cwd, args = []) {
|
|
@@ -4898,8 +5140,8 @@ __export(proof_offline_exports, {
|
|
|
4898
5140
|
runOfflineProofStandalone: () => runOfflineProofStandalone,
|
|
4899
5141
|
runRelationBootstrapLeg: () => runRelationBootstrapLeg
|
|
4900
5142
|
});
|
|
4901
|
-
import { existsSync as
|
|
4902
|
-
import { basename, dirname as
|
|
5143
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
|
|
5144
|
+
import { basename, dirname as dirname6, join as join9 } from "node:path";
|
|
4903
5145
|
function parseOfflineLegs(proofSource) {
|
|
4904
5146
|
if (!proofSource.includes("AUTO-GENERATED by nomos-compile")) {
|
|
4905
5147
|
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 +5566,16 @@ function actorFromPayload(payload, field) {
|
|
|
5324
5566
|
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
5325
5567
|
}
|
|
5326
5568
|
async function runOfflineProofStandalone(proofPath, cloud, domain) {
|
|
5327
|
-
const src =
|
|
5569
|
+
const src = readFileSync7(proofPath, "utf8");
|
|
5328
5570
|
const packageName = basename(proofPath).replace(/\.proof\.mts$/, "");
|
|
5329
|
-
const deployFile =
|
|
5330
|
-
if (!
|
|
5571
|
+
const deployFile = join9(dirname6(proofPath), `${packageName}.deploy.json`);
|
|
5572
|
+
if (!existsSync7(deployFile)) {
|
|
5331
5573
|
throw new Error(`missing ${deployFile} \u2014 run \`githolon compile\` (the proof and the deploy body are built together)`);
|
|
5332
5574
|
}
|
|
5333
5575
|
let legs;
|
|
5334
|
-
const legsFile =
|
|
5335
|
-
if (
|
|
5336
|
-
const index = JSON.parse(
|
|
5576
|
+
const legsFile = join9(dirname6(proofPath), `${packageName}.proof-legs.json`);
|
|
5577
|
+
if (existsSync7(legsFile)) {
|
|
5578
|
+
const index = JSON.parse(readFileSync7(legsFile, "utf8"));
|
|
5337
5579
|
const keys = Object.keys(index.domains);
|
|
5338
5580
|
const chosen = domain ?? index.default;
|
|
5339
5581
|
if (index.domains[chosen] === void 0) {
|
|
@@ -5351,7 +5593,7 @@ async function runOfflineProofStandalone(proofPath, cloud, domain) {
|
|
|
5351
5593
|
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
5594
|
legs = parseOfflineLegs(src);
|
|
5353
5595
|
}
|
|
5354
|
-
const deployBody = JSON.parse(
|
|
5596
|
+
const deployBody = JSON.parse(readFileSync7(deployFile, "utf8"));
|
|
5355
5597
|
const lawHash = await sha256hex(deployBody.packageUsda);
|
|
5356
5598
|
console.log(`githolon proof \u2014 OFFLINE legs on a local holon (the cloud loop: githolon proof --live)`);
|
|
5357
5599
|
const { eng } = await holonEngine(cloud, deployBody, "githolon-proof");
|
|
@@ -5378,147 +5620,6 @@ var init_proof_offline = __esm({
|
|
|
5378
5620
|
}
|
|
5379
5621
|
});
|
|
5380
5622
|
|
|
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
5623
|
// src/mcp.ts
|
|
5523
5624
|
var mcp_exports = {};
|
|
5524
5625
|
__export(mcp_exports, {
|
|
@@ -7258,20 +7359,20 @@ init_engine();
|
|
|
7258
7359
|
init_cloud();
|
|
7259
7360
|
init_compile();
|
|
7260
7361
|
init_local_holon();
|
|
7261
|
-
import { existsSync as
|
|
7362
|
+
import { existsSync as existsSync8, readFileSync as readFileSync8, watch } from "node:fs";
|
|
7262
7363
|
import { createServer } from "node:http";
|
|
7263
|
-
import { dirname as
|
|
7264
|
-
import { pathToFileURL as
|
|
7364
|
+
import { dirname as dirname7, join as join10, resolve as resolve2 } from "node:path";
|
|
7365
|
+
import { pathToFileURL as pathToFileURL4 } from "node:url";
|
|
7265
7366
|
|
|
7266
7367
|
// src/project.ts
|
|
7267
|
-
import { existsSync as
|
|
7268
|
-
import { join as
|
|
7269
|
-
import { pathToFileURL as
|
|
7368
|
+
import { existsSync as existsSync6, statSync as statSync2 } from "node:fs";
|
|
7369
|
+
import { join as join8 } from "node:path";
|
|
7370
|
+
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
7270
7371
|
var CONFIG_FILE = "nomos.package.mjs";
|
|
7271
7372
|
async function loadProject(cwd, opts = {}) {
|
|
7272
|
-
const configPath =
|
|
7273
|
-
if (!
|
|
7274
|
-
const href =
|
|
7373
|
+
const configPath = join8(cwd, CONFIG_FILE);
|
|
7374
|
+
if (!existsSync6(configPath)) return void 0;
|
|
7375
|
+
const href = pathToFileURL3(configPath).href + (opts.bust === true ? `?v=${statSync2(configPath).mtimeMs}-${Date.now()}` : "");
|
|
7275
7376
|
const mod = await import(href);
|
|
7276
7377
|
const cfg = mod.default;
|
|
7277
7378
|
if (cfg === void 0 || typeof cfg.name !== "string" || cfg.name.length === 0) {
|
|
@@ -7435,11 +7536,11 @@ function startServer(s) {
|
|
|
7435
7536
|
});
|
|
7436
7537
|
}
|
|
7437
7538
|
function readDeployBody2(cwd, packageName) {
|
|
7438
|
-
const file =
|
|
7439
|
-
if (!
|
|
7539
|
+
const file = join10(cwd, "build", `${packageName}.deploy.json`);
|
|
7540
|
+
if (!existsSync8(file)) {
|
|
7440
7541
|
throw new Error(`compile produced no ${file} \u2014 check the compile output above`);
|
|
7441
7542
|
}
|
|
7442
|
-
return JSON.parse(
|
|
7543
|
+
return JSON.parse(readFileSync8(file, "utf8"));
|
|
7443
7544
|
}
|
|
7444
7545
|
async function installLaw(s, deployBody, installedBy) {
|
|
7445
7546
|
const newHash = await sha256hex(deployBody.packageUsda);
|
|
@@ -7455,11 +7556,11 @@ async function installLaw(s, deployBody, installedBy) {
|
|
|
7455
7556
|
return { ok: true };
|
|
7456
7557
|
}
|
|
7457
7558
|
async function runProofCycle(s, cwd, deployBody, installedBy) {
|
|
7458
|
-
const proofPath =
|
|
7459
|
-
if (!
|
|
7559
|
+
const proofPath = join10(cwd, "build", `${s.packageName}.proof.mts`);
|
|
7560
|
+
if (!existsSync8(proofPath)) return void 0;
|
|
7460
7561
|
const scratch = `proof-${s.cycle}`;
|
|
7461
7562
|
try {
|
|
7462
|
-
const legs = parseOfflineLegs(
|
|
7563
|
+
const legs = parseOfflineLegs(readFileSync8(proofPath, "utf8"));
|
|
7463
7564
|
await mountFresh(s.eng, scratch);
|
|
7464
7565
|
author(s.eng, scratch, "bootstrap", "installDomain", installPayload(s.eng.hashes.nomos, s.eng.nomosPkg, installedBy), "");
|
|
7465
7566
|
author(s.eng, scratch, "nomos", "installDomain", installPayload(s.lawHash, deployBody.packageUsda, installedBy), s.eng.hashes.nomos);
|
|
@@ -7478,7 +7579,7 @@ async function dev(opts) {
|
|
|
7478
7579
|
return void 0;
|
|
7479
7580
|
});
|
|
7480
7581
|
if (project === void 0) {
|
|
7481
|
-
if (!
|
|
7582
|
+
if (!existsSync8(join10(cwd, CONFIG_FILE))) {
|
|
7482
7583
|
err5(`no ${CONFIG_FILE} here (${cwd}) \u2014 \`githolon dev\` runs inside a project; scaffold one from examples/guestbook or \`githolon generate domain <name>\``);
|
|
7483
7584
|
}
|
|
7484
7585
|
return 1;
|
|
@@ -7543,14 +7644,14 @@ ${firstCompile.output}`);
|
|
|
7543
7644
|
}
|
|
7544
7645
|
const moduleDirs = /* @__PURE__ */ new Set();
|
|
7545
7646
|
try {
|
|
7546
|
-
const cfgModule = await import(
|
|
7647
|
+
const cfgModule = await import(pathToFileURL4(project.configPath).href);
|
|
7547
7648
|
for (const d of cfgModule.default?.domains ?? []) {
|
|
7548
|
-
for (const m of d.modules ?? []) moduleDirs.add(
|
|
7649
|
+
for (const m of d.modules ?? []) moduleDirs.add(dirname7(resolve2(cwd, m)));
|
|
7549
7650
|
}
|
|
7550
7651
|
} catch {
|
|
7551
|
-
moduleDirs.add(
|
|
7652
|
+
moduleDirs.add(join10(cwd, "domains"));
|
|
7552
7653
|
}
|
|
7553
|
-
if (moduleDirs.size === 0) moduleDirs.add(
|
|
7654
|
+
if (moduleDirs.size === 0) moduleDirs.add(join10(cwd, "domains"));
|
|
7554
7655
|
let timer;
|
|
7555
7656
|
let cycling = false;
|
|
7556
7657
|
let queued = false;
|
|
@@ -7600,7 +7701,7 @@ ${run.output}`);
|
|
|
7600
7701
|
};
|
|
7601
7702
|
const watchers = [];
|
|
7602
7703
|
for (const d of moduleDirs) {
|
|
7603
|
-
if (!
|
|
7704
|
+
if (!existsSync8(d)) continue;
|
|
7604
7705
|
watchers.push(watch(d, { recursive: true }, (_evt, f) => onChange(f)));
|
|
7605
7706
|
s.watchRoots.push(d.startsWith(cwd) ? d.slice(cwd.length + 1) + "/" : d);
|
|
7606
7707
|
}
|
|
@@ -7625,13 +7726,13 @@ ${run.output}`);
|
|
|
7625
7726
|
|
|
7626
7727
|
// src/git.ts
|
|
7627
7728
|
init_cloud();
|
|
7628
|
-
import { spawnSync as
|
|
7729
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
7629
7730
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
7630
|
-
import { readFileSync as
|
|
7731
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
7631
7732
|
var out6 = (s) => void process.stdout.write(s + "\n");
|
|
7632
7733
|
var err6 = (s) => void process.stderr.write("error: " + s + "\n");
|
|
7633
7734
|
function git(args, opts = {}) {
|
|
7634
|
-
const r =
|
|
7735
|
+
const r = spawnSync3("git", args, { stdio: opts.quiet === true ? "ignore" : "inherit" });
|
|
7635
7736
|
return r.status ?? 1;
|
|
7636
7737
|
}
|
|
7637
7738
|
function ensureSecret(cloud, ws) {
|
|
@@ -7656,7 +7757,7 @@ function workspaceFromPath(path) {
|
|
|
7656
7757
|
}
|
|
7657
7758
|
async function gitCredential(action) {
|
|
7658
7759
|
if (action !== "get") return 0;
|
|
7659
|
-
const kv = parseCredentialInput(
|
|
7760
|
+
const kv = parseCredentialInput(readFileSync9(0, "utf8"));
|
|
7660
7761
|
const ws = workspaceFromPath(kv["path"]);
|
|
7661
7762
|
if (kv["protocol"] !== "https" || ws === void 0) return 0;
|
|
7662
7763
|
const cloud = `https://${kv["host"]}`;
|
|
@@ -7878,6 +7979,23 @@ var HELP = {
|
|
|
7878
7979
|
"githolon gov relay root co2.offer.json"
|
|
7879
7980
|
]
|
|
7880
7981
|
},
|
|
7982
|
+
rebirth: {
|
|
7983
|
+
usage: "githolon rebirth plan <ws> [--reason <text>] [--out <dir>]\n githolon rebirth apply --plan <plan.json> --gcp-secret nomos-root-custodian-key [--yes]",
|
|
7984
|
+
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)",
|
|
7985
|
+
flags: [
|
|
7986
|
+
["--reason <text>", "the mandatory audit justification (fill it into the plan before apply)"],
|
|
7987
|
+
["--out <dir>", "plan: an alternate output dir (default: rebirths/<date>-<ws>)"],
|
|
7988
|
+
["--plan <plan.json>", "apply: the reviewed plan file to execute (drift-pinned)"],
|
|
7989
|
+
["--gcp-secret <name>", "apply: read the root custodian seed from this GCP secret (blessed: nomos-root-custodian-key)"],
|
|
7990
|
+
["--seed-secret <b64>", "apply: break-glass \u2014 the seed inline (avoid in shell history)"],
|
|
7991
|
+
["--yes", "apply: skip the interactive confirm"],
|
|
7992
|
+
["--cloud <url>", "target cloud"]
|
|
7993
|
+
],
|
|
7994
|
+
examples: [
|
|
7995
|
+
"githolon rebirth plan co2-platform --reason 'evolve-gate scar at intent 74'",
|
|
7996
|
+
"githolon rebirth apply --plan rebirths/2026-07-09-co2-platform/plan.json --gcp-secret nomos-root-custodian-key --yes"
|
|
7997
|
+
]
|
|
7998
|
+
},
|
|
7881
7999
|
grant: {
|
|
7882
8000
|
usage: "githolon grant <admin|creation|quota> <principal> [--max <N>] [--label <L>] [--parent <ws>] [--cloud <url>]",
|
|
7883
8001
|
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 +8076,15 @@ function commandHelp(cmd) {
|
|
|
7958
8076
|
init_engine();
|
|
7959
8077
|
init_cloud();
|
|
7960
8078
|
init_local_holon();
|
|
7961
|
-
import { spawnSync as
|
|
7962
|
-
import { existsSync as
|
|
7963
|
-
import { join as
|
|
8079
|
+
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
8080
|
+
import { existsSync as existsSync9, readdirSync as readdirSync4, readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "node:fs";
|
|
8081
|
+
import { join as join11 } from "node:path";
|
|
7964
8082
|
var out7 = (s) => void process.stdout.write(s + "\n");
|
|
7965
8083
|
var err7 = (s) => void process.stderr.write("error: " + s + "\n");
|
|
7966
8084
|
var WS2 = "local";
|
|
7967
8085
|
async function ledgerInit(dir, opts) {
|
|
7968
8086
|
const cloud = cloudBase(opts.cloud);
|
|
7969
|
-
if (
|
|
8087
|
+
if (existsSync9(dir) && readdirSync4(dir).length > 0) {
|
|
7970
8088
|
err7(`refusing to mint into non-empty directory: ${dir}`);
|
|
7971
8089
|
return 1;
|
|
7972
8090
|
}
|
|
@@ -7977,7 +8095,7 @@ async function ledgerInit(dir, opts) {
|
|
|
7977
8095
|
err7(e.message);
|
|
7978
8096
|
return 1;
|
|
7979
8097
|
}
|
|
7980
|
-
const deployBody = JSON.parse(
|
|
8098
|
+
const deployBody = JSON.parse(readFileSync10(deployFile, "utf8"));
|
|
7981
8099
|
const domainHash = await sha256hex(deployBody.packageUsda);
|
|
7982
8100
|
const c = loadCreds();
|
|
7983
8101
|
const principal = await sessionToken().catch(() => void 0) !== void 0 ? c.session.uid : c.principal;
|
|
@@ -7993,11 +8111,11 @@ async function ledgerInit(dir, opts) {
|
|
|
7993
8111
|
const verdict = verifyChainLocal(eng, WS2);
|
|
7994
8112
|
if (!printVerdict(verdict)) return 1;
|
|
7995
8113
|
const gitTree = eng.preopen.dir.contents.get("ws").contents.get(WS2).contents.get("nomos.git");
|
|
7996
|
-
const gitDir =
|
|
8114
|
+
const gitDir = join11(dir, ".git");
|
|
7997
8115
|
writeTreeToDisk(gitTree, gitDir);
|
|
7998
|
-
const cfgPath =
|
|
7999
|
-
|
|
8000
|
-
|
|
8116
|
+
const cfgPath = join11(gitDir, "config");
|
|
8117
|
+
writeFileSync7(cfgPath, readFileSync10(cfgPath, "utf8").replace(/bare = true/, "bare = false"), "utf8");
|
|
8118
|
+
spawnSync4("git", ["-C", dir, "reset", "--hard", "main"], { stdio: "ignore" });
|
|
8001
8119
|
out7(`\u2713 holon written \u2192 ${dir} (a normal git repo; git log IS the audit trail)`);
|
|
8002
8120
|
out7(`
|
|
8003
8121
|
Birth it on Nomos Cloud (the cloud re-derives this exact verdict):`);
|
|
@@ -8005,8 +8123,8 @@ Birth it on Nomos Cloud (the cloud re-derives this exact verdict):`);
|
|
|
8005
8123
|
return 0;
|
|
8006
8124
|
}
|
|
8007
8125
|
async function ledgerVerify(dir, opts) {
|
|
8008
|
-
const gitDir =
|
|
8009
|
-
if (!
|
|
8126
|
+
const gitDir = existsSync9(join11(dir, ".git")) ? join11(dir, ".git") : dir;
|
|
8127
|
+
if (!existsSync9(join11(gitDir, "HEAD"))) {
|
|
8010
8128
|
err7(`${dir} is not a git repo (no HEAD)`);
|
|
8011
8129
|
return 1;
|
|
8012
8130
|
}
|
|
@@ -8480,7 +8598,8 @@ Governance (SIGNED client-side, relayed as {intentBytes} \u2014 never a host-aut
|
|
|
8480
8598
|
githolon gov rebirth <ws> --reason <text> LAWFUL SUPERSESSION (recovery verb 3): supersede a
|
|
8481
8599
|
[--dry-run [--json]] [--yes] scarred chain; --dry-run = READ-ONLY impact report
|
|
8482
8600
|
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>
|
|
8601
|
+
githolon rebirth apply --plan <plan.json> drift-pinned apply of a reviewed plan \u2192 certificate.json
|
|
8602
|
+
--gcp-secret nomos-root-custodian-key [--yes] (apply needs the ROOT CUSTODIAN seed; --gcp-secret is blessed)
|
|
8484
8603
|
githolon replay <ws> --repair execute the repair matching a red verify (\u2192 certificate)
|
|
8485
8604
|
githolon grant <admin|creation> <principal> [--label L] grant authority at the parent (default root)
|
|
8486
8605
|
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.2",
|
|
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.2",
|
|
33
|
+
"@githolon/dsl": "^0.69.2",
|
|
34
34
|
"isomorphic-git": "^1.38.4"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|