@githolon/dsl 0.102.4 → 0.103.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compile_package.mjs +43 -2
- package/compile_proof.d.mts +47 -0
- package/compile_proof.mjs +343 -0
- package/dart/CHANGELOG.md +7 -0
- package/dart/lib/src/dev_cloud.dart +8 -8
- package/dart/lib/src/nms_generated_runtime.dart +2 -0
- package/dart/lib/src/runner/node-entry.mjs +5504 -1236
- package/dart/lib/src/runner/offline-install.mjs +4578 -528
- package/dart/lib/src/test_harness.dart +206 -152
- package/dart/lib/src/webview_bridge.dart +196 -89
- package/dart/pubspec.lock +1 -1
- package/dart/pubspec.yaml +2 -2
- package/dart/test/acquire_session_credentials_test.dart +4 -3
- package/dart/test/adv_realm_interference_test.dart +7 -6
- package/dart/test/cloud_bound_topology_test.dart +3 -3
- package/dart/test/cluster_births_test.dart +4 -3
- package/dart/test/cluster_device_keyed_acceptance_test.dart +10 -16
- package/dart/test/cluster_local_autosync_test.dart +3 -2
- package/dart/test/cluster_scale_test.dart +3 -2
- package/dart/test/dlq_session_surface_test.dart +7 -6
- package/dart/test/first_app_gauntlet_test.dart +14 -21
- package/dart/test/fixtures/wedge/fake-install.mjs +1 -1
- package/dart/test/four_layer_nested_topology_test.dart +4 -4
- package/dart/test/harness_phase_timeout_test.dart +2 -2
- package/dart/test/local_sync_inert_test.dart +1 -1
- package/dart/test/parent_signer_recovery_test.dart +2 -2
- package/dart/test/sealing_client_test.dart +4 -3
- package/dart/test/session_bound_test.dart +8 -7
- package/dart/test/test_harness_test.dart +13 -12
- package/dart/test/vo_read_typing_test.dart +4 -3
- package/dart/test/watch_after_offer_stall_test.dart +4 -3
- package/dart/test/webview_bridge_test.dart +102 -5
- package/dart_types/CHANGELOG.md +5 -0
- package/dart_types/lib/nomos_types.dart +9 -0
- package/dart_types/lib/src/nomos_ref.dart +20 -0
- package/dart_types/lib/src/optional_ref.dart +85 -0
- package/dart_types/lib/src/sha256_digest.dart +41 -0
- package/dart_types/lib/src/versioned_nomos_ref.dart +81 -0
- package/dart_types/pubspec.yaml +1 -1
- package/dart_types/test/optional_ref_test.dart +44 -0
- package/dart_types/test/sha256_digest_test.dart +18 -0
- package/package.json +9 -5
- package/runtime/generated-application-host.js +5365 -1105
- package/src/aggregate.ts +18 -0
- package/src/application_composition.ts +6 -32
- package/src/attested_core.ts +6 -3
- package/src/birth_meter.ts +1 -0
- package/src/birth_meter_ensure.ts +28 -2
- package/src/births.ts +1 -1
- package/src/build_package.ts +162 -538
- package/src/business_birth.ts +19 -3
- package/src/canonical_json.ts +21 -0
- package/src/check_package_main.ts +76 -35
- package/src/clear_directive.ts +19 -8
- package/src/codegen_dart.ts +305 -22
- package/src/codegen_dart_application.ts +844 -292
- package/src/codegen_dart_client.ts +1084 -407
- package/src/codegen_dart_scenario.ts +12 -12
- package/src/codegen_proof.ts +169 -39
- package/src/codegen_provider_dart.ts +17 -1
- package/src/codegen_ts.ts +298 -106
- package/src/compat_manifest.ts +2 -2
- package/src/compat_package_main.ts +8 -12
- package/src/compile_package_main.ts +1866 -597
- package/src/compose.ts +1 -1
- package/src/directive.ts +208 -15
- package/src/engine_entry.ts +165 -111
- package/src/evolve_preview.ts +43 -81
- package/src/extremum.ts +1 -1
- package/src/fields.ts +183 -4
- package/src/flow_gate.ts +75 -2
- package/src/framework/application_home.ts +2 -0
- package/src/framework/auth_provider_law.ts +2 -2
- package/src/framework/birth_meter.ts +7 -19
- package/src/framework/bootstrap.ts +0 -2
- package/src/framework/business_corrections.ts +9 -5
- package/src/framework/domain_lifecycle.ts +15 -29
- package/src/framework/encryption_scope.ts +2 -1
- package/src/framework/framework_aggregates.ts +2 -0
- package/src/framework/genesis.ts +16 -14
- package/src/framework/home.ts +20 -14
- package/src/framework/owned_custody.ts +9 -3
- package/src/framework/platform_admin.ts +3 -3
- package/src/framework/relations.ts +21 -13
- package/src/framework/signing_identity.ts +45 -40
- package/src/framework/workspace_invariant.ts +245 -0
- package/src/framework/workspaces.ts +23 -29
- package/src/index.ts +36 -16
- package/src/intent.ts +178 -6
- package/src/law_check.ts +32 -11
- package/src/law_graph.ts +2902 -0
- package/src/law_graph_usda.ts +1799 -0
- package/src/law_identity.ts +435 -0
- package/src/law_value_type.ts +230 -0
- package/src/lsp_server.ts +61 -31
- package/src/ops.ts +7 -0
- package/src/package_config.ts +141 -0
- package/src/package_dependencies.ts +108 -0
- package/src/package_dependency_usage.ts +150 -0
- package/src/package_source_imports.ts +71 -0
- package/src/plan_source_slice.ts +335 -0
- package/src/point_guard.ts +192 -0
- package/src/precondition.ts +44 -9
- package/src/read_projection_namespace.ts +1 -1
- package/src/runtime_zod.ts +44 -0
- package/src/secondary_ensure.ts +67 -14
- package/src/shape_compat.ts +1 -1
- package/src/stable_id_identity_bridge.ts +149 -0
- package/src/stable_id_lockfile.ts +278 -0
- package/src/stable_ids.ts +7 -2
- package/src/stable_ids_for_module.ts +348 -0
- package/src/stable_ids_types.ts +1 -1
- package/src/sum.ts +1 -1
- package/src/usd_state.ts +1 -1
- package/src/usda_relationship_integrity.ts +66 -0
- package/src/usda_text.ts +18 -0
- package/src/usdz.ts +78 -0
- package/src/value_object.ts +95 -0
- package/src/wire.ts +19 -0
- package/src/wire_encode.ts +22 -0
- package/src/workspace_sharding.ts +52 -36
- package/src/workspace_sharing.ts +28 -4
- package/src/zod_introspection.ts +1 -1
- package/dart/test/cluster_attested_test.dart +0 -201
- package/src/compile_engine.ts +0 -595
- package/src/manifest.ts +0 -1476
- package/src/read_projection_composition.ts +0 -117
- package/src/read_projection_manifest.ts +0 -115
- package/src/relation_composition.ts +0 -286
- package/src/usd.ts +0 -1967
- package/src/usd_layers.ts +0 -1776
package/src/business_birth.ts
CHANGED
|
@@ -54,10 +54,16 @@ export const CURRENT_LAW_PREFIX = "nomos:current-law:";
|
|
|
54
54
|
|
|
55
55
|
export interface BusinessBirthMetadata {
|
|
56
56
|
readonly aggregateId: string;
|
|
57
|
+
/** Owning law domain for closure-safe cross-workspace intent linking. */
|
|
58
|
+
readonly domain: string;
|
|
57
59
|
readonly publicPayloadSchema: z.ZodObject<z.ZodRawShape>;
|
|
58
60
|
readonly rootId: string;
|
|
59
61
|
readonly namespace: string;
|
|
60
62
|
readonly keyField: string;
|
|
63
|
+
/** Exact child-genesis offer route prepared before the parent birth dispatch. */
|
|
64
|
+
readonly seedDirectiveId: string;
|
|
65
|
+
/** Compiler-owned child-genesis routes which may be appended after the business seed. */
|
|
66
|
+
readonly genesisDirectiveIds: readonly string[];
|
|
61
67
|
/** Private proof/lowering policy; omitted from every generated tenant payload. */
|
|
62
68
|
readonly founderRoles: readonly string[];
|
|
63
69
|
readonly founderScope: string;
|
|
@@ -69,6 +75,7 @@ export interface BusinessBirthDirective extends Directive<Record<string, unknown
|
|
|
69
75
|
|
|
70
76
|
type BusinessBirthInternalDirective<P = Record<string, unknown>> = Directive<P> & {
|
|
71
77
|
readonly businessBirthInternal: true;
|
|
78
|
+
readonly businessBirthSeed?: true;
|
|
72
79
|
};
|
|
73
80
|
|
|
74
81
|
function internalDirective<P>(d: Directive<P>): BusinessBirthInternalDirective<P> {
|
|
@@ -189,10 +196,12 @@ function lowerOne<P extends Record<string, unknown>, F extends Record<string, Fi
|
|
|
189
196
|
}),
|
|
190
197
|
),
|
|
191
198
|
];
|
|
192
|
-
})
|
|
199
|
+
})
|
|
200
|
+
.alsoEnsures(RelationTuple);
|
|
193
201
|
const seed = {
|
|
194
202
|
...seedBase,
|
|
195
203
|
businessBirthInternal: true,
|
|
204
|
+
businessBirthSeed: true,
|
|
196
205
|
} as BusinessBirthInternalDirective;
|
|
197
206
|
|
|
198
207
|
const birthBase = directive(birthId)
|
|
@@ -228,7 +237,6 @@ function lowerOne<P extends Record<string, unknown>, F extends Record<string, Fi
|
|
|
228
237
|
actor: founder,
|
|
229
238
|
payload: { domainHash: `${CURRENT_LAW_PREFIX}nomos` },
|
|
230
239
|
domainHash: `${CURRENT_LAW_PREFIX}nomos`,
|
|
231
|
-
domainPackageB64: "",
|
|
232
240
|
},
|
|
233
241
|
{
|
|
234
242
|
domain: "nomos",
|
|
@@ -236,7 +244,6 @@ function lowerOne<P extends Record<string, unknown>, F extends Record<string, Fi
|
|
|
236
244
|
actor: founder,
|
|
237
245
|
payload: { domainHash: `${CURRENT_LAW_PREFIX}${domain}` },
|
|
238
246
|
domainHash: `${CURRENT_LAW_PREFIX}${domain}`,
|
|
239
|
-
domainPackageB64: "",
|
|
240
247
|
},
|
|
241
248
|
{
|
|
242
249
|
domain,
|
|
@@ -298,10 +305,19 @@ function lowerOne<P extends Record<string, unknown>, F extends Record<string, Fi
|
|
|
298
305
|
|
|
299
306
|
const metadata: BusinessBirthMetadata = {
|
|
300
307
|
aggregateId: decl.aggregate.id,
|
|
308
|
+
domain,
|
|
301
309
|
publicPayloadSchema: publicSchema,
|
|
302
310
|
rootId,
|
|
303
311
|
namespace,
|
|
304
312
|
keyField: decl.keyField,
|
|
313
|
+
seedDirectiveId: seedId,
|
|
314
|
+
genesisDirectiveIds: [
|
|
315
|
+
"enrollSigner",
|
|
316
|
+
"seedAuthProvider",
|
|
317
|
+
"seedBirthAttestation",
|
|
318
|
+
"seedGenesis",
|
|
319
|
+
"nomosBirthRecordEnsure",
|
|
320
|
+
],
|
|
305
321
|
founderRoles: decl.founderRoles,
|
|
306
322
|
founderScope: decl.founderScope,
|
|
307
323
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic JSON for compiler-internal fingerprints whose model is already typed.
|
|
3
|
+
*
|
|
4
|
+
* This is a byte-stable serializer, not a law representation. Canonical Nomos law is
|
|
5
|
+
* typed USDA; callers use this only when a small derived compiler value (for example a
|
|
6
|
+
* generated client interface) needs a reproducible digest.
|
|
7
|
+
*/
|
|
8
|
+
function canonicalize(value: unknown): unknown {
|
|
9
|
+
if (Array.isArray(value)) return value.map(canonicalize);
|
|
10
|
+
if (value !== null && typeof value === "object") {
|
|
11
|
+
const object = value as Record<string, unknown>;
|
|
12
|
+
const sorted: Record<string, unknown> = {};
|
|
13
|
+
for (const key of Object.keys(object).sort()) sorted[key] = canonicalize(object[key]);
|
|
14
|
+
return sorted;
|
|
15
|
+
}
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function canonicalJson(value: unknown): string {
|
|
20
|
+
return JSON.stringify(canonicalize(value));
|
|
21
|
+
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* `githolon check` — the author-time gate as a standalone command
|
|
8
|
-
* (architecture/author_time_gate.md, slice 1). Loads `nomos.
|
|
8
|
+
* (architecture/author_time_gate.md, slice 1). Loads `nomos.project.ts`, composes each
|
|
9
9
|
* domain the SAME way `compile` does (`composeDomainModule` — the one owner of directive
|
|
10
10
|
* discovery), runs {@link checkDomainModules}, prints the unified report, and exits
|
|
11
11
|
* non-zero on any REFUSE-level finding. `compile` runs the same twins implicitly.
|
|
@@ -21,20 +21,26 @@ import { LawSourceMap } from "./law_source_map.js";
|
|
|
21
21
|
import {
|
|
22
22
|
currentEvolveLaw,
|
|
23
23
|
evolveDiff,
|
|
24
|
-
|
|
24
|
+
evolveLawFromInterface,
|
|
25
25
|
evolveLawFromLockfile,
|
|
26
26
|
type EvolveLaw,
|
|
27
27
|
type StableIdLockfile,
|
|
28
28
|
} from "./evolve_preview.js";
|
|
29
|
+
import { parseStableIdLockfile } from "./stable_id_lockfile.js";
|
|
30
|
+
import {
|
|
31
|
+
validateNomosPackageConfig,
|
|
32
|
+
type NomosPackageConfig,
|
|
33
|
+
} from "./package_config.js";
|
|
34
|
+
import { assertPublicPackageImports } from "./package_source_imports.js";
|
|
35
|
+
import { packageDependencyUsageFindings } from "./package_dependency_usage.js";
|
|
29
36
|
|
|
30
37
|
interface DomainConfig {
|
|
31
38
|
key: string;
|
|
32
39
|
name?: string;
|
|
33
40
|
modules: string[];
|
|
34
41
|
}
|
|
35
|
-
interface PackageConfig {
|
|
36
|
-
|
|
37
|
-
domains: DomainConfig[];
|
|
42
|
+
interface PackageConfig extends NomosPackageConfig {
|
|
43
|
+
readonly domains: readonly DomainConfig[];
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
function fail(msg: string): never {
|
|
@@ -43,7 +49,7 @@ function fail(msg: string): never {
|
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
/**
|
|
46
|
-
* Compose the package's domain modules from `nomos.
|
|
52
|
+
* Compose the package's domain modules from `nomos.project.ts` — the check-time subset of what
|
|
47
53
|
* `compile_package_main` does: import the config, import each domain's TS modules, and hand them to
|
|
48
54
|
* `composeDomainModule` (the shared composition primitive that discovers directives/aggregates and
|
|
49
55
|
* applies the secondary-ensure auto-declare). Returns the composed modules ready for the twins.
|
|
@@ -59,62 +65,84 @@ export async function loadComposedModules(configArg: string): Promise<DomainModu
|
|
|
59
65
|
*/
|
|
60
66
|
export async function loadComposedModulesWithSources(
|
|
61
67
|
configArg: string,
|
|
62
|
-
): Promise<{
|
|
68
|
+
): Promise<{
|
|
69
|
+
modules: DomainModule[];
|
|
70
|
+
domainFiles: Map<string, string[]>;
|
|
71
|
+
dependencyFindings: readonly Finding[];
|
|
72
|
+
}> {
|
|
63
73
|
const configPath = path.resolve(process.cwd(), configArg);
|
|
64
74
|
if (!existsSync(configPath)) fail(`config not found: ${configPath}`);
|
|
65
75
|
const cfgDir = path.dirname(configPath);
|
|
66
76
|
// Cache-bust the config import so a re-load (the LSP re-check) sees edits, not the first-import cache.
|
|
67
77
|
const cfgUrl = `${pathToFileURL(configPath).href}?t=${Date.now()}`;
|
|
68
78
|
const cfgModule = (await import(cfgUrl)) as { default?: PackageConfig };
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
79
|
+
let cfg: PackageConfig;
|
|
80
|
+
let runtimeDependencies: ReturnType<typeof validateNomosPackageConfig>["runtimeDependencies"];
|
|
81
|
+
try {
|
|
82
|
+
const validated = validateNomosPackageConfig(cfgModule.default);
|
|
83
|
+
cfg = validated.config as PackageConfig;
|
|
84
|
+
runtimeDependencies = validated.runtimeDependencies;
|
|
85
|
+
} catch (error) {
|
|
86
|
+
fail(`package contract refused: ${(error as Error).message}`);
|
|
72
87
|
}
|
|
73
88
|
const composed: DomainModule[] = [];
|
|
74
89
|
const domainFiles = new Map<string, string[]>();
|
|
75
90
|
for (const d of cfg.domains) {
|
|
76
|
-
if (typeof d.key !== "string" || !Array.isArray(d.modules) || d.modules.length === 0) {
|
|
77
|
-
fail(`each domain needs { key, modules: [path, ...] }; got ${JSON.stringify(d)}`);
|
|
78
|
-
}
|
|
79
91
|
const mods: Mod[] = [];
|
|
80
92
|
const files: string[] = [];
|
|
81
93
|
for (const rel of d.modules) {
|
|
82
94
|
const abs = path.resolve(cfgDir, rel);
|
|
83
95
|
if (!existsSync(abs)) fail(`domain '${d.key}': module not found: ${abs}`);
|
|
84
96
|
files.push(abs);
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
assertPublicPackageImports(files);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
fail(`package import boundary refused: ${(error as Error).message}`);
|
|
102
|
+
}
|
|
103
|
+
for (const abs of files) {
|
|
85
104
|
// Cache-bust so a re-import (the LSP re-check after an edit) re-evaluates the edited module.
|
|
86
105
|
mods.push((await import(`${pathToFileURL(abs).href}?t=${Date.now()}`)) as Mod);
|
|
87
106
|
}
|
|
88
107
|
domainFiles.set(d.key, files);
|
|
89
108
|
composed.push(composeDomainModule({ name: d.name ?? d.key, domain: d.key, modules: mods }));
|
|
90
109
|
}
|
|
91
|
-
return {
|
|
110
|
+
return {
|
|
111
|
+
modules: composed,
|
|
112
|
+
domainFiles,
|
|
113
|
+
dependencyFindings: packageDependencyUsageFindings({
|
|
114
|
+
packageName: cfg.name,
|
|
115
|
+
exportedDomains: cfg.domains.map((domain) => domain.key),
|
|
116
|
+
runtimeDependencies,
|
|
117
|
+
modules: composed,
|
|
118
|
+
}),
|
|
119
|
+
};
|
|
92
120
|
}
|
|
93
121
|
|
|
94
122
|
/**
|
|
95
123
|
* Load the PRIOR law surface for `--against <path>` (the evolve preview's baseline). The supported
|
|
96
|
-
* prior is a
|
|
124
|
+
* prior is a diagnostic `build/<name>.interface.json`, a BUILD DIR / package dir containing one, or
|
|
97
125
|
* the committed `nomos.stable-ids.json` LOCKFILE (aggregate identity only — no directive payloads).
|
|
98
126
|
* A live `https://…` prior is NOT supported (the installed package's stable-ids aren't retrievable
|
|
99
|
-
* from GET /domains); point `--against` at the deployed
|
|
127
|
+
* from GET /domains); point `--against` at the deployed source's interface and lock sidecars instead.
|
|
100
128
|
*/
|
|
101
129
|
function loadPriorEvolveLaw(arg: string): { law: EvolveLaw; source: string; note?: string } {
|
|
102
130
|
if (/^https?:\/\//.test(arg)) {
|
|
103
131
|
fail(
|
|
104
132
|
`--against does not support a live URL (${arg}) — the installed package's #58 stable-ids are ` +
|
|
105
|
-
`not retrievable from GET /domains. Point --against at the deployed
|
|
133
|
+
`not retrievable from GET /domains. Point --against at the deployed source's build/<name>.interface.json.`,
|
|
106
134
|
);
|
|
107
135
|
}
|
|
108
136
|
const abs = path.resolve(process.cwd(), arg);
|
|
109
137
|
if (!existsSync(abs)) fail(`--against: prior not found: ${abs}`);
|
|
110
|
-
// Resolve a directory to
|
|
138
|
+
// Resolve a directory to its diagnostic interface or stable-id lockfile.
|
|
111
139
|
let file = abs;
|
|
112
140
|
if (statSync(abs).isDirectory()) {
|
|
113
|
-
const
|
|
141
|
+
const iface = findInterfaceJson(abs);
|
|
114
142
|
const lock = path.join(abs, "nomos.stable-ids.json");
|
|
115
|
-
if (
|
|
143
|
+
if (iface !== undefined) file = iface;
|
|
116
144
|
else if (existsSync(lock)) file = lock;
|
|
117
|
-
else fail(`--against: no *.
|
|
145
|
+
else fail(`--against: no *.interface.json or nomos.stable-ids.json under ${abs}`);
|
|
118
146
|
}
|
|
119
147
|
let parsed: unknown;
|
|
120
148
|
try {
|
|
@@ -122,22 +150,35 @@ function loadPriorEvolveLaw(arg: string): { law: EvolveLaw; source: string; note
|
|
|
122
150
|
} catch (e) {
|
|
123
151
|
fail(`--against: could not parse ${file}: ${(e as Error).message}`);
|
|
124
152
|
}
|
|
125
|
-
|
|
126
|
-
if (p.domains !== undefined && p.interface === undefined && p.packageUsda === undefined) {
|
|
153
|
+
if (path.basename(file) === "nomos.stable-ids.json") {
|
|
127
154
|
return {
|
|
128
|
-
law: evolveLawFromLockfile(parsed
|
|
155
|
+
law: evolveLawFromLockfile(parseStableIdLockfile(parsed)),
|
|
129
156
|
source: file,
|
|
130
|
-
note: `prior is a lockfile — aggregate/field identity is diffed, but directive payload changes
|
|
157
|
+
note: `prior is a lockfile — aggregate/field identity is diffed, but directive payload changes require the sibling interface sidecar.`,
|
|
131
158
|
};
|
|
132
159
|
}
|
|
133
|
-
|
|
160
|
+
const lockCandidates = [
|
|
161
|
+
path.join(path.dirname(file), "nomos.stable-ids.json"),
|
|
162
|
+
path.join(path.dirname(path.dirname(file)), "nomos.stable-ids.json"),
|
|
163
|
+
];
|
|
164
|
+
const lockFile = lockCandidates.find((candidate) => existsSync(candidate));
|
|
165
|
+
const lock = lockFile === undefined
|
|
166
|
+
? undefined
|
|
167
|
+
: parseStableIdLockfile(JSON.parse(readFileSync(lockFile, "utf8")));
|
|
168
|
+
return {
|
|
169
|
+
law: evolveLawFromInterface(parsed as Parameters<typeof evolveLawFromInterface>[0], lock),
|
|
170
|
+
source: lockFile === undefined ? file : `${file} + ${lockFile}`,
|
|
171
|
+
...(lockFile === undefined
|
|
172
|
+
? { note: `prior has no stable-id lock beside it — directive shapes are checked, but driver and contract evolution evidence is incomplete.` }
|
|
173
|
+
: {}),
|
|
174
|
+
};
|
|
134
175
|
}
|
|
135
176
|
|
|
136
|
-
/** Find a `*.
|
|
137
|
-
function
|
|
177
|
+
/** Find a compiler diagnostic `*.interface.json` directly or one level down in `build/`. */
|
|
178
|
+
function findInterfaceJson(dir: string): string | undefined {
|
|
138
179
|
const scan = (d: string): string | undefined => {
|
|
139
180
|
if (!existsSync(d)) return undefined;
|
|
140
|
-
const hit = readdirSync(d).find((f) => f.endsWith(".
|
|
181
|
+
const hit = readdirSync(d).find((f) => f.endsWith(".interface.json"));
|
|
141
182
|
return hit !== undefined ? path.join(d, hit) : undefined;
|
|
142
183
|
};
|
|
143
184
|
return scan(dir) ?? scan(path.join(dir, "build"));
|
|
@@ -149,7 +190,7 @@ function loadCwdLockfile(configArg: string): StableIdLockfile | undefined {
|
|
|
149
190
|
const lockPath = path.join(cfgDir, "nomos.stable-ids.json");
|
|
150
191
|
if (!existsSync(lockPath)) return undefined;
|
|
151
192
|
try {
|
|
152
|
-
return JSON.parse(readFileSync(lockPath, "utf8"))
|
|
193
|
+
return parseStableIdLockfile(JSON.parse(readFileSync(lockPath, "utf8")));
|
|
153
194
|
} catch {
|
|
154
195
|
return undefined;
|
|
155
196
|
}
|
|
@@ -161,7 +202,7 @@ async function main(): Promise<void> {
|
|
|
161
202
|
// positional — `prior.json` belongs to the flag, not the config slot).
|
|
162
203
|
const againstIdx = argv.findIndex((a) => a === "--against");
|
|
163
204
|
const positionals = argv.filter((a, i) => !a.startsWith("--") && i !== againstIdx + 1);
|
|
164
|
-
const configArg = positionals[0] ?? "nomos.
|
|
205
|
+
const configArg = positionals[0] ?? "nomos.project.ts";
|
|
165
206
|
const againstArg =
|
|
166
207
|
againstIdx >= 0
|
|
167
208
|
? argv[againstIdx + 1]
|
|
@@ -169,14 +210,14 @@ async function main(): Promise<void> {
|
|
|
169
210
|
|
|
170
211
|
const asJson = argv.includes("--json");
|
|
171
212
|
|
|
172
|
-
const { modules, domainFiles } = await loadComposedModulesWithSources(configArg);
|
|
173
|
-
const findings: Finding[] = [...checkDomainModules(modules)];
|
|
213
|
+
const { modules, domainFiles, dependencyFindings } = await loadComposedModulesWithSources(configArg);
|
|
214
|
+
const findings: Finding[] = [...dependencyFindings, ...checkDomainModules(modules)];
|
|
174
215
|
|
|
175
216
|
// ── EVOLVE PREVIEW (--against): diff the current build against a prior law + pre-fire the gate. ──
|
|
176
217
|
let evolveDispositions: Record<string, unknown> | undefined;
|
|
177
218
|
if (againstIdx >= 0 || againstArg !== undefined) {
|
|
178
219
|
if (againstArg === undefined || againstArg.startsWith("--")) {
|
|
179
|
-
fail(`--against needs a path: --against <build/<name>.
|
|
220
|
+
fail(`--against needs a path: --against <build/<name>.interface.json | build dir | nomos.stable-ids.json>`);
|
|
180
221
|
}
|
|
181
222
|
const lock = loadCwdLockfile(configArg);
|
|
182
223
|
if (lock === undefined && !asJson) {
|
|
@@ -223,7 +264,7 @@ async function main(): Promise<void> {
|
|
|
223
264
|
// The consolidated, pasteable dispositions the destructive evolves demand (per domain).
|
|
224
265
|
if (evolveDispositions !== undefined) {
|
|
225
266
|
console.log(
|
|
226
|
-
"\ngitholon check: to admit the destructive evolve,
|
|
267
|
+
"\ngitholon check: to admit the destructive evolve, include `dispositions` in the installation offer:",
|
|
227
268
|
);
|
|
228
269
|
console.log(JSON.stringify(evolveDispositions, null, 2));
|
|
229
270
|
}
|
package/src/clear_directive.ts
CHANGED
|
@@ -51,7 +51,12 @@ export function clearDirectiveId(aggregateId: string, field: string): string {
|
|
|
51
51
|
* needn't read it), plan = the one `clear` op. `.requires(relation)` iff the field declared
|
|
52
52
|
* `clearRequires`.
|
|
53
53
|
*/
|
|
54
|
-
export function makeClearDirective(
|
|
54
|
+
export function makeClearDirective(
|
|
55
|
+
agg: AggregateHandle,
|
|
56
|
+
field: string,
|
|
57
|
+
requires?: string,
|
|
58
|
+
object?: string,
|
|
59
|
+
): Directive<unknown> {
|
|
55
60
|
const payloadId = idOf(agg);
|
|
56
61
|
const built = directive(clearDirectiveId(agg.id, field))
|
|
57
62
|
.mutates(agg)
|
|
@@ -60,14 +65,20 @@ export function makeClearDirective(agg: AggregateHandle, field: string, requires
|
|
|
60
65
|
.doc(
|
|
61
66
|
`Explicitly clears the '${field}' field of a ${agg.id} (writes an explicit null — the declared clearable lane).`,
|
|
62
67
|
) as unknown as RequirableDirective<unknown>;
|
|
63
|
-
return requires !== undefined
|
|
68
|
+
return requires !== undefined
|
|
69
|
+
? built.requires(requires, object === undefined ? undefined : { object })
|
|
70
|
+
: built;
|
|
64
71
|
}
|
|
65
72
|
|
|
66
|
-
/** The clearable `(field, requires?)` entries of one aggregate handle. */
|
|
67
|
-
function clearableFieldsOf(agg: AggregateHandle): { field: string; requires?: string }[] {
|
|
68
|
-
const out: { field: string; requires?: string }[] = [];
|
|
73
|
+
/** The clearable `(field, requires?, object?)` entries of one aggregate handle. */
|
|
74
|
+
function clearableFieldsOf(agg: AggregateHandle): { field: string; requires?: string; object?: string }[] {
|
|
75
|
+
const out: { field: string; requires?: string; object?: string }[] = [];
|
|
69
76
|
for (const [name, f0] of Object.entries(agg.fields as Record<string, Field>)) {
|
|
70
|
-
if (f0.isClearable === true) out.push({
|
|
77
|
+
if (f0.isClearable === true) out.push({
|
|
78
|
+
field: name,
|
|
79
|
+
...(f0.clearRequires !== undefined ? { requires: f0.clearRequires } : {}),
|
|
80
|
+
...(f0.clearRequiresObject !== undefined ? { object: f0.clearRequiresObject } : {}),
|
|
81
|
+
});
|
|
71
82
|
}
|
|
72
83
|
return out;
|
|
73
84
|
}
|
|
@@ -94,10 +105,10 @@ export function withClearDirectives<M extends Record<string, unknown>>(mod: M):
|
|
|
94
105
|
|
|
95
106
|
const additions: Record<string, unknown> = {};
|
|
96
107
|
for (const agg of aggs) {
|
|
97
|
-
for (const { field, requires } of clearableFieldsOf(agg)) {
|
|
108
|
+
for (const { field, requires, object } of clearableFieldsOf(agg)) {
|
|
98
109
|
const id = clearDirectiveId(agg.id, field);
|
|
99
110
|
if (existingIds.has(id) || id in mod) continue;
|
|
100
|
-
additions[id] = makeClearDirective(agg, field, requires);
|
|
111
|
+
additions[id] = makeClearDirective(agg, field, requires, object);
|
|
101
112
|
existingIds.add(id);
|
|
102
113
|
}
|
|
103
114
|
}
|