brepjs-cad 0.176.0 → 0.178.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.
Files changed (33) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +3 -2
  3. package/dist/brepjs-cad.cjs +2 -2
  4. package/dist/brepjs-cad.js +2 -2
  5. package/dist/cli/exportPart.d.ts +1 -0
  6. package/dist/cli/main.cjs +47 -14
  7. package/dist/cli/main.js +41 -8
  8. package/dist/cli/watch.d.ts +1 -1
  9. package/dist/{diff-CmIV_qOi.cjs → diff-CBp5KDNZ.cjs} +1 -1
  10. package/dist/{diff-C2vDUt9F.js → diff-DmFtXXiX.js} +1 -1
  11. package/dist/disposeShape-B4lsczOO.js +7 -0
  12. package/dist/disposeShape-Bui9k40G.cjs +12 -0
  13. package/dist/evaluate-C6FBiEVI.js +11816 -0
  14. package/dist/evaluate-sRn-Xvw4.cjs +11832 -0
  15. package/dist/export3dm/export3dm.cjs +144 -0
  16. package/dist/export3dm/export3dm.d.ts +10 -0
  17. package/dist/export3dm/export3dm.js +141 -0
  18. package/dist/loader/brepjsResolve.mjs +10 -4
  19. package/dist/mcp/server.cjs +2 -2
  20. package/dist/mcp/server.js +2 -2
  21. package/dist/{openBrowser-C1AiX6cC.cjs → openBrowser-Bip99cQv.cjs} +13 -15
  22. package/dist/{openBrowser-BBYw6VVb.js → openBrowser-Dg9oDOte.js} +14 -10
  23. package/dist/preview/evaluate.d.ts +10 -1
  24. package/dist/preview/preview.cjs +52 -11839
  25. package/dist/preview/preview.js +52 -11840
  26. package/dist/snapshot/static.cjs +7 -1
  27. package/dist/snapshot/static.js +7 -1
  28. package/dist/{usingCtx-DOzK2eJh.js → usingCtx-BDYtpr4t.js} +21 -12
  29. package/dist/{usingCtx-DNbyRoEg.cjs → usingCtx-LY0tPCbQ.cjs} +26 -11
  30. package/dist/verify/typecheck.d.ts +7 -0
  31. package/package.json +3 -2
  32. package/viewer/dist/assets/{index-Cq6KRusM.js → index-DpWxoifW.js} +2 -2
  33. package/viewer/dist/index.html +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.178.0](https://github.com/andymai/brepjs/compare/brepjs-cad-v0.177.0...brepjs-cad-v0.178.0) (2026-08-29)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **brepjs-cad:** ship the Z-up preview camera in the bundled viewer ([#2265](https://github.com/andymai/brepjs/issues/2265)) ([9993376](https://github.com/andymai/brepjs/commit/9993376b323ff47ee67583a57d88f82f0d343fc2)), closes [#2264](https://github.com/andymai/brepjs/issues/2264)
9
+
10
+ ## [0.177.0](https://github.com/andymai/brepjs/compare/brepjs-cad-v0.176.0...brepjs-cad-v0.177.0) (2026-08-26)
11
+
12
+
13
+ ### Features
14
+
15
+ * **brepjs-cad:** brep export --3dm — element-aware Rhino export ([#2236](https://github.com/andymai/brepjs/issues/2236)) ([91b0235](https://github.com/andymai/brepjs/commit/91b02355d9ba005f69dd4c72002a946600179398))
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * **brepjs-cad:** quality pass over the preview/loader/3dm/scaffold delta ([#2243](https://github.com/andymai/brepjs/issues/2243)) ([b6ae66e](https://github.com/andymai/brepjs/commit/b6ae66e6a1c4175bfd13846b382972e1d7356adc))
21
+
3
22
  ## [0.176.0](https://github.com/andymai/brepjs/compare/brepjs-cad-v0.175.0...brepjs-cad-v0.176.0) (2026-08-26)
4
23
 
5
24
 
package/README.md CHANGED
@@ -53,7 +53,7 @@ npx -y -p brepjs-cad brep part.brep.ts --serve # p
53
53
  npx -y -p brepjs-cad brep part.brep.ts --serve --no-open # preview server; just print the URL (no browser)
54
54
  ```
55
55
 
56
- `--snapshot`/`--serve` use the bundled viewer (shipped under `viewer/dist`, including the OCCT WASM). The `--serve` link is interactive: a toolbar offers view presets + fit, solid/wireframe/x-ray modes, edge/grid toggles, a turntable, click-to-inspect face picking, a section/clipping plane, a measurements panel, and an in-browser PNG screenshot. `--snapshot` loads the same page with `ui=0` to suppress the toolbar, and burns the bounding-box size into each PNG (`dims=1`) so the agent can read scale from the image.
56
+ `--snapshot`/`--serve` use the bundled viewer (shipped under `viewer/dist`, including the OCCT WASM). It renders in brepjs's native Z-up coordinates: Z is up, the XY plane is horizontal, and models are never rotated to fit the renderer's convention. The `--serve` link is interactive: a toolbar offers view presets + fit, solid/wireframe/x-ray modes, edge/grid toggles, a turntable, click-to-inspect face picking, a section/clipping plane, a measurements panel, and an in-browser PNG screenshot. `--snapshot` loads the same page with `ui=0` to suppress the toolbar, and burns the bounding-box size into each PNG (`dims=1`) so the agent can read scale from the image.
57
57
 
58
58
  `--serve` prints the viewer URL and, in an interactive terminal, opens it in your default browser. Auto-open is skipped when it would be unwanted: when the server is reused (a tab is already open), under CI, when output is piped (non-TTY, e.g. agent runs), or on Linux with no display server. Pass `--no-open` to always suppress it.
59
59
 
@@ -66,7 +66,8 @@ The `brep` bin is a multi-command CLI. `verify` is the default command, so `brep
66
66
  | `brep verify <files...>` | Default command. Loads the part, runs deterministic checks, prints the JSON report. Flags: `--check`, `--json <out\|->`, `--step <out>`, `--glb <out>`, `--snapshot <dir>`, `--serve`, `--no-open`, `--expect-code <CODE>` / `--expect-invalid` (assert a known-bad part fails the right way — for fixtures/eval). Multiple files or a quoted glob → a validity-only JSON array. Exits non-zero when not `ok` (unless `--serve`). |
67
67
  | `brep init <name>` | Scaffolds a parameterized `<name>.brep.ts` + `tsconfig.json` + `README.md` into `./<name>` (or `--out <dir>`). Never overwrites existing files. |
68
68
  | `brep watch <file>` | Re-verifies on every save until Ctrl-C (debounced; watches the parent dir to survive editor rename-on-save). |
69
- | `brep export <file>` | Batch artifacts behind a validity gate: `--step`, `--glb`, `--stl`, or `--all`; `--out <dir>` (default `.`). Exits non-zero on failure. |
69
+ | `brep preview <file>` | Element-aware live viewer for a model module (families element tree, resolved tree, or plain shape): key-path picking, failed elements listed, real edges. `--watch` re-evaluates on save and pushes to the open tab; `--write-only` (CI), `--glb <out>`, `--json <out>`, `--port <n>`, `--no-open`. |
70
+ | `brep export <file>` | Batch artifacts behind a validity gate: `--step`, `--glb`, `--stl`, or `--all`; `--3dm` writes an element-aware Rhino file (one named object per element, layered; needs the optional `rhino3dm` install; not combinable with the other formats); `--out <dir>` (default `.`). Exits non-zero on failure. |
70
71
  | `brep measure <a> [b]` | Measurements for one part; with a second module, the distance between the two parts. |
71
72
  | `brep diff <a> <b>` | Compares the measurements of a baseline and a comparison module. |
72
73
  | `brep snapshot <file>` | Standalone multi-view PNG capture (no report assertions): `--out <dir>`, `--label <tag>` (subfolder, for pre/post A/B pairing). Renders on a private ephemeral server so parallel snapshots don't contend. Requires the optional `puppeteer`/Chrome dependency; degrades with a clear message when absent. (Also available inline via `verify --snapshot <dir>`.) |
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_usingCtx = require("./usingCtx-DNbyRoEg.cjs");
3
- const require_diff = require("./diff-CmIV_qOi.cjs");
2
+ const require_usingCtx = require("./usingCtx-LY0tPCbQ.cjs");
3
+ const require_diff = require("./diff-CBp5KDNZ.cjs");
4
4
  exports.DEFAULT_TOLERANCE_PCT = require_usingCtx.DEFAULT_TOLERANCE_PCT;
5
5
  exports.TYPECHECK_CODE = require_usingCtx.TYPECHECK_CODE;
6
6
  exports.emptyReport = require_usingCtx.emptyReport;
@@ -1,3 +1,3 @@
1
- import { c as evaluateExpected, d as runChecks, f as emptyReport, h as serializeReport, i as TYPECHECK_CODE, l as isExpectedDims, o as typecheckPart, r as runPart, s as DEFAULT_TOLERANCE_PCT, u as pctDelta } from "./usingCtx-DOzK2eJh.js";
2
- import { n as runMeasure, t as runDiff } from "./diff-C2vDUt9F.js";
1
+ import { c as DEFAULT_TOLERANCE_PCT, d as pctDelta, f as runChecks, g as serializeReport, i as TYPECHECK_CODE, l as evaluateExpected, p as emptyReport, r as runPart, s as typecheckPart, u as isExpectedDims } from "./usingCtx-BDYtpr4t.js";
2
+ import { n as runMeasure, t as runDiff } from "./diff-DmFtXXiX.js";
3
3
  export { DEFAULT_TOLERANCE_PCT, TYPECHECK_CODE, emptyReport, evaluateExpected, isExpectedDims, pctDelta, runChecks, runDiff, runMeasure, runPart, serializeReport, typecheckPart };
@@ -10,4 +10,5 @@ export interface ExportResult {
10
10
  written: string[];
11
11
  errors: string[];
12
12
  }
13
+ export declare function stem(file: string): string;
13
14
  export declare function exportPart(modulePath: string, formats: ExportFormats, outDir: string): Promise<ExportResult>;
package/dist/cli/main.cjs CHANGED
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const require_usingCtx = require("../usingCtx-DNbyRoEg.cjs");
4
- const require_diff = require("../diff-CmIV_qOi.cjs");
5
- const require_openBrowser = require("../openBrowser-C1AiX6cC.cjs");
3
+ const require_usingCtx = require("../usingCtx-LY0tPCbQ.cjs");
4
+ const require_diff = require("../diff-CBp5KDNZ.cjs");
5
+ const require_openBrowser = require("../openBrowser-Bip99cQv.cjs");
6
+ const require_disposeShape = require("../disposeShape-Bui9k40G.cjs");
6
7
  let node_url = require("node:url");
7
8
  let node_fs = require("node:fs");
8
9
  let node_path = require("node:path");
@@ -101,7 +102,7 @@ function scaffoldPart(name, dir) {
101
102
  //#endregion
102
103
  //#region src/cli/exportPart.ts
103
104
  function stem(file) {
104
- return (0, node_path.basename)(file).replace(/\.brep\.ts$/, "").replace(/\.ts$/, "");
105
+ return (0, node_path.basename)(file).replace(/\.brep\.ts$/, "").replace(/\.(?:m?ts|tsx)$/, "");
105
106
  }
106
107
  async function exportPart(modulePath, formats, outDir) {
107
108
  const { shape, report, step, glb } = await require_usingCtx.runPart(modulePath, {
@@ -111,7 +112,7 @@ async function exportPart(modulePath, formats, outDir) {
111
112
  const errors = [];
112
113
  const written = [];
113
114
  if (!(require_usingCtx.reportOk(report) && shape !== null)) {
114
- require_openBrowser.disposeShape(shape);
115
+ require_disposeShape.disposeShape(shape);
115
116
  const failures = report.errorInfos.map((e) => e.message);
116
117
  return {
117
118
  ok: false,
@@ -147,7 +148,7 @@ async function exportPart(modulePath, formats, outDir) {
147
148
  } else errors.push(`STL export: ${r.error.message}`);
148
149
  }
149
150
  } finally {
150
- require_openBrowser.disposeShape(shape);
151
+ require_disposeShape.disposeShape(shape);
151
152
  }
152
153
  return {
153
154
  ok: errors.length === 0,
@@ -246,7 +247,7 @@ program.command("verify", { isDefault: true }).argument("<files...>", "path(s) o
246
247
  check: Boolean(opts.check),
247
248
  metrics: Boolean(opts.metrics)
248
249
  });
249
- require_openBrowser.disposeShape(shape);
250
+ require_disposeShape.disposeShape(shape);
250
251
  results.push({
251
252
  file: f,
252
253
  ok: require_usingCtx.reportOk(report),
@@ -291,7 +292,7 @@ program.command("verify", { isDefault: true }).argument("<files...>", "path(s) o
291
292
  } catch (e) {
292
293
  require_usingCtx.pushError(report, { message: `artifact write failed: ${e.message}` });
293
294
  } finally {
294
- require_openBrowser.disposeShape(shape);
295
+ require_disposeShape.disposeShape(shape);
295
296
  }
296
297
  const json = require_usingCtx.serializeReport(report);
297
298
  if (opts.json && opts.json !== "-") (0, node_fs.writeFileSync)(opts.json, json);
@@ -361,7 +362,7 @@ program.command("snapshot").argument("<file>", "path to a .brep.ts module; rende
361
362
  });
362
363
  for (const p of pngs) process.stdout.write(`${p}\n`);
363
364
  } finally {
364
- require_openBrowser.disposeShape(shape);
365
+ require_disposeShape.disposeShape(shape);
365
366
  }
366
367
  });
367
368
  program.command("init").argument("<name>", "part name; scaffolds <name>.brep.ts + tsconfig.json + README.md").option("--out <dir>", "target directory (defaults to ./<name>)").action((name, opts) => {
@@ -380,7 +381,7 @@ program.command("watch").argument("<file>", "path to a .brep.ts module; re-verif
380
381
  try {
381
382
  process.stdout.write(require_usingCtx.serializeReport(report) + "\n");
382
383
  } finally {
383
- require_openBrowser.disposeShape(shape);
384
+ require_disposeShape.disposeShape(shape);
384
385
  }
385
386
  } catch (e) {
386
387
  process.stderr.write(`watch run failed: ${e.message}\n`);
@@ -400,7 +401,7 @@ program.command("watch").argument("<file>", "path to a .brep.ts module; re-verif
400
401
  process.on("SIGINT", stop);
401
402
  process.on("SIGTERM", stop);
402
403
  });
403
- program.command("preview").argument("<file>", "path to a model module (.ts/.tsx); a families element tree renders per element").option("--watch", "re-evaluate on save and push updates to the open viewer tab").option("--write-only", "write artifacts and exit without starting the viewer server").option("--glb <out>", "write a merged GLB of the whole model").option("--json <out>", "write the JSON summary to this path").option("--port <n>", "viewer server port (default: OS-assigned)", (v) => parseInt(v, 10)).option("--no-open", "do not auto-open the browser").action(async (file, opts) => {
404
+ program.command("preview").argument("<file>", "path to a model module (.ts/.tsx); a families element tree renders per element").option("--watch", "re-evaluate on save and push updates to the open viewer tab").option("--write-only", "write artifacts without starting the viewer server (exits unless --watch)").option("--glb <out>", "write a merged GLB of the whole model").option("--json <out>", "write the JSON summary to this path").option("--port <n>", "viewer server port (default: OS-assigned)", (v) => parseInt(v, 10)).option("--no-open", "do not auto-open the browser").action(async (file, opts) => {
404
405
  const { runPreview } = await Promise.resolve().then(() => require("../preview/preview.cjs"));
405
406
  try {
406
407
  await runPreview((0, node_path.resolve)(file), opts);
@@ -409,7 +410,39 @@ program.command("preview").argument("<file>", "path to a model module (.ts/.tsx)
409
410
  process.exitCode = 1;
410
411
  }
411
412
  });
412
- program.command("export").argument("<file>", "path to a .brep.ts module").option("--step", "write a STEP artifact").option("--glb", "write a GLB artifact").option("--stl", "write an STL artifact").option("--all", "write STEP + GLB + STL").option("--out <dir>", "output directory", ".").action(async (file, opts) => {
413
+ program.command("export").argument("<file>", "path to a part (.brep.ts) module; --3dm also accepts a model (.ts/.tsx) default-exporting a families element tree").option("--step", "write a STEP artifact").option("--glb", "write a GLB artifact").option("--stl", "write an STL artifact").option("--all", "write STEP + GLB + STL").option("--3dm", "write a Rhino .3dm (element-aware: one named object per element, layered)").option("--out <dir>", "output directory", ".").action(async (file, opts) => {
414
+ const path = (0, node_path.resolve)(file);
415
+ if (opts["3dm"] && (opts.step || opts.glb || opts.stl || opts.all)) {
416
+ process.stderr.write("--3dm cannot be combined with --step/--glb/--stl/--all\n");
417
+ process.exitCode = 1;
418
+ return;
419
+ }
420
+ if (opts["3dm"]) {
421
+ let run;
422
+ try {
423
+ ({export3dm: run} = await Promise.resolve().then(() => require("../export3dm/export3dm.cjs")));
424
+ } catch {
425
+ process.stderr.write(".3dm export needs rhino3dm — run: npm i rhino3dm\n");
426
+ process.exitCode = 1;
427
+ return;
428
+ }
429
+ const outPath = (0, node_path.join)((0, node_path.resolve)(opts.out), stem(path) + ".3dm");
430
+ try {
431
+ const r = await run(path, outPath);
432
+ process.stderr.write(`wrote: ${outPath}\n`);
433
+ process.stdout.write(JSON.stringify({
434
+ ok: r.failed.length === 0,
435
+ written: [outPath],
436
+ elements: r.elements,
437
+ failed: r.failed
438
+ }, null, 2) + "\n");
439
+ if (r.failed.length > 0) process.exitCode = 1;
440
+ } catch (e) {
441
+ process.stderr.write(`3dm export failed: ${e.message}\n`);
442
+ process.exitCode = 1;
443
+ }
444
+ return;
445
+ }
413
446
  const formats = opts.all ? {
414
447
  step: true,
415
448
  glb: true,
@@ -420,11 +453,11 @@ program.command("export").argument("<file>", "path to a .brep.ts module").option
420
453
  stl: Boolean(opts.stl)
421
454
  };
422
455
  if (!formats.step && !formats.glb && !formats.stl) {
423
- process.stderr.write("no formats requested — pass --step/--glb/--stl or --all\n");
456
+ process.stderr.write("no formats requested — pass --step/--glb/--stl/--3dm or --all\n");
424
457
  process.exitCode = 1;
425
458
  return;
426
459
  }
427
- const result = await exportPart((0, node_path.resolve)(file), formats, (0, node_path.resolve)(opts.out));
460
+ const result = await exportPart(path, formats, (0, node_path.resolve)(opts.out));
428
461
  for (const p of result.written) process.stderr.write(`wrote: ${p}\n`);
429
462
  for (const e of result.errors) process.stderr.write(`error: ${e}\n`);
430
463
  process.stdout.write(JSON.stringify({
package/dist/cli/main.js CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { _ as loadBrep, h as serializeReport, m as reportOk, p as pushError, r as runPart } from "../usingCtx-DOzK2eJh.js";
3
- import { n as runMeasure, t as runDiff } from "../diff-C2vDUt9F.js";
4
- import { a as debounce, c as watchTree, i as createSerialRunner, n as shouldAutoOpen, o as isWatchRelevant, r as disposeShape, s as watchRootFor, t as openBrowser } from "../openBrowser-BBYw6VVb.js";
2
+ import { g as serializeReport, h as reportOk, m as pushError, r as runPart, v as loadBrep } from "../usingCtx-BDYtpr4t.js";
3
+ import { n as runMeasure, t as runDiff } from "../diff-DmFtXXiX.js";
4
+ import { a as isWatchRelevant, i as debounce, n as shouldAutoOpen, o as watchRootFor, r as createSerialRunner, s as watchTree, t as openBrowser } from "../openBrowser-Dg9oDOte.js";
5
+ import { t as disposeShape } from "../disposeShape-B4lsczOO.js";
5
6
  import { fileURLToPath } from "node:url";
6
7
  import { existsSync, globSync, mkdirSync, realpathSync, writeFileSync } from "node:fs";
7
8
  import { basename, join, resolve } from "node:path";
@@ -100,7 +101,7 @@ function scaffoldPart(name, dir) {
100
101
  //#endregion
101
102
  //#region src/cli/exportPart.ts
102
103
  function stem(file) {
103
- return basename(file).replace(/\.brep\.ts$/, "").replace(/\.ts$/, "");
104
+ return basename(file).replace(/\.brep\.ts$/, "").replace(/\.(?:m?ts|tsx)$/, "");
104
105
  }
105
106
  async function exportPart(modulePath, formats, outDir) {
106
107
  const { shape, report, step, glb } = await runPart(modulePath, {
@@ -399,7 +400,7 @@ program.command("watch").argument("<file>", "path to a .brep.ts module; re-verif
399
400
  process.on("SIGINT", stop);
400
401
  process.on("SIGTERM", stop);
401
402
  });
402
- program.command("preview").argument("<file>", "path to a model module (.ts/.tsx); a families element tree renders per element").option("--watch", "re-evaluate on save and push updates to the open viewer tab").option("--write-only", "write artifacts and exit without starting the viewer server").option("--glb <out>", "write a merged GLB of the whole model").option("--json <out>", "write the JSON summary to this path").option("--port <n>", "viewer server port (default: OS-assigned)", (v) => parseInt(v, 10)).option("--no-open", "do not auto-open the browser").action(async (file, opts) => {
403
+ program.command("preview").argument("<file>", "path to a model module (.ts/.tsx); a families element tree renders per element").option("--watch", "re-evaluate on save and push updates to the open viewer tab").option("--write-only", "write artifacts without starting the viewer server (exits unless --watch)").option("--glb <out>", "write a merged GLB of the whole model").option("--json <out>", "write the JSON summary to this path").option("--port <n>", "viewer server port (default: OS-assigned)", (v) => parseInt(v, 10)).option("--no-open", "do not auto-open the browser").action(async (file, opts) => {
403
404
  const { runPreview } = await import("../preview/preview.js");
404
405
  try {
405
406
  await runPreview(resolve(file), opts);
@@ -408,7 +409,39 @@ program.command("preview").argument("<file>", "path to a model module (.ts/.tsx)
408
409
  process.exitCode = 1;
409
410
  }
410
411
  });
411
- program.command("export").argument("<file>", "path to a .brep.ts module").option("--step", "write a STEP artifact").option("--glb", "write a GLB artifact").option("--stl", "write an STL artifact").option("--all", "write STEP + GLB + STL").option("--out <dir>", "output directory", ".").action(async (file, opts) => {
412
+ program.command("export").argument("<file>", "path to a part (.brep.ts) module; --3dm also accepts a model (.ts/.tsx) default-exporting a families element tree").option("--step", "write a STEP artifact").option("--glb", "write a GLB artifact").option("--stl", "write an STL artifact").option("--all", "write STEP + GLB + STL").option("--3dm", "write a Rhino .3dm (element-aware: one named object per element, layered)").option("--out <dir>", "output directory", ".").action(async (file, opts) => {
413
+ const path = resolve(file);
414
+ if (opts["3dm"] && (opts.step || opts.glb || opts.stl || opts.all)) {
415
+ process.stderr.write("--3dm cannot be combined with --step/--glb/--stl/--all\n");
416
+ process.exitCode = 1;
417
+ return;
418
+ }
419
+ if (opts["3dm"]) {
420
+ let run;
421
+ try {
422
+ ({export3dm: run} = await import("../export3dm/export3dm.js"));
423
+ } catch {
424
+ process.stderr.write(".3dm export needs rhino3dm — run: npm i rhino3dm\n");
425
+ process.exitCode = 1;
426
+ return;
427
+ }
428
+ const outPath = join(resolve(opts.out), stem(path) + ".3dm");
429
+ try {
430
+ const r = await run(path, outPath);
431
+ process.stderr.write(`wrote: ${outPath}\n`);
432
+ process.stdout.write(JSON.stringify({
433
+ ok: r.failed.length === 0,
434
+ written: [outPath],
435
+ elements: r.elements,
436
+ failed: r.failed
437
+ }, null, 2) + "\n");
438
+ if (r.failed.length > 0) process.exitCode = 1;
439
+ } catch (e) {
440
+ process.stderr.write(`3dm export failed: ${e.message}\n`);
441
+ process.exitCode = 1;
442
+ }
443
+ return;
444
+ }
412
445
  const formats = opts.all ? {
413
446
  step: true,
414
447
  glb: true,
@@ -419,11 +452,11 @@ program.command("export").argument("<file>", "path to a .brep.ts module").option
419
452
  stl: Boolean(opts.stl)
420
453
  };
421
454
  if (!formats.step && !formats.glb && !formats.stl) {
422
- process.stderr.write("no formats requested — pass --step/--glb/--stl or --all\n");
455
+ process.stderr.write("no formats requested — pass --step/--glb/--stl/--3dm or --all\n");
423
456
  process.exitCode = 1;
424
457
  return;
425
458
  }
426
- const result = await exportPart(resolve(file), formats, resolve(opts.out));
459
+ const result = await exportPart(path, formats, resolve(opts.out));
427
460
  for (const p of result.written) process.stderr.write(`wrote: ${p}\n`);
428
461
  for (const e of result.errors) process.stderr.write(`error: ${e}\n`);
429
462
  process.stdout.write(JSON.stringify({
@@ -10,7 +10,7 @@ export declare function isWatchRelevant(filename: string | Buffer | null | undef
10
10
  * and `../` imports live one level up. Nearest package.json or tsconfig.json walking up
11
11
  * wins; entries with no project marker fall back to their own directory.
12
12
  */
13
- export declare function watchRootFor(entryPath: string): string;
13
+ export declare function watchRootFor(entryPath: string, stopDir?: string): string;
14
14
  /**
15
15
  * Watch a directory tree with one non-recursive `fs.watch` per directory, skipping
16
16
  * node_modules/dist/.git and never following symlinks. `fs.watch({recursive})` has no
@@ -1,4 +1,4 @@
1
- const require_usingCtx = require("./usingCtx-DNbyRoEg.cjs");
1
+ const require_usingCtx = require("./usingCtx-LY0tPCbQ.cjs");
2
2
  //#region src/verify/measure.ts
3
3
  async function runMeasure(aPath, bPath) {
4
4
  try {
@@ -1,4 +1,4 @@
1
- import { _ as loadBrep, r as runPart, t as _usingCtx } from "./usingCtx-DOzK2eJh.js";
1
+ import { r as runPart, t as _usingCtx, v as loadBrep } from "./usingCtx-BDYtpr4t.js";
2
2
  //#region src/verify/measure.ts
3
3
  async function runMeasure(aPath, bPath) {
4
4
  try {
@@ -0,0 +1,7 @@
1
+ //#region src/disposeShape.ts
2
+ function disposeShape(shape) {
3
+ const disposer = shape?.[Symbol.dispose];
4
+ if (typeof disposer === "function") disposer.call(shape);
5
+ }
6
+ //#endregion
7
+ export { disposeShape as t };
@@ -0,0 +1,12 @@
1
+ //#region src/disposeShape.ts
2
+ function disposeShape(shape) {
3
+ const disposer = shape?.[Symbol.dispose];
4
+ if (typeof disposer === "function") disposer.call(shape);
5
+ }
6
+ //#endregion
7
+ Object.defineProperty(exports, "disposeShape", {
8
+ enumerable: true,
9
+ get: function() {
10
+ return disposeShape;
11
+ }
12
+ });