@githolon/dsl 0.112.4 → 0.112.6
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/compile_proof.d.mts +2 -0
- package/compile_proof.mjs +17 -10
- package/package.json +2 -2
- package/src/compile_package_main.ts +30 -23
- package/src/compiler_cache.ts +26 -0
- package/src/operation_contract_check.ts +2 -1
package/compile_proof.d.mts
CHANGED
|
@@ -36,12 +36,14 @@ export function writePlanCompileProof(options: {
|
|
|
36
36
|
plan: string;
|
|
37
37
|
planSha256: string;
|
|
38
38
|
inputs: readonly { readonly path: string; readonly sha256: string }[];
|
|
39
|
+
sourceRoot?: string;
|
|
39
40
|
}): void;
|
|
40
41
|
export function readPlanCompileProof(options: {
|
|
41
42
|
proofPath: string;
|
|
42
43
|
baseIdentity: string;
|
|
43
44
|
runtimeSha256: string;
|
|
44
45
|
digestFile?: (file: string) => string;
|
|
46
|
+
sourceRoot?: string;
|
|
45
47
|
}): { javascript: string; sha256: string } | undefined;
|
|
46
48
|
export function writeKeyProofUsda(file: string, format: string, key: string): void;
|
|
47
49
|
export function readKeyProofUsda(file: string, format: string): string | undefined;
|
package/compile_proof.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// A content-addressed compiler proof expressed as USDA, not a parallel JSON manifest.
|
|
2
|
-
// It is disposable build cache metadata under
|
|
2
|
+
// It is disposable build cache metadata under .nomos-cache: law and custody
|
|
3
3
|
// remain the emitted typed USDA closure.
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
5
|
import {
|
|
@@ -123,7 +123,7 @@ export function compileInputs({ cwd, dslDir, configPath, argumentIdentity }) {
|
|
|
123
123
|
|
|
124
124
|
export function compileProofPath(cwd, configPath) {
|
|
125
125
|
const key = sha256(path.resolve(configPath)).slice(0, 24);
|
|
126
|
-
return path.join(cwd, "
|
|
126
|
+
return path.join(cwd, ".nomos-cache", `${key}.compile-proof.usda`);
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
function artifactPrim(kind, entry, proofDir) {
|
|
@@ -253,14 +253,14 @@ export function readCompileProof({ proofPath, inputs }) {
|
|
|
253
253
|
};
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
-
function emitPlanCompileProof({ proofPath, baseIdentity, runtimeSha256, plan, planSha256, inputs }) {
|
|
256
|
+
function emitPlanCompileProof({ proofPath, baseIdentity, runtimeSha256, plan, planSha256, inputs, sourceRoot }) {
|
|
257
257
|
const proofDir = path.dirname(proofPath);
|
|
258
|
-
const inputPrims = inputs.map((entry) => artifactPrim("input", entry, proofDir));
|
|
258
|
+
const inputPrims = inputs.map((entry) => artifactPrim("input", entry, sourceRoot ?? proofDir));
|
|
259
259
|
return [
|
|
260
260
|
"#usda 1.0",
|
|
261
261
|
"(",
|
|
262
262
|
" customLayerData = {",
|
|
263
|
-
|
|
263
|
+
` string "nomos:format" = "nomos.plan-compile-proof.${sourceRoot === undefined ? "v1" : "v2"}"`,
|
|
264
264
|
" }",
|
|
265
265
|
")",
|
|
266
266
|
"",
|
|
@@ -284,28 +284,33 @@ function emitPlanCompileProof({ proofPath, baseIdentity, runtimeSha256, plan, pl
|
|
|
284
284
|
].join("\n");
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
-
export function writePlanCompileProof({ proofPath, baseIdentity, runtimeSha256, plan, planSha256, inputs }) {
|
|
287
|
+
export function writePlanCompileProof({ proofPath, baseIdentity, runtimeSha256, plan, planSha256, inputs, sourceRoot }) {
|
|
288
288
|
if (![baseIdentity, runtimeSha256, planSha256, ...inputs.map((entry) => entry.sha256)].every((value) => HASH.test(value))) {
|
|
289
289
|
throw new Error("plan compile proof requires content-addressed identities");
|
|
290
290
|
}
|
|
291
|
+
if (sourceRoot !== undefined && inputs.some(({ path: file }) => {
|
|
292
|
+
const relative = path.relative(sourceRoot, file);
|
|
293
|
+
return relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative);
|
|
294
|
+
})) throw new Error("portable plan compile proof requires inputs inside source root");
|
|
291
295
|
mkdirSync(path.dirname(proofPath), { recursive: true });
|
|
292
296
|
const temporary = `${proofPath}.tmp-${process.pid}`;
|
|
293
297
|
writeFileSync(
|
|
294
298
|
temporary,
|
|
295
|
-
emitPlanCompileProof({ proofPath, baseIdentity, runtimeSha256, plan, planSha256, inputs }),
|
|
299
|
+
emitPlanCompileProof({ proofPath, baseIdentity, runtimeSha256, plan, planSha256, inputs, sourceRoot }),
|
|
296
300
|
"utf8",
|
|
297
301
|
);
|
|
298
302
|
renameSync(temporary, proofPath);
|
|
299
303
|
}
|
|
300
304
|
|
|
301
|
-
export function readPlanCompileProof({ proofPath, baseIdentity, runtimeSha256, digestFile }) {
|
|
305
|
+
export function readPlanCompileProof({ proofPath, baseIdentity, runtimeSha256, digestFile, sourceRoot }) {
|
|
302
306
|
let text;
|
|
303
307
|
try {
|
|
304
308
|
text = readFileSync(proofPath, "utf8");
|
|
305
309
|
} catch {
|
|
306
310
|
return undefined;
|
|
307
311
|
}
|
|
308
|
-
|
|
312
|
+
const format = `nomos.plan-compile-proof.${sourceRoot === undefined ? "v1" : "v2"}`;
|
|
313
|
+
if (!text.includes(`string "nomos:format" = "${format}"`)) return undefined;
|
|
309
314
|
if (property(text, "baseIdentity") !== baseIdentity || property(text, "runtimeSha256") !== runtimeSha256) {
|
|
310
315
|
return undefined;
|
|
311
316
|
}
|
|
@@ -314,7 +319,9 @@ export function readPlanCompileProof({ proofPath, baseIdentity, runtimeSha256, d
|
|
|
314
319
|
const inputs = [];
|
|
315
320
|
const inputPattern = /def NomosCompileInput "[^"]+"\s*\{\s*custom uniform asset nomos:path = @([^@]+)@\s*custom uniform string nomos:sha256 = "([0-9a-f]{64})"\s*\}/gu;
|
|
316
321
|
for (const match of inputsScope.matchAll(inputPattern)) {
|
|
317
|
-
|
|
322
|
+
const relative = match[1];
|
|
323
|
+
if (sourceRoot !== undefined && (path.isAbsolute(relative) || relative === ".." || relative.startsWith("../"))) return undefined;
|
|
324
|
+
inputs.push({ path: path.resolve(sourceRoot ?? path.dirname(proofPath), relative), sha256: match[2] });
|
|
318
325
|
}
|
|
319
326
|
if (inputs.length === 0) return undefined;
|
|
320
327
|
for (const input of inputs) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@githolon/dsl",
|
|
3
|
-
"version": "0.112.
|
|
3
|
+
"version": "0.112.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "Nomos 2 domain-authoring DSL: aggregates + directives in TS, executed and encoded to the Rust kernel's wire shapes.",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"test": "vitest run"
|
|
74
74
|
},
|
|
75
75
|
"dependencies": {
|
|
76
|
-
"@githolon/runtime": "^0.112.
|
|
76
|
+
"@githolon/runtime": "^0.112.6",
|
|
77
77
|
"@bufbuild/protobuf": "^2.13.0",
|
|
78
78
|
"@bufbuild/protoc-gen-es": "^2.13.0",
|
|
79
79
|
"esbuild": "0.24.2",
|
|
@@ -46,6 +46,7 @@ import type { Directive } from "./directive.js";
|
|
|
46
46
|
import { execFile, execFileSync } from "node:child_process";
|
|
47
47
|
import { promisify } from "node:util";
|
|
48
48
|
import { checkOperationContracts } from "./operation_contract_check.js";
|
|
49
|
+
import { compilerIntermediateCacheRoot, compilerSourceName, compilerSourceRoot } from "./compiler_cache.js";
|
|
49
50
|
import {
|
|
50
51
|
APPLICATION_CONTRACT_MODULE,
|
|
51
52
|
assertGeneratedClientBundleBoundary,
|
|
@@ -1902,10 +1903,7 @@ function tsOperationProtoCache(
|
|
|
1902
1903
|
.update(readFileSync(generatorPackage))
|
|
1903
1904
|
.digest("hex");
|
|
1904
1905
|
const cacheDir = path.join(
|
|
1905
|
-
cacheRoot,
|
|
1906
|
-
"node_modules",
|
|
1907
|
-
".cache",
|
|
1908
|
-
"nomos",
|
|
1906
|
+
compilerIntermediateCacheRoot(cacheRoot),
|
|
1909
1907
|
"operation-protobuf",
|
|
1910
1908
|
"typescript"
|
|
1911
1909
|
);
|
|
@@ -1970,8 +1968,11 @@ function dartOperationProtoCache(
|
|
|
1970
1968
|
path.join(path.dirname(path.dirname(plugin)), "pubspec.lock"),
|
|
1971
1969
|
];
|
|
1972
1970
|
const digest = createHash("sha256");
|
|
1971
|
+
const sourceRoot = compilerSourceRoot();
|
|
1973
1972
|
for (const file of files) {
|
|
1974
|
-
|
|
1973
|
+
const name = sourceRoot !== undefined && path.resolve(file).startsWith(`${sourceRoot}${path.sep}`)
|
|
1974
|
+
? compilerSourceName(file, sourceRoot) : file;
|
|
1975
|
+
digest.update(`\0${name}\0`);
|
|
1975
1976
|
if (existsSync(file)) digest.update(readFileSync(file));
|
|
1976
1977
|
}
|
|
1977
1978
|
return digest.digest("hex");
|
|
@@ -1985,10 +1986,7 @@ function dartOperationProtoCache(
|
|
|
1985
1986
|
.update(generatorIdentity)
|
|
1986
1987
|
.digest("hex");
|
|
1987
1988
|
const cacheDir = path.join(
|
|
1988
|
-
process.cwd(),
|
|
1989
|
-
"node_modules",
|
|
1990
|
-
".cache",
|
|
1991
|
-
"nomos",
|
|
1989
|
+
compilerIntermediateCacheRoot(process.cwd()),
|
|
1992
1990
|
"operation-protobuf",
|
|
1993
1991
|
"dart"
|
|
1994
1992
|
);
|
|
@@ -2546,7 +2544,7 @@ const NOMOS_TYPES_DEP = "^0.11.3";
|
|
|
2546
2544
|
// DomainNotInstalledForSession, engine.follow, pendingConflicts lanes) — the generated client
|
|
2547
2545
|
// REQUIRES this surface. 0.48.1 fixes NomosSession.watchPendingConflicts delegation.
|
|
2548
2546
|
const NOMOS_CLIENT_DEP = "^0.66.11";
|
|
2549
|
-
const NOMOS_FLUTTER_DEP = "^0.65.
|
|
2547
|
+
const NOMOS_FLUTTER_DEP = "^0.65.19";
|
|
2550
2548
|
// DRIFT TRIPWIRE: pubspec_pins.test.ts asserts these equal the CURRENT versions in the Dart and Flutter
|
|
2551
2549
|
// package pubspecs — a release without this bump fails the suite, so tenants never
|
|
2552
2550
|
// land back in dependency_overrides (the exact co2 report this closes, third occurrence).
|
|
@@ -6442,6 +6440,7 @@ async function main(): Promise<void> {
|
|
|
6442
6440
|
baseIdentity: string;
|
|
6443
6441
|
runtimeSha256: string;
|
|
6444
6442
|
digestFile?: (file: string) => string;
|
|
6443
|
+
sourceRoot?: string;
|
|
6445
6444
|
}): { javascript: string; sha256: string } | undefined;
|
|
6446
6445
|
writePlanCompileProof(options: {
|
|
6447
6446
|
proofPath: string;
|
|
@@ -6450,15 +6449,20 @@ async function main(): Promise<void> {
|
|
|
6450
6449
|
plan: string;
|
|
6451
6450
|
planSha256: string;
|
|
6452
6451
|
inputs: readonly { readonly path: string; readonly sha256: string }[];
|
|
6452
|
+
sourceRoot?: string;
|
|
6453
6453
|
}): void;
|
|
6454
6454
|
};
|
|
6455
6455
|
const planCacheDir = path.join(
|
|
6456
|
-
cfgDir,
|
|
6457
|
-
"node_modules",
|
|
6458
|
-
".cache",
|
|
6459
|
-
"nomos",
|
|
6456
|
+
compilerIntermediateCacheRoot(cfgDir),
|
|
6460
6457
|
"plans"
|
|
6461
6458
|
);
|
|
6459
|
+
const configuredSourceRoot = compilerSourceRoot();
|
|
6460
|
+
const planSourceRoot = configuredSourceRoot !== undefined &&
|
|
6461
|
+
!path.relative(configuredSourceRoot, cfgDir).startsWith("..") &&
|
|
6462
|
+
!path.isAbsolute(path.relative(configuredSourceRoot, cfgDir))
|
|
6463
|
+
? configuredSourceRoot : undefined;
|
|
6464
|
+
const portablePlanText = (value: string): string => planSourceRoot === undefined
|
|
6465
|
+
? value : value.replaceAll(planSourceRoot, "<nomos-source-root>");
|
|
6462
6466
|
const planInputDigestCache = new Map<string, string>();
|
|
6463
6467
|
const planBytesDigest = (bytes: Uint8Array): string =>
|
|
6464
6468
|
createHash("sha256").update(bytes).digest("hex");
|
|
@@ -6910,10 +6914,10 @@ async function main(): Promise<void> {
|
|
|
6910
6914
|
[
|
|
6911
6915
|
planCompilerIdentity,
|
|
6912
6916
|
runtimeSha256,
|
|
6913
|
-
path.resolve(cfgDir),
|
|
6917
|
+
planSourceRoot === undefined ? path.resolve(cfgDir) : compilerSourceName(cfgDir, planSourceRoot),
|
|
6914
6918
|
compact ? "compact" : "readable",
|
|
6915
|
-
signature,
|
|
6916
|
-
entrySource,
|
|
6919
|
+
portablePlanText(signature),
|
|
6920
|
+
portablePlanText(entrySource),
|
|
6917
6921
|
].join("\0")
|
|
6918
6922
|
);
|
|
6919
6923
|
const cachePlanPath = path.join(planCacheDir, `${baseIdentity}.mjs`);
|
|
@@ -6928,6 +6932,7 @@ async function main(): Promise<void> {
|
|
|
6928
6932
|
baseIdentity,
|
|
6929
6933
|
runtimeSha256,
|
|
6930
6934
|
digestFile: planInputDigest,
|
|
6935
|
+
...(planSourceRoot === undefined ? {} : { sourceRoot: planSourceRoot }),
|
|
6931
6936
|
});
|
|
6932
6937
|
let bundled: string;
|
|
6933
6938
|
if (cached !== undefined) {
|
|
@@ -6984,7 +6989,11 @@ async function main(): Promise<void> {
|
|
|
6984
6989
|
.filter((file) => existsSync(file))
|
|
6985
6990
|
.map((file) => ({ path: file, sha256: planInputDigest(file) }))
|
|
6986
6991
|
.sort((left, right) => left.path.localeCompare(right.path));
|
|
6987
|
-
|
|
6992
|
+
const inputsArePortable = planSourceRoot === undefined || inputs.every(({ path: file }) => {
|
|
6993
|
+
const relative = path.relative(planSourceRoot, file);
|
|
6994
|
+
return relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
|
|
6995
|
+
});
|
|
6996
|
+
if (inputs.length > 0 && inputsArePortable) {
|
|
6988
6997
|
mkdirSync(planCacheDir, { recursive: true });
|
|
6989
6998
|
const temporary = `${cachePlanPath}.tmp-${process.pid}`;
|
|
6990
6999
|
writeFileSync(temporary, bundled, "utf8");
|
|
@@ -6996,6 +7005,7 @@ async function main(): Promise<void> {
|
|
|
6996
7005
|
plan: cachePlanPath,
|
|
6997
7006
|
planSha256: sha256HexUtf8(bundled),
|
|
6998
7007
|
inputs,
|
|
7008
|
+
...(planSourceRoot === undefined ? {} : { sourceRoot: planSourceRoot }),
|
|
6999
7009
|
});
|
|
7000
7010
|
}
|
|
7001
7011
|
}
|
|
@@ -8369,10 +8379,7 @@ async function main(): Promise<void> {
|
|
|
8369
8379
|
.update(readFileSync(fileURLToPath(import.meta.url)))
|
|
8370
8380
|
.digest("hex");
|
|
8371
8381
|
const declarationCacheDir = path.join(
|
|
8372
|
-
cfgDir,
|
|
8373
|
-
"node_modules",
|
|
8374
|
-
".cache",
|
|
8375
|
-
"nomos",
|
|
8382
|
+
compilerIntermediateCacheRoot(cfgDir),
|
|
8376
8383
|
"typescript-declarations"
|
|
8377
8384
|
);
|
|
8378
8385
|
const declarationCachePath = path.join(
|
|
@@ -9468,7 +9475,7 @@ async function main(): Promise<void> {
|
|
|
9468
9475
|
if (analyzeFlag) runDartAnalyze(dartOut);
|
|
9469
9476
|
|
|
9470
9477
|
// The unchanged lane is itself USDA: a disposable content proof under
|
|
9471
|
-
//
|
|
9478
|
+
// .nomos-cache relates authored/compiler inputs to every generated
|
|
9472
9479
|
// artifact. It is not another law manifest and carries no semantic opinions.
|
|
9473
9480
|
const compileProofPath = process.env.NOMOS_COMPILE_PROOF_PATH;
|
|
9474
9481
|
const compileArgumentIdentity = process.env.NOMOS_COMPILE_ARGUMENT_IDENTITY;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
/** Disposable compiler intermediates may live on one machine for all local runners. */
|
|
5
|
+
export function compilerIntermediateCacheRoot(localRoot: string): string {
|
|
6
|
+
const configured = process.env.NOMOS_COMPILER_CACHE_ROOT;
|
|
7
|
+
if (configured === undefined || configured === "") return path.join(localRoot, ".nomos-cache");
|
|
8
|
+
const expanded = configured === "~" ? homedir() : configured.startsWith(`~${path.sep}`)
|
|
9
|
+
? path.join(homedir(), configured.slice(2)) : configured;
|
|
10
|
+
if (!path.isAbsolute(expanded)) throw new Error("NOMOS_COMPILER_CACHE_ROOT must be absolute or start with ~/");
|
|
11
|
+
return path.resolve(expanded);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Relative source names keep content-addressed plans portable between runner checkouts. */
|
|
15
|
+
export function compilerSourceRoot(): string | undefined {
|
|
16
|
+
const configured = process.env.NOMOS_COMPILER_SOURCE_ROOT;
|
|
17
|
+
return configured === undefined || configured === "" ? undefined : path.resolve(configured);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function compilerSourceName(file: string, sourceRoot: string): string {
|
|
21
|
+
const relative = path.relative(sourceRoot, path.resolve(file));
|
|
22
|
+
if (relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
|
|
23
|
+
throw new Error(`compiler input is outside NOMOS_COMPILER_SOURCE_ROOT: ${file}`);
|
|
24
|
+
}
|
|
25
|
+
return (relative || ".").replaceAll(path.sep, "/");
|
|
26
|
+
}
|
|
@@ -2,6 +2,7 @@ import { execFileSync } from 'node:child_process';
|
|
|
2
2
|
import { createHash } from 'node:crypto';
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
+
import { compilerIntermediateCacheRoot } from './compiler_cache.js';
|
|
5
6
|
|
|
6
7
|
/** Validate the emitted law, not a second in-memory interpretation of the DSL.
|
|
7
8
|
* Cached results accelerate compilation only; they never enter custody or stand
|
|
@@ -14,7 +15,7 @@ export function checkOperationContracts(lawPath: string, descriptorPath: string,
|
|
|
14
15
|
const key = createHash('sha256').update('nomos.operation-contract-check.v1\0')
|
|
15
16
|
.update(readFileSync(artifact)).update(readFileSync(checker)).update(readFileSync(lawPath))
|
|
16
17
|
.update(readFileSync(descriptorPath)).digest('hex');
|
|
17
|
-
const cache = path.join(cacheRoot, '
|
|
18
|
+
const cache = path.join(compilerIntermediateCacheRoot(cacheRoot), 'operation-contracts');
|
|
18
19
|
const receipt = path.join(cache, `${key}.ok`);
|
|
19
20
|
if (existsSync(receipt)) return;
|
|
20
21
|
try {
|