brep-io-kernel 1.0.0-ci.10

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 (271) hide show
  1. package/LICENSE.md +32 -0
  2. package/README.md +157 -0
  3. package/dist-kernel/brep-kernel.js +74699 -0
  4. package/package.json +58 -0
  5. package/src/BREP/AssemblyComponent.js +42 -0
  6. package/src/BREP/BREP.js +43 -0
  7. package/src/BREP/BetterSolid.js +805 -0
  8. package/src/BREP/Edge.js +103 -0
  9. package/src/BREP/Extrude.js +403 -0
  10. package/src/BREP/Face.js +187 -0
  11. package/src/BREP/MeshRepairer.js +634 -0
  12. package/src/BREP/OffsetShellSolid.js +614 -0
  13. package/src/BREP/PointCloudWrap.js +302 -0
  14. package/src/BREP/Revolve.js +345 -0
  15. package/src/BREP/SolidMethods/authoring.js +112 -0
  16. package/src/BREP/SolidMethods/booleanOps.js +230 -0
  17. package/src/BREP/SolidMethods/chamfer.js +122 -0
  18. package/src/BREP/SolidMethods/edgeResolution.js +25 -0
  19. package/src/BREP/SolidMethods/fillet.js +792 -0
  20. package/src/BREP/SolidMethods/index.js +72 -0
  21. package/src/BREP/SolidMethods/io.js +105 -0
  22. package/src/BREP/SolidMethods/lifecycle.js +103 -0
  23. package/src/BREP/SolidMethods/manifoldOps.js +375 -0
  24. package/src/BREP/SolidMethods/meshCleanup.js +2512 -0
  25. package/src/BREP/SolidMethods/meshQueries.js +264 -0
  26. package/src/BREP/SolidMethods/metadata.js +106 -0
  27. package/src/BREP/SolidMethods/metrics.js +51 -0
  28. package/src/BREP/SolidMethods/transforms.js +361 -0
  29. package/src/BREP/SolidMethods/visualize.js +508 -0
  30. package/src/BREP/SolidShared.js +26 -0
  31. package/src/BREP/Sweep.js +1596 -0
  32. package/src/BREP/Tube.js +857 -0
  33. package/src/BREP/Vertex.js +43 -0
  34. package/src/BREP/applyBooleanOperation.js +704 -0
  35. package/src/BREP/boundsUtils.js +48 -0
  36. package/src/BREP/chamfer.js +551 -0
  37. package/src/BREP/edgePolylineUtils.js +85 -0
  38. package/src/BREP/fillets/common.js +388 -0
  39. package/src/BREP/fillets/fillet.js +1422 -0
  40. package/src/BREP/fillets/filletGeometry.js +15 -0
  41. package/src/BREP/fillets/inset.js +389 -0
  42. package/src/BREP/fillets/offsetHelper.js +143 -0
  43. package/src/BREP/fillets/outset.js +88 -0
  44. package/src/BREP/helix.js +193 -0
  45. package/src/BREP/meshToBrep.js +234 -0
  46. package/src/BREP/primitives.js +279 -0
  47. package/src/BREP/setupManifold.js +71 -0
  48. package/src/BREP/threadGeometry.js +1120 -0
  49. package/src/BREP/triangleUtils.js +8 -0
  50. package/src/BREP/triangulate.js +608 -0
  51. package/src/FeatureRegistry.js +183 -0
  52. package/src/PartHistory.js +1132 -0
  53. package/src/UI/AccordionWidget.js +292 -0
  54. package/src/UI/CADmaterials.js +850 -0
  55. package/src/UI/EnvMonacoEditor.js +522 -0
  56. package/src/UI/FloatingWindow.js +396 -0
  57. package/src/UI/HistoryWidget.js +457 -0
  58. package/src/UI/MainToolbar.js +131 -0
  59. package/src/UI/ModelLibraryView.js +194 -0
  60. package/src/UI/OrthoCameraIdle.js +206 -0
  61. package/src/UI/PluginsWidget.js +280 -0
  62. package/src/UI/SceneListing.js +606 -0
  63. package/src/UI/SelectionFilter.js +629 -0
  64. package/src/UI/ViewCube.js +389 -0
  65. package/src/UI/assembly/AssemblyConstraintCollectionWidget.js +329 -0
  66. package/src/UI/assembly/AssemblyConstraintControlsWidget.js +282 -0
  67. package/src/UI/assembly/AssemblyConstraintsWidget.css +292 -0
  68. package/src/UI/assembly/AssemblyConstraintsWidget.js +1373 -0
  69. package/src/UI/assembly/constraintFaceUtils.js +115 -0
  70. package/src/UI/assembly/constraintHighlightUtils.js +70 -0
  71. package/src/UI/assembly/constraintLabelUtils.js +31 -0
  72. package/src/UI/assembly/constraintPointUtils.js +64 -0
  73. package/src/UI/assembly/constraintSelectionUtils.js +185 -0
  74. package/src/UI/assembly/constraintStatusUtils.js +142 -0
  75. package/src/UI/componentSelectorModal.js +240 -0
  76. package/src/UI/controls/CombinedTransformControls.js +386 -0
  77. package/src/UI/dialogs.js +351 -0
  78. package/src/UI/expressionsManager.js +100 -0
  79. package/src/UI/featureDialogWidgets/booleanField.js +25 -0
  80. package/src/UI/featureDialogWidgets/booleanOperationField.js +97 -0
  81. package/src/UI/featureDialogWidgets/buttonField.js +45 -0
  82. package/src/UI/featureDialogWidgets/componentSelectorField.js +102 -0
  83. package/src/UI/featureDialogWidgets/defaultField.js +23 -0
  84. package/src/UI/featureDialogWidgets/fileField.js +66 -0
  85. package/src/UI/featureDialogWidgets/index.js +34 -0
  86. package/src/UI/featureDialogWidgets/numberField.js +165 -0
  87. package/src/UI/featureDialogWidgets/optionsField.js +33 -0
  88. package/src/UI/featureDialogWidgets/referenceSelectionField.js +208 -0
  89. package/src/UI/featureDialogWidgets/stringField.js +24 -0
  90. package/src/UI/featureDialogWidgets/textareaField.js +28 -0
  91. package/src/UI/featureDialogWidgets/threadDesignationField.js +160 -0
  92. package/src/UI/featureDialogWidgets/transformField.js +252 -0
  93. package/src/UI/featureDialogWidgets/utils.js +43 -0
  94. package/src/UI/featureDialogWidgets/vec3Field.js +133 -0
  95. package/src/UI/featureDialogs.js +1414 -0
  96. package/src/UI/fileManagerWidget.js +615 -0
  97. package/src/UI/history/HistoryCollectionWidget.js +1294 -0
  98. package/src/UI/history/historyCollectionWidget.css.js +257 -0
  99. package/src/UI/history/historyDisplayInfo.js +133 -0
  100. package/src/UI/mobile.js +28 -0
  101. package/src/UI/objectDump.js +442 -0
  102. package/src/UI/pmi/AnnotationCollectionWidget.js +120 -0
  103. package/src/UI/pmi/AnnotationHistory.js +353 -0
  104. package/src/UI/pmi/AnnotationRegistry.js +90 -0
  105. package/src/UI/pmi/BaseAnnotation.js +269 -0
  106. package/src/UI/pmi/LabelOverlay.css +102 -0
  107. package/src/UI/pmi/LabelOverlay.js +191 -0
  108. package/src/UI/pmi/PMIMode.js +1550 -0
  109. package/src/UI/pmi/PMIViewsWidget.js +1098 -0
  110. package/src/UI/pmi/annUtils.js +729 -0
  111. package/src/UI/pmi/dimensions/AngleDimensionAnnotation.js +647 -0
  112. package/src/UI/pmi/dimensions/ExplodeBodyAnnotation.js +507 -0
  113. package/src/UI/pmi/dimensions/HoleCalloutAnnotation.js +462 -0
  114. package/src/UI/pmi/dimensions/LeaderAnnotation.js +403 -0
  115. package/src/UI/pmi/dimensions/LinearDimensionAnnotation.js +532 -0
  116. package/src/UI/pmi/dimensions/NoteAnnotation.js +110 -0
  117. package/src/UI/pmi/dimensions/RadialDimensionAnnotation.js +659 -0
  118. package/src/UI/pmi/pmiStyle.js +44 -0
  119. package/src/UI/sketcher/SketchMode3D.js +4095 -0
  120. package/src/UI/sketcher/dimensions.js +674 -0
  121. package/src/UI/sketcher/glyphs.js +236 -0
  122. package/src/UI/sketcher/highlights.js +60 -0
  123. package/src/UI/toolbarButtons/aboutButton.js +5 -0
  124. package/src/UI/toolbarButtons/exportButton.js +609 -0
  125. package/src/UI/toolbarButtons/flatPatternButton.js +307 -0
  126. package/src/UI/toolbarButtons/importButton.js +160 -0
  127. package/src/UI/toolbarButtons/inspectorToggleButton.js +12 -0
  128. package/src/UI/toolbarButtons/metadataButton.js +1063 -0
  129. package/src/UI/toolbarButtons/orientToFaceButton.js +114 -0
  130. package/src/UI/toolbarButtons/registerDefaultButtons.js +46 -0
  131. package/src/UI/toolbarButtons/saveButton.js +99 -0
  132. package/src/UI/toolbarButtons/scriptRunnerButton.js +302 -0
  133. package/src/UI/toolbarButtons/testsButton.js +26 -0
  134. package/src/UI/toolbarButtons/undoRedoButtons.js +25 -0
  135. package/src/UI/toolbarButtons/wireframeToggleButton.js +5 -0
  136. package/src/UI/toolbarButtons/zoomToFitButton.js +5 -0
  137. package/src/UI/triangleDebuggerWindow.js +945 -0
  138. package/src/UI/viewer.js +4228 -0
  139. package/src/assemblyConstraints/AssemblyConstraintHistory.js +1576 -0
  140. package/src/assemblyConstraints/AssemblyConstraintRegistry.js +120 -0
  141. package/src/assemblyConstraints/BaseAssemblyConstraint.js +66 -0
  142. package/src/assemblyConstraints/constraintExpressionUtils.js +35 -0
  143. package/src/assemblyConstraints/constraintUtils/parallelAlignment.js +676 -0
  144. package/src/assemblyConstraints/constraints/AngleConstraint.js +485 -0
  145. package/src/assemblyConstraints/constraints/CoincidentConstraint.js +194 -0
  146. package/src/assemblyConstraints/constraints/DistanceConstraint.js +616 -0
  147. package/src/assemblyConstraints/constraints/FixedConstraint.js +78 -0
  148. package/src/assemblyConstraints/constraints/ParallelConstraint.js +252 -0
  149. package/src/assemblyConstraints/constraints/TouchAlignConstraint.js +961 -0
  150. package/src/core/entities/HistoryCollectionBase.js +72 -0
  151. package/src/core/entities/ListEntityBase.js +109 -0
  152. package/src/core/entities/schemaProcesser.js +121 -0
  153. package/src/exporters/sheetMetalFlatPattern.js +659 -0
  154. package/src/exporters/sheetMetalUnfold.js +862 -0
  155. package/src/exporters/step.js +1135 -0
  156. package/src/exporters/threeMF.js +575 -0
  157. package/src/features/assemblyComponent/AssemblyComponentFeature.js +780 -0
  158. package/src/features/boolean/BooleanFeature.js +94 -0
  159. package/src/features/chamfer/ChamferFeature.js +116 -0
  160. package/src/features/datium/DatiumFeature.js +80 -0
  161. package/src/features/edgeFeatureUtils.js +41 -0
  162. package/src/features/extrude/ExtrudeFeature.js +143 -0
  163. package/src/features/fillet/FilletFeature.js +197 -0
  164. package/src/features/helix/HelixFeature.js +405 -0
  165. package/src/features/hole/HoleFeature.js +1050 -0
  166. package/src/features/hole/screwClearance.js +86 -0
  167. package/src/features/hole/threadDesignationCatalog.js +149 -0
  168. package/src/features/imageHeightSolid/ImageHeightmapSolidFeature.js +463 -0
  169. package/src/features/imageToFace/ImageToFaceFeature.js +727 -0
  170. package/src/features/imageToFace/imageEditor.js +1270 -0
  171. package/src/features/imageToFace/traceUtils.js +971 -0
  172. package/src/features/import3dModel/Import3dModelFeature.js +151 -0
  173. package/src/features/loft/LoftFeature.js +605 -0
  174. package/src/features/mirror/MirrorFeature.js +151 -0
  175. package/src/features/offsetFace/OffsetFaceFeature.js +370 -0
  176. package/src/features/offsetShell/OffsetShellFeature.js +89 -0
  177. package/src/features/overlapCleanup/OverlapCleanupFeature.js +85 -0
  178. package/src/features/pattern/PatternFeature.js +275 -0
  179. package/src/features/patternLinear/PatternLinearFeature.js +120 -0
  180. package/src/features/patternRadial/PatternRadialFeature.js +186 -0
  181. package/src/features/plane/PlaneFeature.js +154 -0
  182. package/src/features/primitiveCone/primitiveConeFeature.js +99 -0
  183. package/src/features/primitiveCube/primitiveCubeFeature.js +70 -0
  184. package/src/features/primitiveCylinder/primitiveCylinderFeature.js +91 -0
  185. package/src/features/primitivePyramid/primitivePyramidFeature.js +72 -0
  186. package/src/features/primitiveSphere/primitiveSphereFeature.js +62 -0
  187. package/src/features/primitiveTorus/primitiveTorusFeature.js +109 -0
  188. package/src/features/remesh/RemeshFeature.js +97 -0
  189. package/src/features/revolve/RevolveFeature.js +111 -0
  190. package/src/features/selectionUtils.js +118 -0
  191. package/src/features/sheetMetal/SheetMetalContourFlangeFeature.js +1656 -0
  192. package/src/features/sheetMetal/SheetMetalCutoutFeature.js +1056 -0
  193. package/src/features/sheetMetal/SheetMetalFlangeFeature.js +1568 -0
  194. package/src/features/sheetMetal/SheetMetalHemFeature.js +43 -0
  195. package/src/features/sheetMetal/SheetMetalObject.js +141 -0
  196. package/src/features/sheetMetal/SheetMetalTabFeature.js +176 -0
  197. package/src/features/sheetMetal/UNFOLD_NEUTRAL_REQUIREMENTS.md +153 -0
  198. package/src/features/sheetMetal/contour-flange-rebuild-spec.md +261 -0
  199. package/src/features/sheetMetal/profileUtils.js +25 -0
  200. package/src/features/sheetMetal/sheetMetalCleanup.js +9 -0
  201. package/src/features/sheetMetal/sheetMetalFaceTypes.js +146 -0
  202. package/src/features/sheetMetal/sheetMetalMetadata.js +165 -0
  203. package/src/features/sheetMetal/sheetMetalPipeline.js +169 -0
  204. package/src/features/sheetMetal/sheetMetalProfileUtils.js +216 -0
  205. package/src/features/sheetMetal/sheetMetalTabUtils.js +29 -0
  206. package/src/features/sheetMetal/sheetMetalTree.js +210 -0
  207. package/src/features/sketch/SketchFeature.js +955 -0
  208. package/src/features/sketch/sketchSolver2D/ConstraintEngine.js +800 -0
  209. package/src/features/sketch/sketchSolver2D/constraintDefinitions.js +704 -0
  210. package/src/features/sketch/sketchSolver2D/mathHelpersMod.js +307 -0
  211. package/src/features/spline/SplineEditorSession.js +988 -0
  212. package/src/features/spline/SplineFeature.js +1388 -0
  213. package/src/features/spline/splineUtils.js +218 -0
  214. package/src/features/sweep/SweepFeature.js +110 -0
  215. package/src/features/transform/TransformFeature.js +152 -0
  216. package/src/features/tube/TubeFeature.js +635 -0
  217. package/src/fs.proxy.js +625 -0
  218. package/src/idbStorage.js +254 -0
  219. package/src/index.js +12 -0
  220. package/src/main.js +15 -0
  221. package/src/metadataManager.js +64 -0
  222. package/src/path.proxy.js +277 -0
  223. package/src/plugins/ghLoader.worker.js +151 -0
  224. package/src/plugins/pluginManager.js +286 -0
  225. package/src/pmi/PMIViewsManager.js +134 -0
  226. package/src/services/componentLibrary.js +198 -0
  227. package/src/tests/ConsoleCapture.js +189 -0
  228. package/src/tests/S7-diagnostics-2025-12-23T18-37-23-570Z.json +630 -0
  229. package/src/tests/browserTests.js +597 -0
  230. package/src/tests/debugBoolean.js +225 -0
  231. package/src/tests/partFiles/badBoolean.json +957 -0
  232. package/src/tests/partFiles/extrudeTest.json +88 -0
  233. package/src/tests/partFiles/filletFail.json +58 -0
  234. package/src/tests/partFiles/import_TEst.part.part.json +646 -0
  235. package/src/tests/partFiles/sheetMetalHem.BREP.json +734 -0
  236. package/src/tests/test_boolean_subtract.js +27 -0
  237. package/src/tests/test_chamfer.js +17 -0
  238. package/src/tests/test_extrudeFace.js +24 -0
  239. package/src/tests/test_fillet.js +17 -0
  240. package/src/tests/test_fillet_nonClosed.js +45 -0
  241. package/src/tests/test_filletsMoreDifficult.js +46 -0
  242. package/src/tests/test_history_features_basic.js +149 -0
  243. package/src/tests/test_hole.js +282 -0
  244. package/src/tests/test_mirror.js +16 -0
  245. package/src/tests/test_offsetShellGrouping.js +85 -0
  246. package/src/tests/test_plane.js +4 -0
  247. package/src/tests/test_primitiveCone.js +11 -0
  248. package/src/tests/test_primitiveCube.js +7 -0
  249. package/src/tests/test_primitiveCylinder.js +8 -0
  250. package/src/tests/test_primitivePyramid.js +9 -0
  251. package/src/tests/test_primitiveSphere.js +17 -0
  252. package/src/tests/test_primitiveTorus.js +21 -0
  253. package/src/tests/test_pushFace.js +126 -0
  254. package/src/tests/test_sheetMetalContourFlange.js +125 -0
  255. package/src/tests/test_sheetMetal_features.js +80 -0
  256. package/src/tests/test_sketch_openLoop.js +45 -0
  257. package/src/tests/test_solidMetrics.js +58 -0
  258. package/src/tests/test_stlLoader.js +1889 -0
  259. package/src/tests/test_sweepFace.js +55 -0
  260. package/src/tests/test_tube.js +45 -0
  261. package/src/tests/test_tube_closedLoop.js +67 -0
  262. package/src/tests/tests.js +493 -0
  263. package/src/tools/assemblyConstraintDialogCapturePage.js +56 -0
  264. package/src/tools/dialogCapturePageFactory.js +227 -0
  265. package/src/tools/featureDialogCapturePage.js +47 -0
  266. package/src/tools/pmiAnnotationDialogCapturePage.js +60 -0
  267. package/src/utils/axisHelpers.js +99 -0
  268. package/src/utils/deepClone.js +69 -0
  269. package/src/utils/geometryTolerance.js +37 -0
  270. package/src/utils/normalizeTypeString.js +8 -0
  271. package/src/utils/xformMath.js +51 -0
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Debug helper for investigating boolean failures inside PartHistory runs.
5
+ *
6
+ * Usage:
7
+ * pnpm run debug:boolean -- badBoolean
8
+ * pnpm run debug:boolean -- badBoolean --feature=E4
9
+ *
10
+ * Flags:
11
+ * --feature=ID[,ID...] Force DEBUG_BOOLEAN filter (defaults to all boolean-bearing features)
12
+ * --list Print the features in the part file and exit
13
+ * --verbose Print extra diagnostic details per feature
14
+ * --stop=FEATURE_ID Stop execution after this feature (mirrors UI stop-at behaviour)
15
+ */
16
+
17
+ import path from 'node:path';
18
+ import fs from 'node:fs/promises';
19
+
20
+ const args = process.argv.slice(2);
21
+
22
+ let partArg = null;
23
+ const manualFeatureFilters = new Set();
24
+ let listOnly = false;
25
+ let verbose = false;
26
+ let stopAfter = null;
27
+
28
+ for (const arg of args) {
29
+ if (arg === '--') {
30
+ continue;
31
+ }
32
+ if (arg === '--list') {
33
+ listOnly = true;
34
+ continue;
35
+ }
36
+ if (arg === '--verbose') {
37
+ verbose = true;
38
+ continue;
39
+ }
40
+ if (arg.startsWith('--feature=')) {
41
+ const raw = arg.slice('--feature='.length).split(/[,;|]+/g).map(t => t.trim()).filter(Boolean);
42
+ raw.forEach(t => manualFeatureFilters.add(t));
43
+ continue;
44
+ }
45
+ if (arg.startsWith('--stop=')) {
46
+ stopAfter = arg.slice('--stop='.length).trim();
47
+ continue;
48
+ }
49
+ if (!partArg) {
50
+ partArg = arg;
51
+ continue;
52
+ }
53
+ manualFeatureFilters.add(arg);
54
+ }
55
+
56
+ const partName = partArg || 'badBoolean';
57
+ const cwd = process.cwd();
58
+ const candidatePath = partName.endsWith('.json')
59
+ ? path.resolve(cwd, partName)
60
+ : path.resolve(cwd, 'src', 'tests', 'partFiles', `${partName}.json`);
61
+
62
+ let partJSON = null;
63
+ try {
64
+ partJSON = await fs.readFile(candidatePath, 'utf8');
65
+ } catch (err) {
66
+ console.error(`[debugBoolean] Failed to read part file at ${candidatePath}: ${err?.message || err}`);
67
+ process.exitCode = 1;
68
+ process.exit(1);
69
+ }
70
+
71
+ let partData = null;
72
+ try {
73
+ partData = JSON.parse(partJSON);
74
+ } catch (err) {
75
+ console.error(`[debugBoolean] Part file is not valid JSON: ${err?.message || err}`);
76
+ process.exitCode = 1;
77
+ process.exit(1);
78
+ }
79
+
80
+ const features = Array.isArray(partData.features) ? partData.features : [];
81
+ const booleanFeatures = features.filter((feature) => {
82
+ const op = feature?.inputParams?.boolean?.operation;
83
+ const opCanonical = String(op || 'NONE').toUpperCase();
84
+ const targets = feature?.inputParams?.boolean?.targets;
85
+ const targetCount = Array.isArray(targets) ? targets.filter(Boolean).length : 0;
86
+ return opCanonical !== 'NONE' && targetCount > 0;
87
+ });
88
+
89
+ if (listOnly) {
90
+ console.log(`Part file: ${candidatePath}`);
91
+ console.log(`Total features: ${features.length}`);
92
+ if (features.length) {
93
+ features.forEach((feature, idx) => {
94
+ const id = feature?.inputParams?.featureID ?? '(no id)';
95
+ console.log(
96
+ `${String(idx + 1).padStart(2, '0')}. ${id} type=${feature?.type || '??'}`
97
+ );
98
+ });
99
+ }
100
+ if (booleanFeatures.length === 0) {
101
+ console.log('No boolean-bearing features detected.');
102
+ } else {
103
+ console.log('\nBoolean-bearing features:');
104
+ for (const feature of booleanFeatures) {
105
+ const id = feature?.inputParams?.featureID ?? '(no id)';
106
+ const op = feature?.inputParams?.boolean?.operation ?? 'NONE';
107
+ const targets = feature?.inputParams?.boolean?.targets ?? [];
108
+ console.log(` - ${id}: op=${op}, targets=${JSON.stringify(targets)}`);
109
+ }
110
+ }
111
+ process.exit(0);
112
+ }
113
+
114
+ const defaultFilters = booleanFeatures
115
+ .map(f => f?.inputParams?.featureID)
116
+ .filter(id => id != null)
117
+ .map(id => String(id));
118
+
119
+ if (!process.env.DEBUG_BOOLEAN) {
120
+ const combined = new Set([...defaultFilters, ...manualFeatureFilters]);
121
+ if (combined.size) {
122
+ process.env.DEBUG_BOOLEAN = Array.from(combined).join(',');
123
+ }
124
+ }
125
+
126
+ const { PartHistory } = await import('../PartHistory.js');
127
+
128
+ const partHistory = new PartHistory();
129
+ await partHistory.fromJSON(partJSON);
130
+ if (stopAfter) {
131
+ partHistory.currentHistoryStepId = stopAfter;
132
+ }
133
+
134
+ const featureIndex = new Map();
135
+ features.forEach((feature, idx) => {
136
+ const id = feature?.inputParams?.featureID;
137
+ if (id != null) featureIndex.set(String(id), { feature, index: idx });
138
+ });
139
+
140
+ const summarizeSolid = (solid) => {
141
+ if (!solid || typeof solid !== 'object') return { name: '(null)' };
142
+ const summary = {
143
+ name: solid.name || solid.owningFeatureID || solid.id || solid.uuid || '(unnamed)',
144
+ };
145
+ if (solid.owningFeatureID && solid.owningFeatureID !== summary.name) {
146
+ summary.owningFeatureID = solid.owningFeatureID;
147
+ }
148
+ try {
149
+ const vp = solid._vertProperties;
150
+ if (Array.isArray(vp)) summary.vertexCount = Math.floor(vp.length / 3);
151
+ } catch { }
152
+ try {
153
+ const tris = solid._triVerts || solid._triangles;
154
+ if (Array.isArray(tris)) summary.triangleCount = Math.floor(tris.length / 3);
155
+ } catch { }
156
+ return summary;
157
+ };
158
+
159
+ partHistory.callbacks.run = async (featureID) => {
160
+ const meta = featureIndex.get(String(featureID));
161
+ const idx = meta?.index ?? -1;
162
+ const label = (idx >= 0) ? `${idx + 1}/${features.length}` : `?/ ${features.length}`;
163
+ const type = meta?.feature?.type || 'unknown';
164
+ console.log(`[debugBoolean] Running ${label} → ${featureID} (${type})`);
165
+ };
166
+
167
+ const startedAt = Date.now();
168
+ try {
169
+ await partHistory.runHistory();
170
+ } catch (err) {
171
+ console.error('[debugBoolean] PartHistory.runHistory failed:', err?.message || err);
172
+ if (err?.stack) console.error(err.stack);
173
+ process.exitCode = 1;
174
+ process.exit(1);
175
+ }
176
+ const durationMs = Date.now() - startedAt;
177
+ console.log(`[debugBoolean] runHistory complete in ${durationMs} ms`);
178
+
179
+ const formatEffectsSummary = (effects) => {
180
+ if (!effects || typeof effects !== 'object') return { added: 0, removed: 0 };
181
+ const added = Array.isArray(effects.added) ? effects.added.length : 0;
182
+ const removed = Array.isArray(effects.removed) ? effects.removed.length : 0;
183
+ return { added, removed };
184
+ };
185
+
186
+ console.log('\n[debugBoolean] Feature outcomes:');
187
+ partHistory.features.forEach((feature, idx) => {
188
+ const id = feature?.inputParams?.featureID ?? '(no id)';
189
+ const lastRun = feature?.lastRun;
190
+ const ok = lastRun?.ok ?? false;
191
+ const status = ok ? 'OK ' : 'ERR';
192
+ const duration = lastRun ? `${lastRun.durationMs ?? 0}ms` : 'n/a';
193
+ const effectsSummary = formatEffectsSummary(feature?.effects);
194
+ let line = `${String(idx + 1).padStart(2, '0')}. [${status}] ${id} (${feature?.type || 'unknown'})`;
195
+ line += ` | t=${duration} | added=${effectsSummary.added} removed=${effectsSummary.removed}`;
196
+ if (!ok && lastRun?.error?.message) {
197
+ line += ` | error=${lastRun.error.message}`;
198
+ }
199
+ console.log(line);
200
+ if (verbose) {
201
+ if (feature?.effects?.added?.length) {
202
+ console.log(' added:', feature.effects.added.map(summarizeSolid));
203
+ }
204
+ if (feature?.effects?.removed?.length) {
205
+ console.log(' removed:', feature.effects.removed.map(summarizeSolid));
206
+ }
207
+ }
208
+ });
209
+
210
+ const solids = (partHistory.scene?.children || []).filter(obj => obj?.type === 'SOLID');
211
+ if (solids.length) {
212
+ console.log('\n[debugBoolean] Solids in scene after run:');
213
+ solids.forEach((solid, idx) => {
214
+ const summary = summarizeSolid(solid);
215
+ console.log(` - ${idx + 1}: ${summary.name} ${JSON.stringify(summary)}`);
216
+ });
217
+ } else {
218
+ console.log('\n[debugBoolean] No solids present in the scene after run.');
219
+ }
220
+
221
+ if (!process.env.DEBUG_BOOLEAN) {
222
+ console.log('\n[debugBoolean] Tip: set DEBUG_BOOLEAN env var or pass --feature=ID for detailed CSG tracing.');
223
+ } else {
224
+ console.log(`\n[debugBoolean] DEBUG_BOOLEAN=${process.env.DEBUG_BOOLEAN}`);
225
+ }