geospec 0.0.0 → 0.1.0-beta.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 (95) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +244 -0
  3. package/agent/doctrine.md +47 -0
  4. package/agent/geospec-authoring/SKILL.md +496 -0
  5. package/agent/geospec-authoring/api-classes.md +13 -0
  6. package/agent/geospec-authoring/api-constants.md +6 -0
  7. package/agent/geospec-authoring/api-functions.md +49 -0
  8. package/agent/geospec-authoring/api-index.md +362 -0
  9. package/agent/geospec-authoring/api-types.md +1700 -0
  10. package/agent/geospec-authoring/public-api-classes.md +22 -0
  11. package/agent/geospec-authoring/public-api-constants.md +19 -0
  12. package/agent/geospec-authoring/public-api-functions.md +196 -0
  13. package/agent/geospec-authoring/public-api-index.md +856 -0
  14. package/agent/geospec-authoring/public-api-types-2.md +1513 -0
  15. package/agent/geospec-authoring/public-api-types.md +2048 -0
  16. package/agent/resources.d.ts +19 -0
  17. package/agent/resources.js +26 -0
  18. package/agent/skills.d.cts +13 -0
  19. package/agent/skills.json +27 -0
  20. package/dist/assertion-client/client.d.mts +124 -0
  21. package/dist/assertion-client/client.mjs +2 -0
  22. package/dist/assertion-client/index.d.mts +5 -0
  23. package/dist/assertion-client/index.mjs +1 -0
  24. package/dist/config/index.d.mts +3 -0
  25. package/dist/config/index.mjs +1 -0
  26. package/dist/config/node/index.d.mts +3 -0
  27. package/dist/config/node/index.mjs +1 -0
  28. package/dist/config/node/load.d.mts +19 -0
  29. package/dist/config/node/load.mjs +1 -0
  30. package/dist/config/tau-project-artifact.d.mts +54 -0
  31. package/dist/config/tau-project-artifact.mjs +3 -0
  32. package/dist/config/types.d.mts +57 -0
  33. package/dist/config/validate.mjs +1 -0
  34. package/dist/create-geospec.d.mts +49 -0
  35. package/dist/create-geospec.mjs +1 -0
  36. package/dist/engine/client.d.mts +93 -0
  37. package/dist/engine/client.mjs +1 -0
  38. package/dist/engine/index.d.mts +3 -0
  39. package/dist/engine/index.mjs +1 -0
  40. package/dist/engine/matchers.d.mts +70 -0
  41. package/dist/engine/matchers.mjs +1 -0
  42. package/dist/engine/pmi.types.d.mts +78 -0
  43. package/dist/engine/protocol.d.mts +20 -0
  44. package/dist/engine/protocol.mjs +1 -0
  45. package/dist/geometry-unit.d.mts +12 -0
  46. package/dist/index.d.mts +6 -0
  47. package/dist/index.mjs +1 -0
  48. package/dist/mesh/index.d.mts +4 -0
  49. package/dist/mesh/index.mjs +1 -0
  50. package/dist/mesh/types.d.mts +575 -0
  51. package/dist/model/errors.d.mts +20 -0
  52. package/dist/model/errors.mjs +2 -0
  53. package/dist/model/export-intent.d.mts +63 -0
  54. package/dist/model/export-intent.mjs +1 -0
  55. package/dist/model/index.d.mts +6 -0
  56. package/dist/model/index.mjs +1 -0
  57. package/dist/model/load-model.d.mts +25 -0
  58. package/dist/model/load-model.mjs +1 -0
  59. package/dist/model/native-model-loader.d.mts +119 -0
  60. package/dist/model/native-model-loader.mjs +1 -0
  61. package/dist/model/subject-assertions.mjs +1 -0
  62. package/dist/model/subject.d.mts +11 -0
  63. package/dist/model/subject.mjs +1 -0
  64. package/dist/model/types.d.mts +207 -0
  65. package/dist/runner/collector.d.mts +62 -0
  66. package/dist/runner/collector.mjs +2 -0
  67. package/dist/runner/discovery.d.mts +93 -0
  68. package/dist/runner/discovery.mjs +1 -0
  69. package/dist/runner/filter.d.mts +50 -0
  70. package/dist/runner/filter.mjs +1 -0
  71. package/dist/runner/index.d.mts +6 -0
  72. package/dist/runner/index.mjs +1 -0
  73. package/dist/runner/native/index.d.mts +4 -0
  74. package/dist/runner/native/index.mjs +1 -0
  75. package/dist/runner/native/native-pool-grants.d.mts +21 -0
  76. package/dist/runner/native/native-pool-grants.mjs +1 -0
  77. package/dist/runner/native/native-serial-runner.d.mts +29 -0
  78. package/dist/runner/native/native-serial-runner.mjs +1 -0
  79. package/dist/runner/pool/pool-messages.d.mts +94 -0
  80. package/dist/runner/run-geospec-module.d.mts +13 -0
  81. package/dist/runner/run-geospec-module.mjs +47 -0
  82. package/dist/runner/types.d.mts +743 -0
  83. package/dist/runner/worker/index.d.mts +4 -0
  84. package/dist/runner/worker/index.mjs +1 -0
  85. package/dist/runner/worker/no-matching-tests-issue.d.mts +12 -0
  86. package/dist/runner/worker/no-matching-tests-issue.mjs +1 -0
  87. package/dist/runner/worker/runner-types.d.mts +146 -0
  88. package/dist/runner/worker/serial-runner.mjs +1 -0
  89. package/dist/selector/types.d.mts +271 -0
  90. package/dist/step/types.d.mts +134 -0
  91. package/dist/vitest/adapter.d.mts +56 -0
  92. package/dist/vitest/adapter.mjs +3 -0
  93. package/dist/vitest/index.d.mts +4 -0
  94. package/dist/vitest/index.mjs +1 -0
  95. package/package.json +114 -5
@@ -0,0 +1,19 @@
1
+ declare const bundles: readonly {
2
+ readonly slug: string;
3
+ readonly name: string;
4
+ readonly description: string;
5
+ readonly version: string;
6
+ readonly whenToUse: string;
7
+ readonly body: string;
8
+ readonly fingerprint: string;
9
+ readonly files: readonly {
10
+ readonly path: string;
11
+ readonly url: string;
12
+ readonly byteLength: number;
13
+ readonly lineCount: number;
14
+ readonly contentKind: "text";
15
+ readonly mediaType: "text/markdown";
16
+ readonly sha256: string;
17
+ }[];
18
+ }[];
19
+ export default bundles;
@@ -0,0 +1,26 @@
1
+ /* Generated by @taucad/api-extractor. Do not edit. */
2
+ export default Object.freeze([
3
+ Object.freeze({
4
+ slug: "geospec-authoring",
5
+ name: "GeoSpec authoring",
6
+ description: "Guides canonical GeoSpec geometry tests in TypeScript or JavaScript for every Tau kernel. Use for *.geospec.ts and *.geospec.js tests.",
7
+ version: "0.1.0-beta.2",
8
+ whenToUse: "Use before creating or editing *.geospec.ts or *.geospec.js tests, for a model in any kernel.",
9
+ body: "---\nname: geospec-authoring\ndescription: Guides canonical GeoSpec geometry tests in TypeScript or JavaScript for every Tau kernel. Use for *.geospec.ts and *.geospec.js tests.\n---\n\n# GeoSpec authoring\n\nWrite tests before implementation; assert deterministic, measurable properties.\n\n## Test shape\n\n- Use `*.geospec.ts` or `*.geospec.js`. Import `describe`, `it` and `expectGeo` from `geospec`, and `loadModel` from `geospec/model`.\n- Await `loadModel`, then assert synchronously with `expectGeo(model)`. The host supplies the compiled binding; authoring does not select an engine.\n- Await or return the complete model-load chain from the test callback; detached future loads are not part of a completed test.\n- Omit `parameters` for model-code defaults; use `{ file, parameters }` for variants. Loaded subjects are opaque.\n\nCanonical TypeScript authoring:\n\n```ts\nimport { describe, expectGeo, it } from 'geospec';\nimport { loadModel } from 'geospec/model';\n\ndescribe('main geometry', () => {\n it('has the intended envelope', async () => {\n const model = await loadModel({ file: 'main.ts', parameters: { width: 120 } });\n expectGeo(model).toHaveBoundingBox({ size: { x: 120 }, tolerance: 1 });\n });\n});\n```\n\nSpecs are always TypeScript or JavaScript, whatever the model's kernel: `loadModel({ file })` evaluates `main.ts`, `main.tsx`, `main.py`, `main.scad`, `main.kcl` or `main.cs` through Tau's runtime. `test_model` discovers `*.geospec.ts` and `*.geospec.js` only.\n\nEvery matcher takes one expectation object:\n\n- Wrong: `expectGeo(model).toHaveVolume(5000, { tolerance: 5 })`. Correct: `expectGeo(model).toHaveVolume({ value: 5000, tolerance: 5 })`.\n- Wrong: `await expectGeo(model)…`. Correct: await `loadModel`, then assert synchronously.\n- Wrong: exact-feature matchers on a mesh kernel (Manifold, JSCAD, OpenSCAD, PicoGK, PicoVoxel). Correct: `toBeValidBrep`, `toHaveTopologyCounts`, the face, hole, pattern, chamfer, fillet and wall-thickness matchers, `toHaveStepUnits`, `toHaveProductStructure` and `toHaveVoidContinuity` need STEP BRep evidence and report unsupported on meshes; assert meshes with bounds, volume, surface area, connected components and `toBeWatertight`.\n\n## Coverage\n\nBounds and physical properties are insufficient. Cover major components, named features, variants, dimensions/positions, disjoint counts, closure, interference and supported exact features. Explicitly report unsupported requirements; proxies cannot fulfill them.\n\n- `toHaveBoundingBox`: size/position.\n- `toHaveConnectedComponents`: qualified material connectivity; visual touching cannot justify tolerance changes.\n- `toBeWatertight`: closed edge incidence, not manifold validity, fusion or material connectivity. Bounds prove none of these. Missing evidence is unsupported.\n- `toHaveSurfaceArea`, `toHaveVolume`, `toHaveCenterOfMass`, `toHaveMass`: physical measurements.\n- `toHaveNoComponentInterference`: overlap; allow deliberate press fits.\n- `loadModel({ file, format: 'step' })`: use BRep evidence for supported topology and feature assertions. Missing occurrence, interference, clearance, containment, lumen, wall, section or motion evidence is unsupported, not a pass or an envelope substitute.\n\nTest assemblies and independent units; preserve sibling coverage when adding files. Non-top-level geometry needs kernel export/invocation, not test removal.\n\nFix geometry at its root; never weaken tolerances, delete assertions, or reduce detail to pass.\n\n`public-api-index.md` covers the host and framework API; authoring needs only the Core API below and `api-*` files.\n\n## Core API\n\nThe symbols real Tau models use most, as verbatim declarations. Anything not shown is in the API reference below.\n\n### Functions\n\n```ts\n// Start a geometry assertion chain\nexport declare function expectGeo(subject: GeoSpecSubject): GeoSpecMatcher;\n\n// A model admitted by one live GeoSpec host scope\nGeoSpecSubject: {\n readonly [subjectBrand]: true\n}\n\n// Load a CAD model into GeoSpec evidence\nexport declare function loadModel<Code extends Record<string, string> = Record<string, string>>(_options: LoadModelOptions<Code>): Promise<GeoSpecSubject>;\n\n// Options accepted by {@link import ('./load-model.js').loadModel}\nLoadModelOptions: LoadModelSourceOptions | LoadModelCodeOptions<Code> | LoadModelFileOptions\n // Geometry format to export\n format?: GeoSpecModelFormat\n // Explicit parameters passed to the runtime\n parameters?: Record<string, unknown>\n // STEP reader strategy used for STEP exports\n stepStreaming?: StepStreamingMode\n // Whether STEP loading should also produce mesh evidence\n mesh?: boolean\n // Linear tolerance used while meshing exact BRep evidence\n meshLinearTolerance?: number\n // Angular tolerance in degrees used while meshing exact BRep evidence\n meshAngularToleranceDegrees?: number\n\n// Geometry formats accepted by {@link import ('./load-model.js').loadModel}\nGeoSpecModelFormat: MeshFileFormat | 'step' | 'stp'\n```\n\n### Types\n\n```ts\n// Assertion chain returned by `expectGeo(subject)`\nGeoSpecMatcher: {\n // Core-owned negation\n readonly not: Omit<GeoSpecMatcher, 'not'>\n // Assert the fixed rational plate contract\n toSatisfyRationalPlate(): GeoSpecAssertion;\n // Assert the fixed parallel-plane distance contract\n toSatisfyParallelPlaneDistance(): GeoSpecAssertion;\n // Assert axis-aligned bounds, size, or center for a loaded geometry subject\n toHaveBoundingBox(first: Vec3 | GeoSpecBoundingBoxExpectation, second?: Vec3): GeoSpecAssertion;\n // Assert how many spatially disjoint chunks the mesh contains\n toHaveConnectedComponents(expected: GeoSpecConnectedComponentsExpectation): GeoSpecAssertion;\n // Assert closed mesh edge incidence\n toBeWatertight(): GeoSpecAssertion;\n // Assert that separate assembly components do not occupy the same solid volume\n toHaveNoComponentInterference(expected?: GeoSpecComponentInterferenceExpectation): GeoSpecAssertion;\n // Assert that named assembly occurrences exist with expected counts and bounds\n toHaveAssemblyOccurrences(expected: GeoSpecAssemblyOccurrencesExpectation): GeoSpecAssertion;\n // Assert that selected entities satisfy declared spatial relationships\n toHaveSpatialRelationships(expected: GeoSpecSpatialRelationshipsExpectation): GeoSpecAssertion;\n // Assert rendered mesh evidence is internally trustworthy for downstream checks\n toHaveMeshIntegrity(expected: GeoSpecMeshIntegrityExpectation): GeoSpecAssertion;\n // Assert that the subject carries no diagnostics at the rejected severities\n toHaveNoDiagnostics(expected?: GeoSpecNoDiagnosticsExpectation): GeoSpecAssertion;\n // Assert total surface area, preferring exact BRep mass properties when available\n toHaveSurfaceArea(expected: GeoSpecSurfaceAreaExpectation): GeoSpecAssertion;\n // Assert enclosed volume, preferring exact BRep mass properties when available\n toHaveVolume(expected: GeoSpecVolumeExpectation): GeoSpecAssertion;\n // Assert mass derived from exact mass properties or volume times density\n toHaveMass(expected: GeoSpecMassExpectation): GeoSpecAssertion;\n // Assert the center of mass or mesh-derived centroid for a closed subject\n toHaveCenterOfMass(expected: GeoSpecCenterOfMassExpectation): GeoSpecAssertion;\n // Assert that exact BRep evidence reports a valid shape\n toBeValidBrep(expected?: GeoSpecValidBrepExpectation): GeoSpecAssertion;\n // Assert exact BRep topology counts\n toHaveTopologyCounts(expected: GeoSpecTopologyCountsExpectation): GeoSpecAssertion;\n // Assert the STEP unit evidence\n toHaveStepUnits(expected: GeoSpecStepUnitsExpectation): GeoSpecAssertion;\n // Assert STEP product-structure evidence\n toHaveProductStructure(expected: GeoSpecProductStructureExpectation): GeoSpecAssertion;\n // Assert that BRep evidence contains a planar face matching the requested constraints\n toHavePlanarFace(expected: GeoSpecPlanarFaceExpectation): GeoSpecAssertion;\n // Assert that BRep evidence contains a cylindrical face with the requested radius and axis\n toHaveCylindricalFace(expected: GeoSpecCylindricalFaceExpectation): GeoSpecAssertion;\n // Assert that BRep evidence contains a circular hole matching diameter, center, and axis\n toHaveCircularHole(expected: GeoSpecCircularHoleExpectation): GeoSpecAssertion;\n // Assert that BRep evidence contains a repeated circular-hole pattern\n toHaveCircularHolePattern(expected: GeoSpecCircularHolePatternExpectation): GeoSpecAssertion;\n // Assert that BRep evidence contains a chamfer feature with the requested distance\n toHaveChamferFeature(expected: GeoSpecChamferFeatureExpectation): GeoSpecAssertion;\n // Assert that BRep evidence contains a fillet feature with the requested radius\n toHaveFilletFeature(expected: GeoSpecFilletFeatureExpectation): GeoSpecAssertion;\n // Assert that BRep evidence reports a minimum wall thickness satisfying the expectation\n toHaveMinimumWallThickness(expected: GeoSpecMinimumWallThicknessExpectation): GeoSpecAssertion;\n // Assert that the declared waypoints share one connected void, stay isolated from the declared…\n toHaveVoidContinuity(expected: GeoSpecVoidContinuityExpectation): GeoSpecAssertion;\n}\n\n// Numeric 3D vector\nVec3: readonly [number, number, number]\n\n// Bounding-box expectation accepted by `expectGeo(...).toHaveBoundingBox(...)`\nGeoSpecBoundingBoxExpectation: {\n min?: Vec3 | Partial<Record<keyof GeoSpecAxisExpectation, GeoSpecNumericExpectation>>\n max?: Vec3 | Partial<Record<keyof GeoSpecAxisExpectation, GeoSpecNumericExpectation>>\n size?: Vec3 | Partial<Record<keyof GeoSpecAxisExpectation, GeoSpecNumericExpectation>>\n center?: Vec3 | Partial<Record<keyof GeoSpecAxisExpectation, GeoSpecNumericExpectation>>\n tolerance?: number\n}\n\n// Connected-components expectation accepted by `expectGeo(...).toHaveConnectedComponents(...)`\nGeoSpecConnectedComponentsExpectation: {\n count: number\n tolerance?: number\n toleranceMm?: number\n}\n\n// Component-interference expectation accepted by `expectGeo(...).toHaveNoComponentInterference(...)`\nGeoSpecComponentInterferenceExpectation: {\n tolerance?: number\n pairs?: GeoSpecComponentInterferencePairExpectation[]\n allowances?: GeoSpecComponentInterferenceAllowance[]\n}\n\n// Assembly occurrence expectation accepted by `expectGeo(...).toHaveAssemblyOccurrences(...)`\nGeoSpecAssemblyOccurrencesExpectation: {\n occurrences: GeoSpecAssemblyOccurrenceExpectation[]\n uniqueNames?: boolean\n}\n\n// Spatial relationship expectation accepted by `expectGeo(...).toHaveSpatialRelationships(...)`\nGeoSpecSpatialRelationshipsExpectation: {\n relationships: GeoSpecSpatialRelationshipExpectation[]\n}\n\n// Mesh integrity expectation accepted by `expectGeo(...).toHaveMeshIntegrity(...)`\nGeoSpecMeshIntegrityExpectation: {\n finitePositions?: boolean\n degenerateTriangles?: {\n count?: number;\n maxCount?: number;\n areaTolerance?: number;\n }\n duplicateFaces?: {\n count?: number;\n maxCount?: number;\n }\n watertight?: boolean\n triangleCount?: GeoSpecNumericExpectation\n}\n\n// Diagnostic severities rejected by `expectGeo(...).toHaveNoDiagnostics(...)`\nGeoSpecNoDiagnosticsExpectation: {\n severities?: Array<GeometryDiagnostic['severity']>\n}\n\n// Surface-area expectation accepted by `expectGeo(...).toHaveSurfaceArea(...)`\nGeoSpecSurfaceAreaExpectation: {\n value: number | GeoSpecNumericExpectation\n tolerance?: number\n}\n\n// Volume expectation accepted by `expectGeo(...).toHaveVolume(...)`\nGeoSpecVolumeExpectation: {\n value: number | GeoSpecNumericExpectation\n tolerance?: number\n}\n\n// Mass expectation accepted by `expectGeo(...).toHaveMass(...)`\nGeoSpecMassExpectation: {\n value: number | GeoSpecNumericExpectation\n density?: number\n tolerance?: number\n}\n\n// Center-of-mass expectation accepted by `expectGeo(...).toHaveCenterOfMass(...)`\nGeoSpecCenterOfMassExpectation: {\n point: GeoSpecPointExpectation\n tolerance?: number\n}\n\n// Exact BRep validity expectation accepted by `expectGeo(...).toBeValidBrep(...)`\nGeoSpecValidBrepExpectation: {\n maxTolerance?: number\n freeBounds?: {\n count?: GeoSpecNumericExpectation;\n }\n minEdgeLength?: number\n sameParameter?: boolean\n closedShells?: boolean\n closedWires?: boolean\n}\n\n// Topology-count expectation accepted by `expectGeo(...).toHaveTopologyCounts(...)`\nGeoSpecTopologyCountsExpectation: {\n vertices?: GeoSpecNumericExpectation\n edges?: GeoSpecNumericExpectation\n wires?: GeoSpecNumericExpectation\n faces?: GeoSpecNumericExpectation\n shells?: GeoSpecNumericExpectation\n solids?: GeoSpecNumericExpectation\n compounds?: GeoSpecNumericExpectation\n tolerance?: number\n}\n\n// STEP unit expectation accepted by `expectGeo(...).toHaveStepUnits(...)`\nGeoSpecStepUnitsExpectation: {\n unit: string\n}\n\n// Product-structure expectation accepted by `expectGeo(...).toHaveProductStructure(...)`\nGeoSpecProductStructureExpectation: {\n names?: string[]\n count?: GeoSpecNumericExpectation\n}\n\n// Planar-face expectation accepted by `expectGeo(...).toHavePlanarFace(...)`\nGeoSpecPlanarFaceExpectation: {\n normal: GeoSpecPointExpectation\n offset: number\n area?: GeoSpecNumericExpectation\n tolerance?: number\n}\n\n// Cylindrical-face expectation accepted by `expectGeo(...).toHaveCylindricalFace(...)`\nGeoSpecCylindricalFaceExpectation: {\n radius: number\n axis: 'x' | 'y' | 'z'\n tolerance?: number\n}\n\n// Circular-hole expectation accepted by `expectGeo(...).toHaveCircularHole(...)`\nGeoSpecCircularHoleExpectation: {\n diameter: number\n through?: boolean\n axis?: 'x' | 'y' | 'z'\n center?: GeoSpecPointExpectation\n tolerance?: number\n}\n\n// Circular-hole-pattern expectation accepted by `expectGeo(...).toHaveCircularHolePattern(...)`\nGeoSpecCircularHolePatternExpectation: {\n count: number\n holeDiameter: number\n boltCircleDiameter?: number\n axis?: 'x' | 'y' | 'z'\n center?: GeoSpecPointExpectation\n tolerance?: number\n}\n\n// Chamfer-feature expectation accepted by `expectGeo(...).toHaveChamferFeature(...)`\nGeoSpecChamferFeatureExpectation: {\n distance: number\n selection?: string\n tolerance?: number\n}\n\n// Fillet-feature expectation accepted by `expectGeo(...).toHaveFilletFeature(...)`\nGeoSpecFilletFeatureExpectation: {\n radius: number\n selection?: string\n tolerance?: number\n}\n\n// Minimum-wall-thickness expectation accepted by `expectGeo(...).toHaveMinimumWallThickness(...)`\nGeoSpecMinimumWallThicknessExpectation: {\n value: GeoSpecNumericExpectation\n tolerance?: number\n}\n\n// Void-continuity expectation accepted by `expectGeo(...).toHaveVoidContinuity(...)`\nGeoSpecVoidContinuityExpectation: {\n // Ordered waypoints (>= 1) known to lie in the void being proven\n path: GeoSpecVoidWaypoint[]\n // Occurrence names whose solids bound the void\n material?: string[]\n // Minimum required bottleneck cross-section (mm²), sampled\n minCrossSection?: number\n // Points that must NOT be reachable from the path void (isolation claim)\n isolatedFrom?: Vec3[]\n // Region bounded for the proof (subject frame)\n bounds?: {\n min: Vec3;\n max: Vec3;\n }\n}\n\n// Axis-keyed numeric expectation used by high-level geometry matchers\nGeoSpecAxisExpectation: {\n x?: number\n y?: number\n z?: number\n}\n\n// Shared scalar expectation used by geometry measurements\nGeoSpecNumericExpectation: number | {\n value?: number;\n greaterThan?: number;\n greaterThanOrEqual?: number;\n lessThan?: number;\n lessThanOrEqual?: number;\n}\n\n// A pair-specific component-interference check accepted by `expectGeo(...).toHaveNoComponentInterference(...)`\nGeoSpecComponentInterferencePairExpectation: {\n left: GeoSpecComponentSelector\n right: GeoSpecComponentSelector\n}\n\n// Intentional component interference allowance accepted by `expectGeo(...).toHaveNoComponentInterference(...)`\nGeoSpecComponentInterferenceAllowance: {\n kind?: 'intentionalInterference'\n left: GeoSpecComponentSelector\n right: GeoSpecComponentSelector\n maxVolume?: number\n reason: string\n}\n\n// Assembly occurrence rule accepted by `expectGeo(...).toHaveAssemblyOccurrences(...)`\nGeoSpecAssemblyOccurrenceExpectation: {\n name: GeoSpecComponentSelector\n count?: GeoSpecNumericExpectation\n bounds?: {\n within?: GeoSpecComponentSelector;\n min?: Vec3 | GeoSpecAxisExpectation;\n max?: Vec3 | GeoSpecAxisExpectation;\n center?: GeoSpecPointExpectation;\n tolerance?: number;\n }\n}\n\n// One spatial relationship accepted by `expectGeo(...).toHaveSpatialRelationships(...)`\nGeoSpecSpatialRelationshipExpectation: {\n id?: string\n kind: 'contact' | 'clearance' | 'coaxial' | 'concentric' | 'coplanar' | 'parallel' | 'perpendicular' | 'angle' | 'containment' | 'insertion' | 'interference'\n subject: GeoSpecGeometrySelector\n target: GeoSpecGeometrySelector\n tolerance?: number\n angularToleranceDegrees?: number\n // Expected angle in degrees for `kind\n angleDegrees?: number\n // Declared insertion axis (subject-frame direction) for `kind\n axis?: Vec3\n min?: number\n max?: number\n minVolume?: number\n maxVolume?: number\n reason?: string\n}\n\n// Shared scalar expectation used by geometry measurements\nGeoSpecNumericExpectation: number | {\n value?: number;\n greaterThan?: number;\n greaterThanOrEqual?: number;\n lessThan?: number;\n lessThanOrEqual?: number;\n}\n\n// Diagnostic emitted by GeoSpec loaders, analyzers, and matchers\nGeometryDiagnostic: {\n code: KernelIssueCode | (string & {})\n severity: 'error' | 'warning' | 'info'\n message: string\n suggestion?: string\n spatial?: {\n min?: Vec3;\n max?: Vec3;\n center?: Vec3;\n }\n details?: unknown\n}\n\n// Shared scalar expectation used by geometry measurements\nGeoSpecNumericExpectation: number | {\n value?: number;\n greaterThan?: number;\n greaterThanOrEqual?: number;\n lessThan?: number;\n lessThanOrEqual?: number;\n}\n\n// Shared scalar expectation used by geometry measurements\nGeoSpecNumericExpectation: number | {\n value?: number;\n greaterThan?: number;\n greaterThanOrEqual?: number;\n lessThan?: number;\n lessThanOrEqual?: number;\n}\n\n// Shared scalar expectation used by geometry measurements\nGeoSpecNumericExpectation: number | {\n value?: number;\n greaterThan?: number;\n greaterThanOrEqual?: number;\n lessThan?: number;\n lessThanOrEqual?: number;\n}\n\n// Point expectation accepted by center and feature matchers\nGeoSpecPointExpectation: Vec3 | GeoSpecAxisExpectation\n\n// Shared scalar expectation used by geometry measurements\nGeoSpecNumericExpectation: number | {\n value?: number;\n greaterThan?: number;\n greaterThanOrEqual?: number;\n lessThan?: number;\n lessThanOrEqual?: number;\n}\n\n// Shared scalar expectation used by geometry measurements\nGeoSpecNumericExpectation: number | {\n value?: number;\n greaterThan?: number;\n greaterThanOrEqual?: number;\n lessThan?: number;\n lessThanOrEqual?: number;\n}\n\n// Shared scalar expectation used by geometry measurements\nGeoSpecNumericExpectation: number | {\n value?: number;\n greaterThan?: number;\n greaterThanOrEqual?: number;\n lessThan?: number;\n lessThanOrEqual?: number;\n}\n```\n\n## API reference\n\nTo read any other signature, grep the skill directory for the name followed by `(` (or the bare type name): each hit is the declaration line and names its file; read a few lines around it for overloads and parameter notes. `api-index.md` lists all 345 symbols by file.\n\n- `api-functions.md` — Functions\n- `api-constants.md` — Constants\n- `api-types.md` — Types\n- `api-classes.md` — Classes\n\nRead ranges, not whole files. Never copy a reference into a source file.\n",
10
+ fingerprint: "10aa6c64b966031d8ceee32a96d89e73119987cadaf52e134052018bdfe42d4c",
11
+ files: Object.freeze([
12
+ Object.freeze({ path: "SKILL.md", url: new URL("./geospec-authoring/SKILL.md", import.meta.url).href, byteLength: 19557, lineCount: 497, contentKind: 'text', mediaType: 'text/markdown', sha256: "3629db0e425baa16580ac06a585d75c60bb1f0ce3c84a6e998dea0c885a9e339" }),
13
+ Object.freeze({ path: "api-index.md", url: new URL("./geospec-authoring/api-index.md", import.meta.url).href, byteLength: 26637, lineCount: 363, contentKind: 'text', mediaType: 'text/markdown', sha256: "af8a4e3de45341da5f7d7f027a8c3c5b12c590f31bfc444f11c6516c9ef43e6a" }),
14
+ Object.freeze({ path: "api-functions.md", url: new URL("./geospec-authoring/api-functions.md", import.meta.url).href, byteLength: 2102, lineCount: 50, contentKind: 'text', mediaType: 'text/markdown', sha256: "ab1388501a1bc433d54677749e0605d0aabde50b9237fdf84f50b31bd21a520d" }),
15
+ Object.freeze({ path: "api-constants.md", url: new URL("./geospec-authoring/api-constants.md", import.meta.url).href, byteLength: 263, lineCount: 7, contentKind: 'text', mediaType: 'text/markdown', sha256: "3d59d19ff3e21072f567f5291047db0cbceed21f5e81bbad395f7c6dd56e393f" }),
16
+ Object.freeze({ path: "api-types.md", url: new URL("./geospec-authoring/api-types.md", import.meta.url).href, byteLength: 55337, lineCount: 1701, contentKind: 'text', mediaType: 'text/markdown', sha256: "26199c8caca04fe0ba77c9837f362909275a0c450420bb871a73d27b6d5ce8c2" }),
17
+ Object.freeze({ path: "api-classes.md", url: new URL("./geospec-authoring/api-classes.md", import.meta.url).href, byteLength: 550, lineCount: 14, contentKind: 'text', mediaType: 'text/markdown', sha256: "d34a48498cfd33aca05e2c5c1059ca3e2d1bec86046fbc75928d16b375fcae30" }),
18
+ Object.freeze({ path: "public-api-index.md", url: new URL("./geospec-authoring/public-api-index.md", import.meta.url).href, byteLength: 60396, lineCount: 857, contentKind: 'text', mediaType: 'text/markdown', sha256: "17e1d9acfaf1cc409dd08409bc235c48a1149408c1f457c34b8185097f3db211" }),
19
+ Object.freeze({ path: "public-api-functions.md", url: new URL("./geospec-authoring/public-api-functions.md", import.meta.url).href, byteLength: 10547, lineCount: 197, contentKind: 'text', mediaType: 'text/markdown', sha256: "6ede58ae4448d38d137bac1f3e3e3f6c5314cccc795355d175aae305807d165e" }),
20
+ Object.freeze({ path: "public-api-constants.md", url: new URL("./geospec-authoring/public-api-constants.md", import.meta.url).href, byteLength: 870, lineCount: 20, contentKind: 'text', mediaType: 'text/markdown', sha256: "5f9fba8f8507b344365bb5d38d2c86c0b6843bb63f889913bb0377a8bd885d0c" }),
21
+ Object.freeze({ path: "public-api-types.md", url: new URL("./geospec-authoring/public-api-types.md", import.meta.url).href, byteLength: 62656, lineCount: 2049, contentKind: 'text', mediaType: 'text/markdown', sha256: "00b8891757f1746300e95ca94884449c330c0e1c8c93c7bc8217668d34762c1d" }),
22
+ Object.freeze({ path: "public-api-types-2.md", url: new URL("./geospec-authoring/public-api-types-2.md", import.meta.url).href, byteLength: 51421, lineCount: 1514, contentKind: 'text', mediaType: 'text/markdown', sha256: "3a71caac412596cdf5a5856bbed3c26f97e3fcaf6c9c337e4bcfaa3702b13ed3" }),
23
+ Object.freeze({ path: "public-api-classes.md", url: new URL("./geospec-authoring/public-api-classes.md", import.meta.url).href, byteLength: 1024, lineCount: 23, contentKind: 'text', mediaType: 'text/markdown', sha256: "569639b75b3a3fae86e3bcbe3dc61a746ddd67cb4dec7ccb6374556d419d02a9" })
24
+ ]),
25
+ }),
26
+ ]);
@@ -0,0 +1,13 @@
1
+ declare const manifest: {
2
+ readonly bundles: ReadonlyArray<{
3
+ readonly slug: string;
4
+ readonly name: string;
5
+ readonly description: string;
6
+ readonly version: string;
7
+ readonly whenToUse: string;
8
+ readonly directory: string;
9
+ readonly files: readonly string[];
10
+ readonly body: string;
11
+ }>;
12
+ };
13
+ export = manifest;
@@ -0,0 +1,27 @@
1
+ {
2
+ "bundles": [
3
+ {
4
+ "slug": "geospec-authoring",
5
+ "name": "GeoSpec authoring",
6
+ "description": "Guides canonical GeoSpec geometry tests in TypeScript or JavaScript for every Tau kernel. Use for *.geospec.ts and *.geospec.js tests.",
7
+ "version": "0.1.0-beta.2",
8
+ "whenToUse": "Use before creating or editing *.geospec.ts or *.geospec.js tests, for a model in any kernel.",
9
+ "directory": "geospec-authoring",
10
+ "files": [
11
+ "SKILL.md",
12
+ "api-index.md",
13
+ "api-functions.md",
14
+ "api-constants.md",
15
+ "api-types.md",
16
+ "api-classes.md",
17
+ "public-api-index.md",
18
+ "public-api-functions.md",
19
+ "public-api-constants.md",
20
+ "public-api-types.md",
21
+ "public-api-types-2.md",
22
+ "public-api-classes.md"
23
+ ],
24
+ "body": "---\nname: geospec-authoring\ndescription: Guides canonical GeoSpec geometry tests in TypeScript or JavaScript for every Tau kernel. Use for *.geospec.ts and *.geospec.js tests.\n---\n\n# GeoSpec authoring\n\nWrite tests before implementation; assert deterministic, measurable properties.\n\n## Test shape\n\n- Use `*.geospec.ts` or `*.geospec.js`. Import `describe`, `it` and `expectGeo` from `geospec`, and `loadModel` from `geospec/model`.\n- Await `loadModel`, then assert synchronously with `expectGeo(model)`. The host supplies the compiled binding; authoring does not select an engine.\n- Await or return the complete model-load chain from the test callback; detached future loads are not part of a completed test.\n- Omit `parameters` for model-code defaults; use `{ file, parameters }` for variants. Loaded subjects are opaque.\n\nCanonical TypeScript authoring:\n\n```ts\nimport { describe, expectGeo, it } from 'geospec';\nimport { loadModel } from 'geospec/model';\n\ndescribe('main geometry', () => {\n it('has the intended envelope', async () => {\n const model = await loadModel({ file: 'main.ts', parameters: { width: 120 } });\n expectGeo(model).toHaveBoundingBox({ size: { x: 120 }, tolerance: 1 });\n });\n});\n```\n\nSpecs are always TypeScript or JavaScript, whatever the model's kernel: `loadModel({ file })` evaluates `main.ts`, `main.tsx`, `main.py`, `main.scad`, `main.kcl` or `main.cs` through Tau's runtime. `test_model` discovers `*.geospec.ts` and `*.geospec.js` only.\n\nEvery matcher takes one expectation object:\n\n- Wrong: `expectGeo(model).toHaveVolume(5000, { tolerance: 5 })`. Correct: `expectGeo(model).toHaveVolume({ value: 5000, tolerance: 5 })`.\n- Wrong: `await expectGeo(model)…`. Correct: await `loadModel`, then assert synchronously.\n- Wrong: exact-feature matchers on a mesh kernel (Manifold, JSCAD, OpenSCAD, PicoGK, PicoVoxel). Correct: `toBeValidBrep`, `toHaveTopologyCounts`, the face, hole, pattern, chamfer, fillet and wall-thickness matchers, `toHaveStepUnits`, `toHaveProductStructure` and `toHaveVoidContinuity` need STEP BRep evidence and report unsupported on meshes; assert meshes with bounds, volume, surface area, connected components and `toBeWatertight`.\n\n## Coverage\n\nBounds and physical properties are insufficient. Cover major components, named features, variants, dimensions/positions, disjoint counts, closure, interference and supported exact features. Explicitly report unsupported requirements; proxies cannot fulfill them.\n\n- `toHaveBoundingBox`: size/position.\n- `toHaveConnectedComponents`: qualified material connectivity; visual touching cannot justify tolerance changes.\n- `toBeWatertight`: closed edge incidence, not manifold validity, fusion or material connectivity. Bounds prove none of these. Missing evidence is unsupported.\n- `toHaveSurfaceArea`, `toHaveVolume`, `toHaveCenterOfMass`, `toHaveMass`: physical measurements.\n- `toHaveNoComponentInterference`: overlap; allow deliberate press fits.\n- `loadModel({ file, format: 'step' })`: use BRep evidence for supported topology and feature assertions. Missing occurrence, interference, clearance, containment, lumen, wall, section or motion evidence is unsupported, not a pass or an envelope substitute.\n\nTest assemblies and independent units; preserve sibling coverage when adding files. Non-top-level geometry needs kernel export/invocation, not test removal.\n\nFix geometry at its root; never weaken tolerances, delete assertions, or reduce detail to pass.\n\n`public-api-index.md` covers the host and framework API; authoring needs only the Core API below and `api-*` files.\n\n## Core API\n\nThe symbols real Tau models use most, as verbatim declarations. Anything not shown is in the API reference below.\n\n### Functions\n\n```ts\n// Start a geometry assertion chain\nexport declare function expectGeo(subject: GeoSpecSubject): GeoSpecMatcher;\n\n// A model admitted by one live GeoSpec host scope\nGeoSpecSubject: {\n readonly [subjectBrand]: true\n}\n\n// Load a CAD model into GeoSpec evidence\nexport declare function loadModel<Code extends Record<string, string> = Record<string, string>>(_options: LoadModelOptions<Code>): Promise<GeoSpecSubject>;\n\n// Options accepted by {@link import ('./load-model.js').loadModel}\nLoadModelOptions: LoadModelSourceOptions | LoadModelCodeOptions<Code> | LoadModelFileOptions\n // Geometry format to export\n format?: GeoSpecModelFormat\n // Explicit parameters passed to the runtime\n parameters?: Record<string, unknown>\n // STEP reader strategy used for STEP exports\n stepStreaming?: StepStreamingMode\n // Whether STEP loading should also produce mesh evidence\n mesh?: boolean\n // Linear tolerance used while meshing exact BRep evidence\n meshLinearTolerance?: number\n // Angular tolerance in degrees used while meshing exact BRep evidence\n meshAngularToleranceDegrees?: number\n\n// Geometry formats accepted by {@link import ('./load-model.js').loadModel}\nGeoSpecModelFormat: MeshFileFormat | 'step' | 'stp'\n```\n\n### Types\n\n```ts\n// Assertion chain returned by `expectGeo(subject)`\nGeoSpecMatcher: {\n // Core-owned negation\n readonly not: Omit<GeoSpecMatcher, 'not'>\n // Assert the fixed rational plate contract\n toSatisfyRationalPlate(): GeoSpecAssertion;\n // Assert the fixed parallel-plane distance contract\n toSatisfyParallelPlaneDistance(): GeoSpecAssertion;\n // Assert axis-aligned bounds, size, or center for a loaded geometry subject\n toHaveBoundingBox(first: Vec3 | GeoSpecBoundingBoxExpectation, second?: Vec3): GeoSpecAssertion;\n // Assert how many spatially disjoint chunks the mesh contains\n toHaveConnectedComponents(expected: GeoSpecConnectedComponentsExpectation): GeoSpecAssertion;\n // Assert closed mesh edge incidence\n toBeWatertight(): GeoSpecAssertion;\n // Assert that separate assembly components do not occupy the same solid volume\n toHaveNoComponentInterference(expected?: GeoSpecComponentInterferenceExpectation): GeoSpecAssertion;\n // Assert that named assembly occurrences exist with expected counts and bounds\n toHaveAssemblyOccurrences(expected: GeoSpecAssemblyOccurrencesExpectation): GeoSpecAssertion;\n // Assert that selected entities satisfy declared spatial relationships\n toHaveSpatialRelationships(expected: GeoSpecSpatialRelationshipsExpectation): GeoSpecAssertion;\n // Assert rendered mesh evidence is internally trustworthy for downstream checks\n toHaveMeshIntegrity(expected: GeoSpecMeshIntegrityExpectation): GeoSpecAssertion;\n // Assert that the subject carries no diagnostics at the rejected severities\n toHaveNoDiagnostics(expected?: GeoSpecNoDiagnosticsExpectation): GeoSpecAssertion;\n // Assert total surface area, preferring exact BRep mass properties when available\n toHaveSurfaceArea(expected: GeoSpecSurfaceAreaExpectation): GeoSpecAssertion;\n // Assert enclosed volume, preferring exact BRep mass properties when available\n toHaveVolume(expected: GeoSpecVolumeExpectation): GeoSpecAssertion;\n // Assert mass derived from exact mass properties or volume times density\n toHaveMass(expected: GeoSpecMassExpectation): GeoSpecAssertion;\n // Assert the center of mass or mesh-derived centroid for a closed subject\n toHaveCenterOfMass(expected: GeoSpecCenterOfMassExpectation): GeoSpecAssertion;\n // Assert that exact BRep evidence reports a valid shape\n toBeValidBrep(expected?: GeoSpecValidBrepExpectation): GeoSpecAssertion;\n // Assert exact BRep topology counts\n toHaveTopologyCounts(expected: GeoSpecTopologyCountsExpectation): GeoSpecAssertion;\n // Assert the STEP unit evidence\n toHaveStepUnits(expected: GeoSpecStepUnitsExpectation): GeoSpecAssertion;\n // Assert STEP product-structure evidence\n toHaveProductStructure(expected: GeoSpecProductStructureExpectation): GeoSpecAssertion;\n // Assert that BRep evidence contains a planar face matching the requested constraints\n toHavePlanarFace(expected: GeoSpecPlanarFaceExpectation): GeoSpecAssertion;\n // Assert that BRep evidence contains a cylindrical face with the requested radius and axis\n toHaveCylindricalFace(expected: GeoSpecCylindricalFaceExpectation): GeoSpecAssertion;\n // Assert that BRep evidence contains a circular hole matching diameter, center, and axis\n toHaveCircularHole(expected: GeoSpecCircularHoleExpectation): GeoSpecAssertion;\n // Assert that BRep evidence contains a repeated circular-hole pattern\n toHaveCircularHolePattern(expected: GeoSpecCircularHolePatternExpectation): GeoSpecAssertion;\n // Assert that BRep evidence contains a chamfer feature with the requested distance\n toHaveChamferFeature(expected: GeoSpecChamferFeatureExpectation): GeoSpecAssertion;\n // Assert that BRep evidence contains a fillet feature with the requested radius\n toHaveFilletFeature(expected: GeoSpecFilletFeatureExpectation): GeoSpecAssertion;\n // Assert that BRep evidence reports a minimum wall thickness satisfying the expectation\n toHaveMinimumWallThickness(expected: GeoSpecMinimumWallThicknessExpectation): GeoSpecAssertion;\n // Assert that the declared waypoints share one connected void, stay isolated from the declared…\n toHaveVoidContinuity(expected: GeoSpecVoidContinuityExpectation): GeoSpecAssertion;\n}\n\n// Numeric 3D vector\nVec3: readonly [number, number, number]\n\n// Bounding-box expectation accepted by `expectGeo(...).toHaveBoundingBox(...)`\nGeoSpecBoundingBoxExpectation: {\n min?: Vec3 | Partial<Record<keyof GeoSpecAxisExpectation, GeoSpecNumericExpectation>>\n max?: Vec3 | Partial<Record<keyof GeoSpecAxisExpectation, GeoSpecNumericExpectation>>\n size?: Vec3 | Partial<Record<keyof GeoSpecAxisExpectation, GeoSpecNumericExpectation>>\n center?: Vec3 | Partial<Record<keyof GeoSpecAxisExpectation, GeoSpecNumericExpectation>>\n tolerance?: number\n}\n\n// Connected-components expectation accepted by `expectGeo(...).toHaveConnectedComponents(...)`\nGeoSpecConnectedComponentsExpectation: {\n count: number\n tolerance?: number\n toleranceMm?: number\n}\n\n// Component-interference expectation accepted by `expectGeo(...).toHaveNoComponentInterference(...)`\nGeoSpecComponentInterferenceExpectation: {\n tolerance?: number\n pairs?: GeoSpecComponentInterferencePairExpectation[]\n allowances?: GeoSpecComponentInterferenceAllowance[]\n}\n\n// Assembly occurrence expectation accepted by `expectGeo(...).toHaveAssemblyOccurrences(...)`\nGeoSpecAssemblyOccurrencesExpectation: {\n occurrences: GeoSpecAssemblyOccurrenceExpectation[]\n uniqueNames?: boolean\n}\n\n// Spatial relationship expectation accepted by `expectGeo(...).toHaveSpatialRelationships(...)`\nGeoSpecSpatialRelationshipsExpectation: {\n relationships: GeoSpecSpatialRelationshipExpectation[]\n}\n\n// Mesh integrity expectation accepted by `expectGeo(...).toHaveMeshIntegrity(...)`\nGeoSpecMeshIntegrityExpectation: {\n finitePositions?: boolean\n degenerateTriangles?: {\n count?: number;\n maxCount?: number;\n areaTolerance?: number;\n }\n duplicateFaces?: {\n count?: number;\n maxCount?: number;\n }\n watertight?: boolean\n triangleCount?: GeoSpecNumericExpectation\n}\n\n// Diagnostic severities rejected by `expectGeo(...).toHaveNoDiagnostics(...)`\nGeoSpecNoDiagnosticsExpectation: {\n severities?: Array<GeometryDiagnostic['severity']>\n}\n\n// Surface-area expectation accepted by `expectGeo(...).toHaveSurfaceArea(...)`\nGeoSpecSurfaceAreaExpectation: {\n value: number | GeoSpecNumericExpectation\n tolerance?: number\n}\n\n// Volume expectation accepted by `expectGeo(...).toHaveVolume(...)`\nGeoSpecVolumeExpectation: {\n value: number | GeoSpecNumericExpectation\n tolerance?: number\n}\n\n// Mass expectation accepted by `expectGeo(...).toHaveMass(...)`\nGeoSpecMassExpectation: {\n value: number | GeoSpecNumericExpectation\n density?: number\n tolerance?: number\n}\n\n// Center-of-mass expectation accepted by `expectGeo(...).toHaveCenterOfMass(...)`\nGeoSpecCenterOfMassExpectation: {\n point: GeoSpecPointExpectation\n tolerance?: number\n}\n\n// Exact BRep validity expectation accepted by `expectGeo(...).toBeValidBrep(...)`\nGeoSpecValidBrepExpectation: {\n maxTolerance?: number\n freeBounds?: {\n count?: GeoSpecNumericExpectation;\n }\n minEdgeLength?: number\n sameParameter?: boolean\n closedShells?: boolean\n closedWires?: boolean\n}\n\n// Topology-count expectation accepted by `expectGeo(...).toHaveTopologyCounts(...)`\nGeoSpecTopologyCountsExpectation: {\n vertices?: GeoSpecNumericExpectation\n edges?: GeoSpecNumericExpectation\n wires?: GeoSpecNumericExpectation\n faces?: GeoSpecNumericExpectation\n shells?: GeoSpecNumericExpectation\n solids?: GeoSpecNumericExpectation\n compounds?: GeoSpecNumericExpectation\n tolerance?: number\n}\n\n// STEP unit expectation accepted by `expectGeo(...).toHaveStepUnits(...)`\nGeoSpecStepUnitsExpectation: {\n unit: string\n}\n\n// Product-structure expectation accepted by `expectGeo(...).toHaveProductStructure(...)`\nGeoSpecProductStructureExpectation: {\n names?: string[]\n count?: GeoSpecNumericExpectation\n}\n\n// Planar-face expectation accepted by `expectGeo(...).toHavePlanarFace(...)`\nGeoSpecPlanarFaceExpectation: {\n normal: GeoSpecPointExpectation\n offset: number\n area?: GeoSpecNumericExpectation\n tolerance?: number\n}\n\n// Cylindrical-face expectation accepted by `expectGeo(...).toHaveCylindricalFace(...)`\nGeoSpecCylindricalFaceExpectation: {\n radius: number\n axis: 'x' | 'y' | 'z'\n tolerance?: number\n}\n\n// Circular-hole expectation accepted by `expectGeo(...).toHaveCircularHole(...)`\nGeoSpecCircularHoleExpectation: {\n diameter: number\n through?: boolean\n axis?: 'x' | 'y' | 'z'\n center?: GeoSpecPointExpectation\n tolerance?: number\n}\n\n// Circular-hole-pattern expectation accepted by `expectGeo(...).toHaveCircularHolePattern(...)`\nGeoSpecCircularHolePatternExpectation: {\n count: number\n holeDiameter: number\n boltCircleDiameter?: number\n axis?: 'x' | 'y' | 'z'\n center?: GeoSpecPointExpectation\n tolerance?: number\n}\n\n// Chamfer-feature expectation accepted by `expectGeo(...).toHaveChamferFeature(...)`\nGeoSpecChamferFeatureExpectation: {\n distance: number\n selection?: string\n tolerance?: number\n}\n\n// Fillet-feature expectation accepted by `expectGeo(...).toHaveFilletFeature(...)`\nGeoSpecFilletFeatureExpectation: {\n radius: number\n selection?: string\n tolerance?: number\n}\n\n// Minimum-wall-thickness expectation accepted by `expectGeo(...).toHaveMinimumWallThickness(...)`\nGeoSpecMinimumWallThicknessExpectation: {\n value: GeoSpecNumericExpectation\n tolerance?: number\n}\n\n// Void-continuity expectation accepted by `expectGeo(...).toHaveVoidContinuity(...)`\nGeoSpecVoidContinuityExpectation: {\n // Ordered waypoints (>= 1) known to lie in the void being proven\n path: GeoSpecVoidWaypoint[]\n // Occurrence names whose solids bound the void\n material?: string[]\n // Minimum required bottleneck cross-section (mm²), sampled\n minCrossSection?: number\n // Points that must NOT be reachable from the path void (isolation claim)\n isolatedFrom?: Vec3[]\n // Region bounded for the proof (subject frame)\n bounds?: {\n min: Vec3;\n max: Vec3;\n }\n}\n\n// Axis-keyed numeric expectation used by high-level geometry matchers\nGeoSpecAxisExpectation: {\n x?: number\n y?: number\n z?: number\n}\n\n// Shared scalar expectation used by geometry measurements\nGeoSpecNumericExpectation: number | {\n value?: number;\n greaterThan?: number;\n greaterThanOrEqual?: number;\n lessThan?: number;\n lessThanOrEqual?: number;\n}\n\n// A pair-specific component-interference check accepted by `expectGeo(...).toHaveNoComponentInterference(...)`\nGeoSpecComponentInterferencePairExpectation: {\n left: GeoSpecComponentSelector\n right: GeoSpecComponentSelector\n}\n\n// Intentional component interference allowance accepted by `expectGeo(...).toHaveNoComponentInterference(...)`\nGeoSpecComponentInterferenceAllowance: {\n kind?: 'intentionalInterference'\n left: GeoSpecComponentSelector\n right: GeoSpecComponentSelector\n maxVolume?: number\n reason: string\n}\n\n// Assembly occurrence rule accepted by `expectGeo(...).toHaveAssemblyOccurrences(...)`\nGeoSpecAssemblyOccurrenceExpectation: {\n name: GeoSpecComponentSelector\n count?: GeoSpecNumericExpectation\n bounds?: {\n within?: GeoSpecComponentSelector;\n min?: Vec3 | GeoSpecAxisExpectation;\n max?: Vec3 | GeoSpecAxisExpectation;\n center?: GeoSpecPointExpectation;\n tolerance?: number;\n }\n}\n\n// One spatial relationship accepted by `expectGeo(...).toHaveSpatialRelationships(...)`\nGeoSpecSpatialRelationshipExpectation: {\n id?: string\n kind: 'contact' | 'clearance' | 'coaxial' | 'concentric' | 'coplanar' | 'parallel' | 'perpendicular' | 'angle' | 'containment' | 'insertion' | 'interference'\n subject: GeoSpecGeometrySelector\n target: GeoSpecGeometrySelector\n tolerance?: number\n angularToleranceDegrees?: number\n // Expected angle in degrees for `kind\n angleDegrees?: number\n // Declared insertion axis (subject-frame direction) for `kind\n axis?: Vec3\n min?: number\n max?: number\n minVolume?: number\n maxVolume?: number\n reason?: string\n}\n\n// Shared scalar expectation used by geometry measurements\nGeoSpecNumericExpectation: number | {\n value?: number;\n greaterThan?: number;\n greaterThanOrEqual?: number;\n lessThan?: number;\n lessThanOrEqual?: number;\n}\n\n// Diagnostic emitted by GeoSpec loaders, analyzers, and matchers\nGeometryDiagnostic: {\n code: KernelIssueCode | (string & {})\n severity: 'error' | 'warning' | 'info'\n message: string\n suggestion?: string\n spatial?: {\n min?: Vec3;\n max?: Vec3;\n center?: Vec3;\n }\n details?: unknown\n}\n\n// Shared scalar expectation used by geometry measurements\nGeoSpecNumericExpectation: number | {\n value?: number;\n greaterThan?: number;\n greaterThanOrEqual?: number;\n lessThan?: number;\n lessThanOrEqual?: number;\n}\n\n// Shared scalar expectation used by geometry measurements\nGeoSpecNumericExpectation: number | {\n value?: number;\n greaterThan?: number;\n greaterThanOrEqual?: number;\n lessThan?: number;\n lessThanOrEqual?: number;\n}\n\n// Shared scalar expectation used by geometry measurements\nGeoSpecNumericExpectation: number | {\n value?: number;\n greaterThan?: number;\n greaterThanOrEqual?: number;\n lessThan?: number;\n lessThanOrEqual?: number;\n}\n\n// Point expectation accepted by center and feature matchers\nGeoSpecPointExpectation: Vec3 | GeoSpecAxisExpectation\n\n// Shared scalar expectation used by geometry measurements\nGeoSpecNumericExpectation: number | {\n value?: number;\n greaterThan?: number;\n greaterThanOrEqual?: number;\n lessThan?: number;\n lessThanOrEqual?: number;\n}\n\n// Shared scalar expectation used by geometry measurements\nGeoSpecNumericExpectation: number | {\n value?: number;\n greaterThan?: number;\n greaterThanOrEqual?: number;\n lessThan?: number;\n lessThanOrEqual?: number;\n}\n\n// Shared scalar expectation used by geometry measurements\nGeoSpecNumericExpectation: number | {\n value?: number;\n greaterThan?: number;\n greaterThanOrEqual?: number;\n lessThan?: number;\n lessThanOrEqual?: number;\n}\n```\n\n## API reference\n\nTo read any other signature, grep the skill directory for the name followed by `(` (or the bare type name): each hit is the declaration line and names its file; read a few lines around it for overloads and parameter notes. `api-index.md` lists all 345 symbols by file.\n\n- `api-functions.md` — Functions\n- `api-constants.md` — Constants\n- `api-types.md` — Types\n- `api-classes.md` — Classes\n\nRead ranges, not whole files. Never copy a reference into a source file.\n"
25
+ }
26
+ ]
27
+ }
@@ -0,0 +1,124 @@
1
+ import { GeoSpecSubject } from "../model/subject.mjs";
2
+ import { GeoSpecAssertion, GeoSpecMatcher } from "../runner/types.mjs";
3
+ import { GeoSpecMatcherName } from "../engine/matchers.mjs";
4
+ import { GeoSpecCanonicalClaimReport, GeoSpecClaimPolarity, GeoSpecNativeEngine, GeoSpecNativeEvidenceProfile, GeoSpecNativeSubject, GeoSpecQueryCapability } from "../engine/client.mjs";
5
+ import { JSONValue } from "@taucad/runtime/types";
6
+ //#region src/assertion-client/client.d.ts
7
+ /** One authored call shared by the collector and native assertion client. @public */
8
+ type GeoSpecAuthoringInvocation = {
9
+ readonly arguments: readonly unknown[];
10
+ readonly expected: unknown;
11
+ readonly kind: GeoSpecAssertion['kind'];
12
+ readonly matcher: GeoSpecMatcherName;
13
+ readonly polarity: GeoSpecClaimPolarity;
14
+ readonly subject: unknown;
15
+ };
16
+ /** Matcher methods derived mechanically from the existing GeoSpec registry. @public */
17
+ type GeoSpecMatcherMethods<Result> = { [Name in GeoSpecMatcherName]: (...arguments_: Parameters<GeoSpecMatcher[Name]>) => Result; };
18
+ /** Standalone native matcher chain, including core-owned negation. @public */
19
+ type GeoSpecAssertionMatchers = GeoSpecMatcherMethods<GeoSpecCanonicalClaimReport> & {
20
+ readonly not: GeoSpecMatcherMethods<GeoSpecCanonicalClaimReport>;
21
+ };
22
+ /** Runner-independent native assertion client. @public */
23
+ type GeoSpecAssertionClient = {
24
+ expectGeo(subject: GeoSpecNativeSubject | GeoSpecSubject): GeoSpecAssertionMatchers;
25
+ query(options: MinimumDistanceQuery): Promise<MinimumDistanceResult>;
26
+ query(options: GeoSpecQueryOptions): Promise<GeoSpecCanonicalClaimReport>;
27
+ };
28
+ /** Complete AP242 minimum over two subject-bound occurrence paths. @public */
29
+ type MinimumDistanceQuery = {
30
+ readonly capability: 'minimumDistance';
31
+ readonly subject: GeoSpecNativeSubject;
32
+ readonly payload: {
33
+ readonly pair: readonly [{
34
+ readonly occurrencePath: string;
35
+ }, {
36
+ readonly occurrencePath: string;
37
+ }];
38
+ };
39
+ };
40
+ /** Complete native minimum and ordered finite witnesses in canonical millimetres/Z-up. @public */
41
+ type MinimumDistanceFact = {
42
+ readonly source: 'ap242';
43
+ readonly assurance: 'exact-brep';
44
+ readonly unit: 'mm';
45
+ readonly coordinateSystem: 'z-up';
46
+ readonly subjectHash: string;
47
+ readonly algorithmProfile: 'geospec-minimum-distance-v1';
48
+ readonly occurrences: readonly [string, string];
49
+ readonly distance: number;
50
+ readonly points: readonly [readonly [number, number, number], readonly [number, number, number]];
51
+ };
52
+ /** Geometry refusal and infrastructure interruption never masquerade as facts. @public */
53
+ type MinimumDistanceResult = {
54
+ readonly status: 'complete';
55
+ readonly fact: MinimumDistanceFact;
56
+ } | {
57
+ readonly status: 'refused';
58
+ readonly code: 'unsupported-evidence' | 'invalid-selection' | 'work-limit';
59
+ readonly message: string;
60
+ } | {
61
+ readonly status: 'interrupted';
62
+ readonly code: 'cancelled' | 'executor-exited' | 'deadline' | 'engine-error';
63
+ readonly message: string;
64
+ };
65
+ /**
66
+ * One positive-only ancillary query. analyzeMesh/analyzeBrep use null payloads;
67
+ * inspectGeometry accepts selectors/evidence and analyzeMeshOverlap accepts
68
+ * pairs/tolerance as in the existing inspection and mesh APIs. queryPmi accepts
69
+ * optional maxRecords/maxOutputBytes limits and reports inventory, not compliance.
70
+ * Ordinary RegExp
71
+ * selectors are serialized by the shared protocol serializer.
72
+ *
73
+ * An explicit claimId leaves the automatic sequence unchanged. Queries return
74
+ * full reports, including failed/refused reports, without assertion errors.
75
+ * @public
76
+ */
77
+ type GeoSpecQueryOptions = {
78
+ readonly capability: GeoSpecQueryCapability;
79
+ readonly claimId?: string;
80
+ readonly payload?: unknown;
81
+ readonly subject: GeoSpecNativeSubject;
82
+ };
83
+ /** Flat construction options for a runner-independent native assertion client. @public */
84
+ type GeoSpecAssertionClientOptions = {
85
+ readonly claimId?: (matcher: GeoSpecMatcherName, sequence: number) => string;
86
+ readonly engine: GeoSpecNativeEngine;
87
+ /** Success-evidence profile of every claim and query; omitted means `complete`. */
88
+ readonly evidenceProfile?: GeoSpecNativeEvidenceProfile;
89
+ readonly subjectSlot?: string;
90
+ readonly workUnitLimit?: number;
91
+ };
92
+ /** A non-passed core assertion report surfaced by standalone `expectGeo`. @public */
93
+ declare class GeoSpecAssertionError extends Error {
94
+ readonly canonicalClaim: Uint8Array<ArrayBuffer>;
95
+ readonly canonicalPlan: Uint8Array<ArrayBuffer>;
96
+ readonly canonicalResult: Uint8Array<ArrayBuffer>;
97
+ readonly claim: Readonly<Record<string, JSONValue>>;
98
+ readonly diagnostics: readonly JSONValue[];
99
+ readonly report: GeoSpecCanonicalClaimReport;
100
+ readonly result: Readonly<Record<string, JSONValue>>;
101
+ constructor(report: GeoSpecCanonicalClaimReport);
102
+ }
103
+ /**
104
+ * Create the one registry-derived matcher surface used by every JavaScript host.
105
+ *
106
+ * @param options - Subject, polarity and host invocation function.
107
+ * @returns All 26 matcher methods in registry order.
108
+ * @public
109
+ */
110
+ declare const createGeoSpecMatcherMethods: <Result>(options: {
111
+ readonly invoke: (invocation: GeoSpecAuthoringInvocation) => Result;
112
+ readonly polarity: GeoSpecClaimPolarity;
113
+ readonly subject: unknown;
114
+ }) => GeoSpecMatcherMethods<Result>;
115
+ /**
116
+ * Create a standalone native GeoSpec assertion client.
117
+ *
118
+ * @param options - Engine, deterministic work limit and optional logical-ID controls.
119
+ * @returns An `expectGeo`-style assertion client independent of any test runner.
120
+ * @public
121
+ */
122
+ declare const createGeoSpecAssertionClient: (options: GeoSpecAssertionClientOptions) => GeoSpecAssertionClient;
123
+ //#endregion
124
+ export { GeoSpecAssertionClient, GeoSpecAssertionClientOptions, GeoSpecAssertionError, GeoSpecAssertionMatchers, GeoSpecAuthoringInvocation, GeoSpecMatcherMethods, GeoSpecQueryOptions, MinimumDistanceFact, MinimumDistanceQuery, MinimumDistanceResult, createGeoSpecAssertionClient, createGeoSpecMatcherMethods };
@@ -0,0 +1,2 @@
1
+ import{geoSpecMatcherDescriptors as e,normalizeGeoSpecExpected as t}from"../engine/matchers.mjs";import{evaluateGeoSpecNativeClaim as n,evaluateGeoSpecNativeQuery as r,resolveGeoSpecNativeWorkUnitLimit as i,supportsGeoSpecNativeMinimumDistance as a}from"../engine/client.mjs";import{resolveGeoSpecSubject as o}from"../model/subject.mjs";const s=(e,t)=>{if(typeof e!=`object`||!e||Array.isArray(e))return;let{fact:n}=e;if(typeof n!=`object`||!n||Array.isArray(n))return;let{distance:r,points:i,occurrences:a,subjectHash:o}=n,s=e=>Array.isArray(e)&&e.length===3&&e.every(e=>typeof e==`number`&&Number.isFinite(e));if(!(e.profile!==`geospec-minimum-distance-v1`||n.source!==`ap242`||n.assurance!==`exact-brep`||n.unit!==`mm`||n.coordinateSystem!==`z-up`||n.algorithmProfile!==`geospec-minimum-distance-v1`||typeof o!=`string`||!/^[0-9a-f]{64}$/u.test(o)||o!==(t.subject.subjectHash??t.subject.contentHash)||typeof r!=`number`||!Number.isFinite(r)||r<0||!Array.isArray(a)||a.length!==2||a[0]!==t.payload.pair[0].occurrencePath||a[1]!==t.payload.pair[1].occurrencePath||!Array.isArray(i)||i.length!==2||!s(i[0])||!s(i[1])))return{source:`ap242`,assurance:`exact-brep`,unit:`mm`,coordinateSystem:`z-up`,subjectHash:o,algorithmProfile:`geospec-minimum-distance-v1`,occurrences:[a[0],a[1]],distance:r,points:[i[0],i[1]]}},c=(e,t)=>{if(e.status===`passed`){let n=s(e.evidence,t);return n===void 0?{status:`interrupted`,code:`engine-error`,message:`Native minimum returned malformed evidence.`}:{status:`complete`,fact:n}}let n=e.diagnostics.find(e=>typeof e==`object`&&!!e&&!Array.isArray(e)),r=typeof n==`object`&&n&&!Array.isArray(n)?n.code:void 0,i=typeof n==`object`&&n&&!Array.isArray(n)&&typeof n.message==`string`?n.message:`Native minimum is unavailable.`;return r===`GEOSPEC_INVALID_SELECTION`?{status:`refused`,code:`invalid-selection`,message:i}:r===`MATCHER_TIMEOUT`?{status:`refused`,code:`work-limit`,message:i}:r===`GEOSPEC_UNSUPPORTED_EVIDENCE`||r===`GEOSPEC_EVIDENCE_UNSUPPORTED`?{status:`refused`,code:`unsupported-evidence`,message:i}:{status:`interrupted`,code:`engine-error`,message:i}};var l=class extends Error{canonicalClaim;canonicalPlan;canonicalResult;claim;diagnostics;report;result;constructor(e){let t=e.diagnostics.flatMap(e=>{if(typeof e!=`object`||!e||Array.isArray(e))return[];let{message:t}=e;return typeof t==`string`?[t]:[]});super(t.join(`
2
+ `)||`GeoSpec assertion '${e.claimId}' ended with status '${e.status}'.`),this.name=`GeoSpecAssertionError`,this.report=e,this.diagnostics=e.diagnostics,this.claim=e.claim,this.result=e.result,this.canonicalClaim=e.canonicalClaim,this.canonicalPlan=e.canonicalPlan,this.canonicalResult=e.canonicalResult}};const u=n=>{let r={};for(let i of Object.keys(e)){let a=e[i];r[i]=(...e)=>{if(a.expected===`true`&&e.length>0)throw TypeError(`GeoSpec matcher ${i} does not accept arguments.`);return n.invoke({arguments:e,expected:t(a.expected,e),kind:a.kind,matcher:i,polarity:n.polarity,subject:n.subject})}}return r},d=e=>{let t=0,s=e.subjectSlot??`subject`,d,f=()=>(d??=i(e.engine,e.workUnitLimit),d),p=(r,i,a)=>u({subject:r,polarity:i,invoke:o=>{a(),t+=1;let c={claimId:e.claimId?.(o.matcher,t)??`geospec-claim-${t}`,engine:e.engine,...e.evidenceProfile===void 0?{}:{evidenceProfile:e.evidenceProfile},polarity:i,subject:r,subjectSlot:s,workUnitLimit:f()},u=n({...c,arguments:o.arguments,capability:o.matcher,kind:o.kind});if(u.status!==`passed`)throw new l(u);return u}});async function m(n){let i=`claimId`in n?n.claimId??`geospec-claim-${++t}`:`geospec-claim-${++t}`;if(n.capability===`minimumDistance`){let t=n.payload?.pair,r=e=>{if(!(typeof e!=`object`||!e||!(`occurrencePath`in e)))return typeof e.occurrencePath==`string`&&e.occurrencePath.length>0?e.occurrencePath:void 0};if(!Array.isArray(t)||t.length!==2||r(t[0])===void 0||r(t[1])===void 0||r(t[0])===r(t[1]))return{status:`refused`,code:`invalid-selection`,message:`Select two distinct resolved AP242 occurrence paths.`};try{if(!a(e.engine))return{status:`refused`,code:`unsupported-evidence`,message:`This native engine does not advertise the complete minimum-distance profile.`}}catch{return{status:`refused`,code:`unsupported-evidence`,message:`This native engine cannot negotiate the complete minimum-distance profile.`}}}try{let t=r({capability:n.capability,claimId:i,engine:e.engine,...e.evidenceProfile===void 0?{}:{evidenceProfile:e.evidenceProfile},payload:n.payload,subject:n.subject,subjectSlot:s,workUnitLimit:f()});return n.capability===`minimumDistance`?c(t,n):t}catch(e){if(n.capability!==`minimumDistance`)throw e;return{status:`interrupted`,code:`engine-error`,message:e instanceof Error?e.message:`Native minimum query failed.`}}}return{query:m,expectGeo(t){let n=`subjectHash`in t||`contentHash`in t,r=n?t:o(t,e.engine).identity,i=()=>{n||o(t,e.engine)},a=p(r,`positive`,i);return Object.assign(a,{not:p(r,`negative`,i)})}}};export{l as GeoSpecAssertionError,d as createGeoSpecAssertionClient,u as createGeoSpecMatcherMethods};
@@ -0,0 +1,5 @@
1
+ import { GeoSpecFixedMatcherDescriptor, GeoSpecMatcherName, geoSpecMatcherDescriptors } from "../engine/matchers.mjs";
2
+ import { GeoSpecCanonicalClaimReport, GeoSpecNativeClaimEvaluation, GeoSpecNativeEngine, GeoSpecNativeEvidenceProfile, GeoSpecNativeQueryOptions, GeoSpecNativeSubject, GeoSpecQueryCapability, evaluateGeoSpecNativeQuery } from "../engine/client.mjs";
3
+ import { GeoSpecAssertionClient, GeoSpecAssertionClientOptions, GeoSpecAssertionError, GeoSpecAssertionMatchers, GeoSpecAuthoringInvocation, GeoSpecMatcherMethods, GeoSpecQueryOptions, MinimumDistanceFact, MinimumDistanceQuery, MinimumDistanceResult, createGeoSpecAssertionClient, createGeoSpecMatcherMethods } from "./client.mjs";
4
+ import { GeoSpecPmiFaceAssociation, GeoSpecPmiField, GeoSpecPmiInventory, GeoSpecPmiLimits, GeoSpecPmiNumber, GeoSpecPmiQueryPayload, GeoSpecPmiQueryValue, GeoSpecPmiRawEntity, GeoSpecPmiRecord, GeoSpecPmiShapeReference } from "../engine/pmi.types.mjs";
5
+ export { type GeoSpecAssertionClient, type GeoSpecAssertionClientOptions, GeoSpecAssertionError, type GeoSpecAssertionMatchers, type GeoSpecAuthoringInvocation, type GeoSpecCanonicalClaimReport, type GeoSpecFixedMatcherDescriptor, type GeoSpecMatcherMethods, type GeoSpecMatcherName, type GeoSpecNativeClaimEvaluation, type GeoSpecNativeEngine, type GeoSpecNativeEvidenceProfile, type GeoSpecNativeQueryOptions, type GeoSpecNativeSubject, type GeoSpecPmiFaceAssociation, type GeoSpecPmiField, type GeoSpecPmiInventory, type GeoSpecPmiLimits, type GeoSpecPmiNumber, type GeoSpecPmiQueryPayload, type GeoSpecPmiQueryValue, type GeoSpecPmiRawEntity, type GeoSpecPmiRecord, type GeoSpecPmiShapeReference, type GeoSpecQueryCapability, type GeoSpecQueryOptions, type MinimumDistanceFact, type MinimumDistanceQuery, type MinimumDistanceResult, createGeoSpecAssertionClient, createGeoSpecMatcherMethods, evaluateGeoSpecNativeQuery, geoSpecMatcherDescriptors };
@@ -0,0 +1 @@
1
+ import{geoSpecMatcherDescriptors as e}from"../engine/matchers.mjs";import{evaluateGeoSpecNativeQuery as t}from"../engine/client.mjs";import{GeoSpecAssertionError as n,createGeoSpecAssertionClient as r,createGeoSpecMatcherMethods as i}from"./client.mjs";export{n as GeoSpecAssertionError,r as createGeoSpecAssertionClient,i as createGeoSpecMatcherMethods,t as evaluateGeoSpecNativeQuery,e as geoSpecMatcherDescriptors};
@@ -0,0 +1,3 @@
1
+ import { GeoSpecConfig, GeoSpecTauProjectDescriptor, LoadGeoSpecConfigOptions, LoadedGeoSpecConfig } from "./types.mjs";
2
+ import { ExportTauProjectArtifactOptions, GeoSpecTauProjectArtifact, GeoSpecTauProjectRuntime, exportTauProjectArtifact } from "./tau-project-artifact.mjs";
3
+ export { type ExportTauProjectArtifactOptions, type GeoSpecConfig, type GeoSpecTauProjectArtifact, type GeoSpecTauProjectDescriptor, type GeoSpecTauProjectRuntime, type LoadGeoSpecConfigOptions, type LoadedGeoSpecConfig, exportTauProjectArtifact };
@@ -0,0 +1 @@
1
+ import{exportTauProjectArtifact as e}from"./tau-project-artifact.mjs";export{e as exportTauProjectArtifact};
@@ -0,0 +1,3 @@
1
+ import { LoadGeoSpecConfigOptions, LoadedGeoSpecConfig } from "../types.mjs";
2
+ import { loadGeoSpecConfig } from "./load.mjs";
3
+ export { type LoadGeoSpecConfigOptions, type LoadedGeoSpecConfig, loadGeoSpecConfig };
@@ -0,0 +1 @@
1
+ import{loadGeoSpecConfig as e}from"./load.mjs";export{e as loadGeoSpecConfig};
@@ -0,0 +1,19 @@
1
+ import { LoadGeoSpecConfigOptions, LoadedGeoSpecConfig } from "../types.mjs";
2
+ //#region src/config/node/load.d.ts
3
+ /**
4
+ * Load one trusted project config using Node's native module loader.
5
+ *
6
+ * Explicit selection or exactly one geospec.config.js/.mjs/.ts/.mts is allowed.
7
+ * TypeScript must use erasable syntax; JSON imports use standard attributes.
8
+ * Executable config/imports are trusted developer code, not sandboxed code.
9
+ * Node's same-process module cache is unchanged: load once per run and use a
10
+ * fresh process when fresh executable imports are required. No reload guarantee
11
+ * or transitive-source identity is supplied here.
12
+ *
13
+ * @public
14
+ * @param options - Project, optional explicit config and defined option overrides.
15
+ * @returns Real config path when present and validated data without runner defaults.
16
+ */
17
+ declare const loadGeoSpecConfig: (options: LoadGeoSpecConfigOptions) => Promise<LoadedGeoSpecConfig>;
18
+ //#endregion
19
+ export { loadGeoSpecConfig };
@@ -0,0 +1 @@
1
+ import{resolveGeoSpecConfig as e}from"../validate.mjs";import{realpath as t,stat as n}from"node:fs/promises";import{extname as r,isAbsolute as i,relative as a,resolve as o,sep as s}from"node:path";import{pathToFileURL as c}from"node:url";const l=[`.js`,`.mjs`,`.ts`,`.mts`],u=async e=>{try{return(await n(e)).isFile()}catch(e){if(typeof e==`object`&&e&&`code`in e&&e.code===`ENOENT`)return!1;throw e}},d=async d=>{let f=await t(d.projectPath),p=d.configPath;if(p===void 0){let e=l.map(e=>`geospec.config${e}`),t=(await Promise.all(e.map(async e=>await u(o(f,e))?e:void 0))).filter(e=>e!==void 0);if(t.length>1)throw TypeError(`Multiple GeoSpec configs found: ${t.join(`, `)}. Select configPath explicitly.`);[p]=t}if(p===void 0)return{options:e({},d.overrides)};let m=r(p);if(!l.some(e=>e===m))throw TypeError(`GeoSpec configPath must select a .js, .mjs, .ts or .mts file.`);let h=await t(o(f,p)),g=a(f,h);if(i(g)||g===`..`||g.startsWith(`..${s}`))throw TypeError(`GeoSpec configPath must resolve within projectPath.`);if(!(await n(h)).isFile())throw TypeError(`GeoSpec configPath must select a file.`);let _=await import(c(h).href);return{configPath:h,options:e(_.default,d.overrides)}};export{d as loadGeoSpecConfig};
@@ -0,0 +1,54 @@
1
+ import { GeometryExportIntent } from "../mesh/types.mjs";
2
+ import { RuntimeClientWithRoutes } from "../model/export-intent.mjs";
3
+ import { GeoSpecTauProjectDescriptor } from "./types.mjs";
4
+ import { ProjectManifest } from "@taucad/project-core";
5
+ import { KernelResult, RuntimeSourceSnapshotFile } from "@taucad/runtime/types";
6
+ import { RuntimeClient } from "@taucad/runtime/client";
7
+ //#region src/config/tau-project-artifact.d.ts
8
+ /** Runtime surface required to snapshot and export one Tau project. @public */
9
+ type GeoSpecTauProjectRuntime = RuntimeClientWithRoutes & Pick<RuntimeClient, 'shutdown' | 'snapshotSource'>;
10
+ /** Input for exporting one validated Tau project descriptor. @public */
11
+ type ExportTauProjectArtifactOptions = {
12
+ readonly descriptor: GeoSpecTauProjectDescriptor;
13
+ /** Called twice so source discovery and export use separate runtime lifetimes. */
14
+ readonly createRuntime: () => GeoSpecTauProjectRuntime | Promise<GeoSpecTauProjectRuntime>;
15
+ readonly signal?: AbortSignal;
16
+ };
17
+ /** Finalized geometry bytes and the exact source/export metadata that produced them. @public */
18
+ type GeoSpecTauProjectArtifact = {
19
+ readonly format: 'step' | 'glb';
20
+ readonly name: string;
21
+ readonly mimeType: string;
22
+ readonly bytes: Uint8Array<ArrayBuffer>;
23
+ readonly frame: {
24
+ readonly coordinateSystem: 'z-up';
25
+ readonly lengthUnit: 'millimeter';
26
+ readonly sourceUnit: 'mm';
27
+ };
28
+ readonly source: {
29
+ readonly manifestPath: string;
30
+ readonly manifestBytes: Uint8Array<ArrayBuffer>;
31
+ readonly manifest: ProjectManifest;
32
+ readonly projectEntryPath: string;
33
+ readonly entryPath: string;
34
+ readonly kernelId: string;
35
+ readonly files: readonly RuntimeSourceSnapshotFile[];
36
+ };
37
+ readonly export: {
38
+ readonly options: Readonly<Record<string, unknown>>;
39
+ readonly route: NonNullable<GeometryExportIntent['route']>;
40
+ };
41
+ };
42
+ /**
43
+ * Export one Tau project from Runtime's coherent source snapshot.
44
+ *
45
+ * This helper preserves finalized bytes and provenance metadata. It does not
46
+ * certify mathematical geometry or grant the runtime trusted-evaluator authority.
47
+ *
48
+ * @param options - Descriptor, fresh-runtime factory, and optional cancellation signal.
49
+ * @returns Runtime-style success or failure with the exact finalized artifact.
50
+ * @public
51
+ */
52
+ declare const exportTauProjectArtifact: (options: ExportTauProjectArtifactOptions) => Promise<KernelResult<GeoSpecTauProjectArtifact>>;
53
+ //#endregion
54
+ export { ExportTauProjectArtifactOptions, GeoSpecTauProjectArtifact, GeoSpecTauProjectRuntime, exportTauProjectArtifact };
@@ -0,0 +1,3 @@
1
+ import{resolveRuntimeExportIntent as e}from"../model/export-intent.mjs";import{resolveGeoSpecConfig as t}from"./validate.mjs";import{parseProjectManifestBytes as n,projectManifestSchema as r,projectRelativePathSchema as i,serializeProjectManifest as a}from"@taucad/project-core";const o=(e,t,n={})=>({success:!1,issues:[...n.priorIssues??[],{code:e,message:t,severity:`error`,type:`runtime`,...n.details===void 0?{}:{details:n.details}}]}),s=(e,t)=>e.byteLength===t.byteLength&&e.every((e,n)=>e===t[n]),c=(e,t)=>{let n=e.lastIndexOf(`/`);return i.parse(n===-1?t:`${e.slice(0,n)}/${t}`)},l=(e,t)=>t.bytes.byteLength===0?!1:e===`step`?t.mimeType===`application/step`:t.mimeType===`model/gltf-binary`,u=async i=>{let u=t({subjects:{selected:i.descriptor}}).subjects?.selected;if(!u)throw TypeError(`GeoSpec Tau descriptor is required.`);let d=structuredClone(u),f=r.safeParse(d.manifest);if(!f.success)throw TypeError(`GeoSpec Tau descriptor manifest must match the current Tau project schema.`);let p=c(d.manifestPath,f.data.assets.main.entryPath),m=await i.createRuntime(),h,g;try{await m.connect(),h=await m.snapshotSource({source:{path:p},additionalPaths:[{path:d.manifestPath,required:!0}],...i.signal===void 0?{}:{signal:i.signal}}),h.success&&(g=structuredClone(e({runtime:m,format:d.format})))}finally{await m.shutdown()}if(!h.success)return h;if(!g)throw TypeError(`Runtime export intent was not resolved from the successful source snapshot.`);if(`success`in g)return o(`KERNEL_CAPABILITY_MISSING`,g.diagnostics.map(({message:e})=>e).join(`
2
+ `),{details:{diagnostics:g.diagnostics},priorIssues:h.issues});let _=g.provenance.route,v=g.provenance.honored;if(_?.kernelId!==h.data.kernelId||_.targetFormat!==d.format||v?.coordinateSystem!==`z-up`||v.sourceUnit!==`mm`||d.format===`glb`&&v.unit?.length!==`millimeter`)return o(`KERNEL_CAPABILITY_MISSING`,`Runtime route did not honor the snapshotted provider and Z-up/mm export.`,{details:{snapshotKernelId:h.data.kernelId,route:_,honored:v},priorIssues:h.issues});if(h.data.entryPath!==p||h.data.unresolvedPaths.length>0)return o(`SOURCE_SNAPSHOT_INVALID`,`Runtime did not return the requested complete Tau source closure.`,{details:{expectedEntryPath:p,actualEntryPath:h.data.entryPath,unresolvedPaths:h.data.unresolvedPaths},priorIssues:h.issues});let y=h.data.files.filter(({path:e})=>e===d.manifestPath);if(y.length!==1)return o(`SOURCE_SNAPSHOT_INVALID`,`Runtime source closure must contain exactly one requested Tau manifest.`,{details:{manifestPath:d.manifestPath,actualCount:y.length},priorIssues:h.issues});let b=y[0],x=n(b.content);if(!x.success)return o(`SOURCE_SNAPSHOT_INVALID`,`Runtime source closure contains an invalid Tau manifest.`,{details:x.issue,priorIssues:h.issues});if(!s(a(f.data),a(x.data)))return o(`SOURCE_SNAPSHOT_CHANGED`,`Imported Tau descriptor does not match the snapshotted manifest bytes.`,{details:{manifestPath:d.manifestPath},priorIssues:h.issues});if(c(d.manifestPath,x.data.assets.main.entryPath)!==h.data.entryPath)return o(`SOURCE_SNAPSHOT_CHANGED`,`Snapshotted Tau manifest selects a different main asset.`,{details:{manifestPath:d.manifestPath},priorIssues:h.issues});let S={};for(let e of h.data.files){if(S[e.path]!==void 0)return o(`SOURCE_SNAPSHOT_INVALID`,`Runtime source closure contains duplicate paths.`,{details:{path:e.path},priorIssues:h.issues});S[e.path]=e.content}let C=await i.createRuntime();if(C===m)throw TypeError(`createRuntime must return a fresh runtime for source replay.`);try{await C.connect();let t=C.open({source:{files:S,entry:h.data.entryPath},parameters:d.parameters??{},watch:!1,...i.signal===void 0?{}:{signal:i.signal}}),n=await(async()=>{try{return await t.export(d.format,{options:g.options,...i.signal===void 0?{}:{signal:i.signal}})}finally{t.close()}})();if(!n.success)return{success:!1,issues:[...h.issues,...n.issues]};let r=e({runtime:C,format:d.format});if(`success`in r)return o(`KERNEL_CAPABILITY_MISSING`,r.diagnostics.map(({message:e})=>e).join(`
3
+ `),{details:{diagnostics:r.diagnostics},priorIssues:[...h.issues,...n.issues]});let a=r.provenance.route,s=r.provenance.honored;if(a?.kernelId!==h.data.kernelId||a.targetFormat!==d.format||s?.coordinateSystem!==`z-up`||s.sourceUnit!==`mm`||d.format===`glb`&&s.unit?.length!==`millimeter`||JSON.stringify(a)!==JSON.stringify(_)||JSON.stringify(r.options)!==JSON.stringify(g.options))return o(`KERNEL_CAPABILITY_MISSING`,`Export runtime did not retain the requested source-bound route and Z-up/mm frame.`,{details:{snapshotKernelId:h.data.kernelId,requested:g,actual:r},priorIssues:[...h.issues,...n.issues]});let c=[...n.files];if(c.length!==1)return o(`EXPORT_ARTIFACT_SET_INVALID`,`Tau project export must produce exactly one usable artifact.`,{details:{actualCount:c.length},priorIssues:[...h.issues,...n.issues]});let[u]=c;if(!u||!l(d.format,u))return o(`EXPORT_ARTIFACT_SET_INVALID`,`Tau project export did not produce the requested usable artifact.`,{details:{format:d.format,artifact:u&&{name:u.name,mimeType:u.mimeType,byteLength:u.bytes.byteLength}},priorIssues:[...h.issues,...n.issues]});let{bytes:f,mimeType:p,name:m}=u;return{success:!0,data:{format:d.format,name:m,mimeType:p,bytes:f,frame:{coordinateSystem:`z-up`,lengthUnit:`millimeter`,sourceUnit:`mm`},source:{manifestPath:d.manifestPath,manifestBytes:b.content,manifest:x.data,projectEntryPath:x.data.assets.main.entryPath,entryPath:h.data.entryPath,kernelId:h.data.kernelId,files:h.data.files},export:{options:g.options,route:a}},issues:[...h.issues,...n.issues]}}finally{await C.shutdown()}};export{u as exportTauProjectArtifact};
@@ -0,0 +1,57 @@
1
+ import { JSONValue } from "@taucad/runtime/types";
2
+ //#region src/config/types.d.ts
3
+ /**
4
+ * Imported Tau project data for later host resolution.
5
+ *
6
+ * This descriptor does not validate the original manifest bytes or its schema,
7
+ * admit an asset, export geometry, or establish finalized-artifact provenance.
8
+ * @public
9
+ */
10
+ type GeoSpecTauProjectDescriptor = {
11
+ readonly kind: 'tau-project';
12
+ /** Normalized project-relative POSIX path identifying the imported manifest. */
13
+ readonly manifestPath: string;
14
+ readonly manifest: Readonly<Record<string, JSONValue>>;
15
+ readonly format: 'step' | 'glb';
16
+ readonly parameters?: Readonly<Record<string, JSONValue>>;
17
+ };
18
+ /**
19
+ * Trusted project configuration using existing discovery and runner options.
20
+ *
21
+ * Omitted values keep their existing owner's defaults. Defined overrides
22
+ * replace whole fields, including empty arrays, false and the subjects map.
23
+ * Existing discovery currently treats an absent or empty include array as its
24
+ * default pattern. Preserving [] here does not change that consumer behavior.
25
+ * This is configuration data, not a canonical engine plan or a geometry result.
26
+ * @public
27
+ */
28
+ type GeoSpecConfig = {
29
+ include?: readonly string[];
30
+ exclude?: readonly string[];
31
+ testNamePattern?: string;
32
+ /** Positive finite milliseconds; the runner owns its default. */
33
+ testTimeout?: number;
34
+ /** Positive finite milliseconds; does not define a geometry verdict. */
35
+ matcherWallBackstop?: number;
36
+ bail?: boolean;
37
+ forensic?: boolean;
38
+ cache?: boolean;
39
+ /** Requested cache location only; loading configuration creates no store. */
40
+ cacheDirectory?: string;
41
+ subjects?: Readonly<Record<string, GeoSpecTauProjectDescriptor>>;
42
+ };
43
+ /** Options for one trusted Node configuration load. @public */
44
+ type LoadGeoSpecConfigOptions = {
45
+ readonly projectPath: string;
46
+ /** Explicit file, resolved relative to the project unless absolute. */
47
+ readonly configPath?: string;
48
+ /** Own defined fields override configuration without deep merging. */
49
+ readonly overrides?: GeoSpecConfig;
50
+ };
51
+ /** Resolved file identity and validated configuration data. @public */
52
+ type LoadedGeoSpecConfig = {
53
+ readonly configPath?: string;
54
+ readonly options: GeoSpecConfig;
55
+ };
56
+ //#endregion
57
+ export { GeoSpecConfig, GeoSpecTauProjectDescriptor, LoadGeoSpecConfigOptions, LoadedGeoSpecConfig };
@@ -0,0 +1 @@
1
+ import{assertGeoSpecJsonValue as e}from"../engine/protocol.mjs";const t=(e,t)=>{if(typeof e!=`object`||!e||Array.isArray(e))throw TypeError(`${t} must be a plain object.`);let n=Object.getPrototypeOf(e);if(n!==Object.prototype&&n!==null)throw TypeError(`${t} must be a plain object.`);return e},n=(n,r)=>{let i=t(n,r);return e(i),i},r=e=>{let r=t(e,`GeoSpec Tau descriptor`);for(let e of Reflect.ownKeys(r))if(typeof e!=`string`||![`kind`,`manifestPath`,`manifest`,`format`,`parameters`].includes(e))throw TypeError(`Unsupported GeoSpec Tau descriptor field '${String(e)}'.`);let{kind:i,manifestPath:a,manifest:o,format:s,parameters:c}=r;if(i!==`tau-project`)throw TypeError(`GeoSpec Tau descriptor kind must be 'tau-project'.`);if(typeof a!=`string`||a.length===0||a.length>2048||a.includes(`\0`)||a.includes(`\\`)||a.startsWith(`/`)||a.split(`/`).some(e=>e.length===0||e===`.`||e===`..`))throw TypeError(`GeoSpec manifestPath must be a normalized project-relative POSIX path.`);if(s!==`step`&&s!==`glb`)throw TypeError(`GeoSpec Tau descriptor format must be 'step' or 'glb'.`);return{kind:i,manifestPath:a,manifest:n(o,`GeoSpec manifest`),format:s,...c===void 0?{}:{parameters:n(c,`GeoSpec parameters`)}}},i=e=>{let n=t(e,`GeoSpec config`),i={};for(let e of Reflect.ownKeys(n)){if(typeof e!=`string`)throw TypeError(`Unsupported GeoSpec config field '${String(e)}'.`);let a=n[e];switch(e){case`include`:case`exclude`:{if(a===void 0)break;if(!Array.isArray(a))throw TypeError(`GeoSpec ${e} must be an array of strings.`);let t=[...a];if(!t.every(e=>typeof e==`string`))throw TypeError(`GeoSpec ${e} must be an array of strings.`);i[e]=t;break}case`testNamePattern`:case`cacheDirectory`:if(a===void 0)break;if(typeof a!=`string`)throw TypeError(`GeoSpec ${e} must be a string.`);i[e]=a;break;case`testTimeout`:case`matcherWallBackstop`:if(a===void 0)break;if(typeof a!=`number`||!Number.isFinite(a)||a<=0)throw TypeError(`GeoSpec ${e} must be positive finite milliseconds.`);i[e]=a;break;case`bail`:case`forensic`:case`cache`:if(a===void 0)break;if(typeof a!=`boolean`)throw TypeError(`GeoSpec ${e} must be a boolean.`);i[e]=a;break;case`subjects`:{if(a===void 0)break;let e=t(a,`GeoSpec subjects`);i.subjects=Object.fromEntries(Reflect.ownKeys(e).map(t=>{if(typeof t!=`string`)throw TypeError(`GeoSpec subjects keys must be strings.`);return[t,r(e[t])]}));break}default:throw TypeError(`Unsupported GeoSpec config field '${e}'.`)}}return i},a=(e,t={})=>({...i(e),...i(t)});export{a as resolveGeoSpecConfig};
@@ -0,0 +1,49 @@
1
+ import { GeoSpecSubject } from "./model/subject.mjs";
2
+ import { GeoSpecMatcher } from "./runner/types.mjs";
3
+ //#region src/create-geospec.d.ts
4
+ type GeoSpecTestCallback = () => unknown | PromiseLike<unknown>;
5
+ type SuiteFunction = {
6
+ (name: string, function_: GeoSpecTestCallback): void;
7
+ skip(name: string, function_?: GeoSpecTestCallback): void;
8
+ };
9
+ type TestFunction = {
10
+ (name: string, function_: GeoSpecTestCallback): void;
11
+ skip(name: string, function_?: GeoSpecTestCallback): void;
12
+ };
13
+ /**
14
+ * GeoSpec suite helper used inside VM-executed test modules.
15
+ *
16
+ * @public
17
+ */
18
+ declare const describe: SuiteFunction;
19
+ /**
20
+ * GeoSpec test helper used inside VM-executed test modules.
21
+ *
22
+ * @public
23
+ */
24
+ declare const it: TestFunction;
25
+ /**
26
+ * Alias for {@link it}.
27
+ *
28
+ * @public
29
+ */
30
+ declare const test: TestFunction;
31
+ /**
32
+ * Start a geometry assertion chain.
33
+ *
34
+ * @param subject - geometry subject under test.
35
+ * @returns GeoSpec geometry matchers.
36
+ * @public
37
+ */
38
+ declare function expectGeo(subject: GeoSpecSubject): GeoSpecMatcher;
39
+ /**
40
+ * Every matcher name exposed by {@link expectGeo}, derived from the live
41
+ * matcher surface so it can never drift from the real implementation. Use it to
42
+ * assert that documentation, prompt examples, or authored suites only reference
43
+ * matchers that actually exist.
44
+ *
45
+ * @public
46
+ */
47
+ declare const geoSpecMatcherNames: readonly string[];
48
+ //#endregion
49
+ export { describe, expectGeo, geoSpecMatcherNames, it, test };
@@ -0,0 +1 @@
1
+ import{geoSpecMatcherDescriptors as e}from"./engine/matchers.mjs";import{getCollector as t}from"./runner/collector.mjs";import{expectGeoSubject as n}from"./model/subject-assertions.mjs";const r=Object.assign((e,n)=>{t().describe(e,n)},{skip(e,n){t().describeSkip(e,n)}}),i=Object.assign((e,n)=>{t().it(e,n)},{skip(e,n){t().itSkip(e,n)}}),a=i;function o(e){return n(e)}const s=Object.freeze(Object.keys(e));export{r as describe,o as expectGeo,s as geoSpecMatcherNames,i as it,a as test};