@ifc-lite/mcp 0.17.0 → 0.20.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.
Files changed (119) hide show
  1. package/dist/authored-attribute-value.d.ts +3 -0
  2. package/dist/authored-attribute-value.d.ts.map +1 -0
  3. package/dist/authored-attribute-value.js +34 -0
  4. package/dist/authored-attribute-value.js.map +1 -0
  5. package/dist/backend-query-relationships.d.ts +5 -0
  6. package/dist/backend-query-relationships.d.ts.map +1 -0
  7. package/dist/backend-query-relationships.js +55 -0
  8. package/dist/backend-query-relationships.js.map +1 -0
  9. package/dist/backend-query.d.ts +5 -6
  10. package/dist/backend-query.d.ts.map +1 -1
  11. package/dist/backend-query.js +81 -140
  12. package/dist/backend-query.js.map +1 -1
  13. package/dist/context.d.ts +8 -0
  14. package/dist/context.d.ts.map +1 -1
  15. package/dist/context.js.map +1 -1
  16. package/dist/effective-entity-membership.d.ts +8 -0
  17. package/dist/effective-entity-membership.d.ts.map +1 -0
  18. package/dist/effective-entity-membership.js +23 -0
  19. package/dist/effective-entity-membership.js.map +1 -0
  20. package/dist/headless-backend-cost-store.d.ts +14 -0
  21. package/dist/headless-backend-cost-store.d.ts.map +1 -0
  22. package/dist/headless-backend-cost-store.js +20 -0
  23. package/dist/headless-backend-cost-store.js.map +1 -0
  24. package/dist/headless-backend-store-stubs.d.ts +12 -0
  25. package/dist/headless-backend-store-stubs.d.ts.map +1 -0
  26. package/dist/headless-backend-store-stubs.js +9 -0
  27. package/dist/headless-backend-store-stubs.js.map +1 -0
  28. package/dist/headless-backend-structural-store.d.ts +21 -0
  29. package/dist/headless-backend-structural-store.d.ts.map +1 -0
  30. package/dist/headless-backend-structural-store.js +20 -0
  31. package/dist/headless-backend-structural-store.js.map +1 -0
  32. package/dist/headless-backend.d.ts +2 -1
  33. package/dist/headless-backend.d.ts.map +1 -1
  34. package/dist/headless-backend.js +9 -9
  35. package/dist/headless-backend.js.map +1 -1
  36. package/dist/index.d.ts +9 -1
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +12 -1
  39. package/dist/index.js.map +1 -1
  40. package/dist/loader.d.ts.map +1 -1
  41. package/dist/loader.js +4 -0
  42. package/dist/loader.js.map +1 -1
  43. package/dist/overlay.d.ts +23 -28
  44. package/dist/overlay.d.ts.map +1 -1
  45. package/dist/overlay.js +84 -99
  46. package/dist/overlay.js.map +1 -1
  47. package/dist/protocol/types.d.ts +0 -1
  48. package/dist/protocol/types.d.ts.map +1 -1
  49. package/dist/schema-tables.d.ts.map +1 -1
  50. package/dist/schema-tables.js +4 -2
  51. package/dist/schema-tables.js.map +1 -1
  52. package/dist/server.js +2 -2
  53. package/dist/server.js.map +1 -1
  54. package/dist/spatial-tree.d.ts.map +1 -1
  55. package/dist/spatial-tree.js +3 -9
  56. package/dist/spatial-tree.js.map +1 -1
  57. package/dist/tools/check-rules.d.ts +3 -0
  58. package/dist/tools/check-rules.d.ts.map +1 -0
  59. package/dist/tools/check-rules.js +75 -0
  60. package/dist/tools/check-rules.js.map +1 -0
  61. package/dist/tools/diff-authored-keys.d.ts +68 -0
  62. package/dist/tools/diff-authored-keys.d.ts.map +1 -0
  63. package/dist/tools/diff-authored-keys.js +166 -0
  64. package/dist/tools/diff-authored-keys.js.map +1 -0
  65. package/dist/tools/diff-content.d.ts +33 -0
  66. package/dist/tools/diff-content.d.ts.map +1 -0
  67. package/dist/tools/diff-content.js +158 -0
  68. package/dist/tools/diff-content.js.map +1 -0
  69. package/dist/tools/diff-entity-scope.d.ts +53 -0
  70. package/dist/tools/diff-entity-scope.d.ts.map +1 -0
  71. package/dist/tools/diff-entity-scope.js +94 -0
  72. package/dist/tools/diff-entity-scope.js.map +1 -0
  73. package/dist/tools/diff-fingerprints.d.ts +4 -2
  74. package/dist/tools/diff-fingerprints.d.ts.map +1 -1
  75. package/dist/tools/diff-fingerprints.js +69 -153
  76. package/dist/tools/diff-fingerprints.js.map +1 -1
  77. package/dist/tools/diff.d.ts.map +1 -1
  78. package/dist/tools/diff.js +40 -117
  79. package/dist/tools/diff.js.map +1 -1
  80. package/dist/tools/entity-target-schema.d.ts +16 -0
  81. package/dist/tools/entity-target-schema.d.ts.map +1 -0
  82. package/dist/tools/entity-target-schema.js +32 -0
  83. package/dist/tools/entity-target-schema.js.map +1 -0
  84. package/dist/tools/flow.d.ts +3 -0
  85. package/dist/tools/flow.d.ts.map +1 -0
  86. package/dist/tools/flow.js +239 -0
  87. package/dist/tools/flow.js.map +1 -0
  88. package/dist/tools/ids-accessor.d.ts +9 -1
  89. package/dist/tools/ids-accessor.d.ts.map +1 -1
  90. package/dist/tools/ids-accessor.js +9 -2
  91. package/dist/tools/ids-accessor.js.map +1 -1
  92. package/dist/tools/index.d.ts +4 -1
  93. package/dist/tools/index.d.ts.map +1 -1
  94. package/dist/tools/index.js +7 -1
  95. package/dist/tools/index.js.map +1 -1
  96. package/dist/tools/mutate.d.ts.map +1 -1
  97. package/dist/tools/mutate.js +15 -46
  98. package/dist/tools/mutate.js.map +1 -1
  99. package/dist/tools/structural.d.ts +11 -0
  100. package/dist/tools/structural.d.ts.map +1 -0
  101. package/dist/tools/structural.js +23 -0
  102. package/dist/tools/structural.js.map +1 -0
  103. package/dist/tools/util.d.ts.map +1 -1
  104. package/dist/tools/util.js +15 -18
  105. package/dist/tools/util.js.map +1 -1
  106. package/dist/tools/validation.d.ts.map +1 -1
  107. package/dist/tools/validation.js +40 -41
  108. package/dist/tools/validation.js.map +1 -1
  109. package/dist/tools/viewer.d.ts.map +1 -1
  110. package/dist/tools/viewer.js +10 -29
  111. package/dist/tools/viewer.js.map +1 -1
  112. package/dist/validate.d.ts +22 -1
  113. package/dist/validate.d.ts.map +1 -1
  114. package/dist/validate.js +45 -10
  115. package/dist/validate.js.map +1 -1
  116. package/dist/viewer-manager.d.ts.map +1 -1
  117. package/dist/viewer-manager.js +1 -0
  118. package/dist/viewer-manager.js.map +1 -1
  119. package/package.json +24 -20
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Attribute reading for the MCP diff adapter, and authored keys (issue #4955): `key_from` keys the
3
+ * comparison on `Tag` or a `Pset.Prop` instead of GlobalId. Read through the
4
+ * session OVERLAY, like every other fingerprinted value, so a queued edit or
5
+ * tombstone is what the comparison sees. Split out of `diff-fingerprints.ts`
6
+ * for size.
7
+ */
8
+ import { EntityExtractor, type IfcDataStore } from '@ifc-lite/parser';
9
+ import type { EntityFingerprint } from '@ifc-lite/diff';
10
+ import type { EffectiveEntity } from '@ifc-lite/data';
11
+ import { type PendingOverlay } from '../overlay.js';
12
+ /** Adapter options (issue #4955); the CLI's `FingerprintAdapterOptions` restated. */
13
+ export interface FingerprintAdapterOptions {
14
+ /** `Tag` or `<PsetName>.<PropertyName>`; see the CLI copy for the rules. */
15
+ keyProperty?: string;
16
+ duplicateAuthoredKeys?: Map<string, number[]>;
17
+ }
18
+ /** Prefix on a fingerprint key taken from an authored property rather than a GlobalId. */
19
+ export declare const AUTHORED_KEY_PREFIX = "prop:";
20
+ /**
21
+ * A collision found on either revision invalidates that authored value on
22
+ * both. The first side may already have been built when the second reveals the
23
+ * collision, so repair its key back to the entity's GlobalId before diffing.
24
+ */
25
+ export declare function fallbackPairDuplicateAuthoredKeys(sides: readonly {
26
+ fingerprints: EntityFingerprint<number>[];
27
+ store: IfcDataStore;
28
+ overlay?: PendingOverlay | null;
29
+ }[], duplicates: ReadonlyMap<string, number[]>): void;
30
+ /**
31
+ * Build the key resolver for one model: `prop:<value>` where the entity carries
32
+ * a non-empty value nobody else does, GlobalId otherwise. Duplicate values are
33
+ * reported on `options.duplicateAuthoredKeys`. Tombstoned entities are not
34
+ * owners: a deleted twin no longer contests the key. A created entity has no
35
+ * store row to read and keeps its GlobalId.
36
+ */
37
+ export declare function authoredKeyResolver(store: IfcDataStore, overlay: PendingOverlay | null | undefined, options: FingerprintAdapterOptions, extractor: EntityExtractor, entities: readonly EffectiveEntity[]): (expressId: number, globalId: string) => string;
38
+ /**
39
+ * One named attribute, read positionally through the **cross-schema** attribute
40
+ * list (issue #2021). The CLI's twin, and it must stay one.
41
+ *
42
+ * `extractAllEntityAttributes` names attributes through the parser's IFC4
43
+ * codegen pin, which answers an EMPTY list for a class the pin does not carry —
44
+ * so a `.find(name === 'Tag')` over it silently finds nothing on every
45
+ * IFC4X3-only type object (`IfcRailType`, `IfcTrackElementType`,
46
+ * `IfcSignalType`, …) while working perfectly on IFC2X3 and IFC4. That is a
47
+ * no-op nobody would notice: the entity is in scope, its class name is right,
48
+ * `isTypeObject` is right, and only the evidence is missing.
49
+ *
50
+ * This is the same pinned-registry family as the membership defect `#2001`
51
+ * fixed, and it has to be answered from the same place: the inheritance chain
52
+ * decides *whether* to read a `Tag`, so the attribute list that decides *where*
53
+ * it sits must span the same schemas. `getAttributeNamesAcrossSchemas` returns
54
+ * the pinned result unchanged for every class the pin does know, so this is
55
+ * additive — no IFC2X3 or IFC4 entity's hash moves because of it.
56
+ *
57
+ * Reads the raw STEP slot rather than reusing `extractAllEntityAttributes`'
58
+ * display normalization: this value is hashed, not shown, so `$` (absent) is
59
+ * the only case that needs interpreting and it arrives as null.
60
+ */
61
+ export declare function attributeAcrossSchemas(store: IfcDataStore, expressId: number, ifcType: string, attributeName: string): string | undefined;
62
+ /**
63
+ * An overlay override wins whenever one exists, including when it is empty —
64
+ * `entity_set_attribute` with `''` clears the attribute, and falling back to
65
+ * the stored value there would hash the edit away.
66
+ */
67
+ export declare function override(edited: string | undefined, stored: string | undefined): string | undefined;
68
+ //# sourceMappingURL=diff-authored-keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-authored-keys.d.ts","sourceRoot":"","sources":["../../src/tools/diff-authored-keys.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,OAAO,EACL,eAAe,EAKf,KAAK,YAAY,EAClB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAE9D,qFAAqF;AACrF,MAAM,WAAW,yBAAyB;IACxC,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qBAAqB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CAC/C;AAED,0FAA0F;AAC1F,eAAO,MAAM,mBAAmB,UAAU,CAAC;AAE3C;;;;GAIG;AACH,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,SAAS;IACd,YAAY,EAAE,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC;IAC1C,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;CACjC,EAAE,EACH,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GACxC,IAAI,CA8BN;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,EAC1C,OAAO,EAAE,yBAAyB,EAClC,SAAS,EAAE,eAAe,EAC1B,QAAQ,EAAE,SAAS,eAAe,EAAE,GACnC,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAoDjD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,GACpB,MAAM,GAAG,SAAS,CAQpB;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAGnG"}
@@ -0,0 +1,166 @@
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
+ * Attribute reading for the MCP diff adapter, and authored keys (issue #4955): `key_from` keys the
6
+ * comparison on `Tag` or a `Pset.Prop` instead of GlobalId. Read through the
7
+ * session OVERLAY, like every other fingerprinted value, so a queued edit or
8
+ * tombstone is what the comparison sees. Split out of `diff-fingerprints.ts`
9
+ * for size.
10
+ */
11
+ import { EntityExtractor, authoredKeyValue, extractRootAttributesFromEntity, getAttributeNamesAcrossSchemas, parseAuthoredKeySpec, } from '@ifc-lite/parser';
12
+ import { stepText } from '../overlay.js';
13
+ /** Prefix on a fingerprint key taken from an authored property rather than a GlobalId. */
14
+ export const AUTHORED_KEY_PREFIX = 'prop:';
15
+ /**
16
+ * A collision found on either revision invalidates that authored value on
17
+ * both. The first side may already have been built when the second reveals the
18
+ * collision, so repair its key back to the entity's GlobalId before diffing.
19
+ */
20
+ export function fallbackPairDuplicateAuthoredKeys(sides, duplicates) {
21
+ if (duplicates.size === 0)
22
+ return;
23
+ for (const { fingerprints, store, overlay } of sides) {
24
+ const extractor = new EntityExtractor(store.source);
25
+ for (const fingerprint of fingerprints) {
26
+ if (!fingerprint.key.startsWith(AUTHORED_KEY_PREFIX))
27
+ continue;
28
+ const value = fingerprint.key.slice(AUTHORED_KEY_PREFIX.length);
29
+ if (!duplicates.has(value))
30
+ continue;
31
+ const named = overlay?.attributes(fingerprint.ref);
32
+ const positional = overlay?.positionalAttributes?.(fingerprint.ref);
33
+ const editedGlobalId = named?.has('GlobalId') ? named.get('GlobalId')
34
+ : positional?.has(0) ? stepText(positional.get(0)) ?? '' : undefined;
35
+ const createdGlobalId = overlay?.createdEntity(fingerprint.ref)?.globalId;
36
+ const tableGlobalId = store.entities.getGlobalId(fingerprint.ref);
37
+ // @raw-entity-enumeration-ok collision fallback uses this point source record only after checking effective and created GlobalIds
38
+ const ref = store.entityIndex.byId.get(fingerprint.ref);
39
+ const entity = ref ? extractor.extractEntity(ref) : undefined;
40
+ const sourceGlobalId = entity ? extractRootAttributesFromEntity(entity).globalId : undefined;
41
+ // An explicit empty edit clears GlobalId. Falling back to the source
42
+ // here would resurrect an identity the session no longer has; the
43
+ // fingerprint builder omits that source entity before this repair pass.
44
+ const globalId = editedGlobalId !== undefined ? editedGlobalId
45
+ : createdGlobalId !== undefined ? createdGlobalId
46
+ : (tableGlobalId || sourceGlobalId);
47
+ if (!globalId) {
48
+ throw new Error(`Cannot restore GlobalId for authored-key collision on #${fingerprint.ref}`);
49
+ }
50
+ fingerprint.key = globalId;
51
+ }
52
+ }
53
+ }
54
+ /**
55
+ * Build the key resolver for one model: `prop:<value>` where the entity carries
56
+ * a non-empty value nobody else does, GlobalId otherwise. Duplicate values are
57
+ * reported on `options.duplicateAuthoredKeys`. Tombstoned entities are not
58
+ * owners: a deleted twin no longer contests the key. A created entity has no
59
+ * store row to read and keeps its GlobalId.
60
+ */
61
+ export function authoredKeyResolver(store, overlay, options, extractor, entities) {
62
+ const keySpec = options.keyProperty ? parseAuthoredKeySpec(options.keyProperty) : undefined;
63
+ if (!keySpec)
64
+ return (_expressId, globalId) => globalId;
65
+ const authoredKeyOf = (expressId) => {
66
+ if (keySpec.kind === 'tag') {
67
+ const edited = overlay?.attributes(expressId).get('Tag');
68
+ if (edited !== undefined)
69
+ return edited.trim().length > 0 ? edited.trim() : undefined;
70
+ const created = overlay?.createdEntity(expressId);
71
+ // @raw-entity-enumeration-ok Tag slot discovery needs the source class for this one entity when no queued retype or creation supplies it
72
+ const effectiveType = overlay?.effectiveType?.(expressId)
73
+ ?? created?.ifcType ?? store.entityIndex.byId.get(expressId)?.type;
74
+ const tagIndex = effectiveType ? getAttributeNamesAcrossSchemas(effectiveType).indexOf('Tag') : -1;
75
+ const positional = overlay?.positionalAttributes?.(expressId);
76
+ if (tagIndex >= 0 && positional?.has(tagIndex))
77
+ return stepText(positional.get(tagIndex));
78
+ if (created) {
79
+ return tagIndex < 0 ? undefined : stepText(created.attributes[tagIndex]);
80
+ }
81
+ }
82
+ else if (overlay) {
83
+ const set = overlay.propertySets(expressId).find((pset) => pset.name === keySpec.pset);
84
+ const property = set?.properties.find((p) => p.name === keySpec.property);
85
+ if (set) {
86
+ const raw = property?.value;
87
+ if (raw === null || raw === undefined)
88
+ return undefined;
89
+ const value = typeof raw === 'object' ? JSON.stringify(raw) : String(raw);
90
+ return value.trim().length > 0 ? value.trim() : undefined;
91
+ }
92
+ }
93
+ return authoredKeyValue(store, expressId, keySpec, extractor);
94
+ };
95
+ // A first pass so a value two entities share can be refused for both,
96
+ // instead of the diff's first-wins index quietly keeping one.
97
+ const owners = new Map();
98
+ const seen = new Set();
99
+ for (const { expressId } of entities) {
100
+ if (seen.has(expressId))
101
+ continue;
102
+ seen.add(expressId);
103
+ const value = authoredKeyOf(expressId);
104
+ if (value === undefined)
105
+ continue;
106
+ const list = owners.get(value);
107
+ if (list)
108
+ list.push(expressId);
109
+ else
110
+ owners.set(value, [expressId]);
111
+ }
112
+ for (const [value, ids] of owners) {
113
+ if (ids.length > 1)
114
+ options.duplicateAuthoredKeys?.set(value, ids);
115
+ }
116
+ return (expressId, globalId) => {
117
+ const value = authoredKeyOf(expressId);
118
+ if (value === undefined)
119
+ return globalId;
120
+ return (owners.get(value)?.length ?? 0) === 1 ? `${AUTHORED_KEY_PREFIX}${value}` : globalId;
121
+ };
122
+ }
123
+ /**
124
+ * One named attribute, read positionally through the **cross-schema** attribute
125
+ * list (issue #2021). The CLI's twin, and it must stay one.
126
+ *
127
+ * `extractAllEntityAttributes` names attributes through the parser's IFC4
128
+ * codegen pin, which answers an EMPTY list for a class the pin does not carry —
129
+ * so a `.find(name === 'Tag')` over it silently finds nothing on every
130
+ * IFC4X3-only type object (`IfcRailType`, `IfcTrackElementType`,
131
+ * `IfcSignalType`, …) while working perfectly on IFC2X3 and IFC4. That is a
132
+ * no-op nobody would notice: the entity is in scope, its class name is right,
133
+ * `isTypeObject` is right, and only the evidence is missing.
134
+ *
135
+ * This is the same pinned-registry family as the membership defect `#2001`
136
+ * fixed, and it has to be answered from the same place: the inheritance chain
137
+ * decides *whether* to read a `Tag`, so the attribute list that decides *where*
138
+ * it sits must span the same schemas. `getAttributeNamesAcrossSchemas` returns
139
+ * the pinned result unchanged for every class the pin does know, so this is
140
+ * additive — no IFC2X3 or IFC4 entity's hash moves because of it.
141
+ *
142
+ * Reads the raw STEP slot rather than reusing `extractAllEntityAttributes`'
143
+ * display normalization: this value is hashed, not shown, so `$` (absent) is
144
+ * the only case that needs interpreting and it arrives as null.
145
+ */
146
+ export function attributeAcrossSchemas(store, expressId, ifcType, attributeName) {
147
+ const index = getAttributeNamesAcrossSchemas(ifcType).indexOf(attributeName);
148
+ if (index < 0)
149
+ return undefined;
150
+ // @raw-entity-enumeration-ok this point source slot is the base value; buildDataInput applies pending named and positional Tag edits
151
+ const ref = store.entityIndex.byId.get(expressId);
152
+ if (!ref)
153
+ return undefined;
154
+ const raw = new EntityExtractor(store.source).extractEntity(ref)?.attributes?.[index];
155
+ return typeof raw === 'string' || typeof raw === 'number' ? String(raw) : undefined;
156
+ }
157
+ /**
158
+ * An overlay override wins whenever one exists, including when it is empty —
159
+ * `entity_set_attribute` with `''` clears the attribute, and falling back to
160
+ * the stored value there would hash the edit away.
161
+ */
162
+ export function override(edited, stored) {
163
+ const value = edited !== undefined ? edited : stored;
164
+ return value ? value : undefined;
165
+ }
166
+ //# sourceMappingURL=diff-authored-keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-authored-keys.js","sourceRoot":"","sources":["../../src/tools/diff-authored-keys.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { type PendingOverlay } from '../overlay.js';
2
+ import type { LoadedModel } from '../context.js';
3
+ /** Default cap on the listed `contentMatches`. Per-kind totals are reported
4
+ * whole, so the cap bounds the payload without hiding anything. */
5
+ export declare const DEFAULT_MAX_MATCHES = 200;
6
+ /**
7
+ * Default cap on the GlobalIds listed per side of one match.
8
+ *
9
+ * `max_matches` bounds how many groups come back, not how big one is, and a
10
+ * `duplicated` / `deduplicated` / `ambiguous` group is a set of candidates that
11
+ * in a repetitive model can run to thousands of entities on each side. Without
12
+ * this, `max_matches: 1` could still return a model-sized payload and overflow
13
+ * the context window the cap exists to protect.
14
+ *
15
+ * 20 is chosen against what the list is *for*. A group is the engine declining
16
+ * to guess, so its members are a hand-off to the caller; twenty candidates on a
17
+ * side is already past what anyone resolves by reading a list rather than by
18
+ * querying the two models. The overwhelmingly common match is a 1:1 `renamed`
19
+ * pair, which this never touches. Every group still reports `baseCount` and
20
+ * `headCount` whole, computed before the cap for the same reason
21
+ * `contentMatchCounts` is: truncation must never be what makes a model look
22
+ * cleanly matched.
23
+ */
24
+ export declare const DEFAULT_MAX_GROUP_MEMBERS = 20;
25
+ /** Run the real `@ifc-lite/diff` engine over two loaded models. See the
26
+ * module doc for the scope and abstention contract. */
27
+ export declare function contentDiff(left: LoadedModel, right: LoadedModel, overlays: {
28
+ left: PendingOverlay | null;
29
+ right: PendingOverlay | null;
30
+ }, maxMatches: number, maxGroupMembers: number, keyProperty?: string, splitMerge?: boolean, successors?: boolean): Record<string, unknown>;
31
+ /** One-line human summary of the engine result, for the text block. */
32
+ export declare function describeCounts(content: Record<string, unknown>): string;
33
+ //# sourceMappingURL=diff-content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-content.d.ts","sourceRoot":"","sources":["../../src/tools/diff-content.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAyB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD;oEACoE;AACpE,eAAO,MAAM,mBAAmB,MAAM,CAAC;AAEvC;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAiB5C;wDACwD;AACxD,wBAAgB,WAAW,CACzB,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE;IAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAAA;CAAE,EACvE,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,EACvB,WAAW,CAAC,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,OAAO,EACpB,UAAU,CAAC,EAAE,OAAO,GACnB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAwFzB;AAgBD,uEAAuE;AACvE,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAOvE"}
@@ -0,0 +1,158 @@
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_diff`'s `by_content` half: the real `@ifc-lite/diff` engine run over
6
+ * two loaded models (issue #1891), plus `split_merge` / `successors`
7
+ * (issue #4956). Split out of `diff.ts` for size.
8
+ *
9
+ * **Data scope only.** This server has no geometry pipeline, so there is no
10
+ * world geometry hash and no bounding box; `scope: 'data'` is the honest
11
+ * description of what it can see, and every unambiguous 1:1 content match is
12
+ * therefore reported as `renamed` rather than `moved`/`reshaped`. `split_merge`
13
+ * and `successors` are geometry-only stages: they are threaded through to
14
+ * `diffModels` so the params exist and cost nothing today, but on this server
15
+ * they currently produce no claims either way (`diff.splitMerges` /
16
+ * `diff.successors` stay `undefined`, the engine's abstention) — they start
17
+ * producing claims the moment this server gains a geometry pass, with no
18
+ * further plumbing change. See `diff-fingerprints.ts`.
19
+ */
20
+ import { diffModels } from '@ifc-lite/diff';
21
+ import { buildModelFingerprints } from './diff-fingerprints.js';
22
+ import { fallbackPairDuplicateAuthoredKeys } from './diff-authored-keys.js';
23
+ import { pendingMutationsField } from '../overlay.js';
24
+ /** Default cap on the listed `contentMatches`. Per-kind totals are reported
25
+ * whole, so the cap bounds the payload without hiding anything. */
26
+ export const DEFAULT_MAX_MATCHES = 200;
27
+ /**
28
+ * Default cap on the GlobalIds listed per side of one match.
29
+ *
30
+ * `max_matches` bounds how many groups come back, not how big one is, and a
31
+ * `duplicated` / `deduplicated` / `ambiguous` group is a set of candidates that
32
+ * in a repetitive model can run to thousands of entities on each side. Without
33
+ * this, `max_matches: 1` could still return a model-sized payload and overflow
34
+ * the context window the cap exists to protect.
35
+ *
36
+ * 20 is chosen against what the list is *for*. A group is the engine declining
37
+ * to guess, so its members are a hand-off to the caller; twenty candidates on a
38
+ * side is already past what anyone resolves by reading a list rather than by
39
+ * querying the two models. The overwhelmingly common match is a 1:1 `renamed`
40
+ * pair, which this never touches. Every group still reports `baseCount` and
41
+ * `headCount` whole, computed before the cap for the same reason
42
+ * `contentMatchCounts` is: truncation must never be what makes a model look
43
+ * cleanly matched.
44
+ */
45
+ export const DEFAULT_MAX_GROUP_MEMBERS = 20;
46
+ /**
47
+ * Kinds an agent has to resolve itself, listed before the ones the engine
48
+ * already retired. Truncating the list must never be what drops the
49
+ * "we could not tell" groups.
50
+ */
51
+ const UNRESOLVED_FIRST = [
52
+ 'ambiguous',
53
+ 'duplicated',
54
+ 'deduplicated',
55
+ 'moved',
56
+ 'reshaped',
57
+ 'respecified',
58
+ 'renamed',
59
+ ];
60
+ /** Run the real `@ifc-lite/diff` engine over two loaded models. See the
61
+ * module doc for the scope and abstention contract. */
62
+ export function contentDiff(left, right, overlays, maxMatches, maxGroupMembers, keyProperty, splitMerge, successors) {
63
+ // Authored keys (issue #4955): `prop:<value>` where the model maintains one,
64
+ // GlobalId otherwise; a value two entities share is refused for both and
65
+ // reported so the agent sees why those two fell back.
66
+ const duplicateAuthoredKeys = new Map();
67
+ const adapter = { keyProperty, duplicateAuthoredKeys };
68
+ const baseFingerprints = buildModelFingerprints(left.store, overlays.left, adapter);
69
+ const headFingerprints = buildModelFingerprints(right.store, overlays.right, adapter);
70
+ fallbackPairDuplicateAuthoredKeys([
71
+ { fingerprints: baseFingerprints, store: left.store, overlay: overlays.left },
72
+ { fingerprints: headFingerprints, store: right.store, overlay: overlays.right },
73
+ ], duplicateAuthoredKeys);
74
+ const diff = diffModels(baseFingerprints, headFingerprints, {
75
+ scope: 'data',
76
+ matchUnpairedByContent: true,
77
+ detectSplitMerge: splitMerge,
78
+ detectSuccessors: successors,
79
+ });
80
+ const matches = [...(diff.contentMatches ?? [])].sort((a, b) => UNRESOLVED_FIRST.indexOf(a.kind) - UNRESOLVED_FIRST.indexOf(b.kind));
81
+ const byKind = {};
82
+ for (const match of matches)
83
+ byKind[match.kind] = (byKind[match.kind] ?? 0) + 1;
84
+ return {
85
+ scope: diff.scope,
86
+ keyProperty: keyProperty ?? null,
87
+ duplicateAuthoredKeys: [...duplicateAuthoredKeys.keys()].sort(),
88
+ counts: diff.counts,
89
+ // Whole totals, computed before the cap: an agent reading `contentMatches`
90
+ // can always tell whether the list it got is the whole story.
91
+ contentMatchCounts: byKind,
92
+ contentMatches: matches.slice(0, maxMatches).map((match) => ({
93
+ kind: match.kind,
94
+ ifcType: match.base[0]?.ifcType ?? match.head[0]?.ifcType,
95
+ // Groups are reported as groups. Collapsing a `duplicated` or
96
+ // `ambiguous` set to a single pair would be the engine guessing, which
97
+ // is exactly what it refuses to do (#1923). Long groups are cut to
98
+ // `maxGroupMembers` per side and say so, whole size included, so a cut
99
+ // group still reads as a group of that size.
100
+ ...listSide('base', match.base, maxGroupMembers),
101
+ ...listSide('head', match.head, maxGroupMembers),
102
+ ...(match.distance !== undefined ? { distance: match.distance } : {}),
103
+ })),
104
+ truncatedMatches: Math.max(0, matches.length - maxMatches),
105
+ // Absent (not `[]`) exactly when the stage did not run, or ran and the
106
+ // geometry abstention fired — this server's current state, always, until
107
+ // it has a geometry pipeline. The engine's "absent means not proved"
108
+ // contract, preserved rather than flattened.
109
+ splitMerges: diff.splitMerges?.map((claim) => ({
110
+ kind: claim.kind,
111
+ confidence: claim.confidence,
112
+ whole: claim.whole.key,
113
+ pieces: claim.pieces.map((piece) => piece.key),
114
+ })),
115
+ successors: diff.successors?.map((claim) => ({
116
+ confidence: claim.confidence,
117
+ base: claim.base.key,
118
+ head: claim.head.key,
119
+ overlap: claim.overlap,
120
+ distance: claim.distance,
121
+ })),
122
+ // Uncommitted edits are folded into the comparison; saying how many there
123
+ // are is what separates "the two files differ" from "this session has
124
+ // edits it has not written yet". Absent when neither model has any.
125
+ //
126
+ // `pendingMutations` is the scalar every other payload carries; the split a
127
+ // two-model comparison can additionally give lives under its own name rather
128
+ // than overloading that one.
129
+ ...pendingMutationsField(overlays.left, overlays.right),
130
+ ...(overlays.left || overlays.right
131
+ ? {
132
+ pendingMutationsBySide: {
133
+ base: overlays.left?.pendingMutations ?? 0,
134
+ head: overlays.right?.pendingMutations ?? 0,
135
+ },
136
+ }
137
+ : {}),
138
+ };
139
+ }
140
+ /** One side of a match: the (capped) keys, the whole count, and whether the
141
+ * list was cut. Emits `base`/`baseCount`/`baseTruncated` (or `head…`). */
142
+ function listSide(side, entities, maxGroupMembers) {
143
+ return {
144
+ [side]: entities.slice(0, maxGroupMembers).map((entity) => entity.key),
145
+ [`${side}Count`]: entities.length,
146
+ [`${side}Truncated`]: entities.length > maxGroupMembers,
147
+ };
148
+ }
149
+ /** One-line human summary of the engine result, for the text block. */
150
+ export function describeCounts(content) {
151
+ const counts = content.counts;
152
+ const byKind = content.contentMatchCounts;
153
+ const kinds = Object.entries(byKind).map(([kind, n]) => `${n} ${kind}`).join(', ');
154
+ return `${counts.added} added, ${counts.modified} modified, ${counts.deleted} deleted, `
155
+ + `${counts.unchanged} unchanged`
156
+ + (kinds ? `; content matches: ${kinds}` : '; no content matches');
157
+ }
158
+ //# sourceMappingURL=diff-content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-content.js","sourceRoot":"","sources":["../../src/tools/diff-content.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /** Membership and type scope for MCP model diff (#5249). */
2
+ import { type EffectiveEntity } from '@ifc-lite/data';
3
+ import { type IfcDataStore } from '@ifc-lite/parser';
4
+ import type { PendingOverlay } from '../overlay.js';
5
+ /** How an uppercase STEP type participates in the comparison. `name` is the
6
+ * registry's PascalCase spelling, used instead of the `EntityTable`'s
7
+ * `'Unknown'` for entities the table never took in. */
8
+ interface TypeRole {
9
+ role: 'independent' | 'dependent' | 'unknown';
10
+ name: string;
11
+ /** Whether the class is an `IfcTypeObject` — the gate on hashing `Tag`
12
+ * (issue #2021). A class no bundled schema declares is `false` rather than
13
+ * guessed; the fingerprint then carries no `Tag`, which is the same answer
14
+ * as a type object that has none. */
15
+ typeObject: boolean;
16
+ }
17
+ /**
18
+ * Classify one STEP type against the three `IfcRoot` branches.
19
+ *
20
+ * The chain has to come from **every bundled schema**, not from the parser's
21
+ * IFC4 codegen pin. `getInheritanceChainForEntity` answers an empty chain for
22
+ * any class the pin does not carry, and that is not a rare corner: IFC2X3 alone
23
+ * puts 23 `IfcObjectDefinition` classes there (`IfcMove`, `IfcOrderAction`,
24
+ * `IfcScheduleTimeControl`, `IfcSpaceProgram`, `IfcServiceLife`, …) and IFC4X3
25
+ * another 77. Judging those as `unknown` dropped the ones the `EntityTable`
26
+ * does not hold — real objects with real GlobalIds — and let through the
27
+ * IFC2X3-only *resource* classes it does hold under a `…STYLE` name, keyed on
28
+ * the Name in slot 0. Both are wrong answers about an IFC2X3 file, which is
29
+ * still most of what is in the wild.
30
+ *
31
+ * `unknown` is still not `dependent`: a vendor extension no schema declares has
32
+ * no chain to judge, so it keeps exactly the reach the `EntityTable` already
33
+ * gave it — which for a `…TYPE` class is a genuine GlobalId, since the parser's
34
+ * type-object branch is name-based and takes those in. Guessing that an
35
+ * unrecognised class is an `IfcObject` and reading its source record instead
36
+ * would cost one STEP extraction per row of every unrecognised bucket in the
37
+ * model, on every call, to reach entities almost no file has. The price of that
38
+ * choice is that a vendor `IfcRoot` subtype whose name does not end in `TYPE`
39
+ * stays uncompared.
40
+ *
41
+ * The one name the chain is not needed for is `IFCREL…`: that prefix is the
42
+ * parser's own rule for taking an unrecognised relationship into the table, and
43
+ * a relationship is excluded here whether any schema can confirm it or not.
44
+ * Without this, an unrecognised `IfcRelXxx` would be the single class of entity
45
+ * that got in through the relationship branch the comparison deliberately shuts.
46
+ */
47
+ export declare function classifyType(typeKey: string): TypeRole;
48
+ /** Limit the canonical walk to potentially comparable classes before it visits
49
+ * geometry buckets. Sparse retype destinations and authored classes are added
50
+ * even when absent from the parsed source index. */
51
+ export declare function comparableEntities(store: IfcDataStore, overlay?: PendingOverlay | null): EffectiveEntity[];
52
+ export {};
53
+ //# sourceMappingURL=diff-entity-scope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-entity-scope.d.ts","sourceRoot":"","sources":["../../src/tools/diff-entity-scope.ts"],"names":[],"mappings":"AAIA,4DAA4D;AAC5D,OAAO,EAA4B,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACvF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD;;wDAEwD;AACxD,UAAU,QAAQ;IAChB,IAAI,EAAE,aAAa,GAAG,WAAW,GAAG,SAAS,CAAC;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb;;;0CAGsC;IACtC,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,CAqBtD;AAED;;oDAEoD;AACpD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,IAAI,GAAG,eAAe,EAAE,CA0B1G"}
@@ -0,0 +1,94 @@
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
+ /** Membership and type scope for MCP model diff (#5249). */
5
+ import { iterateEffectiveEntities } from '@ifc-lite/data';
6
+ import { getInheritanceChainAcrossSchemas } from '@ifc-lite/parser';
7
+ /**
8
+ * Classify one STEP type against the three `IfcRoot` branches.
9
+ *
10
+ * The chain has to come from **every bundled schema**, not from the parser's
11
+ * IFC4 codegen pin. `getInheritanceChainForEntity` answers an empty chain for
12
+ * any class the pin does not carry, and that is not a rare corner: IFC2X3 alone
13
+ * puts 23 `IfcObjectDefinition` classes there (`IfcMove`, `IfcOrderAction`,
14
+ * `IfcScheduleTimeControl`, `IfcSpaceProgram`, `IfcServiceLife`, …) and IFC4X3
15
+ * another 77. Judging those as `unknown` dropped the ones the `EntityTable`
16
+ * does not hold — real objects with real GlobalIds — and let through the
17
+ * IFC2X3-only *resource* classes it does hold under a `…STYLE` name, keyed on
18
+ * the Name in slot 0. Both are wrong answers about an IFC2X3 file, which is
19
+ * still most of what is in the wild.
20
+ *
21
+ * `unknown` is still not `dependent`: a vendor extension no schema declares has
22
+ * no chain to judge, so it keeps exactly the reach the `EntityTable` already
23
+ * gave it — which for a `…TYPE` class is a genuine GlobalId, since the parser's
24
+ * type-object branch is name-based and takes those in. Guessing that an
25
+ * unrecognised class is an `IfcObject` and reading its source record instead
26
+ * would cost one STEP extraction per row of every unrecognised bucket in the
27
+ * model, on every call, to reach entities almost no file has. The price of that
28
+ * choice is that a vendor `IfcRoot` subtype whose name does not end in `TYPE`
29
+ * stays uncompared.
30
+ *
31
+ * The one name the chain is not needed for is `IFCREL…`: that prefix is the
32
+ * parser's own rule for taking an unrecognised relationship into the table, and
33
+ * a relationship is excluded here whether any schema can confirm it or not.
34
+ * Without this, an unrecognised `IfcRelXxx` would be the single class of entity
35
+ * that got in through the relationship branch the comparison deliberately shuts.
36
+ */
37
+ export function classifyType(typeKey) {
38
+ const upper = typeKey.toUpperCase();
39
+ const chain = getInheritanceChainAcrossSchemas(upper);
40
+ if (chain.length === 0) {
41
+ return {
42
+ role: upper.startsWith('IFCREL') ? 'dependent' : 'unknown',
43
+ name: typeKey,
44
+ typeObject: false,
45
+ };
46
+ }
47
+ // The chain holds the class itself plus its supertypes; which end the leaf
48
+ // sits at is the schema source's business — the union walk answers leaf→root
49
+ // and the IFC4 pin it falls back to answers root→leaf — so find it by name.
50
+ const name = chain.find((ancestor) => ancestor.toUpperCase() === upper) ?? typeKey;
51
+ const typeObject = chain.includes('IfcTypeObject');
52
+ if (!chain.includes('IfcRoot'))
53
+ return { role: 'dependent', name, typeObject };
54
+ return {
55
+ role: chain.includes('IfcObjectDefinition') ? 'independent' : 'dependent',
56
+ name,
57
+ typeObject,
58
+ };
59
+ }
60
+ /** Limit the canonical walk to potentially comparable classes before it visits
61
+ * geometry buckets. Sparse retype destinations and authored classes are added
62
+ * even when absent from the parsed source index. */
63
+ export function comparableEntities(store, overlay) {
64
+ const types = new Set();
65
+ // @raw-entity-enumeration-ok the diff chooses candidate source CLASS keys only; iterateEffectiveEntities handles membership below
66
+ for (const type of store.entityIndex.byType.keys()) {
67
+ if (classifyType(type).role !== 'dependent')
68
+ types.add(type);
69
+ }
70
+ const retypes = overlay?.typeMutations?.();
71
+ for (const change of retypes?.values() ?? []) {
72
+ if (classifyType(change.newType).role !== 'dependent')
73
+ types.add(change.newType);
74
+ }
75
+ const created = overlay?.created ?? [];
76
+ for (const entity of created) {
77
+ if (classifyType(entity.ifcType).role !== 'dependent')
78
+ types.add(entity.ifcType);
79
+ }
80
+ if (types.size === 0)
81
+ return [];
82
+ const createdById = new Map(created.map(entity => [entity.expressId, entity]));
83
+ const membership = overlay ? {
84
+ isDeleted: (id) => overlay.deleted.has(id),
85
+ getNewEntities: () => created.map(entity => ({ expressId: entity.expressId, type: entity.ifcType })),
86
+ getNewEntity: (id) => {
87
+ const entity = createdById.get(id);
88
+ return entity ? { type: entity.ifcType } : null;
89
+ },
90
+ getTypeMutations: () => retypes ?? new Map(),
91
+ } : null;
92
+ return [...iterateEffectiveEntities(store, membership, [...types])];
93
+ }
94
+ //# sourceMappingURL=diff-entity-scope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-entity-scope.js","sourceRoot":"","sources":["../../src/tools/diff-entity-scope.ts"],"names":[],"mappings":"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"}
@@ -84,7 +84,9 @@
84
84
  */
85
85
  import { type EntityFingerprint } from '@ifc-lite/diff';
86
86
  import { type IfcDataStore } from '@ifc-lite/parser';
87
- import type { PendingOverlay } from '../overlay.js';
87
+ import { type FingerprintAdapterOptions } from './diff-authored-keys.js';
88
+ export { AUTHORED_KEY_PREFIX, type FingerprintAdapterOptions } from './diff-authored-keys.js';
89
+ import { type PendingOverlay } from '../overlay.js';
88
90
  /** Adapter handle threaded through the diff: the entity's express id. */
89
91
  export type DiffRef = number;
90
92
  /**
@@ -102,5 +104,5 @@ export type DiffRef = number;
102
104
  * values. Omitting it (the CLI twin has no session to overlay) is the original
103
105
  * store-only behaviour exactly.
104
106
  */
105
- export declare function buildModelFingerprints(store: IfcDataStore, overlay?: PendingOverlay | null): EntityFingerprint<DiffRef>[];
107
+ export declare function buildModelFingerprints(store: IfcDataStore, overlay?: PendingOverlay | null, options?: FingerprintAdapterOptions): EntityFingerprint<DiffRef>[];
106
108
  //# sourceMappingURL=diff-fingerprints.d.ts.map