@ifc-lite/cli 0.27.0 → 0.28.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/README.md CHANGED
@@ -48,7 +48,7 @@ Global flags: `--json`, `--out <file>`, `--verbose`, `--quiet`, `--debug`, `--lo
48
48
 
49
49
  ## gym
50
50
 
51
- `ifc-lite gym` is a prototype reset/step/reward environment API over the existing headless checks: the skeleton of an RLVR environment for buildings (see [`docs/vision/moonshots-tech.md`](../../docs/vision/moonshots-tech.md) M2 and [`docs/vision/moonshots-execution-plan.md`](../../docs/vision/moonshots-execution-plan.md) B0.4). It wraps a model - either a fixed file (`--model`) or a procedurally generated World Gym episode (`--seed`) - and lets an agent apply data-mutation ops, scoring each step against the same schema/clash/ids checks the `validate`, `clash`, and `ids` commands already run.
51
+ `ifc-lite gym` is a prototype reset/step/reward environment API over the existing headless checks: the skeleton of an RLVR environment for buildings (see [`tools/world-gym/README.md`](../../tools/world-gym/README.md) M2 and [`tools/world-gym/benchmark/BENCHMARK.md`](../../tools/world-gym/benchmark/BENCHMARK.md) B0.4). It wraps a model - either a fixed file (`--model`) or a procedurally generated World Gym episode (`--seed`) - and lets an agent apply data-mutation ops, scoring each step against the same schema/clash/ids checks the `validate`, `clash`, and `ids` commands already run.
52
52
 
53
53
  ```bash
54
54
  ifc-lite gym --model model.ifc --checks schema,clash
@@ -0,0 +1,56 @@
1
+ import { type IfcDataStore } from '@ifc-lite/parser';
2
+ import { type ValidationIssue } from './validate.js';
3
+ export type CheckStatus = 'pass' | 'fail' | 'error';
4
+ export interface LoadedModel {
5
+ path: string;
6
+ /** SHA-256 of the exact bytes read from disk (post ifcZIP unwrap: the STEP text actually checked). */
7
+ sha256: string;
8
+ store: IfcDataStore;
9
+ }
10
+ export interface ModelLoadError {
11
+ path: string;
12
+ error: string;
13
+ }
14
+ /** Load one model file for delivery checking, never throwing and never exiting the process. */
15
+ export declare function loadModelForDelivery(path: string): Promise<LoadedModel | ModelLoadError>;
16
+ export interface StructuralCheckResult {
17
+ type: 'structural';
18
+ model: string;
19
+ status: CheckStatus;
20
+ errorCount: number;
21
+ warningCount: number;
22
+ infoCount: number;
23
+ issues: ValidationIssue[];
24
+ error?: string;
25
+ }
26
+ /** Run the same structural rules `ifc-lite validate` runs. `fail` iff at least one error-severity issue was found. */
27
+ export declare function runStructuralCheck(modelPath: string, store: IfcDataStore): StructuralCheckResult;
28
+ export interface IdsCheckResult {
29
+ type: 'ids';
30
+ model: string;
31
+ source: string;
32
+ status: CheckStatus;
33
+ totalSpecifications?: number;
34
+ passedSpecifications?: number;
35
+ failedSpecifications?: number;
36
+ notApplicableSpecifications?: number;
37
+ totalEntities?: number;
38
+ passedEntities?: number;
39
+ failedEntities?: number;
40
+ error?: string;
41
+ }
42
+ /**
43
+ * Run one IDS rule file against one already-loaded model.
44
+ *
45
+ * `status` is `error` when the IDS file itself could not be read/parsed, or
46
+ * when it declares zero specifications (nothing was actually evaluated —
47
+ * reporting that as `pass` would hide an empty ruleset behind a green
48
+ * check). Otherwise `fail` iff at least one specification failed; a
49
+ * specification whose applicability matched no entities counts as neither
50
+ * pass nor fail (`notApplicableSpecifications`) — if EVERY specification
51
+ * lands there (nothing was definitively satisfied OR violated), the check
52
+ * reports `error` rather than a `pass` that would rest on zero actual
53
+ * evidence.
54
+ */
55
+ export declare function runIdsCheck(modelPath: string, store: IfcDataStore, idsPath: string): Promise<IdsCheckResult>;
56
+ //# sourceMappingURL=delivery-checks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-checks.d.ts","sourceRoot":"","sources":["../../src/commands/delivery-checks.ts"],"names":[],"mappings":"AA6BA,OAAO,EAA+B,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGlF,OAAO,EAA2B,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAE9E,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEpD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,sGAAsG;IACtG,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,YAAY,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,+FAA+F;AAC/F,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,cAAc,CAAC,CAyC9F;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,sHAAsH;AACtH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,qBAAqB,CAchG;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA+GD;;;;;;;;;;;;GAYG;AACH,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CA6ClH"}
@@ -0,0 +1,222 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * Model loading and per-check evaluation for `ifc-lite delivery`.
6
+ *
7
+ * Three outcomes exist for every check, never just two:
8
+ * - `pass` — the check ran and found nothing to report.
9
+ * - `fail` — the check ran and found a violation.
10
+ * - `error` — the check could NOT be run (unreadable model, unreadable or
11
+ * unparsable IDS file, an IDS document declaring zero
12
+ * specifications). An unevaluable check must never be folded
13
+ * into `pass`: a delivery report that silently skips a rule
14
+ * and still reads as clean is worse than no report.
15
+ *
16
+ * `loadModelForDelivery` deliberately does NOT reuse `loader.ts`'s
17
+ * `loadIfcFile`/`loadIfcBytes`: those call `process.exit(1)` directly on an
18
+ * empty, non-STEP, or unparsable file, which is correct for a single-file
19
+ * command but would kill the whole `delivery` process on the SECOND model in
20
+ * a multi-model recipe just because the first one was bad. This loader
21
+ * performs the same validation (STEP signature, ifcZIP unwrap, parse) but
22
+ * returns a `{ error }` result instead of exiting, so one unreadable model
23
+ * becomes one `error` entry in the report — never a crashed run and never a
24
+ * silently-passing verdict.
25
+ */
26
+ import { readFile } from 'node:fs/promises';
27
+ import { createHash } from 'node:crypto';
28
+ import { IfcParser, unwrapIfcZipView } from '@ifc-lite/parser';
29
+ import { createDataAccessor } from '@ifc-lite/ids/bridge';
30
+ import { IDSNamespace } from '@ifc-lite/sdk';
31
+ import { computeValidationIssues } from './validate.js';
32
+ /** Load one model file for delivery checking, never throwing and never exiting the process. */
33
+ export async function loadModelForDelivery(path) {
34
+ let bytes;
35
+ try {
36
+ bytes = await readFile(path);
37
+ }
38
+ catch (err) {
39
+ return { path, error: `could not be read: ${err.message}` };
40
+ }
41
+ if (bytes.byteLength === 0) {
42
+ return { path, error: 'is empty (0 bytes)' };
43
+ }
44
+ try {
45
+ bytes = new Uint8Array(await unwrapIfcZipView(bytes));
46
+ }
47
+ catch (err) {
48
+ return { path, error: `could not be unwrapped: ${err.message}` };
49
+ }
50
+ const headerSnippet = new TextDecoder('latin1').decode(bytes.subarray(0, Math.min(bytes.byteLength, 256)));
51
+ if (!headerSnippet.includes('ISO-10303-21')) {
52
+ return { path, error: 'is not a valid IFC/STEP file' };
53
+ }
54
+ const sha256 = createHash('sha256').update(bytes).digest('hex');
55
+ const parser = new IfcParser();
56
+ const origLog = console.log;
57
+ const origWarn = console.warn;
58
+ console.log = () => { };
59
+ console.warn = () => { };
60
+ try {
61
+ const arrayBuffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
62
+ const store = await parser.parseColumnar(arrayBuffer, {});
63
+ store.fileSize = bytes.byteLength;
64
+ return { path, sha256, store };
65
+ }
66
+ catch (err) {
67
+ return { path, error: `could not be parsed: ${err.message}` };
68
+ }
69
+ finally {
70
+ console.log = origLog;
71
+ console.warn = origWarn;
72
+ }
73
+ }
74
+ /** Run the same structural rules `ifc-lite validate` runs. `fail` iff at least one error-severity issue was found. */
75
+ export function runStructuralCheck(modelPath, store) {
76
+ const issues = computeValidationIssues(store);
77
+ const errorCount = issues.filter(i => i.severity === 'error').length;
78
+ const warningCount = issues.filter(i => i.severity === 'warning').length;
79
+ const infoCount = issues.filter(i => i.severity === 'info').length;
80
+ return {
81
+ type: 'structural',
82
+ model: modelPath,
83
+ status: errorCount > 0 ? 'fail' : 'pass',
84
+ errorCount,
85
+ warningCount,
86
+ infoCount,
87
+ issues,
88
+ };
89
+ }
90
+ /**
91
+ * A specification counts as genuinely evaluated only when its cardinality
92
+ * bound could actually have been violated by SOME entity count, or it
93
+ * checked at least one entity's requirements. `minOccurs="0"` with no
94
+ * finite upper bound (the IDS "optional, if present" cardinality) is
95
+ * satisfied by zero matches for every possible model — no entity count
96
+ * could ever fail it — so treating that as `pass` reports success for a
97
+ * rule that could not possibly have failed and checked nothing. That is
98
+ * distinct from a `maxOccurs="0"` prohibition ("must not exist"), which a
99
+ * nonzero applicable count WOULD have violated, so zero matches there is
100
+ * real evidence, not a vacuous result — `@ifc-lite/ids`'s own corpus fixture
101
+ * `pass-prohibited_specifications_passes_if_the_applicability_does_not_matches.ids`
102
+ * exercises exactly this and must keep reading `pass`.
103
+ */
104
+ function isVacuousSpecification(spec) {
105
+ if (spec.status === 'not_applicable')
106
+ return true;
107
+ const c = spec.cardinalityResult;
108
+ if (!c || c.actualCount !== 0)
109
+ return false;
110
+ return c.minExpected === 0 && (c.maxExpected === undefined || c.maxExpected === 'unbounded');
111
+ }
112
+ /**
113
+ * Summarize a real `IDSValidationReport` for the delivery checker.
114
+ *
115
+ * This intentionally does NOT call `bim.ids.summarize()` (`@ifc-lite/sdk`)
116
+ * for the specification-level bucketing: that helper defers entirely to
117
+ * the validator's own per-specification `status`, and the validator marks
118
+ * a `minOccurs="0"`/unbounded-`maxOccurs` specification `pass` whenever it
119
+ * matches zero entities (see `isVacuousSpecification` above) — correct IDS
120
+ * semantics for an "optional" clause, but exactly the vacuous-check defect
121
+ * a delivery checker must not fold into `pass`. Entity counts ARE summed
122
+ * directly here for the same reason `bim.ids.summarize()` would need
123
+ * `includePassingEntities: true` to get them right: that option controls
124
+ * whether PASSING entities are even present in `entityResults`, and this
125
+ * file used to call `validate()` with it `false`, which is harmless for the
126
+ * raw validator's own `summary.totalEntitiesChecked` (computed from each
127
+ * specification's `passedCount`/`failedCount`, not from `entityResults`)
128
+ * but would silently undercount any per-entity tally derived from
129
+ * `entityResults` directly, `bim.ids.summarize()` included.
130
+ */
131
+ function summarizeIdsReport(report) {
132
+ let passedSpecifications = 0;
133
+ let failedSpecifications = 0;
134
+ let notApplicableSpecifications = 0;
135
+ let totalEntities = 0;
136
+ let passedEntities = 0;
137
+ let failedEntities = 0;
138
+ for (const spec of report.specificationResults) {
139
+ for (const entity of spec.entityResults) {
140
+ totalEntities++;
141
+ if (entity.passed)
142
+ passedEntities++;
143
+ else
144
+ failedEntities++;
145
+ }
146
+ if (spec.status === 'fail') {
147
+ failedSpecifications++;
148
+ }
149
+ else if (isVacuousSpecification(spec)) {
150
+ notApplicableSpecifications++;
151
+ }
152
+ else {
153
+ passedSpecifications++;
154
+ }
155
+ }
156
+ return {
157
+ totalSpecifications: report.specificationResults.length,
158
+ passedSpecifications,
159
+ failedSpecifications,
160
+ notApplicableSpecifications,
161
+ totalEntities,
162
+ passedEntities,
163
+ failedEntities,
164
+ };
165
+ }
166
+ /**
167
+ * Run one IDS rule file against one already-loaded model.
168
+ *
169
+ * `status` is `error` when the IDS file itself could not be read/parsed, or
170
+ * when it declares zero specifications (nothing was actually evaluated —
171
+ * reporting that as `pass` would hide an empty ruleset behind a green
172
+ * check). Otherwise `fail` iff at least one specification failed; a
173
+ * specification whose applicability matched no entities counts as neither
174
+ * pass nor fail (`notApplicableSpecifications`) — if EVERY specification
175
+ * lands there (nothing was definitively satisfied OR violated), the check
176
+ * reports `error` rather than a `pass` that would rest on zero actual
177
+ * evidence.
178
+ */
179
+ export async function runIdsCheck(modelPath, store, idsPath) {
180
+ const base = { type: 'ids', model: modelPath, source: idsPath };
181
+ let idsContent;
182
+ try {
183
+ idsContent = await readFile(idsPath, 'utf-8');
184
+ }
185
+ catch (err) {
186
+ return { ...base, status: 'error', error: `could not be read: ${err.message}` };
187
+ }
188
+ const ids = new IDSNamespace();
189
+ let idsDoc;
190
+ try {
191
+ idsDoc = await ids.parse(idsContent);
192
+ }
193
+ catch (err) {
194
+ return { ...base, status: 'error', error: `could not be parsed: ${err.message}` };
195
+ }
196
+ const accessor = createDataAccessor(store);
197
+ let report;
198
+ try {
199
+ report = (await ids.validate(idsDoc, {
200
+ accessor,
201
+ modelInfo: { schemaVersion: store.schemaVersion },
202
+ locale: 'en',
203
+ includePassingEntities: true,
204
+ }));
205
+ }
206
+ catch (err) {
207
+ return { ...base, status: 'error', error: `validation failed: ${err.message}` };
208
+ }
209
+ const s = summarizeIdsReport(report);
210
+ if (s.totalSpecifications === 0) {
211
+ return { ...base, status: 'error', error: 'declares zero specifications', ...s };
212
+ }
213
+ const evaluated = s.passedSpecifications + s.failedSpecifications;
214
+ const status = s.failedSpecifications > 0 ? 'fail' : evaluated > 0 ? 'pass' : 'error';
215
+ return {
216
+ ...base,
217
+ status,
218
+ ...s,
219
+ ...(status === 'error' ? { error: 'every specification was not-applicable — nothing was evaluated' } : {}),
220
+ };
221
+ }
222
+ //# sourceMappingURL=delivery-checks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-checks.js","sourceRoot":"","sources":["../../src/commands/delivery-checks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /** The recipe fields as declared in the JSON file (paths not yet resolved). */
2
+ export interface DeliveryRecipe {
3
+ models: string[];
4
+ structural: boolean;
5
+ ids: string[];
6
+ }
7
+ /** A recipe with every `models`/`ids` path resolved to an absolute path. */
8
+ export interface ResolvedDeliveryRecipe extends DeliveryRecipe {
9
+ /** Absolute path to the recipe file itself. */
10
+ recipePath: string;
11
+ /** `models`, resolved to absolute paths, in declared order. */
12
+ resolvedModels: string[];
13
+ /** `ids`, resolved to absolute paths, in declared order. */
14
+ resolvedIds: string[];
15
+ }
16
+ /**
17
+ * Load and validate a delivery recipe, resolving every declared path
18
+ * relative to the recipe file's own directory. Every failure mode is a
19
+ * `fatal(...)` with a specific reason — never a silently empty or
20
+ * partially-applied recipe.
21
+ */
22
+ export declare function loadDeliveryRecipe(path: string): Promise<ResolvedDeliveryRecipe>;
23
+ //# sourceMappingURL=delivery-recipe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-recipe.d.ts","sourceRoot":"","sources":["../../src/commands/delivery-recipe.ts"],"names":[],"mappings":"AAuCA,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,GAAG,EAAE,MAAM,EAAE,CAAC;CACf;AAED,4EAA4E;AAC5E,MAAM,WAAW,sBAAuB,SAAQ,cAAc;IAC5D,+CAA+C;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,4DAA4D;IAC5D,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAQD;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAiEtF"}
@@ -0,0 +1,104 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * The saved recipe `ifc-lite delivery` runs.
6
+ *
7
+ * A recipe is a plain JSON file naming one or more model files and the
8
+ * checks to run against every one of them — `structural` (the same rules
9
+ * `ifc-lite validate` runs) and/or one or more `ids` rule files (the same
10
+ * validator `ifc-lite ids` runs). It exists so a delivery check is a single,
11
+ * versioned, reviewable artifact a team commits and re-runs, rather than a
12
+ * remembered shell invocation.
13
+ *
14
+ * ```json
15
+ * {
16
+ * "models": ["model.ifc"],
17
+ * "structural": true,
18
+ * "ids": ["door-rules.ids"]
19
+ * }
20
+ * ```
21
+ *
22
+ * Every `models`/`ids` path is resolved relative to the DIRECTORY CONTAINING
23
+ * THE RECIPE FILE, not the process's current working directory — a recipe
24
+ * committed alongside its fixtures stays runnable from anywhere.
25
+ *
26
+ * A malformed recipe is a `fatal(...)`, matching every other saved-definition
27
+ * loader in this CLI (`schedule-spec.ts`): not valid JSON, not a JSON object,
28
+ * an unrecognised field, a field of the wrong type, an empty/missing
29
+ * `models` list, or declaring NEITHER `structural: true` NOR a non-empty
30
+ * `ids` list (a recipe with zero applicable checks can never produce a
31
+ * meaningful delivery verdict, so it is rejected up front rather than
32
+ * silently reporting an empty "pass").
33
+ */
34
+ import { readFile } from 'node:fs/promises';
35
+ import { dirname, resolve } from 'node:path';
36
+ import { fatal } from '../output.js';
37
+ const RECIPE_FIELDS = ['models', 'structural', 'ids'];
38
+ function isStringArray(value) {
39
+ return Array.isArray(value) && value.every(v => typeof v === 'string');
40
+ }
41
+ /**
42
+ * Load and validate a delivery recipe, resolving every declared path
43
+ * relative to the recipe file's own directory. Every failure mode is a
44
+ * `fatal(...)` with a specific reason — never a silently empty or
45
+ * partially-applied recipe.
46
+ */
47
+ export async function loadDeliveryRecipe(path) {
48
+ let content;
49
+ try {
50
+ content = await readFile(path, 'utf-8');
51
+ }
52
+ catch (err) {
53
+ fatal(`Recipe "${path}" could not be read: ${err.message}`);
54
+ }
55
+ let parsed;
56
+ try {
57
+ parsed = JSON.parse(content);
58
+ }
59
+ catch (err) {
60
+ fatal(`Recipe "${path}" is not valid JSON: ${err.message}`);
61
+ }
62
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
63
+ fatal(`Recipe "${path}" must be a JSON object with "models" and at least one of "structural"/"ids", got ${Array.isArray(parsed) ? 'an array' : typeof parsed}.`);
64
+ }
65
+ const obj = parsed;
66
+ const unknownKeys = Object.keys(obj).filter(k => !RECIPE_FIELDS.includes(k));
67
+ if (unknownKeys.length > 0) {
68
+ fatal(`Recipe "${path}" has unrecognised field(s): ${unknownKeys.join(', ')}. Valid fields: ${RECIPE_FIELDS.join(', ')}.`);
69
+ }
70
+ if (!('models' in obj) || !isStringArray(obj.models) || obj.models.length === 0) {
71
+ fatal(`Recipe "${path}": "models" must be a non-empty array of file paths.`);
72
+ }
73
+ const models = obj.models;
74
+ if ('structural' in obj && typeof obj.structural !== 'boolean') {
75
+ fatal(`Recipe "${path}": "structural" must be a boolean, got ${typeof obj.structural}.`);
76
+ }
77
+ const structural = obj.structural ?? false;
78
+ if ('ids' in obj && !isStringArray(obj.ids)) {
79
+ fatal(`Recipe "${path}": "ids" must be an array of file paths.`);
80
+ }
81
+ const ids = obj.ids ?? [];
82
+ if (!structural && ids.length === 0) {
83
+ fatal(`Recipe "${path}" declares no applicable checks: set "structural": true and/or a non-empty "ids" list. A zero-check recipe can never produce a delivery verdict.`);
84
+ }
85
+ // Duplicate model/ids entries are rejected rather than silently
86
+ // deduplicated or run twice under one collapsed key: a repeated path is
87
+ // almost certainly a copy-paste mistake in the recipe, and either
88
+ // response (silent dedup, or a doubled report entry) would misrepresent
89
+ // what the recipe actually says it checks.
90
+ const dupModels = models.filter((m, i) => models.indexOf(m) !== i);
91
+ if (dupModels.length > 0) {
92
+ fatal(`Recipe "${path}": "models" lists the same path more than once: ${[...new Set(dupModels)].join(', ')}.`);
93
+ }
94
+ const dupIds = ids.filter((m, i) => ids.indexOf(m) !== i);
95
+ if (dupIds.length > 0) {
96
+ fatal(`Recipe "${path}": "ids" lists the same path more than once: ${[...new Set(dupIds)].join(', ')}.`);
97
+ }
98
+ const recipePath = resolve(path);
99
+ const baseDir = dirname(recipePath);
100
+ const resolvedModels = models.map(m => resolve(baseDir, m));
101
+ const resolvedIds = ids.map(i => resolve(baseDir, i));
102
+ return { recipePath, models, structural, ids, resolvedModels, resolvedIds };
103
+ }
104
+ //# sourceMappingURL=delivery-recipe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-recipe.js","sourceRoot":"","sources":["../../src/commands/delivery-recipe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Consolidated report assembly and HTML rendering for `ifc-lite delivery`.
3
+ *
4
+ * Determinism contract: `buildDeliveryReport` never reads the wall clock,
5
+ * never iterates a `Map`/object in insertion-order-dependent ways, and never
6
+ * keys a result by a derived string (model path, IDS file name, check type)
7
+ * — every check is one entry in a flat, declared-order ARRAY. Two collisions
8
+ * this codebase has actually shipped (a subtotal silently overwritten in
9
+ * `schedule`'s output, a duplicate `--columns` header collapsing a row in
10
+ * JSON) both came from keying a result object by a name that two distinct
11
+ * inputs could share; an array keeps every check's own model/type/source
12
+ * fields as data instead of forcing them into a Map/object key that could
13
+ * collide. The result: the SAME recipe run twice, with no model or IDS file
14
+ * changed on disk, produces byte-identical JSON (`tool.version` and the
15
+ * `sha256` fingerprints are the only fields that could ever legitimately
16
+ * differ between two runs, and neither depends on wall-clock time or
17
+ * iteration order).
18
+ */
19
+ import type { StructuralCheckResult, IdsCheckResult } from './delivery-checks.js';
20
+ import type { ResolvedDeliveryRecipe } from './delivery-recipe.js';
21
+ export type DeliveryCheckResult = StructuralCheckResult | IdsCheckResult;
22
+ export interface DeliveryModelEntry {
23
+ /** Path exactly as declared in the recipe (relative, for a readable report). */
24
+ path: string;
25
+ /** SHA-256 of the model's bytes, or undefined when the model could not be loaded. */
26
+ sha256?: string;
27
+ /** Set when the model could not be loaded; every check for this model then reports `error`. */
28
+ loadError?: string;
29
+ }
30
+ export interface DeliveryReport {
31
+ tool: {
32
+ name: 'ifc-lite';
33
+ version: string;
34
+ };
35
+ recipe: string;
36
+ models: DeliveryModelEntry[];
37
+ checks: DeliveryCheckResult[];
38
+ /** `pass` iff every check in `checks` is `pass` and `checks` is non-empty. */
39
+ verdict: 'pass' | 'fail';
40
+ summary: {
41
+ total: number;
42
+ pass: number;
43
+ fail: number;
44
+ error: number;
45
+ };
46
+ }
47
+ /** Build the consolidated report from a resolved recipe, its per-model load outcomes, and every check result. */
48
+ export declare function buildDeliveryReport(recipe: ResolvedDeliveryRecipe, version: string, models: DeliveryModelEntry[], checks: DeliveryCheckResult[]): DeliveryReport;
49
+ /** Render the report as a standalone HTML document — no external assets, safe to open from disk. */
50
+ export declare function renderDeliveryHtml(report: DeliveryReport): string;
51
+ //# sourceMappingURL=delivery-report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-report.d.ts","sourceRoot":"","sources":["../../src/commands/delivery-report.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,cAAc,EAAe,MAAM,sBAAsB,CAAC;AAC/F,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE,MAAM,MAAM,mBAAmB,GAAG,qBAAqB,GAAG,cAAc,CAAC;AAEzE,MAAM,WAAW,kBAAkB;IACjC,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,qFAAqF;IACrF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+FAA+F;IAC/F,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAC9B,8EAA8E;IAC9E,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAED,iHAAiH;AACjH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,kBAAkB,EAAE,EAC5B,MAAM,EAAE,mBAAmB,EAAE,GAC5B,cAAc,CAchB;AA+BD,oGAAoG;AACpG,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAoEjE"}
@@ -0,0 +1,114 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /** Build the consolidated report from a resolved recipe, its per-model load outcomes, and every check result. */
5
+ export function buildDeliveryReport(recipe, version, models, checks) {
6
+ const counts = { total: checks.length, pass: 0, fail: 0, error: 0 };
7
+ for (const c of checks)
8
+ counts[c.status]++;
9
+ const verdict = checks.length > 0 && counts.fail === 0 && counts.error === 0 ? 'pass' : 'fail';
10
+ return {
11
+ tool: { name: 'ifc-lite', version },
12
+ recipe: recipe.recipePath,
13
+ models,
14
+ checks,
15
+ verdict,
16
+ summary: counts,
17
+ };
18
+ }
19
+ function escapeHtml(value) {
20
+ return value
21
+ .replace(/&/g, '&amp;')
22
+ .replace(/</g, '&lt;')
23
+ .replace(/>/g, '&gt;')
24
+ .replace(/"/g, '&quot;')
25
+ .replace(/'/g, '&#39;');
26
+ }
27
+ function statusBadge(status) {
28
+ const label = status.toUpperCase();
29
+ return `<span class="badge badge-${status}">${label}</span>`;
30
+ }
31
+ function describeCheck(check) {
32
+ if (check.type === 'structural') {
33
+ return `${check.errorCount} error(s), ${check.warningCount} warning(s), ${check.infoCount} info`;
34
+ }
35
+ const parts = [];
36
+ if (check.totalSpecifications !== undefined) {
37
+ parts.push(`${check.passedSpecifications ?? 0}/${check.totalSpecifications} specification(s) passed`);
38
+ }
39
+ if (check.failedEntities !== undefined && check.totalEntities !== undefined) {
40
+ parts.push(`${check.failedEntities}/${check.totalEntities} entities failed`);
41
+ }
42
+ if (check.error)
43
+ parts.push(check.error);
44
+ return parts.join(' — ') || (check.error ?? '');
45
+ }
46
+ /** Render the report as a standalone HTML document — no external assets, safe to open from disk. */
47
+ export function renderDeliveryHtml(report) {
48
+ const rows = report.checks
49
+ .map(check => {
50
+ const source = check.type === 'structural' ? 'structural' : check.source;
51
+ return ` <tr class="row-${check.status}">
52
+ <td>${escapeHtml(check.model)}</td>
53
+ <td>${escapeHtml(check.type)}</td>
54
+ <td>${escapeHtml(source)}</td>
55
+ <td>${statusBadge(check.status)}</td>
56
+ <td>${escapeHtml(describeCheck(check))}</td>
57
+ </tr>`;
58
+ })
59
+ .join('\n');
60
+ const modelRows = report.models
61
+ .map(m => ` <tr>
62
+ <td>${escapeHtml(m.path)}</td>
63
+ <td><code>${escapeHtml(m.sha256 ?? '')}</code></td>
64
+ <td>${m.loadError ? `<span class="badge badge-error">ERROR</span> ${escapeHtml(m.loadError)}` : 'OK'}</td>
65
+ </tr>`)
66
+ .join('\n');
67
+ return `<!doctype html>
68
+ <html lang="en">
69
+ <head>
70
+ <meta charset="utf-8">
71
+ <title>IFC Delivery Check Report</title>
72
+ <style>
73
+ body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; margin: 2rem; color: #1a1a1a; }
74
+ h1 { font-size: 1.4rem; }
75
+ .verdict { font-size: 1.1rem; font-weight: 600; padding: 0.5rem 1rem; border-radius: 4px; display: inline-block; }
76
+ .verdict-pass { background: #e6f4ea; color: #1e7e34; }
77
+ .verdict-fail { background: #fce8e6; color: #c5221f; }
78
+ table { border-collapse: collapse; width: 100%; margin-top: 1rem; }
79
+ th, td { border: 1px solid #ddd; padding: 0.4rem 0.6rem; text-align: left; font-size: 0.9rem; }
80
+ th { background: #f5f5f5; }
81
+ .badge { display: inline-block; padding: 0.1rem 0.5rem; border-radius: 3px; font-size: 0.75rem; font-weight: 600; }
82
+ .badge-pass { background: #e6f4ea; color: #1e7e34; }
83
+ .badge-fail { background: #fce8e6; color: #c5221f; }
84
+ .badge-error { background: #fef7e0; color: #8a6d00; }
85
+ .row-error td { background: #fffdf5; }
86
+ </style>
87
+ </head>
88
+ <body>
89
+ <h1>IFC Delivery Check Report</h1>
90
+ <p><strong>Tool:</strong> ${escapeHtml(report.tool.name)} ${escapeHtml(report.tool.version)}<br>
91
+ <strong>Recipe:</strong> <code>${escapeHtml(report.recipe)}</code></p>
92
+ <p class="verdict verdict-${report.verdict}">Verdict: ${report.verdict.toUpperCase()}</p>
93
+ <p>${report.summary.pass} pass, ${report.summary.fail} fail, ${report.summary.error} error (of ${report.summary.total} check(s))</p>
94
+
95
+ <h2>Models</h2>
96
+ <table>
97
+ <thead><tr><th>Path</th><th>SHA-256</th><th>Status</th></tr></thead>
98
+ <tbody>
99
+ ${modelRows}
100
+ </tbody>
101
+ </table>
102
+
103
+ <h2>Checks</h2>
104
+ <table>
105
+ <thead><tr><th>Model</th><th>Type</th><th>Source</th><th>Status</th><th>Evidence</th></tr></thead>
106
+ <tbody>
107
+ ${rows}
108
+ </tbody>
109
+ </table>
110
+ </body>
111
+ </html>
112
+ `;
113
+ }
114
+ //# sourceMappingURL=delivery-report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-report.js","sourceRoot":"","sources":["../../src/commands/delivery-report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function deliveryCommand(args: string[]): Promise<void>;
2
+ //# sourceMappingURL=delivery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../../src/commands/delivery.ts"],"names":[],"mappings":"AAyCA,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA0EnE"}
@@ -0,0 +1,127 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * ifc-lite delivery <recipe.json> [--json] [--out <report.json>] [--html <report.html>]
6
+ *
7
+ * Run a repeatable, reviewable model-delivery check from a saved recipe
8
+ * (see `delivery-recipe.ts`): structural validation (the same rules
9
+ * `ifc-lite validate` runs) and/or IDS validation (the same validator
10
+ * `ifc-lite ids` runs), against one or more model files, in one invocation.
11
+ *
12
+ * Every check reports one of `pass` / `fail` / `error` — never folded
13
+ * together (see `delivery-checks.ts`). The overall verdict is `pass` only
14
+ * when every declared check on every declared model passed; an unreadable
15
+ * model, an unreadable/empty IDS ruleset, or any failed check all produce a
16
+ * `fail` verdict, matching the boundary in issue #3931: "Zero applicable
17
+ * checks or an unreadable model must not be a successful delivery verdict."
18
+ *
19
+ * Output: a human-readable summary to stdout by default, `--json` for the
20
+ * consolidated machine-readable report instead (or `--out <file>` to write
21
+ * that JSON to disk rather than stdout), and `--html <file>` to additionally
22
+ * write a standalone HTML report — the two forms the issue asks for,
23
+ * produced by one invocation.
24
+ *
25
+ * Determinism: given the same recipe and the same bytes on disk, running
26
+ * this command twice produces byte-identical `--json` output (see the
27
+ * contract documented in `delivery-report.ts`).
28
+ */
29
+ import { getFlag, hasFlag, fatal, printJson, writeOutput } from '../output.js';
30
+ import { readCliVersion } from '../version.js';
31
+ import { fileURLToPath } from 'node:url';
32
+ import { dirname, join, relative } from 'node:path';
33
+ import { loadDeliveryRecipe } from './delivery-recipe.js';
34
+ import { loadModelForDelivery, runStructuralCheck, runIdsCheck } from './delivery-checks.js';
35
+ import { buildDeliveryReport, renderDeliveryHtml } from './delivery-report.js';
36
+ const __dirname = dirname(fileURLToPath(import.meta.url));
37
+ const CLI_VERSION = readCliVersion(join(__dirname, '..', '..', 'package.json'));
38
+ export async function deliveryCommand(args) {
39
+ const recipePath = args.find(a => !a.startsWith('-'));
40
+ if (!recipePath) {
41
+ fatal('Usage: ifc-lite delivery <recipe.json> [--json] [--out report.json] [--html report.html]');
42
+ }
43
+ const jsonOutput = hasFlag(args, '--json');
44
+ const outPath = getFlag(args, '--out');
45
+ const htmlPath = getFlag(args, '--html');
46
+ const recipe = await loadDeliveryRecipe(recipePath);
47
+ const models = [];
48
+ const checks = [];
49
+ // Declared order throughout: models in recipe order, and within each
50
+ // model, structural first (when requested) then every --ids file in
51
+ // recipe order. No Map/object iteration anywhere in this loop — see
52
+ // delivery-report.ts's determinism contract.
53
+ for (let i = 0; i < recipe.resolvedModels.length; i++) {
54
+ const declaredPath = recipe.models[i];
55
+ const absPath = recipe.resolvedModels[i];
56
+ const loaded = await loadModelForDelivery(absPath);
57
+ if ('error' in loaded) {
58
+ models.push({ path: declaredPath, loadError: loaded.error });
59
+ // The model could not be loaded: every check the recipe declares for
60
+ // it is unevaluable, and reports `error` — never silently omitted
61
+ // (which would shrink the check count and could flip an
62
+ // otherwise-failing recipe to a false "pass") and never `pass`.
63
+ if (recipe.structural) {
64
+ checks.push({
65
+ type: 'structural', model: declaredPath, status: 'error',
66
+ errorCount: 0, warningCount: 0, infoCount: 0, issues: [],
67
+ error: `model ${loaded.error}`,
68
+ });
69
+ }
70
+ for (const idsDeclared of recipe.ids) {
71
+ checks.push({
72
+ type: 'ids', model: declaredPath, source: idsDeclared, status: 'error',
73
+ error: `model ${loaded.error}`,
74
+ });
75
+ }
76
+ continue;
77
+ }
78
+ models.push({ path: declaredPath, sha256: loaded.sha256 });
79
+ if (recipe.structural) {
80
+ checks.push(runStructuralCheck(declaredPath, loaded.store));
81
+ }
82
+ for (let j = 0; j < recipe.resolvedIds.length; j++) {
83
+ const result = await runIdsCheck(declaredPath, loaded.store, recipe.resolvedIds[j]);
84
+ checks.push({ ...result, source: recipe.ids[j] });
85
+ }
86
+ }
87
+ const report = buildDeliveryReport(recipe, CLI_VERSION, models, checks);
88
+ if (htmlPath) {
89
+ await writeOutput(renderDeliveryHtml(report), htmlPath);
90
+ }
91
+ if (jsonOutput || outPath) {
92
+ if (outPath) {
93
+ await writeOutput(JSON.stringify(report, null, 2), outPath);
94
+ }
95
+ else {
96
+ printJson(report);
97
+ }
98
+ }
99
+ else {
100
+ printHumanSummary(report, recipePath);
101
+ }
102
+ if (report.verdict !== 'pass')
103
+ process.exitCode = 1;
104
+ }
105
+ function printHumanSummary(report, recipePath) {
106
+ process.stdout.write(`\n Delivery check: ${recipePath}\n`);
107
+ process.stdout.write(` ifc-lite ${report.tool.version}\n\n`);
108
+ for (const m of report.models) {
109
+ const rel = relative(process.cwd(), m.path);
110
+ if (m.loadError) {
111
+ process.stdout.write(` [ERR] ${rel}: ${m.loadError}\n`);
112
+ }
113
+ else {
114
+ process.stdout.write(` [OK] ${rel} (sha256 ${m.sha256?.slice(0, 12)}…)\n`);
115
+ }
116
+ }
117
+ process.stdout.write('\n');
118
+ for (const c of report.checks) {
119
+ const icon = c.status === 'pass' ? 'PASS' : c.status === 'fail' ? 'FAIL' : 'ERR ';
120
+ const source = c.type === 'structural' ? 'structural' : c.source;
121
+ const detail = c.error ? ` — ${c.error}` : '';
122
+ process.stdout.write(` [${icon}] ${relative(process.cwd(), c.model)} :: ${source}${detail}\n`);
123
+ }
124
+ process.stdout.write(`\n ${report.summary.pass} pass, ${report.summary.fail} fail, ${report.summary.error} error (of ${report.summary.total})\n`);
125
+ process.stdout.write(` Verdict: ${report.verdict.toUpperCase()}\n\n`);
126
+ }
127
+ //# sourceMappingURL=delivery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery.js","sourceRoot":"","sources":["../../src/commands/delivery.ts"],"names":[],"mappings":"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"}
@@ -5,8 +5,8 @@
5
5
  * `ifc-lite gym (--model <file.ifc> | --seed <n>) [--checks schema,clash,ids] [--ids <rules.xml>]`
6
6
  *
7
7
  * A reset/step/reward environment loop over the existing headless checks:
8
- * the skeleton of an RLVR environment for buildings (docs/vision/moonshots-tech.md
9
- * M2, docs/vision/moonshots-execution-plan.md B0.4). The environment wraps a
8
+ * the skeleton of an RLVR environment for buildings (tools/world-gym/README.md
9
+ * M2, tools/world-gym/benchmark/BENCHMARK.md B0.4). The environment wraps a
10
10
  * model - either a fixed file (`--model`) or a procedurally generated World
11
11
  * Gym episode (`--seed`, see `gym/episode.ts`) - and lets an agent apply
12
12
  * data-mutation ops, scoring each step against the same schema/clash/ids
package/dist/index.js CHANGED
@@ -42,6 +42,7 @@ import { extCommand } from './commands/ext.js';
42
42
  import { layerCommand } from './commands/layer.js';
43
43
  import { refCommand } from './commands/ref.js';
44
44
  import { gymCommand } from './commands/gym.js';
45
+ import { deliveryCommand } from './commands/delivery.js';
45
46
  import { fileURLToPath } from 'node:url';
46
47
  import { dirname, join } from 'node:path';
47
48
  import { readCliVersion } from './version.js';
@@ -104,6 +105,8 @@ const HELP = `
104
105
  layer <publish|diff|merge|log|bake|...> Layered change tracking over a local store (.ifc-lite/)
105
106
  ref <list|create|move|protect> Manage named refs in the layer store
106
107
  gym --model <file.ifc> | --seed <n> reset/step/reward environment loop (JSONL over stdin/stdout)
108
+ delivery <recipe.json> [--json] [--out F] [--html F] Repeatable delivery check (structural + IDS) from a saved recipe
109
+ recipe: {"models":["m.ifc"],"structural":true,"ids":["rules.ids"]}, paths relative to the recipe file
107
110
 
108
111
  Options:
109
112
  --help, -h Show help
@@ -345,6 +348,9 @@ async function main() {
345
348
  case 'gym':
346
349
  await gymCommand(commandArgs);
347
350
  break;
351
+ case 'delivery':
352
+ await deliveryCommand(commandArgs);
353
+ break;
348
354
  default:
349
355
  process.stderr.write(`Unknown command: ${command}\n`);
350
356
  process.stderr.write(`Run 'ifc-lite --help' for usage.\n`);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ifc-lite/cli",
3
- "version": "0.27.0",
3
+ "version": "0.28.0",
4
4
  "description": "CLI toolkit for IFC files — query, validate, export, create, and script BIM data",
5
5
  "type": "module",
6
6
  "bin": {
@@ -20,25 +20,25 @@
20
20
  "README.md"
21
21
  ],
22
22
  "dependencies": {
23
- "@ifc-lite/clash": "^2.0.0",
23
+ "@ifc-lite/bcf": "^3.0.0",
24
+ "@ifc-lite/clash": "^2.1.0",
24
25
  "@ifc-lite/create": "^2.2.1",
25
26
  "@ifc-lite/data": "^4.0.0",
26
- "@ifc-lite/bcf": "^3.0.0",
27
27
  "@ifc-lite/diff": "^0.8.0",
28
- "@ifc-lite/extensions": "^0.6.0",
29
28
  "@ifc-lite/export": "^4.0.0",
30
29
  "@ifc-lite/geometry": "^4.2.0",
31
- "@ifc-lite/ids": "^1.15.53",
30
+ "@ifc-lite/ids": "^1.15.54",
31
+ "@ifc-lite/merge": "^0.4.5",
32
+ "@ifc-lite/extensions": "^0.6.0",
32
33
  "@ifc-lite/ifcx": "^4.0.0",
33
34
  "@ifc-lite/mcp": "^0.13.0",
34
35
  "@ifc-lite/mutations": "^2.0.0",
35
- "@ifc-lite/merge": "^0.4.5",
36
- "@ifc-lite/parser": "^5.0.0",
36
+ "@ifc-lite/query": "^2.1.0",
37
37
  "@ifc-lite/sandbox": "^2.2.2",
38
+ "@ifc-lite/parser": "^5.1.0",
39
+ "@ifc-lite/sdk": "^4.0.1",
38
40
  "@ifc-lite/viewer-core": "^0.2.15",
39
- "@ifc-lite/sdk": "^4.0.0",
40
- "@ifc-lite/query": "^2.1.0",
41
- "@ifc-lite/wasm": "^6.2.0"
41
+ "@ifc-lite/wasm": "^6.3.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/node": "^26.4.0",