@tendrilapp/cli 0.1.21 → 0.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tendril.js CHANGED
@@ -14,11 +14,11 @@ var __export = (target, all) => {
14
14
  __defProp(target, name, { get: all[name], enumerable: true });
15
15
  };
16
16
 
17
- // packages/core/src/ir.ts
17
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/core/src/ir.ts
18
18
  import { z } from "zod";
19
19
  var IrLayoutSchema, IrMotionSchema, IrPositionSchema, IrNodeSchema, ComponentIrSchema;
20
20
  var init_ir = __esm({
21
- "packages/core/src/ir.ts"() {
21
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/core/src/ir.ts"() {
22
22
  "use strict";
23
23
  IrLayoutSchema = z.object({
24
24
  mode: z.enum(["flex-row", "flex-column", "grid", "none"]),
@@ -110,14 +110,14 @@ var init_ir = __esm({
110
110
  }
111
111
  });
112
112
 
113
- // packages/figma/src/source.ts
113
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/source.ts
114
114
  var init_source = __esm({
115
- "packages/figma/src/source.ts"() {
115
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/source.ts"() {
116
116
  "use strict";
117
117
  }
118
118
  });
119
119
 
120
- // packages/figma/src/svg-safety.ts
120
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/svg-safety.ts
121
121
  function checkSvgSafety(source) {
122
122
  const issues = [];
123
123
  if (!/<\s*svg\b/i.test(source)) issues.push("not an <svg> document");
@@ -132,7 +132,7 @@ function assetExportName(key) {
132
132
  }
133
133
  var UNSAFE_PATTERNS;
134
134
  var init_svg_safety = __esm({
135
- "packages/figma/src/svg-safety.ts"() {
135
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/svg-safety.ts"() {
136
136
  "use strict";
137
137
  UNSAFE_PATTERNS = [
138
138
  [/<\s*script\b/i, "script element"],
@@ -146,11 +146,11 @@ var init_svg_safety = __esm({
146
146
  }
147
147
  });
148
148
 
149
- // packages/figma/src/provided.ts
149
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/provided.ts
150
150
  import { z as z2 } from "zod";
151
151
  var ProvidedVariableSchema, RangeSchema, PinnedPlacementSchema, VariantValueFactsSchema, ProvidedMetadataSchema, ProvidedContextSchema, ProvidedContextSource;
152
152
  var init_provided = __esm({
153
- "packages/figma/src/provided.ts"() {
153
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/provided.ts"() {
154
154
  "use strict";
155
155
  init_svg_safety();
156
156
  ProvidedVariableSchema = z2.object({
@@ -269,7 +269,7 @@ var init_provided = __esm({
269
269
  }
270
270
  });
271
271
 
272
- // packages/figma/src/mcp/client.ts
272
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mcp/client.ts
273
273
  function parseMessages(body, contentType) {
274
274
  if (body.trim() === "") return [];
275
275
  if (!contentType.includes("text/event-stream")) {
@@ -285,7 +285,7 @@ function parseMessages(body, contentType) {
285
285
  }
286
286
  var PROTOCOL_VERSION, McpUnavailableError, McpProtocolError, McpHttpClient;
287
287
  var init_client = __esm({
288
- "packages/figma/src/mcp/client.ts"() {
288
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mcp/client.ts"() {
289
289
  "use strict";
290
290
  PROTOCOL_VERSION = "2025-06-18";
291
291
  McpUnavailableError = class extends Error {
@@ -389,7 +389,7 @@ var init_client = __esm({
389
389
  }
390
390
  });
391
391
 
392
- // packages/figma/src/mcp/normalize.ts
392
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mcp/normalize.ts
393
393
  function decodeXmlEntities(v) {
394
394
  return v.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&amp;/g, "&");
395
395
  }
@@ -472,7 +472,7 @@ function mergeVariantAxes(childNames) {
472
472
  }
473
473
  var TAG_TO_TYPE, TAG_RE, ATTR_RE;
474
474
  var init_normalize = __esm({
475
- "packages/figma/src/mcp/normalize.ts"() {
475
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mcp/normalize.ts"() {
476
476
  "use strict";
477
477
  init_svg_safety();
478
478
  TAG_TO_TYPE = {
@@ -488,10 +488,10 @@ var init_normalize = __esm({
488
488
  }
489
489
  });
490
490
 
491
- // packages/figma/src/mock/fixtures/button.ts
491
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mock/fixtures/button.ts
492
492
  var buttonVariables, buttonMetadata, buttonNodeTree;
493
493
  var init_button = __esm({
494
- "packages/figma/src/mock/fixtures/button.ts"() {
494
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mock/fixtures/button.ts"() {
495
495
  "use strict";
496
496
  buttonVariables = [
497
497
  {
@@ -600,10 +600,10 @@ var init_button = __esm({
600
600
  }
601
601
  });
602
602
 
603
- // packages/figma/src/mock/mock-source.ts
603
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mock/mock-source.ts
604
604
  var MockFigmaSource;
605
605
  var init_mock_source = __esm({
606
- "packages/figma/src/mock/mock-source.ts"() {
606
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mock/mock-source.ts"() {
607
607
  "use strict";
608
608
  init_button();
609
609
  MockFigmaSource = class {
@@ -640,7 +640,7 @@ var init_mock_source = __esm({
640
640
  }
641
641
  });
642
642
 
643
- // packages/figma/src/css-ident.ts
643
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/css-ident.ts
644
644
  function canonicalCssIdentPart(part) {
645
645
  return part.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
646
646
  }
@@ -649,27 +649,27 @@ function variableNameToCssVar(name) {
649
649
  return `--${parts.join("-")}`;
650
650
  }
651
651
  var init_css_ident = __esm({
652
- "packages/figma/src/css-ident.ts"() {
652
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/css-ident.ts"() {
653
653
  "use strict";
654
654
  }
655
655
  });
656
656
 
657
- // packages/figma/src/mcp/var-decoder.ts
657
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mcp/var-decoder.ts
658
658
  var init_var_decoder = __esm({
659
- "packages/figma/src/mcp/var-decoder.ts"() {
659
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mcp/var-decoder.ts"() {
660
660
  "use strict";
661
661
  init_css_ident();
662
662
  }
663
663
  });
664
664
 
665
- // packages/figma/src/mcp/font-normalize.ts
665
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mcp/font-normalize.ts
666
666
  var init_font_normalize = __esm({
667
- "packages/figma/src/mcp/font-normalize.ts"() {
667
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mcp/font-normalize.ts"() {
668
668
  "use strict";
669
669
  }
670
670
  });
671
671
 
672
- // packages/figma/src/provided-recording.ts
672
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/provided-recording.ts
673
673
  import { z as z3 } from "zod";
674
674
  function checkPngPayload(base64) {
675
675
  let raw;
@@ -684,7 +684,7 @@ function checkPngPayload(base64) {
684
684
  }
685
685
  var MAX_EMISSION_BYTES, MAX_IMAGE_BYTES, MAX_ASSET_BYTES, PNG_MAGIC, TextEnvelopeSchema, ImageEnvelopeSchema, ProvidedRepSchema, ManifestWireSchema, ProvidedRecordingSetSchema;
686
686
  var init_provided_recording = __esm({
687
- "packages/figma/src/provided-recording.ts"() {
687
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/provided-recording.ts"() {
688
688
  "use strict";
689
689
  init_svg_safety();
690
690
  MAX_EMISSION_BYTES = 2 * 1024 * 1024;
@@ -752,7 +752,7 @@ var init_provided_recording = __esm({
752
752
  }
753
753
  });
754
754
 
755
- // packages/figma/src/recording/axis-defaults.ts
755
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/recording/axis-defaults.ts
756
756
  function resolveAxisDefaultWithRule(domain, recorded, override) {
757
757
  if (override !== void 0) return { value: override, rule: "override" };
758
758
  const literal = domain.find((v) => kebab(v) === "default" || kebab(v) === "enabled");
@@ -787,7 +787,7 @@ function resolveAxisDefault(domain, recorded, override) {
787
787
  }
788
788
  var INTERACTION_STATES, BOOLEAN_STATES, ENGAGED_STATES, INTERACTION_EVIDENCE_VALUES, kebab, OFF_VALUES, ON_VALUES;
789
789
  var init_axis_defaults = __esm({
790
- "packages/figma/src/recording/axis-defaults.ts"() {
790
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/recording/axis-defaults.ts"() {
791
791
  "use strict";
792
792
  INTERACTION_STATES = /* @__PURE__ */ new Set(["hover", "focus", "focus-visible", "active", "pressed"]);
793
793
  BOOLEAN_STATES = /* @__PURE__ */ new Set(["disabled", "loading"]);
@@ -810,7 +810,7 @@ var init_axis_defaults = __esm({
810
810
  }
811
811
  });
812
812
 
813
- // packages/figma/src/recording/plan.ts
813
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/recording/plan.ts
814
814
  function singleAxes(name) {
815
815
  const parsed = parseVariantAxes(name);
816
816
  if (parsed === void 0) return void 0;
@@ -920,7 +920,7 @@ function planQueue(symbols, opts = {}) {
920
920
  }
921
921
  var kebab2;
922
922
  var init_plan = __esm({
923
- "packages/figma/src/recording/plan.ts"() {
923
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/recording/plan.ts"() {
924
924
  "use strict";
925
925
  init_normalize();
926
926
  init_axis_defaults();
@@ -928,7 +928,7 @@ var init_plan = __esm({
928
928
  }
929
929
  });
930
930
 
931
- // packages/figma/src/recording/session.ts
931
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/recording/session.ts
932
932
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
933
933
  import path from "node:path";
934
934
  import { z as z4 } from "zod";
@@ -939,14 +939,25 @@ function manifestMains(manifest) {
939
939
  function requiredToolsFor(manifest, slug) {
940
940
  return manifestMains(manifest).includes(slug) ? [...REQUIRED_TOOLS, INTERIOR_TOOL] : REQUIRED_TOOLS;
941
941
  }
942
- function loadManifest(setDir) {
942
+ function readManifestFile(setDir) {
943
943
  const p = manifestPath(setDir);
944
944
  if (!existsSync(p)) throw new Error(`no recording-set.json in ${setDir} \u2014 run \`tendril record plan\` first`);
945
- return SessionManifestSchema.parse(JSON.parse(readFileSync(p, "utf8")));
945
+ const raw = JSON.parse(readFileSync(p, "utf8"));
946
+ return { manifest: SessionManifestSchema.parse(raw), raw };
947
+ }
948
+ function loadManifest(setDir) {
949
+ return readManifestFile(setDir).manifest;
950
+ }
951
+ function writeManifest(setDir, raw) {
952
+ const manifest = SessionManifestSchema.parse(raw);
953
+ mkdirSync(setDir, { recursive: true });
954
+ writeFileSync(manifestPath(setDir), `${JSON.stringify(raw, null, 1)}
955
+ `);
956
+ return manifest;
946
957
  }
947
958
  function planSet(setDir, component, symbols, opts = {}) {
948
959
  if (existsSync(manifestPath(setDir))) {
949
- const existing = loadManifest(setDir);
960
+ const { manifest: existing, raw } = readManifestFile(setDir);
950
961
  const wantsNewDefaults = opts.defaults !== void 0 && JSON.stringify(opts.defaults) !== JSON.stringify(existing.defaults ?? {});
951
962
  const anythingRecorded = existing.reps.some((r) => RECORD_TOOLS.some((t) => existsSync(path.join(setDir, r.slug, `${t}.json`))));
952
963
  if (!wantsNewDefaults || anythingRecorded) {
@@ -963,12 +974,11 @@ function planSet(setDir, component, symbols, opts = {}) {
963
974
  usedSlugs.add(slug);
964
975
  return { slug, nodeId: r.nodeId, ...r.sourceFrame !== void 0 ? { sourceFrame: r.sourceFrame } : {} };
965
976
  });
966
- existing.reps.push(...appended);
967
- existing.planMode = "full";
968
- delete existing.notRecorded;
969
- writeFileSync(manifestPath(setDir), `${JSON.stringify(existing, null, 1)}
970
- `);
971
- return { manifest: existing, plan: { reps: [], notRecorded: [] }, resumed: true, toppedUp: appended.map((a) => ({ slug: a.slug, nodeId: a.nodeId })) };
977
+ raw["reps"].push(...appended);
978
+ raw["planMode"] = "full";
979
+ delete raw["notRecorded"];
980
+ const manifest2 = writeManifest(setDir, raw);
981
+ return { manifest: manifest2, plan: { reps: [], notRecorded: [] }, resumed: true, toppedUp: appended.map((a) => ({ slug: a.slug, nodeId: a.nodeId })) };
972
982
  }
973
983
  }
974
984
  return { manifest: existing, plan: { reps: [], notRecorded: [] }, resumed: true };
@@ -989,9 +999,7 @@ function planSet(setDir, component, symbols, opts = {}) {
989
999
  planMode: opts.sample === true ? "sample" : "full",
990
1000
  ...plan.notRecorded.length > 0 ? { notRecorded: plan.notRecorded.map((n) => `${n.name} (${n.nodeId}): ${n.reason}`).join("; ") } : {}
991
1001
  };
992
- mkdirSync(setDir, { recursive: true });
993
- writeFileSync(manifestPath(setDir), `${JSON.stringify(manifest, null, 1)}
994
- `);
1002
+ writeManifest(setDir, manifest);
995
1003
  return { manifest, plan, resumed: false };
996
1004
  }
997
1005
  function sessionStatus(setDir) {
@@ -1070,7 +1078,7 @@ function ingestAsset(setDir, slug, name, content) {
1070
1078
  }
1071
1079
  var RECORD_TOOLS, INTERIOR_TOOL, REQUIRED_TOOLS, SessionManifestSchema, manifestPath, PROTOCOL_ORDER, byProtocolOrder;
1072
1080
  var init_session = __esm({
1073
- "packages/figma/src/recording/session.ts"() {
1081
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/recording/session.ts"() {
1074
1082
  "use strict";
1075
1083
  init_svg_safety();
1076
1084
  init_provided_recording();
@@ -1115,7 +1123,7 @@ var init_session = __esm({
1115
1123
  }
1116
1124
  });
1117
1125
 
1118
- // packages/figma/src/recording/roles.ts
1126
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/recording/roles.ts
1119
1127
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
1120
1128
  import path2 from "node:path";
1121
1129
  function emissionIdSets(emission) {
@@ -1184,16 +1192,16 @@ function deriveRoles(setDir, manifest) {
1184
1192
  }
1185
1193
  var NODE_ID_RE;
1186
1194
  var init_roles = __esm({
1187
- "packages/figma/src/recording/roles.ts"() {
1195
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/recording/roles.ts"() {
1188
1196
  "use strict";
1189
1197
  init_session();
1190
1198
  NODE_ID_RE = /data-node-id="([^"]+)"/g;
1191
1199
  }
1192
1200
  });
1193
1201
 
1194
- // packages/figma/src/index.ts
1202
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/index.ts
1195
1203
  var init_src = __esm({
1196
- "packages/figma/src/index.ts"() {
1204
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/index.ts"() {
1197
1205
  "use strict";
1198
1206
  init_source();
1199
1207
  init_provided();
@@ -1212,7 +1220,7 @@ var init_src = __esm({
1212
1220
  }
1213
1221
  });
1214
1222
 
1215
- // packages/tokens/src/dtcg.ts
1223
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/tokens/src/dtcg.ts
1216
1224
  function variableNameToPath(name) {
1217
1225
  return name.split("/").map(canonicalCssIdentPart).filter((part) => part.length > 0);
1218
1226
  }
@@ -1318,7 +1326,7 @@ function mapVariablesToDtcg(variables, defaultMode = "light") {
1318
1326
  }
1319
1327
  var DIMENSION_COLLECTIONS, DtcgMappingError;
1320
1328
  var init_dtcg = __esm({
1321
- "packages/tokens/src/dtcg.ts"() {
1329
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/tokens/src/dtcg.ts"() {
1322
1330
  "use strict";
1323
1331
  init_src();
1324
1332
  DIMENSION_COLLECTIONS = /* @__PURE__ */ new Set(["spacing", "radius", "size", "border-width"]);
@@ -1333,7 +1341,7 @@ var init_dtcg = __esm({
1333
1341
  }
1334
1342
  });
1335
1343
 
1336
- // packages/tokens/src/emit.ts
1344
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/tokens/src/emit.ts
1337
1345
  function decomposeFontValue(raw, valueByCssVar) {
1338
1346
  const field = (name) => new RegExp(`${name}:\\s*("[^"]*"|[^,)]+)`).exec(raw)?.[1]?.trim();
1339
1347
  const resolve = (v) => {
@@ -1400,7 +1408,7 @@ export default {
1400
1408
  }
1401
1409
  var STYLE_WEIGHTS;
1402
1410
  var init_emit = __esm({
1403
- "packages/tokens/src/emit.ts"() {
1411
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/tokens/src/emit.ts"() {
1404
1412
  "use strict";
1405
1413
  init_src();
1406
1414
  STYLE_WEIGHTS = {
@@ -1419,7 +1427,7 @@ var init_emit = __esm({
1419
1427
  }
1420
1428
  });
1421
1429
 
1422
- // packages/tokens/src/synthesize.ts
1430
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/tokens/src/synthesize.ts
1423
1431
  function synthesizeSpacingVariables(tree, variantFacts, existing) {
1424
1432
  if (existing.some((v) => v.collection === "spacing")) return [];
1425
1433
  const values = /* @__PURE__ */ new Set();
@@ -1458,7 +1466,7 @@ function synthesizeSpacingVariables(tree, variantFacts, existing) {
1458
1466
  }
1459
1467
  var SPACING_FIELDS;
1460
1468
  var init_synthesize = __esm({
1461
- "packages/tokens/src/synthesize.ts"() {
1469
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/tokens/src/synthesize.ts"() {
1462
1470
  "use strict";
1463
1471
  SPACING_FIELDS = [
1464
1472
  "paddingTop",
@@ -1470,9 +1478,9 @@ var init_synthesize = __esm({
1470
1478
  }
1471
1479
  });
1472
1480
 
1473
- // packages/tokens/src/index.ts
1481
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/tokens/src/index.ts
1474
1482
  var init_src2 = __esm({
1475
- "packages/tokens/src/index.ts"() {
1483
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/tokens/src/index.ts"() {
1476
1484
  "use strict";
1477
1485
  init_dtcg();
1478
1486
  init_emit();
@@ -1481,7 +1489,7 @@ var init_src2 = __esm({
1481
1489
  }
1482
1490
  });
1483
1491
 
1484
- // packages/core/src/ir-builder.ts
1492
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/core/src/ir-builder.ts
1485
1493
  function isObject(value) {
1486
1494
  return typeof value === "object" && value !== null && !Array.isArray(value);
1487
1495
  }
@@ -1666,7 +1674,7 @@ function canonicalizeFactIdents(variantFacts) {
1666
1674
  }
1667
1675
  var RAW_PAYLOAD_FLAG_BYTES, MIN_HEALTHY_RATIO, RATIO_CHECK_MIN_BYTES, PADDING_FIELDS;
1668
1676
  var init_ir_builder = __esm({
1669
- "packages/core/src/ir-builder.ts"() {
1677
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/core/src/ir-builder.ts"() {
1670
1678
  "use strict";
1671
1679
  init_src2();
1672
1680
  init_src2();
@@ -1677,10 +1685,10 @@ var init_ir_builder = __esm({
1677
1685
  }
1678
1686
  });
1679
1687
 
1680
- // packages/core/src/exit-codes.ts
1688
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/core/src/exit-codes.ts
1681
1689
  var ExitCode;
1682
1690
  var init_exit_codes = __esm({
1683
- "packages/core/src/exit-codes.ts"() {
1691
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/core/src/exit-codes.ts"() {
1684
1692
  "use strict";
1685
1693
  ExitCode = {
1686
1694
  Success: 0,
@@ -1701,7 +1709,7 @@ var init_exit_codes = __esm({
1701
1709
  }
1702
1710
  });
1703
1711
 
1704
- // packages/core/src/readiness.ts
1712
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/core/src/readiness.ts
1705
1713
  function collectDefaultNamedLayers(tree, found) {
1706
1714
  const name = tree["name"];
1707
1715
  const visible = tree["visible"];
@@ -1751,15 +1759,15 @@ function scoreReadiness(metadata, tree) {
1751
1759
  }
1752
1760
  var DEFAULT_LAYER_NAME;
1753
1761
  var init_readiness = __esm({
1754
- "packages/core/src/readiness.ts"() {
1762
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/core/src/readiness.ts"() {
1755
1763
  "use strict";
1756
1764
  DEFAULT_LAYER_NAME = /^(Group|Frame|Rectangle|Ellipse|Vector|Component)\s*\d*$/;
1757
1765
  }
1758
1766
  });
1759
1767
 
1760
- // packages/core/src/index.ts
1768
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/core/src/index.ts
1761
1769
  var init_src3 = __esm({
1762
- "packages/core/src/index.ts"() {
1770
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/core/src/index.ts"() {
1763
1771
  "use strict";
1764
1772
  init_ir();
1765
1773
  init_ir_builder();
@@ -1768,7 +1776,7 @@ var init_src3 = __esm({
1768
1776
  }
1769
1777
  });
1770
1778
 
1771
- // packages/verify/src/browser.ts
1779
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/browser.ts
1772
1780
  import { execFileSync } from "node:child_process";
1773
1781
  import { existsSync as existsSync3, readdirSync } from "node:fs";
1774
1782
  import path3 from "node:path";
@@ -1826,7 +1834,7 @@ function chromeVersion() {
1826
1834
  }
1827
1835
  var MAC_CANDIDATES, WIN_CANDIDATES, PATH_NAMES, _version;
1828
1836
  var init_browser = __esm({
1829
- "packages/verify/src/browser.ts"() {
1837
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/browser.ts"() {
1830
1838
  "use strict";
1831
1839
  MAC_CANDIDATES = [
1832
1840
  "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
@@ -1841,7 +1849,7 @@ var init_browser = __esm({
1841
1849
  }
1842
1850
  });
1843
1851
 
1844
- // packages/verify/src/runtime.ts
1852
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/runtime.ts
1845
1853
  import { existsSync as existsSync4, mkdtempSync, symlinkSync } from "node:fs";
1846
1854
  import { createRequire } from "node:module";
1847
1855
  import os from "node:os";
@@ -1891,12 +1899,12 @@ function reactPinPlugin() {
1891
1899
  };
1892
1900
  }
1893
1901
  var init_runtime = __esm({
1894
- "packages/verify/src/runtime.ts"() {
1902
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/runtime.ts"() {
1895
1903
  "use strict";
1896
1904
  }
1897
1905
  });
1898
1906
 
1899
- // packages/verify/src/gates.ts
1907
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/gates.ts
1900
1908
  function scanForbiddenPatterns(source) {
1901
1909
  const violations = [];
1902
1910
  const lines = source.split("\n");
@@ -1915,7 +1923,7 @@ function scanForbiddenPatterns(source) {
1915
1923
  }
1916
1924
  var FORBIDDEN_PATTERNS;
1917
1925
  var init_gates = __esm({
1918
- "packages/verify/src/gates.ts"() {
1926
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/gates.ts"() {
1919
1927
  "use strict";
1920
1928
  FORBIDDEN_PATTERNS = [
1921
1929
  { name: "eslint-disable", regex: /eslint-disable/ },
@@ -1927,7 +1935,7 @@ var init_gates = __esm({
1927
1935
  }
1928
1936
  });
1929
1937
 
1930
- // packages/verify/src/tsc-check.ts
1938
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/tsc-check.ts
1931
1939
  import ts from "typescript";
1932
1940
  import path5 from "node:path";
1933
1941
  function runTscStrict(files) {
@@ -1947,7 +1955,7 @@ function runTscStrict(files) {
1947
1955
  }
1948
1956
  var STRICT_OPTIONS;
1949
1957
  var init_tsc_check = __esm({
1950
- "packages/verify/src/tsc-check.ts"() {
1958
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/tsc-check.ts"() {
1951
1959
  "use strict";
1952
1960
  STRICT_OPTIONS = {
1953
1961
  strict: true,
@@ -1967,7 +1975,7 @@ var init_tsc_check = __esm({
1967
1975
  }
1968
1976
  });
1969
1977
 
1970
- // packages/verify/src/token-lint.ts
1978
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/token-lint.ts
1971
1979
  import strictValue from "stylelint-declaration-strict-value";
1972
1980
  import stylelint from "stylelint";
1973
1981
  async function runTokenLint(css, fileLabel = "generated.css", definedVars2, recordedMapEmpty = false) {
@@ -2028,7 +2036,7 @@ async function runTokenLint(css, fileLabel = "generated.css", definedVars2, reco
2028
2036
  }
2029
2037
  var TOKEN_ENFORCED_PROPERTIES, ALLOWED_KEYWORDS, STYLELINT_CONFIG, LEGAL_CUSTOM_PROP;
2030
2038
  var init_token_lint = __esm({
2031
- "packages/verify/src/token-lint.ts"() {
2039
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/token-lint.ts"() {
2032
2040
  "use strict";
2033
2041
  TOKEN_ENFORCED_PROPERTIES = [
2034
2042
  "/color$/",
@@ -2088,7 +2096,7 @@ var init_token_lint = __esm({
2088
2096
  }
2089
2097
  });
2090
2098
 
2091
- // packages/verify/src/loop.ts
2099
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/loop.ts
2092
2100
  import { rmSync, writeFileSync as writeFileSync2 } from "node:fs";
2093
2101
  import path6 from "node:path";
2094
2102
  async function runChecks(componentName, files, extraFiles, definedVars2) {
@@ -2162,7 +2170,7 @@ function definedVarsFrom(tokensCss) {
2162
2170
  }
2163
2171
  var SKIPPED_CHECKS;
2164
2172
  var init_loop = __esm({
2165
- "packages/verify/src/loop.ts"() {
2173
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/loop.ts"() {
2166
2174
  "use strict";
2167
2175
  init_runtime();
2168
2176
  init_gates();
@@ -2172,7 +2180,7 @@ var init_loop = __esm({
2172
2180
  }
2173
2181
  });
2174
2182
 
2175
- // packages/verify/src/report.ts
2183
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/report.ts
2176
2184
  import { z as z5 } from "zod";
2177
2185
  function isTokenEnforcedProperty(property) {
2178
2186
  return enforcedMatchers.some((m) => m.test(property));
@@ -2212,7 +2220,7 @@ function buildReport(input) {
2212
2220
  }
2213
2221
  var ReportSchema, enforcedMatchers;
2214
2222
  var init_report = __esm({
2215
- "packages/verify/src/report.ts"() {
2223
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/report.ts"() {
2216
2224
  "use strict";
2217
2225
  init_token_lint();
2218
2226
  ReportSchema = z5.object({
@@ -2274,12 +2282,12 @@ var init_report = __esm({
2274
2282
  }
2275
2283
  });
2276
2284
 
2277
- // packages/verify/src/mount-limits.ts
2278
- function lcdTextDisabled() {
2279
- return process.env["TENDRIL_DISABLE_LCD_TEXT"] === "1";
2285
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/mount-limits.ts
2286
+ function lcdTextEnabled() {
2287
+ return process.env["TENDRIL_ENABLE_LCD_TEXT"] === "1";
2280
2288
  }
2281
2289
  function mountArgs() {
2282
- return [MEMORY_CAP_ARG, ...lcdTextDisabled() ? ["--disable-lcd-text"] : []];
2290
+ return [MEMORY_CAP_ARG, ...lcdTextEnabled() ? [] : ["--disable-lcd-text"]];
2283
2291
  }
2284
2292
  function raceMountDeadline(work, deadlineMs, onDeadline) {
2285
2293
  return Promise.race([
@@ -2292,14 +2300,14 @@ function raceMountDeadline(work, deadlineMs, onDeadline) {
2292
2300
  }
2293
2301
  var MEMORY_CAP_ARG, ENGINE_MOUNT_DEADLINE_MS;
2294
2302
  var init_mount_limits = __esm({
2295
- "packages/verify/src/mount-limits.ts"() {
2303
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/mount-limits.ts"() {
2296
2304
  "use strict";
2297
2305
  MEMORY_CAP_ARG = "--js-flags=--max-old-space-size=512";
2298
2306
  ENGINE_MOUNT_DEADLINE_MS = 3e4;
2299
2307
  }
2300
2308
  });
2301
2309
 
2302
- // packages/verify/src/image-diff.ts
2310
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/image-diff.ts
2303
2311
  import { PNG } from "pngjs";
2304
2312
  import pixelmatch from "pixelmatch";
2305
2313
  function channelDistance(a, b) {
@@ -2741,7 +2749,7 @@ function cropPng(png, x, y, width, height) {
2741
2749
  }
2742
2750
  var INK_DELTA, ABSENT_RADIUS, ABSENT_MIN_PX;
2743
2751
  var init_image_diff = __esm({
2744
- "packages/verify/src/image-diff.ts"() {
2752
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/image-diff.ts"() {
2745
2753
  "use strict";
2746
2754
  INK_DELTA = 30;
2747
2755
  ABSENT_RADIUS = 3;
@@ -2749,7 +2757,7 @@ var init_image_diff = __esm({
2749
2757
  }
2750
2758
  });
2751
2759
 
2752
- // packages/verify/src/visual-facts.ts
2760
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/visual-facts.ts
2753
2761
  import path7 from "node:path";
2754
2762
  import { fileURLToPath as fileURLToPath2 } from "node:url";
2755
2763
  import { build } from "esbuild";
@@ -3290,7 +3298,7 @@ ${input.files.css}
3290
3298
  }
3291
3299
  var RESOLVE_DIR, TOLERANCE_PX, WIDTH_SLACK, IMAGE_SIMILARITY_FLOOR, INK_RECALL_FLOOR;
3292
3300
  var init_visual_facts = __esm({
3293
- "packages/verify/src/visual-facts.ts"() {
3301
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/visual-facts.ts"() {
3294
3302
  "use strict";
3295
3303
  init_browser();
3296
3304
  init_mount_limits();
@@ -3303,19 +3311,19 @@ var init_visual_facts = __esm({
3303
3311
  }
3304
3312
  });
3305
3313
 
3306
- // packages/verify/src/paths.ts
3314
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/paths.ts
3307
3315
  import path8 from "node:path";
3308
3316
  import { fileURLToPath as fileURLToPath3 } from "node:url";
3309
3317
  var VERIFY_PKG_DIR, REPO_ROOT;
3310
3318
  var init_paths = __esm({
3311
- "packages/verify/src/paths.ts"() {
3319
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/paths.ts"() {
3312
3320
  "use strict";
3313
3321
  VERIFY_PKG_DIR = path8.resolve(path8.dirname(fileURLToPath3(import.meta.url)), "..");
3314
3322
  REPO_ROOT = path8.resolve(VERIFY_PKG_DIR, "..", "..");
3315
3323
  }
3316
3324
  });
3317
3325
 
3318
- // packages/verify/src/font-resolve.ts
3326
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/font-resolve.ts
3319
3327
  import { createHash } from "node:crypto";
3320
3328
  import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
3321
3329
  import os2 from "node:os";
@@ -3325,6 +3333,21 @@ function fontCacheDir() {
3325
3333
  if (env !== void 0 && env !== "") return path9.resolve(env);
3326
3334
  return path9.join(os2.homedir(), ".tendril", "fonts");
3327
3335
  }
3336
+ function normalizeFontLicense(value) {
3337
+ return typeof value === "string" && FONT_LICENSES.includes(value) ? value : "unknown";
3338
+ }
3339
+ async function googleFontMetadata(queryName) {
3340
+ try {
3341
+ const res = await fetch(`https://fonts.google.com/metadata/fonts/${encodeURIComponent(queryName)}`, { headers: { "User-Agent": UA } });
3342
+ if (!res.ok) return { license: "unknown", family: null };
3343
+ const parsed = JSON.parse((await res.text()).replace(/^\)\]\}'\s*/, ""));
3344
+ const family = typeof parsed.family === "string" && parsed.family !== "" ? parsed.family : null;
3345
+ if (parsed.isOpenSource !== true || typeof parsed.license !== "string") return { license: "unknown", family };
3346
+ return { license: GOOGLE_LICENSE_IDS.get(parsed.license.toLowerCase()) ?? "unknown", family };
3347
+ } catch {
3348
+ return { license: "unknown", family: null };
3349
+ }
3350
+ }
3328
3351
  function googleQueryCandidates(family) {
3329
3352
  const stripped = family.replace(/\s+(Variable|VF)$/i, "");
3330
3353
  return stripped === family ? [family] : [family, stripped];
@@ -3335,12 +3358,14 @@ async function resolveFonts(family, weights, cacheDir = DEFAULT_FONT_CACHE) {
3335
3358
  const failures = [];
3336
3359
  let css = null;
3337
3360
  let lastStatus = 0;
3361
+ let servedName = family;
3338
3362
  try {
3339
3363
  for (const queryName of googleQueryCandidates(family)) {
3340
3364
  const cssUrl = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(queryName).replace(/%20/g, "+")}:wght@${weights.join(";")}&display=swap`;
3341
3365
  const res = await fetch(cssUrl, { headers: { "User-Agent": UA } });
3342
3366
  if (res.ok) {
3343
3367
  css = await res.text();
3368
+ servedName = queryName;
3344
3369
  break;
3345
3370
  }
3346
3371
  lastStatus = res.status;
@@ -3354,6 +3379,7 @@ async function resolveFonts(family, weights, cacheDir = DEFAULT_FONT_CACHE) {
3354
3379
  } catch (err) {
3355
3380
  return { resolved, failures: weights.map((weight) => ({ family, weight, reason: `offline or fetch failed: ${err instanceof Error ? err.message : String(err)}` })) };
3356
3381
  }
3382
+ const meta = await googleFontMetadata(servedName);
3357
3383
  for (const weight of weights) {
3358
3384
  const blocks = [...css.matchAll(/@font-face\s*{[^}]*}/g)].map((m) => m[0]);
3359
3385
  const block = blocks.find((b) => b.includes(`font-weight: ${weight}`) && /unicode-range:[^;]*U\+0000/.test(b));
@@ -3372,7 +3398,7 @@ async function resolveFonts(family, weights, cacheDir = DEFAULT_FONT_CACHE) {
3372
3398
  const sha256 = createHash("sha256").update(bytes).digest("hex");
3373
3399
  const file = path9.join(cacheDir, `${family.toLowerCase().replace(/\s+/g, "-")}-${weight}.woff2`);
3374
3400
  writeFileSync3(file, bytes);
3375
- resolved.push({ family, weight, source: url, sha256, file });
3401
+ resolved.push({ family, weight, source: url, sha256, file, license: meta.license, ...meta.family !== null ? { servedFamily: meta.family } : {} });
3376
3402
  } catch (err) {
3377
3403
  failures.push({ family, weight, reason: `download failed: ${err instanceof Error ? err.message : String(err)}` });
3378
3404
  }
@@ -3398,7 +3424,7 @@ function addLocalFont(family, weight, filePath, cacheDir = DEFAULT_FONT_CACHE) {
3398
3424
  const sha256 = createHash("sha256").update(bytes).digest("hex");
3399
3425
  const file = path9.join(cacheDir, `${family.toLowerCase().replace(/\s+/g, "-")}-${weight}${ext}`);
3400
3426
  writeFileSync3(file, bytes);
3401
- const face = { family, weight, source: `local:${path9.basename(src)}`, sha256, file };
3427
+ const face = { family, weight, source: `local:${path9.basename(src)}`, sha256, file, license: "unknown" };
3402
3428
  const mPath = path9.join(cacheDir, "manifest.json");
3403
3429
  const prior = existsSync5(mPath) ? JSON.parse(readFileSync3(mPath, "utf8")) : [];
3404
3430
  const merged = [...prior.filter((p) => !(p.family === family && p.weight === weight)), { ...face, file: path9.basename(file) }];
@@ -3438,7 +3464,28 @@ function requiredFontsManifest(families, cacheDir = DEFAULT_FONT_CACHE) {
3438
3464
  const mPath = path9.join(cacheDir, "manifest.json");
3439
3465
  const manifest = existsSync5(mPath) ? JSON.parse(readFileSync3(mPath, "utf8")) : [];
3440
3466
  const wanted = new Set(families.map((f) => f.toLowerCase()));
3441
- return manifest.filter((f) => wanted.has(f.family.toLowerCase()));
3467
+ return manifest.filter((f) => wanted.has(f.family.toLowerCase())).map((f) => ({
3468
+ family: f.family,
3469
+ weight: f.weight,
3470
+ source: f.source,
3471
+ sha256: f.sha256,
3472
+ file: f.file,
3473
+ license: normalizeFontLicense(f.license),
3474
+ ...typeof f.servedFamily === "string" && f.servedFamily !== "" ? { servedFamily: f.servedFamily } : {}
3475
+ }));
3476
+ }
3477
+ function facesMissingLicense(cacheDir = DEFAULT_FONT_CACHE) {
3478
+ const mPath = path9.join(cacheDir, "manifest.json");
3479
+ if (!existsSync5(mPath)) return [];
3480
+ let entries;
3481
+ try {
3482
+ entries = JSON.parse(readFileSync3(mPath, "utf8"));
3483
+ } catch {
3484
+ return [];
3485
+ }
3486
+ return entries.filter(
3487
+ (e) => typeof e.family === "string" && typeof e.weight === "number" && typeof e.source === "string" && e.source.startsWith(GOOGLE_FONT_FILE_PREFIX) && !(typeof e.license === "string" && FONT_LICENSES.includes(e.license))
3488
+ ).map((e) => ({ family: e.family, weight: e.weight, sha256: e.sha256 }));
3442
3489
  }
3443
3490
  function verifiedFontFamilies(cacheDir = DEFAULT_FONT_CACHE) {
3444
3491
  const mPath = path9.join(cacheDir, "manifest.json");
@@ -3461,16 +3508,24 @@ function verifiedFontFamilies(cacheDir = DEFAULT_FONT_CACHE) {
3461
3508
  }
3462
3509
  return [...byFamily.entries()].map(([family, w]) => ({ family, weights: [...w].sort((a, b) => a - b) }));
3463
3510
  }
3464
- var DEFAULT_FONT_CACHE, UA;
3511
+ var DEFAULT_FONT_CACHE, UA, FONT_LICENSES, GOOGLE_LICENSE_IDS, GOOGLE_FONT_FILE_PREFIX;
3465
3512
  var init_font_resolve = __esm({
3466
- "packages/verify/src/font-resolve.ts"() {
3513
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/font-resolve.ts"() {
3467
3514
  "use strict";
3468
3515
  DEFAULT_FONT_CACHE = fontCacheDir();
3469
3516
  UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36";
3517
+ FONT_LICENSES = ["OFL-1.1", "Apache-2.0", "UFL-1.0", "proprietary", "unknown"];
3518
+ GOOGLE_LICENSE_IDS = /* @__PURE__ */ new Map([
3519
+ ["ofl", "OFL-1.1"],
3520
+ ["apache2", "Apache-2.0"],
3521
+ ["apache", "Apache-2.0"],
3522
+ ["ufl", "UFL-1.0"]
3523
+ ]);
3524
+ GOOGLE_FONT_FILE_PREFIX = "https://fonts.gstatic.com/";
3470
3525
  }
3471
3526
  });
3472
3527
 
3473
- // packages/verify/src/font-faces.ts
3528
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/font-faces.ts
3474
3529
  import { createHash as createHash2 } from "node:crypto";
3475
3530
  import { existsSync as existsSync6, readFileSync as readFileSync4 } from "node:fs";
3476
3531
  import path10 from "node:path";
@@ -3505,13 +3560,13 @@ function fontFaceCss(manifestPath2 = path10.join(fontCacheDir(), "manifest.json"
3505
3560
  }).join("\n");
3506
3561
  }
3507
3562
  var init_font_faces = __esm({
3508
- "packages/verify/src/font-faces.ts"() {
3563
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/font-faces.ts"() {
3509
3564
  "use strict";
3510
3565
  init_font_resolve();
3511
3566
  }
3512
3567
  });
3513
3568
 
3514
- // packages/verify/src/admission.ts
3569
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/admission.ts
3515
3570
  import { readFileSync as readFileSync5, readdirSync as readdirSync2, existsSync as existsSync7, writeFileSync as writeFileSync4 } from "node:fs";
3516
3571
  import path11 from "node:path";
3517
3572
  import { build as build2 } from "esbuild";
@@ -3528,7 +3583,7 @@ function fontWeightsByFamily() {
3528
3583
  }
3529
3584
  var FONT_WEIGHTS;
3530
3585
  var init_admission = __esm({
3531
- "packages/verify/src/admission.ts"() {
3586
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/admission.ts"() {
3532
3587
  "use strict";
3533
3588
  init_paths();
3534
3589
  init_src();
@@ -3541,11 +3596,11 @@ var init_admission = __esm({
3541
3596
  }
3542
3597
  });
3543
3598
 
3544
- // packages/verify/src/tasks.ts
3599
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/tasks.ts
3545
3600
  import path12 from "node:path";
3546
3601
  var CALENDAR_CONFIGS, CALENDAR_API, CALENDAR_BEHAVIORS, BUTTON_CONFIGS, BUTTON_API, COMBO_FIX, COMBO_CONFIGS, COMBO_API, MODAL_CONFIGS, MODAL_API, BUTTON_BEHAVIORS, COMBO_BEHAVIORS, MODAL_BEHAVIORS, TASKS;
3547
3602
  var init_tasks = __esm({
3548
- "packages/verify/src/tasks.ts"() {
3603
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/tasks.ts"() {
3549
3604
  "use strict";
3550
3605
  init_paths();
3551
3606
  CALENDAR_CONFIGS = [
@@ -3737,7 +3792,7 @@ BEHAVIORAL CONTRACT (machine-verified, gating): the primary action and close con
3737
3792
  }
3738
3793
  });
3739
3794
 
3740
- // packages/verify/src/behavior.ts
3795
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/behavior.ts
3741
3796
  var behavior_exports = {};
3742
3797
  __export(behavior_exports, {
3743
3798
  checkBehaviors: () => checkBehaviors,
@@ -4193,7 +4248,7 @@ body{margin:0;padding:20px}
4193
4248
  }
4194
4249
  var _fontFaces, ANIMATED_PROBE, COMMIT_GAP_CLOSED, POSE_GAP_FLOOR, PRELUDE_ROOT_PROPS;
4195
4250
  var init_behavior = __esm({
4196
- "packages/verify/src/behavior.ts"() {
4251
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/behavior.ts"() {
4197
4252
  "use strict";
4198
4253
  init_runtime();
4199
4254
  init_browser();
@@ -4228,7 +4283,7 @@ var init_behavior = __esm({
4228
4283
  }
4229
4284
  });
4230
4285
 
4231
- // packages/verify/src/bundle-quality.ts
4286
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/bundle-quality.ts
4232
4287
  import { readFileSync as readFileSync7, rmSync as rmSync2, writeFileSync as writeFileSync5, existsSync as existsSync9 } from "node:fs";
4233
4288
  import path14 from "node:path";
4234
4289
  function definedVars(tokensCss) {
@@ -4286,7 +4341,7 @@ async function checkBundleQuality(bundleDir, entry, set) {
4286
4341
  return { findings, tokensAbsent: tokensCss === void 0 && !/var\(\s*--/.test(css) };
4287
4342
  }
4288
4343
  var init_bundle_quality = __esm({
4289
- "packages/verify/src/bundle-quality.ts"() {
4344
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/bundle-quality.ts"() {
4290
4345
  "use strict";
4291
4346
  init_src();
4292
4347
  init_runtime();
@@ -4295,7 +4350,7 @@ var init_bundle_quality = __esm({
4295
4350
  }
4296
4351
  });
4297
4352
 
4298
- // packages/verify/src/effect-geometry.ts
4353
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/effect-geometry.ts
4299
4354
  function fold(into, dx, dy, radius, spread) {
4300
4355
  const reach = radius + spread;
4301
4356
  into.top = Math.max(into.top, reach - dy);
@@ -4327,13 +4382,13 @@ function extentsExplainPad(near, far, pad, tolerance = 2) {
4327
4382
  }
4328
4383
  var NO_EXTENTS;
4329
4384
  var init_effect_geometry = __esm({
4330
- "packages/verify/src/effect-geometry.ts"() {
4385
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/effect-geometry.ts"() {
4331
4386
  "use strict";
4332
4387
  NO_EXTENTS = { top: 0, right: 0, bottom: 0, left: 0 };
4333
4388
  }
4334
4389
  });
4335
4390
 
4336
- // packages/verify/src/bundle-score.ts
4391
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/bundle-score.ts
4337
4392
  import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "node:fs";
4338
4393
  import path15 from "node:path";
4339
4394
  import { build as build4 } from "esbuild";
@@ -4633,7 +4688,7 @@ body{margin:0;background:rgb(${backdrop.join(",")})}
4633
4688
  }
4634
4689
  var BAR, MARGIN, _fontFaces2, CONFIGS, SEAT_WINDOW, EFFECT_BLEED_MAX;
4635
4690
  var init_bundle_score = __esm({
4636
- "packages/verify/src/bundle-score.ts"() {
4691
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/bundle-score.ts"() {
4637
4692
  "use strict";
4638
4693
  init_runtime();
4639
4694
  init_browser();
@@ -4651,11 +4706,11 @@ var init_bundle_score = __esm({
4651
4706
  }
4652
4707
  });
4653
4708
 
4654
- // packages/verify/src/containment.ts
4709
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/containment.ts
4655
4710
  import { build as build5 } from "esbuild";
4656
4711
  import { chromium as chromium5 } from "playwright-core";
4657
4712
  var init_containment = __esm({
4658
- "packages/verify/src/containment.ts"() {
4713
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/containment.ts"() {
4659
4714
  "use strict";
4660
4715
  init_runtime();
4661
4716
  init_browser();
@@ -4665,10 +4720,10 @@ var init_containment = __esm({
4665
4720
  }
4666
4721
  });
4667
4722
 
4668
- // packages/verify/src/prelude.ts
4723
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/prelude.ts
4669
4724
  var PRELUDE_CONTRACT;
4670
4725
  var init_prelude = __esm({
4671
- "packages/verify/src/prelude.ts"() {
4726
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/prelude.ts"() {
4672
4727
  "use strict";
4673
4728
  PRELUDE_CONTRACT = `BUNDLE PRELUDE (machine-verified on computed styles \u2014 the harness page provides NONE of this; your CSS must):
4674
4729
  - Containment reset on the component subtree: margin 0, box-sizing border-box, line-height/letter-spacing/font-family inherited from the root (host globals must not leak in).
@@ -4680,7 +4735,7 @@ var init_prelude = __esm({
4680
4735
  }
4681
4736
  });
4682
4737
 
4683
- // packages/verify/src/parity.ts
4738
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/parity.ts
4684
4739
  import { existsSync as existsSync11, readFileSync as readFileSync9 } from "node:fs";
4685
4740
  import path16 from "node:path";
4686
4741
  import { chromium as chromium6 } from "playwright-core";
@@ -4780,7 +4835,7 @@ body{margin:0;padding:20px}
4780
4835
  }
4781
4836
  var _fontFaces3;
4782
4837
  var init_parity = __esm({
4783
- "packages/verify/src/parity.ts"() {
4838
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/parity.ts"() {
4784
4839
  "use strict";
4785
4840
  init_browser();
4786
4841
  init_behavior();
@@ -4789,7 +4844,7 @@ var init_parity = __esm({
4789
4844
  }
4790
4845
  });
4791
4846
 
4792
- // packages/verify/src/composition.ts
4847
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/composition.ts
4793
4848
  import { createRequire as createRequire2 } from "node:module";
4794
4849
  import { existsSync as existsSync12, readFileSync as readFileSync10 } from "node:fs";
4795
4850
  import path17 from "node:path";
@@ -5055,7 +5110,7 @@ body{margin:0;padding:20px}
5055
5110
  }
5056
5111
  var _fontFaces4, REAL_JSX_SPEC, JSX_SHIM, CROP_BAR, cropId;
5057
5112
  var init_composition = __esm({
5058
- "packages/verify/src/composition.ts"() {
5113
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/composition.ts"() {
5059
5114
  "use strict";
5060
5115
  init_runtime();
5061
5116
  init_browser();
@@ -5079,7 +5134,7 @@ export const jsxs = (t, p, k) => real.jsxs(t, inject(t, p), k);
5079
5134
  }
5080
5135
  });
5081
5136
 
5082
- // packages/verify/src/occlusion.ts
5137
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/occlusion.ts
5083
5138
  import { existsSync as existsSync13 } from "node:fs";
5084
5139
  import path18 from "node:path";
5085
5140
  import { build as build7 } from "esbuild";
@@ -5228,7 +5283,7 @@ body{margin:0;padding:16px;display:flex;flex-direction:column;gap:8px;align-item
5228
5283
  }
5229
5284
  var OVERLAY_SELECTOR;
5230
5285
  var init_occlusion = __esm({
5231
- "packages/verify/src/occlusion.ts"() {
5286
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/occlusion.ts"() {
5232
5287
  "use strict";
5233
5288
  init_runtime();
5234
5289
  init_browser();
@@ -5237,9 +5292,9 @@ var init_occlusion = __esm({
5237
5292
  }
5238
5293
  });
5239
5294
 
5240
- // packages/verify/src/index.ts
5295
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/index.ts
5241
5296
  var init_src4 = __esm({
5242
- "packages/verify/src/index.ts"() {
5297
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/index.ts"() {
5243
5298
  "use strict";
5244
5299
  init_browser();
5245
5300
  init_runtime();
@@ -5267,7 +5322,7 @@ var init_src4 = __esm({
5267
5322
  }
5268
5323
  });
5269
5324
 
5270
- // packages/cli/src/environment.ts
5325
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/environment.ts
5271
5326
  import { existsSync as existsSync14, readFileSync as readFileSync11 } from "node:fs";
5272
5327
  import path19 from "node:path";
5273
5328
  import { createHash as createHash3 } from "node:crypto";
@@ -5298,24 +5353,24 @@ function environmentStamp(taskFamilies) {
5298
5353
  } catch {
5299
5354
  }
5300
5355
  const ver = chrome === "unavailable" ? null : chromeVersion();
5301
- const lcdOff = lcdTextDisabled() ? " (lcd-text-disabled)" : "";
5302
- return { chrome, chromeVersion: ver === null ? null : ver + lcdOff, fontsManifestSha256: fontsHash };
5356
+ const lcdSuffix = lcdTextEnabled() ? " (lcd-text-enabled)" : "";
5357
+ return { chrome, chromeVersion: ver === null ? null : ver + lcdSuffix, fontsManifestSha256: fontsHash };
5303
5358
  }
5304
5359
  var init_environment = __esm({
5305
- "packages/cli/src/environment.ts"() {
5360
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/environment.ts"() {
5306
5361
  "use strict";
5307
5362
  init_src4();
5308
5363
  }
5309
5364
  });
5310
5365
 
5311
- // packages/cli/src/describe.ts
5366
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/describe.ts
5312
5367
  function printDescription(description) {
5313
5368
  process.stdout.write(`${JSON.stringify(description, null, 2)}
5314
5369
  `);
5315
5370
  }
5316
5371
  var COMMON_EXIT_CODES;
5317
5372
  var init_describe = __esm({
5318
- "packages/cli/src/describe.ts"() {
5373
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/describe.ts"() {
5319
5374
  "use strict";
5320
5375
  COMMON_EXIT_CODES = {
5321
5376
  0: "success",
@@ -5327,7 +5382,7 @@ var init_describe = __esm({
5327
5382
  }
5328
5383
  });
5329
5384
 
5330
- // packages/cli/src/env.ts
5385
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/env.ts
5331
5386
  import { existsSync as existsSync15, readFileSync as readFileSync12 } from "node:fs";
5332
5387
  import path20 from "node:path";
5333
5388
  function parseEnv(content) {
@@ -5346,12 +5401,12 @@ function resolveCredential(name) {
5346
5401
  return parseEnv(readFileSync12(envPath, "utf8")).get(name);
5347
5402
  }
5348
5403
  var init_env = __esm({
5349
- "packages/cli/src/env.ts"() {
5404
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/env.ts"() {
5350
5405
  "use strict";
5351
5406
  }
5352
5407
  });
5353
5408
 
5354
- // packages/cli/src/output.ts
5409
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/output.ts
5355
5410
  var output_exports = {};
5356
5411
  __export(output_exports, {
5357
5412
  PROGRESS_PREFIX: () => PROGRESS_PREFIX,
@@ -5395,14 +5450,14 @@ function warn(flags, message) {
5395
5450
  }
5396
5451
  var PROGRESS_PREFIX;
5397
5452
  var init_output = __esm({
5398
- "packages/cli/src/output.ts"() {
5453
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/output.ts"() {
5399
5454
  "use strict";
5400
5455
  init_src3();
5401
5456
  PROGRESS_PREFIX = "@tendril-progress ";
5402
5457
  }
5403
5458
  });
5404
5459
 
5405
- // packages/cli/src/entitlement.ts
5460
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/entitlement.ts
5406
5461
  import { chmodSync, existsSync as existsSync16, mkdirSync as mkdirSync4, readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "node:fs";
5407
5462
  import crypto from "node:crypto";
5408
5463
  import os3 from "node:os";
@@ -5490,7 +5545,7 @@ function requireEntitlement(flags) {
5490
5545
  }
5491
5546
  var ENT_PREFIX, PUBLIC_KEYS, TOLERANCE_MS, CLOCK_ROLLBACK_MS, b64urlDecode, ACTIVATE_REMEDIATION;
5492
5547
  var init_entitlement = __esm({
5493
- "packages/cli/src/entitlement.ts"() {
5548
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/entitlement.ts"() {
5494
5549
  "use strict";
5495
5550
  init_src3();
5496
5551
  init_output();
@@ -5503,7 +5558,7 @@ var init_entitlement = __esm({
5503
5558
  }
5504
5559
  });
5505
5560
 
5506
- // packages/cli/src/commands/doctor.ts
5561
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/doctor.ts
5507
5562
  import { spawnSync } from "node:child_process";
5508
5563
  import { existsSync as existsSync17, readFileSync as readFileSync14, readdirSync as readdirSync3 } from "node:fs";
5509
5564
  import os4 from "node:os";
@@ -5542,7 +5597,7 @@ async function runDoctorChecks(options) {
5542
5597
  );
5543
5598
  try {
5544
5599
  const chrome = resolveChrome();
5545
- checks.push({ name: "browser", ok: true, detail: `${chromeVersion() ?? "version unknown"}${lcdTextDisabled() ? " \u2014 EXPERIMENT override active (lcd-text-disabled): scores not comparable to default runs" : ""} at ${chrome}` });
5600
+ checks.push({ name: "browser", ok: true, detail: `${chromeVersion() ?? "version unknown"}${lcdTextEnabled() ? " \u2014 EXPERIMENT override active (lcd-text-enabled): scores not comparable to canonical greyscale runs" : ""} at ${chrome}` });
5546
5601
  } catch (err) {
5547
5602
  checks.push({
5548
5603
  name: "browser",
@@ -5680,7 +5735,7 @@ async function runDoctor(flags) {
5680
5735
  }
5681
5736
  var DEFAULT_MCP_URL, DOCTOR_DESCRIPTION;
5682
5737
  var init_doctor = __esm({
5683
- "packages/cli/src/commands/doctor.ts"() {
5738
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/doctor.ts"() {
5684
5739
  "use strict";
5685
5740
  init_src4();
5686
5741
  init_src();
@@ -5708,7 +5763,7 @@ var init_doctor = __esm({
5708
5763
  }
5709
5764
  });
5710
5765
 
5711
- // packages/llm/src/model-config.ts
5766
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/model-config.ts
5712
5767
  import { z as z6 } from "zod";
5713
5768
  function resolveModel(config, requestedId) {
5714
5769
  const entry = config.allowlist.find((m) => m.id === requestedId);
@@ -5729,7 +5784,7 @@ function resolveModel(config, requestedId) {
5729
5784
  }
5730
5785
  var ModelStatusSchema, ModelEntrySchema, ModelConfigSchema, DEFAULT_MODEL_CONFIG;
5731
5786
  var init_model_config = __esm({
5732
- "packages/llm/src/model-config.ts"() {
5787
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/model-config.ts"() {
5733
5788
  "use strict";
5734
5789
  ModelStatusSchema = z6.enum(["verified", "degraded"]);
5735
5790
  ModelEntrySchema = z6.object({
@@ -5818,10 +5873,10 @@ var init_model_config = __esm({
5818
5873
  }
5819
5874
  });
5820
5875
 
5821
- // packages/llm/src/openrouter.ts
5876
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/openrouter.ts
5822
5877
  var FALLBACK_KINDS, DEFAULT_REQUEST_TIMEOUT_MS, OpenRouterClient;
5823
5878
  var init_openrouter = __esm({
5824
- "packages/llm/src/openrouter.ts"() {
5879
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/openrouter.ts"() {
5825
5880
  "use strict";
5826
5881
  FALLBACK_KINDS = /* @__PURE__ */ new Set(["rate-limit", "server", "network", "timeout"]);
5827
5882
  DEFAULT_REQUEST_TIMEOUT_MS = 6e5;
@@ -5948,7 +6003,7 @@ var init_openrouter = __esm({
5948
6003
  }
5949
6004
  });
5950
6005
 
5951
- // packages/llm/src/semantics.ts
6006
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/semantics.ts
5952
6007
  import { z as z7 } from "zod";
5953
6008
  function portable(node) {
5954
6009
  if (Array.isArray(node)) return node.map(portable);
@@ -5986,7 +6041,7 @@ function docsJsonSchema() {
5986
6041
  }
5987
6042
  var PropTypeSchema, SemanticsSchema, CodegenOutputSchema, DocsOutputSchema;
5988
6043
  var init_semantics = __esm({
5989
- "packages/llm/src/semantics.ts"() {
6044
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/semantics.ts"() {
5990
6045
  "use strict";
5991
6046
  PropTypeSchema = z7.discriminatedUnion("kind", [
5992
6047
  z7.object({ kind: z7.literal("enum"), values: z7.array(z7.string()).min(1) }),
@@ -6075,10 +6130,10 @@ var init_semantics = __esm({
6075
6130
  }
6076
6131
  });
6077
6132
 
6078
- // packages/llm/src/golden/button.ts
6133
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/golden/button.ts
6079
6134
  var goldenButtonSemantics, goldenButtonCode, goldenButtonDocs;
6080
6135
  var init_button2 = __esm({
6081
- "packages/llm/src/golden/button.ts"() {
6136
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/golden/button.ts"() {
6082
6137
  "use strict";
6083
6138
  goldenButtonSemantics = {
6084
6139
  componentName: "Button",
@@ -6236,7 +6291,7 @@ handling come from the platform.
6236
6291
  }
6237
6292
  });
6238
6293
 
6239
- // packages/llm/src/prompt.ts
6294
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/prompt.ts
6240
6295
  function buildStablePrefix(input) {
6241
6296
  const tokens = [...input.tokenLines].sort().join("\n");
6242
6297
  const golden = `GOLDEN EXAMPLE (canonical quality bar)
@@ -6270,7 +6325,7 @@ ${input.irJson}` });
6270
6325
  }
6271
6326
  var SYSTEM_RULES;
6272
6327
  var init_prompt = __esm({
6273
- "packages/llm/src/prompt.ts"() {
6328
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/prompt.ts"() {
6274
6329
  "use strict";
6275
6330
  init_button2();
6276
6331
  SYSTEM_RULES = `You generate production React components from a design-system IR.
@@ -6366,10 +6421,10 @@ strictly in the requested JSON shape.`;
6366
6421
  }
6367
6422
  });
6368
6423
 
6369
- // packages/llm/src/generation-model.ts
6424
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/generation-model.ts
6370
6425
  var MockGenerationModel, MAX_SCHEMA_ATTEMPTS, OpenRouterGenerationModel;
6371
6426
  var init_generation_model = __esm({
6372
- "packages/llm/src/generation-model.ts"() {
6427
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/generation-model.ts"() {
6373
6428
  "use strict";
6374
6429
  init_openrouter();
6375
6430
  init_prompt();
@@ -6526,9 +6581,9 @@ ${JSON.stringify(semantics)}`,
6526
6581
  }
6527
6582
  });
6528
6583
 
6529
- // packages/llm/src/index.ts
6584
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/index.ts
6530
6585
  var init_src5 = __esm({
6531
- "packages/llm/src/index.ts"() {
6586
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/index.ts"() {
6532
6587
  "use strict";
6533
6588
  init_model_config();
6534
6589
  init_openrouter();
@@ -6539,11 +6594,11 @@ var init_src5 = __esm({
6539
6594
  }
6540
6595
  });
6541
6596
 
6542
- // packages/metadata/src/component-json.ts
6597
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/metadata/src/component-json.ts
6543
6598
  import { z as z8 } from "zod";
6544
6599
  var TokenUseSchema, AntiPatternSchema, ComponentJsonSchema;
6545
6600
  var init_component_json = __esm({
6546
- "packages/metadata/src/component-json.ts"() {
6601
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/metadata/src/component-json.ts"() {
6547
6602
  "use strict";
6548
6603
  TokenUseSchema = z8.object({
6549
6604
  /** DTCG token path, e.g. "color.primary". */
@@ -6595,7 +6650,7 @@ var init_component_json = __esm({
6595
6650
  }
6596
6651
  });
6597
6652
 
6598
- // packages/metadata/src/extract.ts
6653
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/metadata/src/extract.ts
6599
6654
  import { parse } from "react-docgen";
6600
6655
  function extractProps(tsxSource, filename) {
6601
6656
  const docs = parse(tsxSource, { filename });
@@ -6668,17 +6723,74 @@ function buildComponentJson(input) {
6668
6723
  });
6669
6724
  }
6670
6725
  var init_extract = __esm({
6671
- "packages/metadata/src/extract.ts"() {
6726
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/metadata/src/extract.ts"() {
6672
6727
  "use strict";
6673
6728
  init_component_json();
6674
6729
  }
6675
6730
  });
6676
6731
 
6677
- // packages/metadata/src/recording-set.ts
6732
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/metadata/src/recording-set.ts
6678
6733
  import { z as z9 } from "zod";
6679
- var RECORDING_SET_VERSION, EnvelopeSchema, RepEntrySchema, RolesSchema, RecordingSetManifestSchema;
6734
+ function roleLossToken(loss) {
6735
+ return loss.kind === "main" ? `main:${loss.main}` : `part:${loss.part}${EDGE_ARROW}${loss.main}`;
6736
+ }
6737
+ function parseRoleLossToken(token) {
6738
+ if (token.startsWith("main:")) {
6739
+ const main2 = token.slice("main:".length);
6740
+ return main2 === "" ? void 0 : { kind: "main", main: main2 };
6741
+ }
6742
+ if (!token.startsWith("part:")) return void 0;
6743
+ const [part, main, ...rest] = token.slice("part:".length).split(EDGE_ARROW);
6744
+ if (rest.length > 0 || part === void 0 || part === "" || main === void 0 || main === "") return void 0;
6745
+ return { kind: "edge", part, main };
6746
+ }
6747
+ function validateRecordingSet(manifest, fileExists) {
6748
+ const issues = [];
6749
+ const parsed = RecordingSetManifestSchema.safeParse(manifest);
6750
+ if (!parsed.success) {
6751
+ return {
6752
+ issues: [
6753
+ {
6754
+ severity: "error",
6755
+ message: `manifest does not match recording-set layout v${RECORDING_SET_VERSION}: ${parsed.error.issues.slice(0, 3).map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`
6756
+ }
6757
+ ]
6758
+ };
6759
+ }
6760
+ const m = parsed.data;
6761
+ const slugs = /* @__PURE__ */ new Set();
6762
+ for (const rep of m.reps) {
6763
+ if (slugs.has(rep.slug)) issues.push({ severity: "error", message: `duplicate rep slug "${rep.slug}"` });
6764
+ slugs.add(rep.slug);
6765
+ for (const f of REQUIRED_REP_FILES) {
6766
+ if (!fileExists(`${rep.slug}/${f}`)) issues.push({ severity: "error", message: `${rep.slug}: missing ${f}` });
6767
+ }
6768
+ if (rep.sourceFrame !== void 0 && m.sourceFrames?.[rep.sourceFrame] === void 0)
6769
+ issues.push({ severity: "warning", message: `${rep.slug}: sourceFrame ${rep.sourceFrame} not described in sourceFrames` });
6770
+ }
6771
+ if (m.roles !== void 0) {
6772
+ for (const slug of m.roles.main)
6773
+ if (!slugs.has(slug)) issues.push({ severity: "error", message: `roles.main references unknown slug "${slug}"` });
6774
+ for (const [slug, part] of Object.entries(m.roles.parts)) {
6775
+ if (!slugs.has(slug)) issues.push({ severity: "error", message: `roles.parts references unknown slug "${slug}"` });
6776
+ for (const of of part.partOf)
6777
+ if (!m.roles.main.includes(of)) issues.push({ severity: "error", message: `roles.parts["${slug}"].partOf references non-main "${of}"` });
6778
+ }
6779
+ for (const token of m.roles.narrowingAccepted ?? []) {
6780
+ const loss = parseRoleLossToken(token);
6781
+ if (loss === void 0) {
6782
+ issues.push({ severity: "error", message: `roles.narrowingAccepted entry "${token}" is not "main:<slug>" or "part:<part-slug>-><main-slug>"` });
6783
+ continue;
6784
+ }
6785
+ for (const slug of loss.kind === "main" ? [loss.main] : [loss.part, loss.main])
6786
+ if (!slugs.has(slug)) issues.push({ severity: "error", message: `roles.narrowingAccepted "${token}" references unknown slug "${slug}"` });
6787
+ }
6788
+ }
6789
+ return { manifest: m, issues };
6790
+ }
6791
+ var RECORDING_SET_VERSION, EnvelopeSchema, RepEntrySchema, RolesSchema, EDGE_ARROW, RecordingSetManifestSchema, REQUIRED_REP_FILES;
6680
6792
  var init_recording_set = __esm({
6681
- "packages/metadata/src/recording-set.ts"() {
6793
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/metadata/src/recording-set.ts"() {
6682
6794
  "use strict";
6683
6795
  RECORDING_SET_VERSION = 1;
6684
6796
  EnvelopeSchema = z9.object({
@@ -6709,10 +6821,21 @@ var init_recording_set = __esm({
6709
6821
  * derivation — disclosed, never silently dropped (Calendar's Icon
6710
6822
  * Buttons; unrecorded base variants). */
6711
6823
  external: z9.array(z9.string()).optional(),
6712
- /** True when a human override changed derived roles (surfaced in
6713
- * provenance downstream). */
6714
- humanOverride: z9.boolean().optional()
6824
+ /** Where this graph came from. A graph with empty `parts` makes the
6825
+ * structural composition check return an affirmative PASS, so a
6826
+ * human-authored override and a derived graph must never be
6827
+ * indistinguishable in a report. The CLI stamps this itself — a
6828
+ * supplied roles file cannot claim "derived" for itself. */
6829
+ rolesSource: z9.enum(["derived", "human-override"]).optional(),
6830
+ /** Losses in the DERIVED relation a human override deliberately
6831
+ * accepts, one token per loss (`roleLossToken`). Named one by one on
6832
+ * purpose: emptying out what composition measures — by dropping a
6833
+ * main, or by dropping/re-pointing a part→main edge — is exactly what
6834
+ * turns composition into a vacuous pass, so it is an acceptance
6835
+ * someone signs rather than an omission nobody notices. */
6836
+ narrowingAccepted: z9.array(z9.string()).optional()
6715
6837
  });
6838
+ EDGE_ARROW = "->";
6716
6839
  RecordingSetManifestSchema = z9.object({
6717
6840
  version: z9.literal(RECORDING_SET_VERSION),
6718
6841
  /** Human-readable component/system name. */
@@ -6724,10 +6847,11 @@ var init_recording_set = __esm({
6724
6847
  notRecorded: z9.string().optional(),
6725
6848
  roles: RolesSchema.optional()
6726
6849
  });
6850
+ REQUIRED_REP_FILES = ["get_design_context.json", "get_metadata.json", "get_screenshot.json"];
6727
6851
  }
6728
6852
  });
6729
6853
 
6730
- // packages/metadata/src/bundle.ts
6854
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/metadata/src/bundle.ts
6731
6855
  import { z as z10 } from "zod";
6732
6856
  function readBundleManifest(raw) {
6733
6857
  if (Buffer.byteLength(raw, "utf8") > MAX_BUNDLE_MANIFEST_BYTES) {
@@ -6796,7 +6920,7 @@ function hashRecordingSet(relPaths, readFile, sha256) {
6796
6920
  }
6797
6921
  var BUNDLE_VERSION, ConfigStatusSchema, PinnedPropSchema, PropAdapterSchema, RequiredFontSchema, ConfigClaimSchema, BehaviorClaimSchema, BundleProvenanceSchema, BundleComponentJsonSchema, MAX_BUNDLE_MANIFEST_BYTES, MAX_BUNDLE_SOURCE_BYTES;
6798
6922
  var init_bundle = __esm({
6799
- "packages/metadata/src/bundle.ts"() {
6923
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/metadata/src/bundle.ts"() {
6800
6924
  "use strict";
6801
6925
  init_recording_set();
6802
6926
  BUNDLE_VERSION = 1;
@@ -6894,9 +7018,9 @@ var init_bundle = __esm({
6894
7018
  }
6895
7019
  });
6896
7020
 
6897
- // packages/metadata/src/index.ts
7021
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/metadata/src/index.ts
6898
7022
  var init_src6 = __esm({
6899
- "packages/metadata/src/index.ts"() {
7023
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/metadata/src/index.ts"() {
6900
7024
  "use strict";
6901
7025
  init_component_json();
6902
7026
  init_extract();
@@ -6905,7 +7029,7 @@ var init_src6 = __esm({
6905
7029
  }
6906
7030
  });
6907
7031
 
6908
- // packages/cli/src/commands/activate.ts
7032
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/activate.ts
6909
7033
  var activate_exports = {};
6910
7034
  __export(activate_exports, {
6911
7035
  ENTITLEMENT_SERVICE_URL: () => ENTITLEMENT_SERVICE_URL,
@@ -6990,7 +7114,7 @@ Waiting for approval\u2026
6990
7114
  }
6991
7115
  var ENTITLEMENT_SERVICE_URL;
6992
7116
  var init_activate = __esm({
6993
- "packages/cli/src/commands/activate.ts"() {
7117
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/activate.ts"() {
6994
7118
  "use strict";
6995
7119
  init_src3();
6996
7120
  init_entitlement();
@@ -6999,12 +7123,13 @@ var init_activate = __esm({
6999
7123
  }
7000
7124
  });
7001
7125
 
7002
- // packages/cli/src/commands/record.ts
7126
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/record.ts
7003
7127
  var record_exports = {};
7004
7128
  __export(record_exports, {
7005
7129
  instanceLeads: () => instanceLeads,
7006
7130
  isFigmaAssetUrl: () => isFigmaAssetUrl,
7007
7131
  isLocalAssetUrl: () => isLocalAssetUrl,
7132
+ narrowedRoles: () => narrowedRoles,
7008
7133
  nextPayload: () => nextPayload,
7009
7134
  runRecordAsset: () => runRecordAsset,
7010
7135
  runRecordFetch: () => runRecordFetch,
@@ -7541,11 +7666,66 @@ ${status.reps.filter((r) => r.missing.length > 0).length} rep(s) pending
7541
7666
  `);
7542
7667
  });
7543
7668
  }
7669
+ function narrowedRoles(derived, override) {
7670
+ const losses = [];
7671
+ const mains = new Set(override.main);
7672
+ for (const main of derived.main) if (!mains.has(main)) losses.push({ kind: "main", main });
7673
+ for (const [part, entry] of Object.entries(derived.parts))
7674
+ for (const main of entry.partOf) if (override.parts[part]?.partOf.includes(main) !== true) losses.push({ kind: "edge", part, main });
7675
+ return losses.sort((a, b) => roleLossToken(a) < roleLossToken(b) ? -1 : 1);
7676
+ }
7677
+ function rolesFromFile(opts, file, derived) {
7678
+ let json;
7679
+ try {
7680
+ json = JSON.parse(readFileSync16(path25.resolve(file), "utf8"));
7681
+ } catch (err) {
7682
+ fail(opts, ExitCode.InputValidation, {
7683
+ error: `cannot read roles file ${file}: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`,
7684
+ code: "roles-file-unreadable",
7685
+ remediation: 'The roles file is JSON: {"main":["<slug>"],"parts":{"<slug>":{"partOf":["<main-slug>"]}}}.'
7686
+ });
7687
+ }
7688
+ const parsed = RolesSchema.safeParse(json);
7689
+ if (!parsed.success) {
7690
+ fail(opts, ExitCode.InputValidation, {
7691
+ error: `roles file rejected: ${parsed.error.issues.slice(0, 3).map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`,
7692
+ code: "roles-file-invalid",
7693
+ remediation: 'The roles file is JSON: {"main":["<slug>"],"parts":{"<slug>":{"partOf":["<main-slug>"]}},"external":["\u2026"]}.'
7694
+ });
7695
+ }
7696
+ const accepted = parsed.data.narrowingAccepted ?? [];
7697
+ const unaccepted = narrowedRoles(derived, parsed.data).filter((loss) => !accepted.includes(roleLossToken(loss)));
7698
+ if (unaccepted.length > 0) {
7699
+ fail(opts, ExitCode.InputValidation, {
7700
+ error: `roles file narrows what this set's derivation found: it ${unaccepted.map(describeRoleLoss).join("; ")} \u2014 a main the graph never names is not composition-checked at all, and a main whose graph names no parts passes the check vacuously`,
7701
+ code: "roles-file-narrows",
7702
+ remediation: `Keep the derived mains and part edges in the graph, or accept each loss by name: add "narrowingAccepted": ${JSON.stringify(
7703
+ [.../* @__PURE__ */ new Set([...accepted, ...unaccepted.map(roleLossToken)])].sort()
7704
+ )} to the roles file.`
7705
+ });
7706
+ }
7707
+ return {
7708
+ main: parsed.data.main,
7709
+ parts: parsed.data.parts,
7710
+ ...parsed.data.external !== void 0 ? { external: parsed.data.external } : {},
7711
+ ...accepted.length > 0 ? { narrowingAccepted: accepted } : {},
7712
+ // Stamped by the CLI, never read from the file: a supplied graph
7713
+ // does not get to describe itself as derived.
7714
+ rolesSource: "human-override"
7715
+ };
7716
+ }
7544
7717
  function runRecordFinish(opts) {
7545
- const manifest = loadManifest(opts.setDir);
7718
+ if (!existsSync19(path25.join(opts.setDir, "recording-set.json"))) {
7719
+ fail(opts, ExitCode.InputValidation, {
7720
+ error: `no recording-set.json in ${opts.setDir}`,
7721
+ code: "no-recording-set",
7722
+ remediation: `Run \`tendril record plan --set ${opts.setDir} --component <name> --metadata <envelope.json>\` first \u2014 \`record finish\` closes a set the planner opened.`
7723
+ });
7724
+ }
7725
+ const { manifest, raw } = readManifestFile(opts.setDir);
7546
7726
  const derived = deriveRoles(opts.setDir, manifest);
7547
- const roles = opts.rolesFile !== void 0 ? { ...JSON.parse(readFileSync16(path25.resolve(opts.rolesFile), "utf8")), humanOverride: true } : { main: derived.main, parts: derived.parts, external: derived.external, humanOverride: false };
7548
- emitData(opts, { derived, confirmed: opts.confirmRoles }, () => {
7727
+ const roles = opts.rolesFile !== void 0 ? rolesFromFile(opts, opts.rolesFile, derived) : { main: derived.main, parts: derived.parts, external: derived.external, rolesSource: "derived" };
7728
+ emitData(opts, { derived, confirmed: opts.confirmRoles, rolesSource: roles.rolesSource, narrowingAccepted: roles.narrowingAccepted ?? [] }, () => {
7549
7729
  process.stdout.write(`derived mains: ${derived.main.join(", ") || "(none)"}
7550
7730
  `);
7551
7731
  for (const [slug, part] of Object.entries(derived.parts)) process.stdout.write(` part ${slug} \u2192 ${part.partOf.join(", ")}
@@ -7570,32 +7750,47 @@ function runRecordFinish(opts) {
7570
7750
  remediation: "A human runs `tendril record finish --set <dir> --confirm-roles` in their own terminal. Agents: show the proposal to your operator instead of confirming it."
7571
7751
  });
7572
7752
  }
7573
- const updated = { ...manifest, roles };
7574
- writeFileSync9(path25.join(opts.setDir, "recording-set.json"), `${JSON.stringify(updated, null, 1)}
7753
+ const merged = { ...raw, roles };
7754
+ const { issues } = validateRecordingSet(merged, (rel) => existsSync19(path25.join(opts.setDir, rel)));
7755
+ const errors = issues.filter((i) => i.severity === "error");
7756
+ if (errors.length > 0) {
7757
+ fail(opts, ExitCode.InputValidation, {
7758
+ error: `recording set rejected \u2014 roles NOT written: ${errors.map((e) => e.message).join("; ")}`,
7759
+ code: "recording-set-invalid",
7760
+ remediation: "Fix the set (`tendril record status --set <dir>` lists missing envelopes) or the roles graph, then re-run `record finish`."
7761
+ });
7762
+ }
7763
+ for (const issue of issues) if (issue.severity === "warning") warn(opts, issue.message);
7764
+ writeManifest(opts.setDir, merged);
7765
+ if (!opts.json) {
7766
+ const accepted = roles.narrowingAccepted ?? [];
7767
+ process.stdout.write(`roles written to recording-set.json (source: ${roles.rolesSource})${accepted.length > 0 ? ` \u2014 narrowing accepted by name: ${accepted.join(", ")}` : ""}
7575
7768
  `);
7576
- if (!opts.json) process.stdout.write("roles written to recording-set.json\n");
7769
+ }
7577
7770
  }
7578
- var ENVELOPE_HELP, isAutoFetchAssetUrl;
7771
+ var ENVELOPE_HELP, isAutoFetchAssetUrl, describeRoleLoss;
7579
7772
  var init_record = __esm({
7580
- "packages/cli/src/commands/record.ts"() {
7773
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/record.ts"() {
7581
7774
  "use strict";
7582
7775
  init_src3();
7583
7776
  init_src();
7777
+ init_src6();
7584
7778
  init_output();
7585
7779
  init_entitlement();
7586
7780
  ENVELOPE_HELP = 'Envelope format: text tools save {"content":[{"type":"text","text":"<VERBATIM response text incl. any Currently-selected-nodes block>"}]}; get_screenshot: do NOT download the image yourself \u2014 pass its image_url to `tendril record fetch` (MCP: tendril_record_fetch), which pulls the bytes to disk directly. That keeps the pixel ground truth out of your context and costs one approval instead of a shell command per asset. Assets are asset-<first-8-hex-of-figma-uuid>.<ext>; their URLs appear as const declarations inside the design-context text and also expire.';
7587
7781
  isAutoFetchAssetUrl = (url) => isFigmaAssetUrl(url) || isLocalAssetUrl(url);
7782
+ describeRoleLoss = (loss) => loss.kind === "main" ? `drops main "${loss.main}"` : `stops "${loss.part}" being a part of main "${loss.main}"`;
7588
7783
  }
7589
7784
  });
7590
7785
 
7591
- // packages/generate/src/engine.ts
7786
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/engine.ts
7592
7787
  var init_engine = __esm({
7593
- "packages/generate/src/engine.ts"() {
7788
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/engine.ts"() {
7594
7789
  "use strict";
7595
7790
  }
7596
7791
  });
7597
7792
 
7598
- // packages/generate/src/parse.ts
7793
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/parse.ts
7599
7794
  function parseFiles(text, entry) {
7600
7795
  const out = /* @__PURE__ */ new Map();
7601
7796
  const re = /```[a-z]*[^\n]*\n(?:\/\/|\/\*)[ \t]*FILE:[ \t]*([\w.]+)[ \t]*(?:\*\/)?[ \t]*\n([\s\S]*?)```/g;
@@ -7628,15 +7823,15 @@ ${content}\`\`\``);
7628
7823
  return blocks.join("\n");
7629
7824
  }
7630
7825
  var init_parse = __esm({
7631
- "packages/generate/src/parse.ts"() {
7826
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/parse.ts"() {
7632
7827
  "use strict";
7633
7828
  }
7634
7829
  });
7635
7830
 
7636
- // packages/generate/src/engine-curated.ts
7831
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/engine-curated.ts
7637
7832
  var CuratedEngine;
7638
7833
  var init_engine_curated = __esm({
7639
- "packages/generate/src/engine-curated.ts"() {
7834
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/engine-curated.ts"() {
7640
7835
  "use strict";
7641
7836
  init_parse();
7642
7837
  CuratedEngine = class {
@@ -7774,7 +7969,7 @@ var init_engine_curated = __esm({
7774
7969
  }
7775
7970
  });
7776
7971
 
7777
- // packages/generate/src/loop.ts
7972
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/loop.ts
7778
7973
  import { existsSync as existsSync20, mkdirSync as mkdirSync6, readFileSync as readFileSync17, renameSync, writeFileSync as writeFileSync10 } from "node:fs";
7779
7974
  import path26 from "node:path";
7780
7975
  import { z as z11 } from "zod";
@@ -7968,7 +8163,7 @@ async function runEngineLoop(opts) {
7968
8163
  }
7969
8164
  var better, RegionSchema, ConfigScoreSchema, BehaviorResultSchema, LoopStateSchema;
7970
8165
  var init_loop2 = __esm({
7971
- "packages/generate/src/loop.ts"() {
8166
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/loop.ts"() {
7972
8167
  "use strict";
7973
8168
  better = (a, b) => a[0] !== b[0] ? a[0] > b[0] : a[1] !== b[1] ? a[1] > b[1] : a[2] > b[2];
7974
8169
  RegionSchema = z11.object({ x0: z11.number(), y0: z11.number(), x1: z11.number(), y1: z11.number(), density: z11.number() });
@@ -8013,7 +8208,7 @@ var init_loop2 = __esm({
8013
8208
  }
8014
8209
  });
8015
8210
 
8016
- // packages/generate/src/brief.ts
8211
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/brief.ts
8017
8212
  import { existsSync as existsSync21, readFileSync as readFileSync18 } from "node:fs";
8018
8213
  import path27 from "node:path";
8019
8214
  function singleAxes2(name) {
@@ -8606,7 +8801,7 @@ RESOLVED FOR THIS RECORDING: it is ${opts.colorScheme}-mode truth, so pin color-
8606
8801
  }
8607
8802
  var PoseCompletenessError, kebab3, camel, pascal, RESERVED_PROPS, axisPropName, isStateAxis, DISMISS_NAMES, symbolName, STYLE_WEIGHTS2, styleWeight;
8608
8803
  var init_brief = __esm({
8609
- "packages/generate/src/brief.ts"() {
8804
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/brief.ts"() {
8610
8805
  "use strict";
8611
8806
  init_src();
8612
8807
  init_src4();
@@ -8660,7 +8855,7 @@ var init_brief = __esm({
8660
8855
  }
8661
8856
  });
8662
8857
 
8663
- // packages/generate/src/segments.ts
8858
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/segments.ts
8664
8859
  import { existsSync as existsSync22, readFileSync as readFileSync19, readdirSync as readdirSync6 } from "node:fs";
8665
8860
  import path28 from "node:path";
8666
8861
  function repText(set, rep, tool) {
@@ -8792,14 +8987,14 @@ Write the COMPLETE files (${task.entry}, styles.css, optional tokens.css) into y
8792
8987
  }
8793
8988
  var cssIdent;
8794
8989
  var init_segments = __esm({
8795
- "packages/generate/src/segments.ts"() {
8990
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/segments.ts"() {
8796
8991
  "use strict";
8797
8992
  init_src();
8798
8993
  cssIdent = (name) => name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
8799
8994
  }
8800
8995
  });
8801
8996
 
8802
- // packages/generate/src/consent.ts
8997
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/consent.ts
8803
8998
  function formatConsentLines(e) {
8804
8999
  return [
8805
9000
  `engine=${e.engineId} model=${e.modelId} route=${e.providerRoute}`,
@@ -8809,12 +9004,12 @@ function formatConsentLines(e) {
8809
9004
  ];
8810
9005
  }
8811
9006
  var init_consent = __esm({
8812
- "packages/generate/src/consent.ts"() {
9007
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/consent.ts"() {
8813
9008
  "use strict";
8814
9009
  }
8815
9010
  });
8816
9011
 
8817
- // packages/generate/src/adapter.ts
9012
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/adapter.ts
8818
9013
  function resolveAdapterSettings(entry, overrides = {}) {
8819
9014
  const notes = [];
8820
9015
  let maxTokens = DEFAULT_MAX_TOKENS;
@@ -8846,13 +9041,13 @@ function resolveAdapterSettings(entry, overrides = {}) {
8846
9041
  }
8847
9042
  var DEFAULT_MAX_TOKENS;
8848
9043
  var init_adapter = __esm({
8849
- "packages/generate/src/adapter.ts"() {
9044
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/adapter.ts"() {
8850
9045
  "use strict";
8851
9046
  DEFAULT_MAX_TOKENS = 2e4;
8852
9047
  }
8853
9048
  });
8854
9049
 
8855
- // packages/generate/src/bundle-emit.ts
9050
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/bundle-emit.ts
8856
9051
  import { createHash as createHash4 } from "node:crypto";
8857
9052
  import { copyFileSync, existsSync as existsSync23, mkdirSync as mkdirSync7, readFileSync as readFileSync20, readdirSync as readdirSync7, rmSync as rmSync3, writeFileSync as writeFileSync11 } from "node:fs";
8858
9053
  import path29 from "node:path";
@@ -8903,6 +9098,11 @@ function cssFontFamilies(css) {
8903
9098
  }
8904
9099
  return [...out];
8905
9100
  }
9101
+ function upstreamAttribution(face) {
9102
+ if (!face.source.startsWith(GOOGLE_FONT_FILE_PREFIX)) return face.source;
9103
+ if (face.servedFamily === void 0) return `the Google Fonts specimen for "${face.family.replace(/[\r\n]+/g, " ")}"`;
9104
+ return `https://fonts.google.com/specimen/${encodeURIComponent(face.servedFamily).replace(/%20/g, "+")}/license`;
9105
+ }
8906
9106
  function fontsCssFor(faces, bundleDir, cacheDir = DEFAULT_FONT_CACHE, substitutedFamilies = []) {
8907
9107
  const header = [
8908
9108
  "/* tendril fonts.css \u2014 the exact faces this bundle was scored with (sha-pinned in",
@@ -8916,27 +9116,73 @@ function fontsCssFor(faces, bundleDir, cacheDir = DEFAULT_FONT_CACHE, substitute
8916
9116
  ] : []
8917
9117
  ];
8918
9118
  const lines = [];
9119
+ const notices = [];
9120
+ const licenseTexts = /* @__PURE__ */ new Map();
8919
9121
  for (const face of faces) {
8920
9122
  const src = path29.join(cacheDir, path29.basename(face.file));
8921
9123
  const target = `./fonts/${path29.basename(face.file)}`;
8922
9124
  const format = FONT_FORMATS[path29.extname(face.file).toLowerCase()] ?? "truetype";
8923
9125
  const family = face.family.replace(/['\\]/g, "").replace(/\*\//g, "");
8924
9126
  const decl = `@font-face { font-family: '${family}'; font-weight: ${face.weight}; font-style: normal; src: url(${target}) format('${format}'); }`;
8925
- if (face.source.startsWith("local:")) {
8926
- lines.push(
8927
- `/* '${family}' ${face.weight} is a user-licensed face (tendril fonts add; sha256 ${face.sha256.slice(0, 16)}\u2026).`,
8928
- ` Licensed bytes are never copied into bundles \u2014 place your copy at ${target} and uncomment: */`,
8929
- `/* ${decl} */`
8930
- );
9127
+ const license = normalizeFontLicense(face.license);
9128
+ const terms = REDISTRIBUTABLE.get(license);
9129
+ if (terms === void 0) {
9130
+ if (face.source.startsWith("local:")) {
9131
+ lines.push(
9132
+ `/* '${family}' ${face.weight} is a user-licensed face (tendril fonts add; sha256 ${face.sha256.slice(0, 16)}\u2026).`,
9133
+ ` Licensed bytes are never copied into bundles \u2014 place your copy at ${target} and uncomment: */`,
9134
+ `/* ${decl} */`
9135
+ );
9136
+ } else if (license === "unknown") {
9137
+ lines.push(
9138
+ `/* '${family}' ${face.weight}: no licence on record (sha256 ${face.sha256.slice(0, 16)}\u2026). That is a gap`,
9139
+ " in the font cache, not a statement about your rights \u2014 Tendril copies font bytes into a",
9140
+ " bundle only under a licence it can name, so this face is declared here instead. Establish",
9141
+ ` the licence with \`tendril fonts resolve "${family}" --weights ${face.weight}\``,
9142
+ " (or `tendril fonts resolve --set <recording-dir>`) and re-emit. If it is a face you licence",
9143
+ ` rather than one free to redistribute, place your copy at ${target} and uncomment: */`,
9144
+ `/* ${decl} */`
9145
+ );
9146
+ } else {
9147
+ lines.push(
9148
+ `/* '${family}' ${face.weight} is recorded as ${license} (sha256 ${face.sha256.slice(0, 16)}\u2026), which does`,
9149
+ " not permit redistribution \u2014 Tendril never copies such bytes. Place your licensed copy",
9150
+ ` at ${target} and uncomment: */`,
9151
+ `/* ${decl} */`
9152
+ );
9153
+ }
8931
9154
  } else if (existsSync23(src) && createHash4("sha256").update(readFileSync20(src)).digest("hex") === face.sha256) {
8932
9155
  mkdirSync7(path29.join(bundleDir, "fonts"), { recursive: true });
8933
9156
  copyFileSync(src, path29.join(bundleDir, "fonts", path29.basename(face.file)));
9157
+ licenseTexts.set(terms.file, terms.text);
9158
+ const upstream = upstreamAttribution(face);
9159
+ notices.push(
9160
+ "",
9161
+ `${face.family.replace(/[\r\n]+/g, " ")} ${face.weight} \u2014 ./${path29.basename(face.file)}`,
9162
+ ` licence: ${terms.title} \u2014 full text in ./${terms.file}`,
9163
+ ` source: ${face.source}`,
9164
+ ` sha256: ${face.sha256}`,
9165
+ " copyright: this face's upstream copyright statement is published with its",
9166
+ ` original release \u2014 ${upstream}`
9167
+ );
8934
9168
  lines.push(decl);
8935
9169
  } else {
8936
9170
  lines.push(`/* '${family}' ${face.weight} (sha256 ${face.sha256.slice(0, 16)}\u2026) could not be shipped: cache bytes missing or hash mismatch \u2014 re-run \`tendril fonts resolve\` and re-emit. */`);
8937
9171
  }
8938
9172
  }
8939
- return lines.length === 0 ? null : `${[...header, ...lines].join("\n")}
9173
+ if (lines.length === 0) return null;
9174
+ if (notices.length > 0) {
9175
+ const fontsDir = path29.join(bundleDir, "fonts");
9176
+ for (const [file, text] of licenseTexts) writeFileSync11(path29.join(fontsDir, file), text);
9177
+ writeFileSync11(path29.join(fontsDir, "NOTICE.txt"), `${[NOTICE_PREAMBLE, ...notices].join("\n")}
9178
+ `);
9179
+ header.push(
9180
+ "/* REDISTRIBUTION: the face files in ./fonts/ are redistributed under the licences",
9181
+ ` recorded in ./fonts/NOTICE.txt; full texts in ${[...licenseTexts.keys()].map((f) => `./fonts/${f}`).join(", ")}.`,
9182
+ " Keep NOTICE.txt and the licence texts with the font files wherever they travel. */"
9183
+ );
9184
+ }
9185
+ return `${[...header, ...lines].join("\n")}
8940
9186
  `;
8941
9187
  }
8942
9188
  function countLatticeSymbols(setDir) {
@@ -9079,9 +9325,9 @@ ${stripped}`);
9079
9325
  const statusLine = `bundle: ${pass}/${statuses.length} recorded configs \u2265 pass bar (${certified} certified), ` + (interaction.length === 0 ? "interaction behaviors NONE VERIFIED" : `interaction behaviors ${interaction.filter((b) => b.pass).length}/${interaction.length}`) + (prelude.length === 0 ? "" : `, page hygiene ${prelude.filter((b) => b.pass).length}/${prelude.length}`) + (unrecorded === null ? "" : `; ${unrecorded} lattice configs UNVERIFIED`) + ` \u2014 claims in component.json, recompute with \`tendril verify\``;
9080
9326
  return { manifest, statusLine, written };
9081
9327
  }
9082
- var FONT_FORMATS, BARS;
9328
+ var FONT_FORMATS, BARS, NOTICE_PREAMBLE, OFL_1_1_TEXT, UFL_1_0_TEXT, APACHE_2_0_TEXT, REDISTRIBUTABLE;
9083
9329
  var init_bundle_emit = __esm({
9084
- "packages/generate/src/bundle-emit.ts"() {
9330
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/bundle-emit.ts"() {
9085
9331
  "use strict";
9086
9332
  init_src6();
9087
9333
  init_src();
@@ -9091,12 +9337,414 @@ var init_bundle_emit = __esm({
9091
9337
  pass: { sim: 0.95, ink: 0.95 },
9092
9338
  cert: { sim: 0.97, ink: 0.95 }
9093
9339
  };
9340
+ NOTICE_PREAMBLE = [
9341
+ "Font redistribution notice \u2014 tendril bundle",
9342
+ "===========================================",
9343
+ "",
9344
+ "The font files in this directory were copied into the bundle because the",
9345
+ "licence they are served under permits redistribution. Each entry below names",
9346
+ "that licence, the exact file the bytes came from, and the sha256 the bundle",
9347
+ "was scored against. Full licence texts sit beside this file \u2014 keep them, and",
9348
+ "this notice, with the font files wherever they travel."
9349
+ ].join("\n");
9350
+ OFL_1_1_TEXT = `-----------------------------------------------------------
9351
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
9352
+ -----------------------------------------------------------
9353
+
9354
+ PREAMBLE
9355
+ The goals of the Open Font License (OFL) are to stimulate worldwide
9356
+ development of collaborative font projects, to support the font creation
9357
+ efforts of academic and linguistic communities, and to provide a free and
9358
+ open framework in which fonts may be shared and improved in partnership
9359
+ with others.
9360
+
9361
+ The OFL allows the licensed fonts to be used, studied, modified and
9362
+ redistributed freely as long as they are not sold by themselves. The
9363
+ fonts, including any derivative works, can be bundled, embedded,
9364
+ redistributed and/or sold with any software provided that any reserved
9365
+ names are not used by derivative works. The fonts and derivatives,
9366
+ however, cannot be released under any other type of license. The
9367
+ requirement for fonts to remain under this license does not apply
9368
+ to any document created using the fonts or their derivatives.
9369
+
9370
+ DEFINITIONS
9371
+ "Font Software" refers to the set of files released by the Copyright
9372
+ Holder(s) under this license and clearly marked as such. This may
9373
+ include source files, build scripts and documentation.
9374
+
9375
+ "Reserved Font Name" refers to any names specified as such after the
9376
+ copyright statement(s).
9377
+
9378
+ "Original Version" refers to the collection of Font Software components as
9379
+ distributed by the Copyright Holder(s).
9380
+
9381
+ "Modified Version" refers to any derivative made by adding to, deleting,
9382
+ or substituting -- in part or in whole -- any of the components of the
9383
+ Original Version, by changing formats or by porting the Font Software to a
9384
+ new environment.
9385
+
9386
+ "Author" refers to any designer, engineer, programmer, technical
9387
+ writer or other person who contributed to the Font Software.
9388
+
9389
+ PERMISSION & CONDITIONS
9390
+ Permission is hereby granted, free of charge, to any person obtaining
9391
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
9392
+ redistribute, and sell modified and unmodified copies of the Font
9393
+ Software, subject to the following conditions:
9394
+
9395
+ 1) Neither the Font Software nor any of its individual components,
9396
+ in Original or Modified Versions, may be sold by itself.
9397
+
9398
+ 2) Original or Modified Versions of the Font Software may be bundled,
9399
+ redistributed and/or sold with any software, provided that each copy
9400
+ contains the above copyright notice and this license. These can be
9401
+ included either as stand-alone text files, human-readable headers or
9402
+ in the appropriate machine-readable metadata fields within text or
9403
+ binary files as long as those fields can be easily viewed by the user.
9404
+
9405
+ 3) No Modified Version of the Font Software may use the Reserved Font
9406
+ Name(s) unless explicit written permission is granted by the corresponding
9407
+ Copyright Holder. This restriction only applies to the primary font name as
9408
+ presented to the users.
9409
+
9410
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
9411
+ Software shall not be used to promote, endorse or advertise any
9412
+ Modified Version, except to acknowledge the contribution(s) of the
9413
+ Copyright Holder(s) and the Author(s) or with their explicit written
9414
+ permission.
9415
+
9416
+ 5) The Font Software, modified or unmodified, in part or in whole,
9417
+ must be distributed entirely under this license, and must not be
9418
+ distributed under any other license. The requirement for fonts to
9419
+ remain under this license does not apply to any document created
9420
+ using the Font Software.
9421
+
9422
+ TERMINATION
9423
+ This license becomes null and void if any of the above conditions are
9424
+ not met.
9425
+
9426
+ DISCLAIMER
9427
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
9428
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
9429
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
9430
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
9431
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
9432
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
9433
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
9434
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
9435
+ OTHER DEALINGS IN THE FONT SOFTWARE.
9436
+ `;
9437
+ UFL_1_0_TEXT = `-------------------------------
9438
+ UBUNTU FONT LICENCE Version 1.0
9439
+ -------------------------------
9440
+
9441
+ PREAMBLE
9442
+ This licence allows the licensed fonts to be used, studied, modified and
9443
+ redistributed freely. The fonts, including any derivative works, can be
9444
+ bundled, embedded, and redistributed provided the terms of this licence
9445
+ are met. The fonts and derivatives, however, cannot be released under
9446
+ any other licence. The requirement for fonts to remain under this
9447
+ licence does not require any document created using the fonts or their
9448
+ derivatives to be published under this licence, as long as the primary
9449
+ purpose of the document is not to be a vehicle for the distribution of
9450
+ the fonts.
9451
+
9452
+ DEFINITIONS
9453
+ "Font Software" refers to the set of files released by the Copyright
9454
+ Holder(s) under this licence and clearly marked as such. This may
9455
+ include source files, build scripts and documentation.
9456
+
9457
+ "Original Version" refers to the collection of Font Software components
9458
+ as received under this licence.
9459
+
9460
+ "Modified Version" refers to any derivative made by adding to, deleting,
9461
+ or substituting -- in part or in whole -- any of the components of the
9462
+ Original Version, by changing formats or by porting the Font Software to
9463
+ a new environment.
9464
+
9465
+ "Copyright Holder(s)" refers to all individuals and companies who have a
9466
+ copyright ownership of the Font Software.
9467
+
9468
+ "Substantially Changed" refers to Modified Versions which can be easily
9469
+ identified as dissimilar to the Font Software by users of the Font
9470
+ Software comparing the Original Version with the Modified Version.
9471
+
9472
+ To "Propagate" a work means to do anything with it that, without
9473
+ permission, would make you directly or secondarily liable for
9474
+ infringement under applicable copyright law, except executing it on a
9475
+ computer or modifying a private copy. Propagation includes copying,
9476
+ distribution (with or without modification and with or without charging
9477
+ a redistribution fee), making available to the public, and in some
9478
+ countries other activities as well.
9479
+
9480
+ PERMISSION & CONDITIONS
9481
+ This licence does not grant any rights under trademark law and all such
9482
+ rights are reserved.
9483
+
9484
+ Permission is hereby granted, free of charge, to any person obtaining a
9485
+ copy of the Font Software, to propagate the Font Software, subject to
9486
+ the below conditions:
9487
+
9488
+ 1) Each copy of the Font Software must contain the above copyright
9489
+ notice and this licence. These can be included either as stand-alone
9490
+ text files, human-readable headers or in the appropriate machine-
9491
+ readable metadata fields within text or binary files as long as those
9492
+ fields can be easily viewed by the user.
9493
+
9494
+ 2) The font name complies with the following:
9495
+ (a) The Original Version must retain its name, unmodified.
9496
+ (b) Modified Versions which are Substantially Changed must be renamed to
9497
+ avoid use of the name of the Original Version or similar names entirely.
9498
+ (c) Modified Versions which are not Substantially Changed must be
9499
+ renamed to both (i) retain the name of the Original Version and (ii) add
9500
+ additional naming elements to distinguish the Modified Version from the
9501
+ Original Version. The name of such Modified Versions must be the name of
9502
+ the Original Version, with "derivative X" where X represents the name of
9503
+ the new work, appended to that name.
9504
+
9505
+ 3) The name(s) of the Copyright Holder(s) and any contributor to the
9506
+ Font Software shall not be used to promote, endorse or advertise any
9507
+ Modified Version, except (i) as required by this licence, (ii) to
9508
+ acknowledge the contribution(s) of the Copyright Holder(s) or (iii) with
9509
+ their explicit written permission.
9510
+
9511
+ 4) The Font Software, modified or unmodified, in part or in whole, must
9512
+ be distributed entirely under this licence, and must not be distributed
9513
+ under any other licence. The requirement for fonts to remain under this
9514
+ licence does not affect any document created using the Font Software,
9515
+ except any version of the Font Software extracted from a document
9516
+ created using the Font Software may only be distributed under this
9517
+ licence.
9518
+
9519
+ TERMINATION
9520
+ This licence becomes null and void if any of the above conditions are
9521
+ not met.
9522
+
9523
+ DISCLAIMER
9524
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
9525
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
9526
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
9527
+ COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
9528
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
9529
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
9530
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
9531
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER
9532
+ DEALINGS IN THE FONT SOFTWARE.
9533
+ `;
9534
+ APACHE_2_0_TEXT = `
9535
+ Apache License
9536
+ Version 2.0, January 2004
9537
+ http://www.apache.org/licenses/
9538
+
9539
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
9540
+
9541
+ 1. Definitions.
9542
+
9543
+ "License" shall mean the terms and conditions for use, reproduction,
9544
+ and distribution as defined by Sections 1 through 9 of this document.
9545
+
9546
+ "Licensor" shall mean the copyright owner or entity authorized by
9547
+ the copyright owner that is granting the License.
9548
+
9549
+ "Legal Entity" shall mean the union of the acting entity and all
9550
+ other entities that control, are controlled by, or are under common
9551
+ control with that entity. For the purposes of this definition,
9552
+ "control" means (i) the power, direct or indirect, to cause the
9553
+ direction or management of such entity, whether by contract or
9554
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
9555
+ outstanding shares, or (iii) beneficial ownership of such entity.
9556
+
9557
+ "You" (or "Your") shall mean an individual or Legal Entity
9558
+ exercising permissions granted by this License.
9559
+
9560
+ "Source" form shall mean the preferred form for making modifications,
9561
+ including but not limited to software source code, documentation
9562
+ source, and configuration files.
9563
+
9564
+ "Object" form shall mean any form resulting from mechanical
9565
+ transformation or translation of a Source form, including but
9566
+ not limited to compiled object code, generated documentation,
9567
+ and conversions to other media types.
9568
+
9569
+ "Work" shall mean the work of authorship, whether in Source or
9570
+ Object form, made available under the License, as indicated by a
9571
+ copyright notice that is included in or attached to the work
9572
+ (an example is provided in the Appendix below).
9573
+
9574
+ "Derivative Works" shall mean any work, whether in Source or Object
9575
+ form, that is based on (or derived from) the Work and for which the
9576
+ editorial revisions, annotations, elaborations, or other modifications
9577
+ represent, as a whole, an original work of authorship. For the purposes
9578
+ of this License, Derivative Works shall not include works that remain
9579
+ separable from, or merely link (or bind by name) to the interfaces of,
9580
+ the Work and Derivative Works thereof.
9581
+
9582
+ "Contribution" shall mean any work of authorship, including
9583
+ the original version of the Work and any modifications or additions
9584
+ to that Work or Derivative Works thereof, that is intentionally
9585
+ submitted to Licensor for inclusion in the Work by the copyright owner
9586
+ or by an individual or Legal Entity authorized to submit on behalf of
9587
+ the copyright owner. For the purposes of this definition, "submitted"
9588
+ means any form of electronic, verbal, or written communication sent
9589
+ to the Licensor or its representatives, including but not limited to
9590
+ communication on electronic mailing lists, source code control systems,
9591
+ and issue tracking systems that are managed by, or on behalf of, the
9592
+ Licensor for the purpose of discussing and improving the Work, but
9593
+ excluding communication that is conspicuously marked or otherwise
9594
+ designated in writing by the copyright owner as "Not a Contribution."
9595
+
9596
+ "Contributor" shall mean Licensor and any individual or Legal Entity
9597
+ on behalf of whom a Contribution has been received by Licensor and
9598
+ subsequently incorporated within the Work.
9599
+
9600
+ 2. Grant of Copyright License. Subject to the terms and conditions of
9601
+ this License, each Contributor hereby grants to You a perpetual,
9602
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
9603
+ copyright license to reproduce, prepare Derivative Works of,
9604
+ publicly display, publicly perform, sublicense, and distribute the
9605
+ Work and such Derivative Works in Source or Object form.
9606
+
9607
+ 3. Grant of Patent License. Subject to the terms and conditions of
9608
+ this License, each Contributor hereby grants to You a perpetual,
9609
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
9610
+ (except as stated in this section) patent license to make, have made,
9611
+ use, offer to sell, sell, import, and otherwise transfer the Work,
9612
+ where such license applies only to those patent claims licensable
9613
+ by such Contributor that are necessarily infringed by their
9614
+ Contribution(s) alone or by combination of their Contribution(s)
9615
+ with the Work to which such Contribution(s) was submitted. If You
9616
+ institute patent litigation against any entity (including a
9617
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
9618
+ or a Contribution incorporated within the Work constitutes direct
9619
+ or contributory patent infringement, then any patent licenses
9620
+ granted to You under this License for that Work shall terminate
9621
+ as of the date such litigation is filed.
9622
+
9623
+ 4. Redistribution. You may reproduce and distribute copies of the
9624
+ Work or Derivative Works thereof in any medium, with or without
9625
+ modifications, and in Source or Object form, provided that You
9626
+ meet the following conditions:
9627
+
9628
+ (a) You must give any other recipients of the Work or
9629
+ Derivative Works a copy of this License; and
9630
+
9631
+ (b) You must cause any modified files to carry prominent notices
9632
+ stating that You changed the files; and
9633
+
9634
+ (c) You must retain, in the Source form of any Derivative Works
9635
+ that You distribute, all copyright, patent, trademark, and
9636
+ attribution notices from the Source form of the Work,
9637
+ excluding those notices that do not pertain to any part of
9638
+ the Derivative Works; and
9639
+
9640
+ (d) If the Work includes a "NOTICE" text file as part of its
9641
+ distribution, then any Derivative Works that You distribute must
9642
+ include a readable copy of the attribution notices contained
9643
+ within such NOTICE file, excluding those notices that do not
9644
+ pertain to any part of the Derivative Works, in at least one
9645
+ of the following places: within a NOTICE text file distributed
9646
+ as part of the Derivative Works; within the Source form or
9647
+ documentation, if provided along with the Derivative Works; or,
9648
+ within a display generated by the Derivative Works, if and
9649
+ wherever such third-party notices normally appear. The contents
9650
+ of the NOTICE file are for informational purposes only and
9651
+ do not modify the License. You may add Your own attribution
9652
+ notices within Derivative Works that You distribute, alongside
9653
+ or as an addendum to the NOTICE text from the Work, provided
9654
+ that such additional attribution notices cannot be construed
9655
+ as modifying the License.
9656
+
9657
+ You may add Your own copyright statement to Your modifications and
9658
+ may provide additional or different license terms and conditions
9659
+ for use, reproduction, or distribution of Your modifications, or
9660
+ for any such Derivative Works as a whole, provided Your use,
9661
+ reproduction, and distribution of the Work otherwise complies with
9662
+ the conditions stated in this License.
9663
+
9664
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
9665
+ any Contribution intentionally submitted for inclusion in the Work
9666
+ by You to the Licensor shall be under the terms and conditions of
9667
+ this License, without any additional terms or conditions.
9668
+ Notwithstanding the above, nothing herein shall supersede or modify
9669
+ the terms of any separate license agreement you may have executed
9670
+ with Licensor regarding such Contributions.
9671
+
9672
+ 6. Trademarks. This License does not grant permission to use the trade
9673
+ names, trademarks, service marks, or product names of the Licensor,
9674
+ except as required for reasonable and customary use in describing the
9675
+ origin of the Work and reproducing the content of the NOTICE file.
9676
+
9677
+ 7. Disclaimer of Warranty. Unless required by applicable law or
9678
+ agreed to in writing, Licensor provides the Work (and each
9679
+ Contributor provides its Contributions) on an "AS IS" BASIS,
9680
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
9681
+ implied, including, without limitation, any warranties or conditions
9682
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
9683
+ PARTICULAR PURPOSE. You are solely responsible for determining the
9684
+ appropriateness of using or redistributing the Work and assume any
9685
+ risks associated with Your exercise of permissions under this License.
9686
+
9687
+ 8. Limitation of Liability. In no event and under no legal theory,
9688
+ whether in tort (including negligence), contract, or otherwise,
9689
+ unless required by applicable law (such as deliberate and grossly
9690
+ negligent acts) or agreed to in writing, shall any Contributor be
9691
+ liable to You for damages, including any direct, indirect, special,
9692
+ incidental, or consequential damages of any character arising as a
9693
+ result of this License or out of the use or inability to use the
9694
+ Work (including but not limited to damages for loss of goodwill,
9695
+ work stoppage, computer failure or malfunction, or any and all
9696
+ other commercial damages or losses), even if such Contributor
9697
+ has been advised of the possibility of such damages.
9698
+
9699
+ 9. Accepting Warranty or Additional Liability. While redistributing
9700
+ the Work or Derivative Works thereof, You may choose to offer,
9701
+ and charge a fee for, acceptance of support, warranty, indemnity,
9702
+ or other liability obligations and/or rights consistent with this
9703
+ License. However, in accepting such obligations, You may act only
9704
+ on Your own behalf and on Your sole responsibility, not on behalf
9705
+ of any other Contributor, and only if You agree to indemnify,
9706
+ defend, and hold each Contributor harmless for any liability
9707
+ incurred by, or claims asserted against, such Contributor by reason
9708
+ of your accepting any such warranty or additional liability.
9709
+
9710
+ END OF TERMS AND CONDITIONS
9711
+
9712
+ APPENDIX: How to apply the Apache License to your work.
9713
+
9714
+ To apply the Apache License to your work, attach the following
9715
+ boilerplate notice, with the fields enclosed by brackets "[]"
9716
+ replaced with your own identifying information. (Don't include
9717
+ the brackets!) The text should be enclosed in the appropriate
9718
+ comment syntax for the file format. We also recommend that a
9719
+ file or class name and description of purpose be included on the
9720
+ same "printed page" as the copyright notice for easier
9721
+ identification within third-party archives.
9722
+
9723
+ Copyright [yyyy] [name of copyright owner]
9724
+
9725
+ Licensed under the Apache License, Version 2.0 (the "License");
9726
+ you may not use this file except in compliance with the License.
9727
+ You may obtain a copy of the License at
9728
+
9729
+ http://www.apache.org/licenses/LICENSE-2.0
9730
+
9731
+ Unless required by applicable law or agreed to in writing, software
9732
+ distributed under the License is distributed on an "AS IS" BASIS,
9733
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9734
+ See the License for the specific language governing permissions and
9735
+ limitations under the License.
9736
+ `;
9737
+ REDISTRIBUTABLE = /* @__PURE__ */ new Map([
9738
+ ["OFL-1.1", { title: "SIL Open Font License 1.1", file: "LICENSE-OFL-1.1.txt", text: OFL_1_1_TEXT }],
9739
+ ["Apache-2.0", { title: "Apache License 2.0", file: "LICENSE-Apache-2.0.txt", text: APACHE_2_0_TEXT }],
9740
+ ["UFL-1.0", { title: "Ubuntu Font Licence 1.0", file: "LICENSE-UFL-1.0.txt", text: UFL_1_0_TEXT }]
9741
+ ]);
9094
9742
  }
9095
9743
  });
9096
9744
 
9097
- // packages/generate/src/index.ts
9745
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/index.ts
9098
9746
  var init_src7 = __esm({
9099
- "packages/generate/src/index.ts"() {
9747
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/index.ts"() {
9100
9748
  "use strict";
9101
9749
  init_engine();
9102
9750
  init_engine_curated();
@@ -9110,7 +9758,7 @@ var init_src7 = __esm({
9110
9758
  }
9111
9759
  });
9112
9760
 
9113
- // packages/cli/src/commands/fonts.ts
9761
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/fonts.ts
9114
9762
  var fonts_exports = {};
9115
9763
  __export(fonts_exports, {
9116
9764
  DEFAULT_FONT_CACHE: () => DEFAULT_FONT_CACHE,
@@ -9155,30 +9803,54 @@ async function runFontsResolveSet(opts) {
9155
9803
  });
9156
9804
  }
9157
9805
  const inCache = new Set(resolvedFontFamilies(opts.cacheDir).flatMap((f) => f.weights.map((w) => `${f.family.toLowerCase()}:${w}`)));
9806
+ const unstamped = new Map(facesMissingLicense(opts.cacheDir).map((f) => [`${f.family.toLowerCase()}:${f.weight}`, f.sha256]));
9158
9807
  const cached = [];
9159
9808
  const resolved = [];
9160
9809
  const failures = [];
9810
+ const relicensed = [];
9811
+ const unlicensed = [];
9812
+ const byteDrift = [];
9161
9813
  for (const need of needs) {
9162
9814
  const missing = [];
9815
+ const toStamp = [];
9163
9816
  for (const w of need.weights) {
9164
- if (inCache.has(`${need.family.toLowerCase()}:${w}`)) cached.push({ family: need.family, weight: w });
9165
- else missing.push(w);
9817
+ const key = `${need.family.toLowerCase()}:${w}`;
9818
+ if (!inCache.has(key)) missing.push(w);
9819
+ else if (unstamped.has(key)) toStamp.push(w);
9820
+ else cached.push({ family: need.family, weight: w });
9821
+ }
9822
+ if (missing.length > 0) {
9823
+ const result = await resolveFonts(need.family, missing, opts.cacheDir);
9824
+ resolved.push(...result.resolved);
9825
+ failures.push(...result.failures);
9826
+ }
9827
+ if (toStamp.length > 0) {
9828
+ const result = await resolveFonts(need.family, toStamp, opts.cacheDir);
9829
+ for (const face of result.resolved) {
9830
+ if (face.license === "unknown") unlicensed.push({ family: face.family, weight: face.weight, reason: "the foundry's metadata named no licence for this family" });
9831
+ else relicensed.push({ family: face.family, weight: face.weight, license: face.license });
9832
+ if (unstamped.get(`${face.family.toLowerCase()}:${face.weight}`) !== face.sha256) byteDrift.push({ family: face.family, weight: face.weight });
9833
+ }
9834
+ unlicensed.push(...result.failures);
9166
9835
  }
9167
- if (missing.length === 0) continue;
9168
- const result = await resolveFonts(need.family, missing, opts.cacheDir);
9169
- resolved.push(...result.resolved);
9170
- failures.push(...result.failures);
9171
9836
  }
9172
- emitData(opts, { set: setDir, needs, cached, resolved, failures }, () => {
9837
+ emitData(opts, { set: setDir, needs, cached, resolved, relicensed, unlicensed, failures }, () => {
9173
9838
  process.stdout.write(`set declares: ${needs.map((n) => `${n.family} (${n.weights.join(", ")})`).join(" \xB7 ")}
9174
9839
  `);
9175
9840
  for (const f of cached) process.stdout.write(`cached ${f.family} ${f.weight}
9176
9841
  `);
9177
9842
  for (const f of resolved) process.stdout.write(`resolved ${f.family} ${f.weight} (${f.sha256.slice(0, 12)}\u2026)
9843
+ `);
9844
+ for (const f of relicensed) process.stdout.write(`licence ${f.family} ${f.weight}: ${f.license} \u2014 recorded now; bundles may ship these bytes with the licence text
9845
+ `);
9846
+ for (const f of unlicensed) process.stdout.write(`licence ${f.family} ${f.weight}: still not on record (${f.reason}) \u2014 the cached face renders as always; bundles declare it instead of copying it
9178
9847
  `);
9179
9848
  for (const f of failures) process.stdout.write(`FAILED ${f.family} ${f.weight}: ${f.reason}
9180
9849
  `);
9181
9850
  });
9851
+ if (byteDrift.length > 0) {
9852
+ warn(opts, `${byteDrift.map((f) => `${f.family} ${f.weight}`).join(", ")}: the foundry now serves different bytes than the cache held \u2014 the faces were re-fetched to record their licence, so re-pin any font lock deliberately`);
9853
+ }
9182
9854
  if (failures.length > 0) {
9183
9855
  warn(opts, `${failures.length} face(s) unresolved \u2014 verification will refuse to score under substitution`);
9184
9856
  process.exitCode = ExitCode.FontsUnproven;
@@ -9234,7 +9906,7 @@ function runFontsAdd(opts) {
9234
9906
  });
9235
9907
  }
9236
9908
  var init_fonts = __esm({
9237
- "packages/cli/src/commands/fonts.ts"() {
9909
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/fonts.ts"() {
9238
9910
  "use strict";
9239
9911
  init_src3();
9240
9912
  init_src4();
@@ -9243,7 +9915,7 @@ var init_fonts = __esm({
9243
9915
  }
9244
9916
  });
9245
9917
 
9246
- // packages/cli/src/font-guidance.ts
9918
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/font-guidance.ts
9247
9919
  function fontsUnprovenRemediation(setDir) {
9248
9920
  if (setDir !== void 0) {
9249
9921
  try {
@@ -9297,18 +9969,24 @@ function missingWeights(setDir, cacheDir) {
9297
9969
  return gaps;
9298
9970
  }
9299
9971
  var init_font_guidance = __esm({
9300
- "packages/cli/src/font-guidance.ts"() {
9972
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/font-guidance.ts"() {
9301
9973
  "use strict";
9302
9974
  init_src4();
9303
9975
  init_src7();
9304
9976
  }
9305
9977
  });
9306
9978
 
9307
- // packages/cli/src/commands/verify.ts
9979
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/verify.ts
9308
9980
  var verify_exports = {};
9309
9981
  __export(verify_exports, {
9982
+ NO_ROLE_MANIFEST: () => NO_ROLE_MANIFEST,
9983
+ ROLES_NOT_RESOLVED: () => ROLES_NOT_RESOLVED,
9984
+ checkSummarySegments: () => checkSummarySegments,
9985
+ compositionReport: () => compositionReport,
9986
+ failureTally: () => failureTally,
9310
9987
  foldConfigStatus: () => foldConfigStatus,
9311
9988
  interactionCoverage: () => interactionCoverage,
9989
+ resolveComposition: () => resolveComposition,
9312
9990
  runVerify: () => runVerify
9313
9991
  });
9314
9992
  import { existsSync as existsSync25, readFileSync as readFileSync22 } from "node:fs";
@@ -9342,6 +10020,46 @@ function foldConfigStatus(s, failDemotions, substitutedFamilies) {
9342
10020
  absentInkDemoted
9343
10021
  };
9344
10022
  }
10023
+ function resolveComposition(raw) {
10024
+ if (raw === void 0) return NO_ROLE_MANIFEST;
10025
+ const parsed = RolesSchema.safeParse(raw);
10026
+ if (parsed.success) return { roles: parsed.data };
10027
+ const why = parsed.error.issues.slice(0, 3).map((i) => `${i.path.join(".") === "" ? "roles" : i.path.join(".")}: ${i.message}`).join("; ");
10028
+ return {
10029
+ short: "roles block REJECTED",
10030
+ unavailable: `the recording set's roles block was REJECTED by the schema (${why}) \u2014 composition (structural + crop) was NEVER CHECKED`,
10031
+ warn: `recording set roles block REJECTED (${why}) \u2014 the composition checks (structural + crop) did NOT run, while the set still reads as role-confirmed. This is an instrument failure, not a clean bill. Repair the set's roles block and re-verify.`
10032
+ };
10033
+ }
10034
+ function rolesSourceLabel(roles) {
10035
+ return roles.rolesSource === "human-override" ? "HUMAN-OVERRIDE" : roles.rolesSource ?? UNSTAMPED_ROLES;
10036
+ }
10037
+ function checkSummarySegments(input) {
10038
+ const tally = (rows) => `${rows.filter((r) => r.pass).length}/${rows.length}`;
10039
+ const { availability } = input;
10040
+ const composition = availability.unavailable !== void 0 ? `composition NOT CHECKED (${availability.short})` : `composition ${tally(input.structural)} structural, ${input.crops !== void 0 ? `${tally(input.crops)} crops` : "crops unavailable"} (roles: ${rolesSourceLabel(availability.roles)}${(availability.roles.narrowingAccepted ?? []).length > 0 ? `, ${(availability.roles.narrowingAccepted ?? []).length} narrowing(s) accepted: ${(availability.roles.narrowingAccepted ?? []).join(", ")}` : ""})`;
10041
+ const occlusion = input.occlusion.length === 0 ? "occlusion not applicable (no overlay declared)" : `occlusion ${tally(input.occlusion)}`;
10042
+ return ` \xB7 ${composition} \xB7 ${occlusion}`;
10043
+ }
10044
+ function compositionReport(input) {
10045
+ const { availability, regions } = input;
10046
+ if (availability.unavailable !== void 0) return { unavailable: availability.unavailable };
10047
+ const cropsUnavailable = regions !== void 0 && "unavailable" in regions ? regions.unavailable : "interior geometry was never computed for this run";
10048
+ return {
10049
+ rolesSource: availability.roles.rolesSource ?? UNSTAMPED_ROLES,
10050
+ // Each token is a derived main, or a part→main edge, that a human
10051
+ // signed away at confirm time. Every one of them REMOVES something
10052
+ // the structural check would otherwise have had to satisfy, so the
10053
+ // list belongs beside the pass it enabled — not only in the manifest
10054
+ // that recorded it.
10055
+ narrowingAccepted: availability.roles.narrowingAccepted ?? [],
10056
+ structural: input.structural,
10057
+ crops: input.crops ?? { unavailable: cropsUnavailable }
10058
+ };
10059
+ }
10060
+ function failureTally(t) {
10061
+ return `${t.configs.length} config(s), ${t.behaviors.length} behavior(s), ${t.structural.length + t.crops.length} composition check(s), ${t.occlusion.length} occlusion check(s) below the ${t.bar} bar${t.evidenceUnverified ? "; PLUS the interaction-evidence instrument gate failed (operability could not be verified \u2014 see FAIL interaction-evidence above)" : ""} \u2014 bundle written, verdict honest (Q4)`;
10062
+ }
9345
10063
  function taskFromManifest(opts, manifest, setDir) {
9346
10064
  const recordedSlugs = loadManifest(setDir).reps.map((r) => r.slug);
9347
10065
  const adapterSlugs = Object.keys(manifest.propAdapter);
@@ -9405,7 +10123,7 @@ async function runVerify(opts) {
9405
10123
  let unmapped = [];
9406
10124
  let interactionEvidence = [];
9407
10125
  let unmappedInteractionEvidence = [];
9408
- let roles;
10126
+ let availability = ROLES_NOT_RESOLVED;
9409
10127
  if (opts.task !== void 0) {
9410
10128
  const registry = TASKS[opts.task];
9411
10129
  if (registry === void 0) {
@@ -9448,8 +10166,8 @@ async function runVerify(opts) {
9448
10166
  interactionEvidence = built.interactionEvidence;
9449
10167
  unmappedInteractionEvidence = built.unmappedInteractionEvidence;
9450
10168
  for (const s of built.adapterOnly) warn(opts, `prop adapter maps "${s}" which is not in the recording set \u2014 ignored`);
9451
- const rolesParse = RolesSchema.safeParse(loadManifest(setDir).roles);
9452
- if (rolesParse.success) roles = rolesParse.data;
10169
+ availability = resolveComposition(loadManifest(setDir).roles);
10170
+ if (availability.warn !== void 0) warn(opts, availability.warn);
9453
10171
  }
9454
10172
  const hash = recordingSetHash(setDir, task.configs);
9455
10173
  if (hash !== manifest.provenance.recordingSet.hash) {
@@ -9474,6 +10192,7 @@ async function runVerify(opts) {
9474
10192
  remediation: `Regenerate the bundle (bundle v1 carries its prop manifest), or pass --task <${Object.keys(TASKS).join("|")}> for legacy bundles.`
9475
10193
  });
9476
10194
  }
10195
+ const roles = availability.roles;
9477
10196
  if (!fontsResolved()) {
9478
10197
  fail(opts, ExitCode.FontsUnproven, {
9479
10198
  error: "resolved font cache absent \u2014 verification under system font substitution is refused",
@@ -9481,8 +10200,8 @@ async function runVerify(opts) {
9481
10200
  remediation: fontsUnprovenRemediation(task.set)
9482
10201
  });
9483
10202
  }
9484
- if (lcdTextDisabled()) {
9485
- warn(opts, "EXPERIMENT override active (TENDRIL_DISABLE_LCD_TEXT=1): text renders greyscale \u2014 scores are NOT comparable to default runs; the environment stamp and report are marked");
10203
+ if (lcdTextEnabled()) {
10204
+ warn(opts, "EXPERIMENT override active (TENDRIL_ENABLE_LCD_TEXT=1): text renders with platform LCD antialiasing instead of canonical greyscale \u2014 scores are NOT comparable to default runs; the environment stamp and report are marked");
9486
10205
  }
9487
10206
  const substitutedFamilies = unprovisionedFamilies(task.set);
9488
10207
  if (substitutedFamilies.length > 0) {
@@ -9548,7 +10267,10 @@ async function runVerify(opts) {
9548
10267
  ...opts.task !== void 0 ? { task: opts.task } : {},
9549
10268
  ...manifest !== void 0 ? { bundleManifest: { name: manifest.name, bundleVersion: manifest.bundleVersion, recordingSetHash: manifest.provenance.recordingSet.hash } } : {},
9550
10269
  targetBar: opts.bar,
9551
- environment: environmentStamp(taskFontFamilies(task.set)),
10270
+ // Canonical mount semantics are VERSION-scoped (0.1.22 review: the
10271
+ // greyscale flip changed Windows pixels under an identical-looking
10272
+ // stamp) — the ruler version is part of the comparability key.
10273
+ environment: { ...environmentStamp(taskFontFamilies(task.set)), ruler: cliVersion() },
9552
10274
  coverage: {
9553
10275
  scoredConfigs: statuses.length,
9554
10276
  certified,
@@ -9593,19 +10315,14 @@ async function runVerify(opts) {
9593
10315
  configs: statuses,
9594
10316
  behaviors,
9595
10317
  evidence: { dir: evidenceDir, files: "per config: <rep>-render.png, <rep>-ref.png, <rep>-diff.png" },
9596
- ...roles !== void 0 ? {
9597
- composition: {
9598
- structural,
9599
- crops: crops ?? { unavailable: regionsOut !== void 0 && "unavailable" in regionsOut ? regionsOut.unavailable : "no role manifest" }
9600
- }
9601
- } : {},
10318
+ composition: compositionReport({ availability, structural, crops, regions: regionsOut }),
9602
10319
  verdict: ok ? "verified" : "verification-failed",
9603
10320
  // Machine-readable cause (adversarial review): a cert-bar failure
9604
10321
  // with zero pixel/behavior/composition failures was only
9605
10322
  // explainable from stderr prose.
9606
10323
  ...certBlockedByAbsentInk.length > 0 ? { certBlockedByAbsentInk } : {},
9607
10324
  ...weightGaps.length > 0 ? { fontWeightGaps: weightGaps } : {},
9608
- ...lcdTextDisabled() ? { environmentOverrides: ["disable-lcd-text"] } : {},
10325
+ ...lcdTextEnabled() ? { environmentOverrides: ["enable-lcd-text"] } : {},
9609
10326
  // Run 13 finding 1: the eye-check nudge lived only in the human
9610
10327
  // footer, so MCP-driven agents — the documented path — were never
9611
10328
  // told the check exists and shipped without ever opening a sheet.
@@ -9636,17 +10353,22 @@ async function runVerify(opts) {
9636
10353
  process.stdout.write(`${o.pass ? "PASS" : "FAIL"} ${o.id}${o.detail !== void 0 ? ` [${o.detail}]` : ""}
9637
10354
  `);
9638
10355
  }
9639
- if (crops !== void 0) {
10356
+ if (availability.unavailable !== void 0) {
10357
+ process.stdout.write(`UNAVAILABLE composition \u2014 ${availability.unavailable}
10358
+ `);
10359
+ } else if (crops !== void 0) {
9640
10360
  for (const c of crops) process.stdout.write(`${c.pass ? "PASS" : "FAIL"} ${c.id} sim=${c.similarity} ink=${c.inkRecall}${c.detail !== void 0 ? ` [${c.detail}]` : ""}
9641
10361
  `);
9642
- } else if (roles !== void 0 && regionsOut !== void 0 && "unavailable" in regionsOut) {
10362
+ } else if (regionsOut !== void 0 && "unavailable" in regionsOut) {
9643
10363
  process.stdout.write(`UNAVAILABLE composition crops \u2014 ${regionsOut.unavailable}
9644
10364
  `);
9645
10365
  }
9646
10366
  const ic = interactionCoverage(behaviors);
9647
10367
  process.stdout.write(
9648
10368
  `
9649
- ${certified}/${statuses.length} certified \xB7 ${report.coverage.pass}/${statuses.length} \u2265 pass bar \xB7 behaviors ${behaviors.length - behaviorFailures.length}/${behaviors.length}${roles !== void 0 ? ` \xB7 composition ${structural.length - structuralFailures.length}/${structural.length} structural${crops !== void 0 ? `, ${crops.length - cropFailures.length}/${crops.length} crops` : ", crops unavailable"}` : ""}
10369
+ ${certified}/${statuses.length} certified \xB7 ${report.coverage.pass}/${statuses.length} \u2265 pass bar \xB7 behaviors ${behaviors.length - behaviorFailures.length}/${behaviors.length}${checkSummarySegments(
10370
+ { availability, structural, crops, occlusion }
10371
+ )}
9650
10372
  `
9651
10373
  );
9652
10374
  const QUALITY_SHOWN = 8;
@@ -9741,14 +10463,22 @@ ${certified}/${statuses.length} certified \xB7 ${report.coverage.pass}/${statuse
9741
10463
  if (!okExceptDemotion) {
9742
10464
  warn(
9743
10465
  opts,
9744
- `${pixelFailures.length} config(s), ${behaviorFailures.length} behavior(s), ${structuralFailures.length + cropFailures.length + occlusionFailures.length} composition check(s) below the ${opts.bar} bar${evidenceUnverified ? "; PLUS the interaction-evidence instrument gate failed (operability could not be verified \u2014 see FAIL interaction-evidence above)" : ""} \u2014 bundle written, verdict honest (Q4)`
10466
+ failureTally({
10467
+ configs: pixelFailures,
10468
+ behaviors: behaviorFailures,
10469
+ structural: structuralFailures,
10470
+ crops: cropFailures,
10471
+ occlusion: occlusionFailures,
10472
+ bar: opts.bar,
10473
+ evidenceUnverified
10474
+ })
9745
10475
  );
9746
10476
  process.exitCode = ExitCode.VerificationFailed;
9747
10477
  }
9748
10478
  }
9749
- var BARS2;
10479
+ var BARS2, NO_ROLE_MANIFEST, ROLES_NOT_RESOLVED, UNSTAMPED_ROLES;
9750
10480
  var init_verify = __esm({
9751
- "packages/cli/src/commands/verify.ts"() {
10481
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/verify.ts"() {
9752
10482
  "use strict";
9753
10483
  init_src3();
9754
10484
  init_src6();
@@ -9762,10 +10492,19 @@ var init_verify = __esm({
9762
10492
  pass: { sim: 0.95, ink: 0.95 },
9763
10493
  cert: { sim: 0.97, ink: 0.95 }
9764
10494
  };
10495
+ NO_ROLE_MANIFEST = Object.freeze({
10496
+ short: "no role manifest",
10497
+ unavailable: "the recording set declares no role manifest \u2014 composition (structural + crop) was NEVER CHECKED; nothing here says the main renders the SHIPPED part modules rather than a pixel-identical re-implementation"
10498
+ });
10499
+ ROLES_NOT_RESOLVED = Object.freeze({
10500
+ short: "roles never resolved on this path",
10501
+ unavailable: "this run never resolved a role manifest \u2014 the legacy --task adapter and pre-manifest reference sets skip the set's roles block entirely, so composition (structural + crop) was NEVER CHECKED and the set was never asked what it declares; nothing here says the main renders the SHIPPED part modules rather than a pixel-identical re-implementation"
10502
+ });
10503
+ UNSTAMPED_ROLES = "unstamped";
9765
10504
  }
9766
10505
  });
9767
10506
 
9768
- // packages/cli/src/commands/engine.ts
10507
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/engine.ts
9769
10508
  var engine_exports = {};
9770
10509
  __export(engine_exports, {
9771
10510
  runEngineBrief: () => runEngineBrief,
@@ -9906,8 +10645,8 @@ async function runEngineScore(opts) {
9906
10645
  remediation: fontsUnprovenRemediation(task.set)
9907
10646
  });
9908
10647
  }
9909
- if (lcdTextDisabled()) {
9910
- warn(opts, "EXPERIMENT override active (TENDRIL_DISABLE_LCD_TEXT=1): text renders greyscale \u2014 scores are NOT comparable to default runs; the environment stamp and report are marked");
10648
+ if (lcdTextEnabled()) {
10649
+ warn(opts, "EXPERIMENT override active (TENDRIL_ENABLE_LCD_TEXT=1): text renders with platform LCD antialiasing instead of canonical greyscale \u2014 scores are NOT comparable to default runs; the environment stamp and report are marked");
9911
10650
  }
9912
10651
  const substitutedFamilies = unprovisionedFamilies(task.set);
9913
10652
  if (substitutedFamilies.length > 0) {
@@ -10008,7 +10747,8 @@ METRIC DEADBAND (read before iterating on near-misses): the scored similarity/in
10008
10747
  bundleManifest: emitted.written[0],
10009
10748
  note: "styles.css was stamped with the bundle provenance comment on line 1 \u2014 preserve it in any post-score edit",
10010
10749
  allPass,
10011
- ...lcdTextDisabled() ? { environmentOverrides: ["disable-lcd-text"] } : {},
10750
+ environment: { ...environmentStamp(taskFontFamilies(task.set)), ruler: cliVersion() },
10751
+ ...lcdTextEnabled() ? { environmentOverrides: ["enable-lcd-text"] } : {},
10012
10752
  // Run 11: generators read allPass:true and reported success on
10013
10753
  // bundles verify then FAILED on the interaction-evidence gate —
10014
10754
  // the oracle must say what verify will say, including this.
@@ -10053,7 +10793,7 @@ ${obj[0]}/${total} \xB7 certified ${certifiedReps.length}/${total} \xB7 floor=${
10053
10793
  }
10054
10794
  var BARS3;
10055
10795
  var init_engine2 = __esm({
10056
- "packages/cli/src/commands/engine.ts"() {
10796
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/engine.ts"() {
10057
10797
  "use strict";
10058
10798
  init_src3();
10059
10799
  init_src7();
@@ -10072,7 +10812,7 @@ var init_engine2 = __esm({
10072
10812
  }
10073
10813
  });
10074
10814
 
10075
- // packages/cli/src/commands/codeconnect.ts
10815
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/codeconnect.ts
10076
10816
  var codeconnect_exports = {};
10077
10817
  __export(codeconnect_exports, {
10078
10818
  runCodeConnect: () => runCodeConnect
@@ -10236,7 +10976,7 @@ function runCodeConnect(opts) {
10236
10976
  }
10237
10977
  var kebab4, q;
10238
10978
  var init_codeconnect = __esm({
10239
- "packages/cli/src/commands/codeconnect.ts"() {
10979
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/codeconnect.ts"() {
10240
10980
  "use strict";
10241
10981
  init_src3();
10242
10982
  init_src7();
@@ -10248,7 +10988,7 @@ var init_codeconnect = __esm({
10248
10988
  }
10249
10989
  });
10250
10990
 
10251
- // packages/mcp/src/server.ts
10991
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/mcp/src/server.ts
10252
10992
  import { createHash as createHash5 } from "node:crypto";
10253
10993
  import { existsSync as existsSync28, mkdtempSync as mkdtempSync3, readFileSync as readFileSync25, readdirSync as readdirSync8, writeFileSync as writeFileSync14 } from "node:fs";
10254
10994
  import os6 from "node:os";
@@ -10266,7 +11006,7 @@ function sourceHash() {
10266
11006
  }
10267
11007
  var REPO_ROOT3, CLI_BIN, BUNDLED_CLI, CLI_SPAWN, str, optStr, TOOLS, BOOT_HASH;
10268
11008
  var init_server = __esm({
10269
- "packages/mcp/src/server.ts"() {
11009
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/mcp/src/server.ts"() {
10270
11010
  "use strict";
10271
11011
  REPO_ROOT3 = path34.resolve(path34.dirname(fileURLToPath5(import.meta.url)), "..", "..", "..");
10272
11012
  CLI_BIN = path34.join(REPO_ROOT3, "packages", "cli", "src", "bin.ts");
@@ -10562,7 +11302,7 @@ var init_server = __esm({
10562
11302
  }
10563
11303
  });
10564
11304
 
10565
- // packages/cli/src/commands/permissions.ts
11305
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/permissions.ts
10566
11306
  var permissions_exports = {};
10567
11307
  __export(permissions_exports, {
10568
11308
  PERMISSIONS_DESCRIPTION: () => PERMISSIONS_DESCRIPTION,
@@ -10676,7 +11416,7 @@ ${result.directConfigNote}
10676
11416
  }
10677
11417
  var FIGMA_TOOL_FALLBACK, PERMISSIONS_DESCRIPTION, TENDRIL_PLUGIN_PREFIX, FIGMA_PLUGIN_PREFIX;
10678
11418
  var init_permissions = __esm({
10679
- "packages/cli/src/commands/permissions.ts"() {
11419
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/permissions.ts"() {
10680
11420
  "use strict";
10681
11421
  init_src3();
10682
11422
  init_src();
@@ -10711,7 +11451,7 @@ var init_permissions = __esm({
10711
11451
  }
10712
11452
  });
10713
11453
 
10714
- // packages/cli/src/commands/inspect.ts
11454
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/inspect.ts
10715
11455
  var inspect_exports = {};
10716
11456
  __export(inspect_exports, {
10717
11457
  INSPECT_DESCRIPTION: () => INSPECT_DESCRIPTION,
@@ -10800,7 +11540,7 @@ ${reps.length} config(s), ${crops} detail crop pair(s) \u2014 open the sheet and
10800
11540
  }
10801
11541
  var INSPECT_DESCRIPTION, esc;
10802
11542
  var init_inspect = __esm({
10803
- "packages/cli/src/commands/inspect.ts"() {
11543
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/inspect.ts"() {
10804
11544
  "use strict";
10805
11545
  init_src3();
10806
11546
  init_src6();
@@ -10828,7 +11568,7 @@ var init_inspect = __esm({
10828
11568
  }
10829
11569
  });
10830
11570
 
10831
- // packages/cli/src/commands/generate-route.ts
11571
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/generate-route.ts
10832
11572
  var generate_route_exports = {};
10833
11573
  __export(generate_route_exports, {
10834
11574
  routeGenerate: () => routeGenerate
@@ -10841,12 +11581,12 @@ function routeGenerate(input) {
10841
11581
  return { path: "facts", ...input.url !== void 0 ? { url: input.url } : {} };
10842
11582
  }
10843
11583
  var init_generate_route = __esm({
10844
- "packages/cli/src/commands/generate-route.ts"() {
11584
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/generate-route.ts"() {
10845
11585
  "use strict";
10846
11586
  }
10847
11587
  });
10848
11588
 
10849
- // packages/cli/src/commands/generate-recorded.ts
11589
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/generate-recorded.ts
10850
11590
  var generate_recorded_exports = {};
10851
11591
  __export(generate_recorded_exports, {
10852
11592
  runGenerateRecorded: () => runGenerateRecorded
@@ -11128,7 +11868,7 @@ ${certified}/${statuses.length} certified \xB7 ${statuses.length - pixelFailures
11128
11868
  }
11129
11869
  var BARS4;
11130
11870
  var init_generate_recorded = __esm({
11131
- "packages/cli/src/commands/generate-recorded.ts"() {
11871
+ "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/generate-recorded.ts"() {
11132
11872
  "use strict";
11133
11873
  init_src3();
11134
11874
  init_src5();
@@ -11147,17 +11887,17 @@ var init_generate_recorded = __esm({
11147
11887
  }
11148
11888
  });
11149
11889
 
11150
- // packages/cli/src/bin.ts
11890
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/bin.ts
11151
11891
  init_src3();
11152
11892
  import { CommanderError } from "commander";
11153
11893
 
11154
- // packages/cli/src/program.ts
11894
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/program.ts
11155
11895
  init_src3();
11156
11896
  init_environment();
11157
11897
  init_doctor();
11158
11898
  import { Command } from "commander";
11159
11899
 
11160
- // packages/cli/src/commands/init.ts
11900
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/init.ts
11161
11901
  init_src3();
11162
11902
  init_describe();
11163
11903
  init_env();
@@ -11267,7 +12007,7 @@ async function runInit(flags) {
11267
12007
  });
11268
12008
  }
11269
12009
 
11270
- // packages/cli/src/commands/generate.ts
12010
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/generate.ts
11271
12011
  init_src3();
11272
12012
  init_src();
11273
12013
  init_src5();
@@ -11279,14 +12019,14 @@ init_entitlement();
11279
12019
  import { confirm as confirm2, isCancel as isCancel2 } from "@clack/prompts";
11280
12020
  import { readFileSync as readFileSync15, readdirSync as readdirSync4, existsSync as existsSync18 } from "node:fs";
11281
12021
 
11282
- // packages/cli/src/pipeline.ts
12022
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/pipeline.ts
11283
12023
  init_src2();
11284
12024
  init_src4();
11285
12025
  init_src6();
11286
12026
  import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync8 } from "node:fs";
11287
12027
  import path24 from "node:path";
11288
12028
 
11289
- // packages/cli/src/assets-module.ts
12029
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/assets-module.ts
11290
12030
  init_src();
11291
12031
  var KEBAB_ATTRS = {
11292
12032
  "fill-rule": "fillRule",
@@ -11397,7 +12137,7 @@ function buildAssetsModule(assets, aliases = {}) {
11397
12137
  return { source, flags };
11398
12138
  }
11399
12139
 
11400
- // packages/cli/src/pipeline.ts
12140
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/pipeline.ts
11401
12141
  var VerifyFailedError = class extends Error {
11402
12142
  constructor(loop) {
11403
12143
  super(
@@ -11658,7 +12398,7 @@ async function runGenerationPipeline(input) {
11658
12398
  return { semantics, loop: finalLoop, report, componentJson, usageMd: docs.usageMd, written };
11659
12399
  }
11660
12400
 
11661
- // packages/cli/src/commands/generate.ts
12401
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/generate.ts
11662
12402
  var TOOL_VERSION = "0.0.0";
11663
12403
  var GENERATE_DESCRIPTION = {
11664
12404
  name: "generate",
@@ -11986,7 +12726,7 @@ bundle written to ${flags.out}/${result.semantics.componentName}/:
11986
12726
  );
11987
12727
  }
11988
12728
 
11989
- // packages/cli/src/program.ts
12729
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/program.ts
11990
12730
  init_src4();
11991
12731
  function globalFlags(cmd) {
11992
12732
  const opts = cmd.optsWithGlobals();
@@ -12243,7 +12983,7 @@ function buildProgram() {
12243
12983
  return program;
12244
12984
  }
12245
12985
 
12246
- // packages/cli/src/bin.ts
12986
+ // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/bin.ts
12247
12987
  try {
12248
12988
  await buildProgram().parseAsync(process.argv);
12249
12989
  } catch (err) {