@tendrilapp/cli 0.1.23 → 0.1.24

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
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/core/src/ir.ts
17
+ // 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
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/core/src/ir.ts"() {
21
+ "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
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/source.ts
113
+ // packages/figma/src/source.ts
114
114
  var init_source = __esm({
115
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/source.ts"() {
115
+ "packages/figma/src/source.ts"() {
116
116
  "use strict";
117
117
  }
118
118
  });
119
119
 
120
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/svg-safety.ts
120
+ // 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
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/svg-safety.ts"() {
135
+ "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
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/provided.ts
149
+ // 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
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/provided.ts"() {
153
+ "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
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mcp/client.ts
272
+ // 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
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mcp/client.ts"() {
288
+ "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
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mcp/normalize.ts
392
+ // 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
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mcp/normalize.ts"() {
475
+ "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
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mock/fixtures/button.ts
491
+ // packages/figma/src/mock/fixtures/button.ts
492
492
  var buttonVariables, buttonMetadata, buttonNodeTree;
493
493
  var init_button = __esm({
494
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mock/fixtures/button.ts"() {
494
+ "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
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mock/mock-source.ts
603
+ // packages/figma/src/mock/mock-source.ts
604
604
  var MockFigmaSource;
605
605
  var init_mock_source = __esm({
606
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mock/mock-source.ts"() {
606
+ "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
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/css-ident.ts
643
+ // 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
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/css-ident.ts"() {
652
+ "packages/figma/src/css-ident.ts"() {
653
653
  "use strict";
654
654
  }
655
655
  });
656
656
 
657
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mcp/var-decoder.ts
657
+ // packages/figma/src/mcp/var-decoder.ts
658
658
  var init_var_decoder = __esm({
659
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mcp/var-decoder.ts"() {
659
+ "packages/figma/src/mcp/var-decoder.ts"() {
660
660
  "use strict";
661
661
  init_css_ident();
662
662
  }
663
663
  });
664
664
 
665
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mcp/font-normalize.ts
665
+ // packages/figma/src/mcp/font-normalize.ts
666
666
  var init_font_normalize = __esm({
667
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/mcp/font-normalize.ts"() {
667
+ "packages/figma/src/mcp/font-normalize.ts"() {
668
668
  "use strict";
669
669
  }
670
670
  });
671
671
 
672
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/provided-recording.ts
672
+ // 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
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/provided-recording.ts"() {
687
+ "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
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/recording/axis-defaults.ts
755
+ // 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
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/recording/axis-defaults.ts"() {
790
+ "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
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/recording/plan.ts
813
+ // 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
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/recording/plan.ts"() {
923
+ "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
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/recording/session.ts
931
+ // 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";
@@ -1078,7 +1078,7 @@ function ingestAsset(setDir, slug, name, content) {
1078
1078
  }
1079
1079
  var RECORD_TOOLS, INTERIOR_TOOL, REQUIRED_TOOLS, SessionManifestSchema, manifestPath, PROTOCOL_ORDER, byProtocolOrder;
1080
1080
  var init_session = __esm({
1081
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/recording/session.ts"() {
1081
+ "packages/figma/src/recording/session.ts"() {
1082
1082
  "use strict";
1083
1083
  init_svg_safety();
1084
1084
  init_provided_recording();
@@ -1123,7 +1123,7 @@ var init_session = __esm({
1123
1123
  }
1124
1124
  });
1125
1125
 
1126
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/recording/roles.ts
1126
+ // packages/figma/src/recording/roles.ts
1127
1127
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
1128
1128
  import path2 from "node:path";
1129
1129
  function emissionIdSets(emission) {
@@ -1192,16 +1192,16 @@ function deriveRoles(setDir, manifest) {
1192
1192
  }
1193
1193
  var NODE_ID_RE;
1194
1194
  var init_roles = __esm({
1195
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/recording/roles.ts"() {
1195
+ "packages/figma/src/recording/roles.ts"() {
1196
1196
  "use strict";
1197
1197
  init_session();
1198
1198
  NODE_ID_RE = /data-node-id="([^"]+)"/g;
1199
1199
  }
1200
1200
  });
1201
1201
 
1202
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/index.ts
1202
+ // packages/figma/src/index.ts
1203
1203
  var init_src = __esm({
1204
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/figma/src/index.ts"() {
1204
+ "packages/figma/src/index.ts"() {
1205
1205
  "use strict";
1206
1206
  init_source();
1207
1207
  init_provided();
@@ -1220,12 +1220,12 @@ var init_src = __esm({
1220
1220
  }
1221
1221
  });
1222
1222
 
1223
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/tokens/src/dtcg.ts
1223
+ // packages/tokens/src/dtcg.ts
1224
1224
  function variableNameToPath(name) {
1225
1225
  return name.split("/").map(canonicalCssIdentPart).filter((part) => part.length > 0);
1226
1226
  }
1227
- function tokenPathToCssVar(path38) {
1228
- return `--${path38.join("-")}`;
1227
+ function tokenPathToCssVar(path40) {
1228
+ return `--${path40.join("-")}`;
1229
1229
  }
1230
1230
  function toDtcgToken(variable, defaultMode) {
1231
1231
  const modes = Object.keys(variable.valuesByMode);
@@ -1269,11 +1269,11 @@ function toDtcgToken(variable, defaultMode) {
1269
1269
  }
1270
1270
  function mapVariablesToDtcg(variables, defaultMode = "light") {
1271
1271
  const entries = variables.map((variable) => {
1272
- const path38 = variableNameToPath(variable.name);
1273
- if (path38.length === 0) {
1272
+ const path40 = variableNameToPath(variable.name);
1273
+ if (path40.length === 0) {
1274
1274
  throw new DtcgMappingError("empty-name", `Figma variable ${variable.id} has an empty name`);
1275
1275
  }
1276
- return { variable, path: path38 };
1276
+ return { variable, path: path40 };
1277
1277
  });
1278
1278
  const groupPrefixes = /* @__PURE__ */ new Set();
1279
1279
  for (const e of entries) {
@@ -1294,21 +1294,21 @@ function mapVariablesToDtcg(variables, defaultMode = "light") {
1294
1294
  }
1295
1295
  const tokens = {};
1296
1296
  const flat = [];
1297
- for (const { variable, path: path38 } of entries) {
1297
+ for (const { variable, path: path40 } of entries) {
1298
1298
  const token = toDtcgToken(variable, defaultMode);
1299
1299
  let group = tokens;
1300
- for (const segment of path38.slice(0, -1)) {
1300
+ for (const segment of path40.slice(0, -1)) {
1301
1301
  const existing = group[segment];
1302
1302
  group = existing ?? (group[segment] = {});
1303
1303
  }
1304
- const leaf = path38[path38.length - 1];
1304
+ const leaf = path40[path40.length - 1];
1305
1305
  if (group[leaf] !== void 0) {
1306
- throw new DtcgMappingError("duplicate-path", `Duplicate token path "${path38.join(".")}" (variable ${variable.id})`);
1306
+ throw new DtcgMappingError("duplicate-path", `Duplicate token path "${path40.join(".")}" (variable ${variable.id})`);
1307
1307
  }
1308
1308
  group[leaf] = token;
1309
1309
  flat.push({
1310
- path: path38.join("."),
1311
- cssVar: tokenPathToCssVar(path38),
1310
+ path: path40.join("."),
1311
+ cssVar: tokenPathToCssVar(path40),
1312
1312
  type: token.$type,
1313
1313
  value: token.$value
1314
1314
  });
@@ -1326,7 +1326,7 @@ function mapVariablesToDtcg(variables, defaultMode = "light") {
1326
1326
  }
1327
1327
  var DIMENSION_COLLECTIONS, DtcgMappingError;
1328
1328
  var init_dtcg = __esm({
1329
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/tokens/src/dtcg.ts"() {
1329
+ "packages/tokens/src/dtcg.ts"() {
1330
1330
  "use strict";
1331
1331
  init_src();
1332
1332
  DIMENSION_COLLECTIONS = /* @__PURE__ */ new Set(["spacing", "radius", "size", "border-width"]);
@@ -1341,7 +1341,7 @@ var init_dtcg = __esm({
1341
1341
  }
1342
1342
  });
1343
1343
 
1344
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/tokens/src/emit.ts
1344
+ // packages/tokens/src/emit.ts
1345
1345
  function decomposeFontValue(raw, valueByCssVar) {
1346
1346
  const field = (name) => new RegExp(`${name}:\\s*("[^"]*"|[^,)]+)`).exec(raw)?.[1]?.trim();
1347
1347
  const resolve = (v) => {
@@ -1408,7 +1408,7 @@ export default {
1408
1408
  }
1409
1409
  var STYLE_WEIGHTS;
1410
1410
  var init_emit = __esm({
1411
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/tokens/src/emit.ts"() {
1411
+ "packages/tokens/src/emit.ts"() {
1412
1412
  "use strict";
1413
1413
  init_src();
1414
1414
  STYLE_WEIGHTS = {
@@ -1427,7 +1427,7 @@ var init_emit = __esm({
1427
1427
  }
1428
1428
  });
1429
1429
 
1430
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/tokens/src/synthesize.ts
1430
+ // packages/tokens/src/synthesize.ts
1431
1431
  function synthesizeSpacingVariables(tree, variantFacts, existing) {
1432
1432
  if (existing.some((v) => v.collection === "spacing")) return [];
1433
1433
  const values = /* @__PURE__ */ new Set();
@@ -1466,7 +1466,7 @@ function synthesizeSpacingVariables(tree, variantFacts, existing) {
1466
1466
  }
1467
1467
  var SPACING_FIELDS;
1468
1468
  var init_synthesize = __esm({
1469
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/tokens/src/synthesize.ts"() {
1469
+ "packages/tokens/src/synthesize.ts"() {
1470
1470
  "use strict";
1471
1471
  SPACING_FIELDS = [
1472
1472
  "paddingTop",
@@ -1478,9 +1478,9 @@ var init_synthesize = __esm({
1478
1478
  }
1479
1479
  });
1480
1480
 
1481
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/tokens/src/index.ts
1481
+ // packages/tokens/src/index.ts
1482
1482
  var init_src2 = __esm({
1483
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/tokens/src/index.ts"() {
1483
+ "packages/tokens/src/index.ts"() {
1484
1484
  "use strict";
1485
1485
  init_dtcg();
1486
1486
  init_emit();
@@ -1489,7 +1489,7 @@ var init_src2 = __esm({
1489
1489
  }
1490
1490
  });
1491
1491
 
1492
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/core/src/ir-builder.ts
1492
+ // packages/core/src/ir-builder.ts
1493
1493
  function isObject(value) {
1494
1494
  return typeof value === "object" && value !== null && !Array.isArray(value);
1495
1495
  }
@@ -1497,9 +1497,9 @@ function boundId(value) {
1497
1497
  return isObject(value) && typeof value["boundVariableId"] === "string" ? value["boundVariableId"] : void 0;
1498
1498
  }
1499
1499
  function resolveBinding(ctx, id) {
1500
- const path38 = ctx.pathById.get(id);
1501
- if (path38 === void 0) ctx.unresolved.add(id);
1502
- return path38;
1500
+ const path40 = ctx.pathById.get(id);
1501
+ if (path40 === void 0) ctx.unresolved.add(id);
1502
+ return path40;
1503
1503
  }
1504
1504
  function parseVariantProps(name) {
1505
1505
  if (!name.includes("=")) return void 0;
@@ -1534,8 +1534,8 @@ function walk(ctx, raw) {
1534
1534
  if (!isObject(paint) || paint["visible"] === false) continue;
1535
1535
  const id = boundId(paint);
1536
1536
  if (id !== void 0) {
1537
- const path38 = resolveBinding(ctx, id);
1538
- if (path38 !== void 0) tokens.add(path38);
1537
+ const path40 = resolveBinding(ctx, id);
1538
+ if (path40 !== void 0) tokens.add(path40);
1539
1539
  } else if (typeof paint["color"] === "string") {
1540
1540
  ctx.hardcoded.push({ node: name, property, value: paint["color"] });
1541
1541
  }
@@ -1543,8 +1543,8 @@ function walk(ctx, raw) {
1543
1543
  }
1544
1544
  const radiusId = boundId(raw["cornerRadius"]);
1545
1545
  if (radiusId !== void 0) {
1546
- const path38 = resolveBinding(ctx, radiusId);
1547
- if (path38 !== void 0) tokens.add(path38);
1546
+ const path40 = resolveBinding(ctx, radiusId);
1547
+ if (path40 !== void 0) tokens.add(path40);
1548
1548
  } else if (typeof raw["cornerRadius"] === "number" && raw["cornerRadius"] !== 0) {
1549
1549
  ctx.hardcoded.push({ node: name, property: "border-radius", value: `${raw["cornerRadius"]}px` });
1550
1550
  }
@@ -1554,10 +1554,10 @@ function walk(ctx, raw) {
1554
1554
  layout = { mode: layoutMode === "HORIZONTAL" ? "flex-row" : "flex-column" };
1555
1555
  const gapId = boundId(raw["itemSpacing"]);
1556
1556
  if (gapId !== void 0) {
1557
- const path38 = resolveBinding(ctx, gapId);
1558
- if (path38 !== void 0) {
1559
- layout.gap = path38;
1560
- tokens.add(path38);
1557
+ const path40 = resolveBinding(ctx, gapId);
1558
+ if (path40 !== void 0) {
1559
+ layout.gap = path40;
1560
+ tokens.add(path40);
1561
1561
  }
1562
1562
  } else if (typeof raw["itemSpacing"] === "number" && raw["itemSpacing"] !== 0) {
1563
1563
  ctx.hardcoded.push({ node: name, property: "gap", value: `${raw["itemSpacing"]}px` });
@@ -1566,10 +1566,10 @@ function walk(ctx, raw) {
1566
1566
  for (const field of PADDING_FIELDS) {
1567
1567
  const id = boundId(raw[field]);
1568
1568
  if (id !== void 0) {
1569
- const path38 = resolveBinding(ctx, id);
1570
- if (path38 !== void 0) {
1571
- paddingPaths.push(path38);
1572
- tokens.add(path38);
1569
+ const path40 = resolveBinding(ctx, id);
1570
+ if (path40 !== void 0) {
1571
+ paddingPaths.push(path40);
1572
+ tokens.add(path40);
1573
1573
  }
1574
1574
  } else if (typeof raw[field] === "number" && raw[field] !== 0) {
1575
1575
  ctx.hardcoded.push({ node: name, property: field, value: `${raw[field]}px` });
@@ -1674,7 +1674,7 @@ function canonicalizeFactIdents(variantFacts) {
1674
1674
  }
1675
1675
  var RAW_PAYLOAD_FLAG_BYTES, MIN_HEALTHY_RATIO, RATIO_CHECK_MIN_BYTES, PADDING_FIELDS;
1676
1676
  var init_ir_builder = __esm({
1677
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/core/src/ir-builder.ts"() {
1677
+ "packages/core/src/ir-builder.ts"() {
1678
1678
  "use strict";
1679
1679
  init_src2();
1680
1680
  init_src2();
@@ -1685,10 +1685,10 @@ var init_ir_builder = __esm({
1685
1685
  }
1686
1686
  });
1687
1687
 
1688
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/core/src/exit-codes.ts
1688
+ // packages/core/src/exit-codes.ts
1689
1689
  var ExitCode;
1690
1690
  var init_exit_codes = __esm({
1691
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/core/src/exit-codes.ts"() {
1691
+ "packages/core/src/exit-codes.ts"() {
1692
1692
  "use strict";
1693
1693
  ExitCode = {
1694
1694
  Success: 0,
@@ -1709,7 +1709,7 @@ var init_exit_codes = __esm({
1709
1709
  }
1710
1710
  });
1711
1711
 
1712
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/core/src/readiness.ts
1712
+ // packages/core/src/readiness.ts
1713
1713
  function collectDefaultNamedLayers(tree, found) {
1714
1714
  const name = tree["name"];
1715
1715
  const visible = tree["visible"];
@@ -1759,15 +1759,15 @@ function scoreReadiness(metadata, tree) {
1759
1759
  }
1760
1760
  var DEFAULT_LAYER_NAME;
1761
1761
  var init_readiness = __esm({
1762
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/core/src/readiness.ts"() {
1762
+ "packages/core/src/readiness.ts"() {
1763
1763
  "use strict";
1764
1764
  DEFAULT_LAYER_NAME = /^(Group|Frame|Rectangle|Ellipse|Vector|Component)\s*\d*$/;
1765
1765
  }
1766
1766
  });
1767
1767
 
1768
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/core/src/index.ts
1768
+ // packages/core/src/index.ts
1769
1769
  var init_src3 = __esm({
1770
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/core/src/index.ts"() {
1770
+ "packages/core/src/index.ts"() {
1771
1771
  "use strict";
1772
1772
  init_ir();
1773
1773
  init_ir_builder();
@@ -1776,20 +1776,72 @@ var init_src3 = __esm({
1776
1776
  }
1777
1777
  });
1778
1778
 
1779
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/browser.ts
1780
- import { execFileSync } from "node:child_process";
1781
- import { existsSync as existsSync3, readdirSync } from "node:fs";
1779
+ // packages/cli/src/invocation.ts
1780
+ import { existsSync as existsSync3, realpathSync } from "node:fs";
1782
1781
  import path3 from "node:path";
1782
+ import { fileURLToPath } from "node:url";
1783
+ function findPathTendril(pathEnv, platform) {
1784
+ const dirs = pathEnv.split(path3.delimiter).filter((d) => d !== "" && !/node_modules[\\/]\.bin/.test(d) && !/[\\/]_npx[\\/]/.test(d));
1785
+ const names = platform === "win32" ? ["tendril.cmd", "tendril.bat"] : ["tendril"];
1786
+ for (const dir of dirs) {
1787
+ for (const name of names) {
1788
+ const candidate = path3.join(dir, name);
1789
+ if (existsSync3(candidate)) return candidate;
1790
+ }
1791
+ }
1792
+ return null;
1793
+ }
1794
+ function packageRootOf(file) {
1795
+ let dir = path3.dirname(file);
1796
+ for (; ; ) {
1797
+ if (existsSync3(path3.join(dir, "package.json"))) return dir;
1798
+ const parent = path3.dirname(dir);
1799
+ if (parent === dir) return null;
1800
+ dir = parent;
1801
+ }
1802
+ }
1803
+ function resolveInvocation(pathEnv, platform, selfFile = fileURLToPath(import.meta.url)) {
1804
+ const binary = findPathTendril(pathEnv, platform);
1805
+ if (binary === null) return NPX_INVOCATION;
1806
+ try {
1807
+ const onPath = packageRootOf(realpathSync(binary));
1808
+ const self = packageRootOf(realpathSync(selfFile));
1809
+ if (onPath === null || self === null) return NPX_INVOCATION;
1810
+ return realpathSync(onPath) === realpathSync(self) ? "tendril" : NPX_INVOCATION;
1811
+ } catch {
1812
+ return NPX_INVOCATION;
1813
+ }
1814
+ }
1815
+ function tendrilInvocation() {
1816
+ cached ??= resolveInvocation(process.env["PATH"] ?? "", process.platform);
1817
+ return cached;
1818
+ }
1819
+ function tendrilCommand(args) {
1820
+ return `${tendrilInvocation()} ${args}`;
1821
+ }
1822
+ var NPX_INVOCATION, cached;
1823
+ var init_invocation = __esm({
1824
+ "packages/cli/src/invocation.ts"() {
1825
+ "use strict";
1826
+ NPX_INVOCATION = "npx -y -p @tendrilapp/cli@latest tendril";
1827
+ cached = null;
1828
+ }
1829
+ });
1830
+
1831
+ // packages/verify/src/browser.ts
1832
+ import { execFileSync } from "node:child_process";
1833
+ import { existsSync as existsSync4, readdirSync } from "node:fs";
1834
+ import path4 from "node:path";
1783
1835
  function resolveChrome() {
1784
1836
  const fromEnv = process.env["TENDRIL_CHROME"] ?? process.env["CHROME_PATH"];
1785
1837
  if (fromEnv !== void 0 && fromEnv !== "") {
1786
- if (!existsSync3(fromEnv)) {
1838
+ if (!existsSync4(fromEnv)) {
1787
1839
  throw new Error(`CHROME_PATH points at ${fromEnv}, which does not exist \u2014 fix the variable or unset it to use discovery`);
1788
1840
  }
1789
1841
  return fromEnv;
1790
1842
  }
1791
1843
  const candidates = process.platform === "darwin" ? MAC_CANDIDATES : process.platform === "win32" ? WIN_CANDIDATES : [];
1792
- for (const c of candidates) if (existsSync3(c)) return c;
1844
+ for (const c of candidates) if (existsSync4(c)) return c;
1793
1845
  if (process.platform !== "win32") {
1794
1846
  for (const name of PATH_NAMES) {
1795
1847
  try {
@@ -1803,7 +1855,7 @@ function resolveChrome() {
1803
1855
  }
1804
1856
  function versionFromInstallDir(exePath) {
1805
1857
  try {
1806
- const builds = readdirSync(path3.dirname(exePath), { withFileTypes: true }).filter((e) => e.isDirectory() && /^\d+(\.\d+){3}$/.test(e.name)).map((e) => e.name.split(".").map(Number));
1858
+ const builds = readdirSync(path4.dirname(exePath), { withFileTypes: true }).filter((e) => e.isDirectory() && /^\d+(\.\d+){3}$/.test(e.name)).map((e) => e.name.split(".").map(Number));
1807
1859
  builds.sort((a, b) => a[0] - b[0] || a[1] - b[1] || a[2] - b[2] || a[3] - b[3]);
1808
1860
  return builds.length === 0 ? null : builds[builds.length - 1].join(".");
1809
1861
  } catch {
@@ -1815,7 +1867,7 @@ function windowsBrowserName(exePath) {
1815
1867
  if (p.includes("\\google\\chrome\\")) return "Google Chrome";
1816
1868
  if (p.includes("\\microsoft\\edge\\")) return "Microsoft Edge";
1817
1869
  if (p.includes("chromium")) return "Chromium";
1818
- return path3.win32.basename(exePath, ".exe");
1870
+ return path4.win32.basename(exePath, ".exe");
1819
1871
  }
1820
1872
  function chromeVersion() {
1821
1873
  if (_version !== void 0) return _version;
@@ -1834,7 +1886,7 @@ function chromeVersion() {
1834
1886
  }
1835
1887
  var MAC_CANDIDATES, WIN_CANDIDATES, PATH_NAMES, _version;
1836
1888
  var init_browser = __esm({
1837
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/browser.ts"() {
1889
+ "packages/verify/src/browser.ts"() {
1838
1890
  "use strict";
1839
1891
  MAC_CANDIDATES = [
1840
1892
  "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
@@ -1849,33 +1901,33 @@ var init_browser = __esm({
1849
1901
  }
1850
1902
  });
1851
1903
 
1852
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/runtime.ts
1853
- import { existsSync as existsSync4, mkdtempSync, symlinkSync } from "node:fs";
1904
+ // packages/verify/src/runtime.ts
1905
+ import { existsSync as existsSync5, mkdtempSync, symlinkSync } from "node:fs";
1854
1906
  import { createRequire } from "node:module";
1855
1907
  import os from "node:os";
1856
- import path4 from "node:path";
1857
- import { fileURLToPath } from "node:url";
1908
+ import path5 from "node:path";
1909
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
1858
1910
  function runtimePackageRoot() {
1859
1911
  const env = process.env["TENDRIL_PACKAGE_ROOT"];
1860
- if (env !== void 0 && env !== "") return path4.resolve(env);
1861
- return path4.resolve(path4.dirname(fileURLToPath(import.meta.url)), "..");
1912
+ if (env !== void 0 && env !== "") return path5.resolve(env);
1913
+ return path5.resolve(path5.dirname(fileURLToPath2(import.meta.url)), "..");
1862
1914
  }
1863
1915
  function runtimeNodeModules() {
1864
1916
  const root = runtimePackageRoot();
1865
- for (let dir = root; ; dir = path4.dirname(dir)) {
1866
- const candidate = path4.basename(dir) === "node_modules" ? dir : path4.join(dir, "node_modules");
1867
- if (existsSync4(path4.join(candidate, "react"))) return candidate;
1868
- if (path4.dirname(dir) === dir) break;
1917
+ for (let dir = root; ; dir = path5.dirname(dir)) {
1918
+ const candidate = path5.basename(dir) === "node_modules" ? dir : path5.join(dir, "node_modules");
1919
+ if (existsSync5(path5.join(candidate, "react"))) return candidate;
1920
+ if (path5.dirname(dir) === dir) break;
1869
1921
  }
1870
1922
  throw new Error(
1871
1923
  `Tendril's installed dependencies are missing: no node_modules containing react found at or above ${root}. This is an INSTALLATION problem, not a component error \u2014 reinstall with \`npm install -g @tendrilapp/cli\` (or \`tendrilapp\`) and retry.`
1872
1924
  );
1873
1925
  }
1874
1926
  function newScratchDir(prefix) {
1875
- const dir = mkdtempSync(path4.join(os.tmpdir(), `tendril-${prefix}-`));
1927
+ const dir = mkdtempSync(path5.join(os.tmpdir(), `tendril-${prefix}-`));
1876
1928
  const nodeModules = runtimeNodeModules();
1877
1929
  try {
1878
- symlinkSync(nodeModules, path4.join(dir, "node_modules"), "junction");
1930
+ symlinkSync(nodeModules, path5.join(dir, "node_modules"), "junction");
1879
1931
  } catch (err) {
1880
1932
  throw new Error(
1881
1933
  `Tendril could not link its dependencies into the scratch dir (${nodeModules} -> ${dir}): ${err instanceof Error ? err.message : String(err)}. This is an environment problem, not a component error.`
@@ -1884,7 +1936,7 @@ function newScratchDir(prefix) {
1884
1936
  return dir;
1885
1937
  }
1886
1938
  function reactPinPlugin() {
1887
- const req = createRequire(path4.join(runtimePackageRoot(), "package.json"));
1939
+ const req = createRequire(path5.join(runtimePackageRoot(), "package.json"));
1888
1940
  return {
1889
1941
  name: "tendril-react-pin",
1890
1942
  setup(b) {
@@ -1899,12 +1951,12 @@ function reactPinPlugin() {
1899
1951
  };
1900
1952
  }
1901
1953
  var init_runtime = __esm({
1902
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/runtime.ts"() {
1954
+ "packages/verify/src/runtime.ts"() {
1903
1955
  "use strict";
1904
1956
  }
1905
1957
  });
1906
1958
 
1907
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/gates.ts
1959
+ // packages/verify/src/gates.ts
1908
1960
  function scanForbiddenPatterns(source) {
1909
1961
  const violations = [];
1910
1962
  const lines = source.split("\n");
@@ -1923,7 +1975,7 @@ function scanForbiddenPatterns(source) {
1923
1975
  }
1924
1976
  var FORBIDDEN_PATTERNS;
1925
1977
  var init_gates = __esm({
1926
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/gates.ts"() {
1978
+ "packages/verify/src/gates.ts"() {
1927
1979
  "use strict";
1928
1980
  FORBIDDEN_PATTERNS = [
1929
1981
  { name: "eslint-disable", regex: /eslint-disable/ },
@@ -1935,11 +1987,11 @@ var init_gates = __esm({
1935
1987
  }
1936
1988
  });
1937
1989
 
1938
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/tsc-check.ts
1990
+ // packages/verify/src/tsc-check.ts
1939
1991
  import ts from "typescript";
1940
- import path5 from "node:path";
1992
+ import path6 from "node:path";
1941
1993
  function runTscStrict(files) {
1942
- const program = ts.createProgram(files.map((f) => path5.resolve(f)), STRICT_OPTIONS);
1994
+ const program = ts.createProgram(files.map((f) => path6.resolve(f)), STRICT_OPTIONS);
1943
1995
  const diagnostics = ts.getPreEmitDiagnostics(program);
1944
1996
  const mapped = diagnostics.map((d) => {
1945
1997
  const file = d.file?.fileName;
@@ -1955,7 +2007,7 @@ function runTscStrict(files) {
1955
2007
  }
1956
2008
  var STRICT_OPTIONS;
1957
2009
  var init_tsc_check = __esm({
1958
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/tsc-check.ts"() {
2010
+ "packages/verify/src/tsc-check.ts"() {
1959
2011
  "use strict";
1960
2012
  STRICT_OPTIONS = {
1961
2013
  strict: true,
@@ -1975,7 +2027,7 @@ var init_tsc_check = __esm({
1975
2027
  }
1976
2028
  });
1977
2029
 
1978
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/token-lint.ts
2030
+ // packages/verify/src/token-lint.ts
1979
2031
  import strictValue from "stylelint-declaration-strict-value";
1980
2032
  import stylelint from "stylelint";
1981
2033
  async function runTokenLint(css, fileLabel = "generated.css", definedVars2, recordedMapEmpty = false) {
@@ -2036,7 +2088,7 @@ async function runTokenLint(css, fileLabel = "generated.css", definedVars2, reco
2036
2088
  }
2037
2089
  var TOKEN_ENFORCED_PROPERTIES, ALLOWED_KEYWORDS, STYLELINT_CONFIG, LEGAL_CUSTOM_PROP;
2038
2090
  var init_token_lint = __esm({
2039
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/token-lint.ts"() {
2091
+ "packages/verify/src/token-lint.ts"() {
2040
2092
  "use strict";
2041
2093
  TOKEN_ENFORCED_PROPERTIES = [
2042
2094
  "/color$/",
@@ -2096,9 +2148,9 @@ var init_token_lint = __esm({
2096
2148
  }
2097
2149
  });
2098
2150
 
2099
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/loop.ts
2151
+ // packages/verify/src/loop.ts
2100
2152
  import { rmSync, writeFileSync as writeFileSync2 } from "node:fs";
2101
- import path6 from "node:path";
2153
+ import path7 from "node:path";
2102
2154
  async function runChecks(componentName, files, extraFiles, definedVars2) {
2103
2155
  const findings = [];
2104
2156
  for (const violation of scanForbiddenPatterns(files.tsx)) {
@@ -2113,10 +2165,10 @@ async function runChecks(componentName, files, extraFiles, definedVars2) {
2113
2165
  }
2114
2166
  const workDir = newScratchDir("loop");
2115
2167
  try {
2116
- const tsxPath = path6.join(workDir, `${componentName}.tsx`);
2168
+ const tsxPath = path7.join(workDir, `${componentName}.tsx`);
2117
2169
  writeFileSync2(tsxPath, files.tsx);
2118
2170
  for (const [name, content] of Object.entries(extraFiles ?? {})) {
2119
- writeFileSync2(path6.join(workDir, name), content);
2171
+ writeFileSync2(path7.join(workDir, name), content);
2120
2172
  }
2121
2173
  const tsc = runTscStrict([tsxPath]);
2122
2174
  for (const d of tsc.diagnostics) {
@@ -2170,7 +2222,7 @@ function definedVarsFrom(tokensCss) {
2170
2222
  }
2171
2223
  var SKIPPED_CHECKS;
2172
2224
  var init_loop = __esm({
2173
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/loop.ts"() {
2225
+ "packages/verify/src/loop.ts"() {
2174
2226
  "use strict";
2175
2227
  init_runtime();
2176
2228
  init_gates();
@@ -2180,7 +2232,7 @@ var init_loop = __esm({
2180
2232
  }
2181
2233
  });
2182
2234
 
2183
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/report.ts
2235
+ // packages/verify/src/report.ts
2184
2236
  import { z as z5 } from "zod";
2185
2237
  function isTokenEnforcedProperty(property) {
2186
2238
  return enforcedMatchers.some((m) => m.test(property));
@@ -2220,7 +2272,7 @@ function buildReport(input) {
2220
2272
  }
2221
2273
  var ReportSchema, enforcedMatchers;
2222
2274
  var init_report = __esm({
2223
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/report.ts"() {
2275
+ "packages/verify/src/report.ts"() {
2224
2276
  "use strict";
2225
2277
  init_token_lint();
2226
2278
  ReportSchema = z5.object({
@@ -2282,7 +2334,7 @@ var init_report = __esm({
2282
2334
  }
2283
2335
  });
2284
2336
 
2285
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/mount-limits.ts
2337
+ // packages/verify/src/mount-limits.ts
2286
2338
  function lcdTextEnabled() {
2287
2339
  return process.env["TENDRIL_ENABLE_LCD_TEXT"] === "1";
2288
2340
  }
@@ -2300,14 +2352,14 @@ function raceMountDeadline(work, deadlineMs, onDeadline) {
2300
2352
  }
2301
2353
  var MEMORY_CAP_ARG, ENGINE_MOUNT_DEADLINE_MS;
2302
2354
  var init_mount_limits = __esm({
2303
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/mount-limits.ts"() {
2355
+ "packages/verify/src/mount-limits.ts"() {
2304
2356
  "use strict";
2305
2357
  MEMORY_CAP_ARG = "--js-flags=--max-old-space-size=512";
2306
2358
  ENGINE_MOUNT_DEADLINE_MS = 3e4;
2307
2359
  }
2308
2360
  });
2309
2361
 
2310
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/image-diff.ts
2362
+ // packages/verify/src/image-diff.ts
2311
2363
  import { PNG } from "pngjs";
2312
2364
  import pixelmatch from "pixelmatch";
2313
2365
  function channelDistance(a, b) {
@@ -2749,7 +2801,7 @@ function cropPng(png, x, y, width, height) {
2749
2801
  }
2750
2802
  var INK_DELTA, ABSENT_RADIUS, ABSENT_MIN_PX;
2751
2803
  var init_image_diff = __esm({
2752
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/image-diff.ts"() {
2804
+ "packages/verify/src/image-diff.ts"() {
2753
2805
  "use strict";
2754
2806
  INK_DELTA = 30;
2755
2807
  ABSENT_RADIUS = 3;
@@ -2757,9 +2809,9 @@ var init_image_diff = __esm({
2757
2809
  }
2758
2810
  });
2759
2811
 
2760
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/visual-facts.ts
2761
- import path7 from "node:path";
2762
- import { fileURLToPath as fileURLToPath2 } from "node:url";
2812
+ // packages/verify/src/visual-facts.ts
2813
+ import path8 from "node:path";
2814
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
2763
2815
  import { build } from "esbuild";
2764
2816
  import { chromium } from "playwright-core";
2765
2817
  function resolveAxisValue(declared, props, axis, value) {
@@ -3298,12 +3350,12 @@ ${input.files.css}
3298
3350
  }
3299
3351
  var RESOLVE_DIR, TOLERANCE_PX, WIDTH_SLACK, IMAGE_SIMILARITY_FLOOR, INK_RECALL_FLOOR;
3300
3352
  var init_visual_facts = __esm({
3301
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/visual-facts.ts"() {
3353
+ "packages/verify/src/visual-facts.ts"() {
3302
3354
  "use strict";
3303
3355
  init_browser();
3304
3356
  init_mount_limits();
3305
3357
  init_image_diff();
3306
- RESOLVE_DIR = path7.resolve(path7.dirname(fileURLToPath2(import.meta.url)), "..");
3358
+ RESOLVE_DIR = path8.resolve(path8.dirname(fileURLToPath3(import.meta.url)), "..");
3307
3359
  TOLERANCE_PX = 2;
3308
3360
  WIDTH_SLACK = 0.25;
3309
3361
  IMAGE_SIMILARITY_FLOOR = 0.8;
@@ -3311,27 +3363,27 @@ var init_visual_facts = __esm({
3311
3363
  }
3312
3364
  });
3313
3365
 
3314
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/paths.ts
3315
- import path8 from "node:path";
3316
- import { fileURLToPath as fileURLToPath3 } from "node:url";
3366
+ // packages/verify/src/paths.ts
3367
+ import path9 from "node:path";
3368
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
3317
3369
  var VERIFY_PKG_DIR, REPO_ROOT;
3318
3370
  var init_paths = __esm({
3319
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/paths.ts"() {
3371
+ "packages/verify/src/paths.ts"() {
3320
3372
  "use strict";
3321
- VERIFY_PKG_DIR = path8.resolve(path8.dirname(fileURLToPath3(import.meta.url)), "..");
3322
- REPO_ROOT = path8.resolve(VERIFY_PKG_DIR, "..", "..");
3373
+ VERIFY_PKG_DIR = path9.resolve(path9.dirname(fileURLToPath4(import.meta.url)), "..");
3374
+ REPO_ROOT = path9.resolve(VERIFY_PKG_DIR, "..", "..");
3323
3375
  }
3324
3376
  });
3325
3377
 
3326
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/font-resolve.ts
3378
+ // packages/verify/src/font-resolve.ts
3327
3379
  import { createHash } from "node:crypto";
3328
- import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
3380
+ import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
3329
3381
  import os2 from "node:os";
3330
- import path9 from "node:path";
3382
+ import path10 from "node:path";
3331
3383
  function fontCacheDir() {
3332
3384
  const env = process.env["TENDRIL_FONT_CACHE"];
3333
- if (env !== void 0 && env !== "") return path9.resolve(env);
3334
- return path9.join(os2.homedir(), ".tendril", "fonts");
3385
+ if (env !== void 0 && env !== "") return path10.resolve(env);
3386
+ return path10.join(os2.homedir(), ".tendril", "fonts");
3335
3387
  }
3336
3388
  function normalizeFontLicense(value) {
3337
3389
  return typeof value === "string" && FONT_LICENSES.includes(value) ? value : "unknown";
@@ -3396,25 +3448,25 @@ async function resolveFonts(family, weights, cacheDir = DEFAULT_FONT_CACHE) {
3396
3448
  }
3397
3449
  const bytes = new Uint8Array(await fileRes.arrayBuffer());
3398
3450
  const sha256 = createHash("sha256").update(bytes).digest("hex");
3399
- const file = path9.join(cacheDir, `${family.toLowerCase().replace(/\s+/g, "-")}-${weight}.woff2`);
3451
+ const file = path10.join(cacheDir, `${family.toLowerCase().replace(/\s+/g, "-")}-${weight}.woff2`);
3400
3452
  writeFileSync3(file, bytes);
3401
3453
  resolved.push({ family, weight, source: url, sha256, file, license: meta.license, ...meta.family !== null ? { servedFamily: meta.family } : {} });
3402
3454
  } catch (err) {
3403
3455
  failures.push({ family, weight, reason: `download failed: ${err instanceof Error ? err.message : String(err)}` });
3404
3456
  }
3405
3457
  }
3406
- const mPath = path9.join(cacheDir, "manifest.json");
3407
- const prior = existsSync5(mPath) ? JSON.parse(readFileSync3(mPath, "utf8")) : [];
3408
- const portable2 = resolved.map((m) => ({ ...m, file: path9.basename(m.file) }));
3458
+ const mPath = path10.join(cacheDir, "manifest.json");
3459
+ const prior = existsSync6(mPath) ? JSON.parse(readFileSync3(mPath, "utf8")) : [];
3460
+ const portable2 = resolved.map((m) => ({ ...m, file: path10.basename(m.file) }));
3409
3461
  const merged = [...prior.filter((p) => !resolved.some((m) => m.family === p.family && m.weight === p.weight)), ...portable2];
3410
3462
  if (resolved.length > 0) writeFileSync3(mPath, `${JSON.stringify(merged, null, 2)}
3411
3463
  `);
3412
3464
  return { resolved, failures };
3413
3465
  }
3414
3466
  function addLocalFont(family, weight, filePath, cacheDir = DEFAULT_FONT_CACHE) {
3415
- const src = path9.resolve(filePath);
3416
- if (!existsSync5(src)) throw new Error(`font file not found: ${src}`);
3417
- const ext = path9.extname(src).toLowerCase();
3467
+ const src = path10.resolve(filePath);
3468
+ if (!existsSync6(src)) throw new Error(`font file not found: ${src}`);
3469
+ const ext = path10.extname(src).toLowerCase();
3418
3470
  if (![".woff2", ".woff", ".ttf", ".otf"].includes(ext)) {
3419
3471
  throw new Error(`unsupported font file "${ext}" \u2014 use .woff2 (preferred), .woff, .ttf or .otf`);
3420
3472
  }
@@ -3422,20 +3474,20 @@ function addLocalFont(family, weight, filePath, cacheDir = DEFAULT_FONT_CACHE) {
3422
3474
  if (bytes.length === 0) throw new Error(`font file is empty: ${src}`);
3423
3475
  mkdirSync2(cacheDir, { recursive: true });
3424
3476
  const sha256 = createHash("sha256").update(bytes).digest("hex");
3425
- const file = path9.join(cacheDir, `${family.toLowerCase().replace(/\s+/g, "-")}-${weight}${ext}`);
3477
+ const file = path10.join(cacheDir, `${family.toLowerCase().replace(/\s+/g, "-")}-${weight}${ext}`);
3426
3478
  writeFileSync3(file, bytes);
3427
- const face = { family, weight, source: `local:${path9.basename(src)}`, sha256, file, license: "unknown" };
3428
- const mPath = path9.join(cacheDir, "manifest.json");
3429
- const prior = existsSync5(mPath) ? JSON.parse(readFileSync3(mPath, "utf8")) : [];
3430
- const merged = [...prior.filter((p) => !(p.family === family && p.weight === weight)), { ...face, file: path9.basename(file) }];
3479
+ const face = { family, weight, source: `local:${path10.basename(src)}`, sha256, file, license: "unknown" };
3480
+ const mPath = path10.join(cacheDir, "manifest.json");
3481
+ const prior = existsSync6(mPath) ? JSON.parse(readFileSync3(mPath, "utf8")) : [];
3482
+ const merged = [...prior.filter((p) => !(p.family === family && p.weight === weight)), { ...face, file: path10.basename(file) }];
3431
3483
  writeFileSync3(mPath, `${JSON.stringify(merged, null, 2)}
3432
3484
  `);
3433
3485
  return face;
3434
3486
  }
3435
3487
  function checkFontLock(lockPath, cacheDir = DEFAULT_FONT_CACHE) {
3436
3488
  const lock = JSON.parse(readFileSync3(lockPath, "utf8"));
3437
- const mPath = path9.join(cacheDir, "manifest.json");
3438
- const manifest = existsSync5(mPath) ? JSON.parse(readFileSync3(mPath, "utf8")) : [];
3489
+ const mPath = path10.join(cacheDir, "manifest.json");
3490
+ const manifest = existsSync6(mPath) ? JSON.parse(readFileSync3(mPath, "utf8")) : [];
3439
3491
  return lock.map((l) => {
3440
3492
  const m = manifest.find((x) => x.family === l.family && x.weight === l.weight);
3441
3493
  if (m === void 0) return { family: l.family, weight: l.weight, status: "missing" };
@@ -3443,8 +3495,8 @@ function checkFontLock(lockPath, cacheDir = DEFAULT_FONT_CACHE) {
3443
3495
  });
3444
3496
  }
3445
3497
  function resolvedFontFamilies(cacheDir = DEFAULT_FONT_CACHE) {
3446
- const mPath = path9.join(cacheDir, "manifest.json");
3447
- if (!existsSync5(mPath)) return [];
3498
+ const mPath = path10.join(cacheDir, "manifest.json");
3499
+ if (!existsSync6(mPath)) return [];
3448
3500
  let entries;
3449
3501
  try {
3450
3502
  entries = JSON.parse(readFileSync3(mPath, "utf8"));
@@ -3461,8 +3513,8 @@ function resolvedFontFamilies(cacheDir = DEFAULT_FONT_CACHE) {
3461
3513
  return [...byFamily.entries()].map(([family, w]) => ({ family, weights: [...w].sort((a, b) => a - b) }));
3462
3514
  }
3463
3515
  function requiredFontsManifest(families, cacheDir = DEFAULT_FONT_CACHE) {
3464
- const mPath = path9.join(cacheDir, "manifest.json");
3465
- const manifest = existsSync5(mPath) ? JSON.parse(readFileSync3(mPath, "utf8")) : [];
3516
+ const mPath = path10.join(cacheDir, "manifest.json");
3517
+ const manifest = existsSync6(mPath) ? JSON.parse(readFileSync3(mPath, "utf8")) : [];
3466
3518
  const wanted = new Set(families.map((f) => f.toLowerCase()));
3467
3519
  return manifest.filter((f) => wanted.has(f.family.toLowerCase())).map((f) => ({
3468
3520
  family: f.family,
@@ -3475,8 +3527,8 @@ function requiredFontsManifest(families, cacheDir = DEFAULT_FONT_CACHE) {
3475
3527
  }));
3476
3528
  }
3477
3529
  function facesMissingLicense(cacheDir = DEFAULT_FONT_CACHE) {
3478
- const mPath = path9.join(cacheDir, "manifest.json");
3479
- if (!existsSync5(mPath)) return [];
3530
+ const mPath = path10.join(cacheDir, "manifest.json");
3531
+ if (!existsSync6(mPath)) return [];
3480
3532
  let entries;
3481
3533
  try {
3482
3534
  entries = JSON.parse(readFileSync3(mPath, "utf8"));
@@ -3488,8 +3540,8 @@ function facesMissingLicense(cacheDir = DEFAULT_FONT_CACHE) {
3488
3540
  ).map((e) => ({ family: e.family, weight: e.weight, sha256: e.sha256 }));
3489
3541
  }
3490
3542
  function verifiedFontFamilies(cacheDir = DEFAULT_FONT_CACHE) {
3491
- const mPath = path9.join(cacheDir, "manifest.json");
3492
- if (!existsSync5(mPath)) return [];
3543
+ const mPath = path10.join(cacheDir, "manifest.json");
3544
+ if (!existsSync6(mPath)) return [];
3493
3545
  let entries;
3494
3546
  try {
3495
3547
  entries = JSON.parse(readFileSync3(mPath, "utf8"));
@@ -3499,8 +3551,8 @@ function verifiedFontFamilies(cacheDir = DEFAULT_FONT_CACHE) {
3499
3551
  const byFamily = /* @__PURE__ */ new Map();
3500
3552
  for (const e of entries) {
3501
3553
  if (typeof e.family !== "string" || typeof e.weight !== "number" || typeof e.file !== "string") continue;
3502
- const file = path9.isAbsolute(e.file) && existsSync5(e.file) ? e.file : path9.resolve(cacheDir, path9.basename(e.file));
3503
- if (!existsSync5(file)) continue;
3554
+ const file = path10.isAbsolute(e.file) && existsSync6(e.file) ? e.file : path10.resolve(cacheDir, path10.basename(e.file));
3555
+ if (!existsSync6(file)) continue;
3504
3556
  if (createHash("sha256").update(readFileSync3(file)).digest("hex") !== e.sha256) continue;
3505
3557
  const set = byFamily.get(e.family) ?? /* @__PURE__ */ new Set();
3506
3558
  set.add(e.weight);
@@ -3510,7 +3562,7 @@ function verifiedFontFamilies(cacheDir = DEFAULT_FONT_CACHE) {
3510
3562
  }
3511
3563
  var DEFAULT_FONT_CACHE, UA, FONT_LICENSES, GOOGLE_LICENSE_IDS, GOOGLE_FONT_FILE_PREFIX;
3512
3564
  var init_font_resolve = __esm({
3513
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/font-resolve.ts"() {
3565
+ "packages/verify/src/font-resolve.ts"() {
3514
3566
  "use strict";
3515
3567
  DEFAULT_FONT_CACHE = fontCacheDir();
3516
3568
  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";
@@ -3525,65 +3577,76 @@ var init_font_resolve = __esm({
3525
3577
  }
3526
3578
  });
3527
3579
 
3528
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/font-faces.ts
3580
+ // packages/verify/src/font-faces.ts
3529
3581
  import { createHash as createHash2 } from "node:crypto";
3530
- import { existsSync as existsSync6, readFileSync as readFileSync4 } from "node:fs";
3531
- import path10 from "node:path";
3532
- function fontFaceCss(manifestPath2 = path10.join(fontCacheDir(), "manifest.json")) {
3533
- if (!existsSync6(manifestPath2)) return "";
3582
+ import { existsSync as existsSync7, readFileSync as readFileSync4 } from "node:fs";
3583
+ import path11 from "node:path";
3584
+ function injectedGroups(manifestPath2) {
3585
+ if (!existsSync7(manifestPath2)) return { groups: [], shared: false };
3534
3586
  const claimed = JSON.parse(readFileSync4(manifestPath2, "utf8"));
3535
- const resolveEntry = (f) => {
3536
- if (path10.isAbsolute(f) && existsSync6(f)) return f;
3537
- return path10.resolve(path10.dirname(manifestPath2), path10.basename(f));
3538
- };
3539
- const manifest = claimed.filter((f) => {
3540
- const file = resolveEntry(f.file);
3541
- if (!existsSync6(file)) return false;
3542
- return createHash2("sha256").update(readFileSync4(file)).digest("hex") === f.sha256;
3543
- });
3544
- const resolveFile = (f) => {
3545
- if (path10.isAbsolute(f) && existsSync6(f)) return f;
3546
- return path10.resolve(path10.dirname(manifestPath2), path10.basename(f));
3547
- };
3587
+ const resolveFile = (f) => path11.isAbsolute(f) && existsSync7(f) ? f : path11.resolve(path11.dirname(manifestPath2), path11.basename(f));
3548
3588
  const byFile = /* @__PURE__ */ new Map();
3549
- for (const f of manifest) {
3589
+ for (const f of claimed) {
3590
+ const file = resolveFile(f.file);
3591
+ if (!existsSync7(file)) continue;
3592
+ if (createHash2("sha256").update(readFileSync4(file)).digest("hex") !== f.sha256) continue;
3550
3593
  const k = `${f.family}:${f.file}`;
3551
- const e = byFile.get(k) ?? { family: f.family, weights: [], file: resolveFile(f.file) };
3594
+ const e = byFile.get(k) ?? { family: f.family, weights: [], file };
3552
3595
  e.weights.push(f.weight);
3553
3596
  byFile.set(k, e);
3554
3597
  }
3555
- const files = new Set([...byFile.values()].map((e) => e.file));
3556
- const shared = files.size < byFile.size;
3557
- return [...byFile.values()].map((e) => {
3558
- const weight = shared || e.weights.length > 1 ? "100 700" : String(e.weights[0]);
3598
+ const groups = [...byFile.values()];
3599
+ return { groups, shared: new Set(groups.map((e) => e.file)).size < groups.length };
3600
+ }
3601
+ function fontFaceCss(manifestPath2 = path11.join(fontCacheDir(), "manifest.json")) {
3602
+ const { groups, shared } = injectedGroups(manifestPath2);
3603
+ return groups.map((e) => {
3604
+ const weight = shared || e.weights.length > 1 ? `${SPAN[0]} ${SPAN[1]}` : String(e.weights[0]);
3559
3605
  return `@font-face { font-family: '${e.family}'; font-weight: ${weight}; font-style: normal; src: url(data:font/woff2;base64,${readFileSync4(e.file).toString("base64")}) format('woff2'); }`;
3560
3606
  }).join("\n");
3561
3607
  }
3608
+ function injectedFamilyWeights(manifestPath2 = path11.join(fontCacheDir(), "manifest.json")) {
3609
+ const { groups, shared } = injectedGroups(manifestPath2);
3610
+ const out = /* @__PURE__ */ new Map();
3611
+ for (const g of groups) {
3612
+ const key = g.family.toLowerCase();
3613
+ const e = out.get(key) ?? { weights: /* @__PURE__ */ new Set(), span: false };
3614
+ for (const w of g.weights) e.weights.add(w);
3615
+ if (shared || g.weights.length > 1) e.span = true;
3616
+ out.set(key, e);
3617
+ }
3618
+ return out;
3619
+ }
3620
+ function servesWeight(coverage, weight) {
3621
+ return coverage.weights.has(weight) || coverage.span && weight >= SPAN[0] && weight <= SPAN[1];
3622
+ }
3623
+ var SPAN;
3562
3624
  var init_font_faces = __esm({
3563
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/font-faces.ts"() {
3625
+ "packages/verify/src/font-faces.ts"() {
3564
3626
  "use strict";
3565
3627
  init_font_resolve();
3628
+ SPAN = [100, 700];
3566
3629
  }
3567
3630
  });
3568
3631
 
3569
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/admission.ts
3570
- import { readFileSync as readFileSync5, readdirSync as readdirSync2, existsSync as existsSync7, writeFileSync as writeFileSync4 } from "node:fs";
3571
- import path11 from "node:path";
3632
+ // packages/verify/src/admission.ts
3633
+ import { readFileSync as readFileSync5, readdirSync as readdirSync2, existsSync as existsSync8, writeFileSync as writeFileSync4 } from "node:fs";
3634
+ import path12 from "node:path";
3572
3635
  import { build as build2 } from "esbuild";
3573
3636
  import postcss from "postcss";
3574
3637
  import tailwindcss from "tailwindcss";
3575
3638
  import { chromium as chromium2 } from "playwright-core";
3576
3639
  function fontWeightsByFamily() {
3577
- const mPath = path11.join(fontCacheDir(), "manifest.json");
3640
+ const mPath = path12.join(fontCacheDir(), "manifest.json");
3578
3641
  const out = /* @__PURE__ */ new Map();
3579
- if (!existsSync7(mPath)) return out;
3642
+ if (!existsSync8(mPath)) return out;
3580
3643
  for (const f of JSON.parse(readFileSync5(mPath, "utf8")))
3581
3644
  out.set(f.family, [...out.get(f.family) ?? [], f.weight]);
3582
3645
  return out;
3583
3646
  }
3584
3647
  var FONT_WEIGHTS;
3585
3648
  var init_admission = __esm({
3586
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/admission.ts"() {
3649
+ "packages/verify/src/admission.ts"() {
3587
3650
  "use strict";
3588
3651
  init_paths();
3589
3652
  init_src();
@@ -3596,11 +3659,11 @@ var init_admission = __esm({
3596
3659
  }
3597
3660
  });
3598
3661
 
3599
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/tasks.ts
3600
- import path12 from "node:path";
3662
+ // packages/verify/src/tasks.ts
3663
+ import path13 from "node:path";
3601
3664
  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;
3602
3665
  var init_tasks = __esm({
3603
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/tasks.ts"() {
3666
+ "packages/verify/src/tasks.ts"() {
3604
3667
  "use strict";
3605
3668
  init_paths();
3606
3669
  CALENDAR_CONFIGS = [
@@ -3757,7 +3820,7 @@ BEHAVIORAL CONTRACT (machine-verified, gating): the primary action and close con
3757
3820
  ];
3758
3821
  TASKS = {
3759
3822
  calendar: {
3760
- set: path12.join(REPO_ROOT, "examples/recordings/shadcn-poc-calendar"),
3823
+ set: path13.join(REPO_ROOT, "examples/recordings/shadcn-poc-calendar"),
3761
3824
  entry: "Calendar.tsx",
3762
3825
  configs: CALENDAR_CONFIGS,
3763
3826
  systemApi: CALENDAR_API,
@@ -3765,7 +3828,7 @@ BEHAVIORAL CONTRACT (machine-verified, gating): the primary action and close con
3765
3828
  prelude: { controls: ['[data-tendril-part="day"]'], textInputs: [] }
3766
3829
  },
3767
3830
  "shadcn-button": {
3768
- set: path12.join(REPO_ROOT, "examples/recordings/shadcn-poc-button"),
3831
+ set: path13.join(REPO_ROOT, "examples/recordings/shadcn-poc-button"),
3769
3832
  entry: "Button.tsx",
3770
3833
  configs: BUTTON_CONFIGS,
3771
3834
  systemApi: BUTTON_API,
@@ -3773,7 +3836,7 @@ BEHAVIORAL CONTRACT (machine-verified, gating): the primary action and close con
3773
3836
  prelude: { controls: ["> *"], textInputs: [] }
3774
3837
  },
3775
3838
  combobox: {
3776
- set: path12.join(REPO_ROOT, "examples/recordings/carbon-poc-combobox"),
3839
+ set: path13.join(REPO_ROOT, "examples/recordings/carbon-poc-combobox"),
3777
3840
  entry: "ComboBox.tsx",
3778
3841
  configs: COMBO_CONFIGS,
3779
3842
  systemApi: COMBO_API,
@@ -3781,7 +3844,7 @@ BEHAVIORAL CONTRACT (machine-verified, gating): the primary action and close con
3781
3844
  prelude: { controls: ['[role="option"]'], textInputs: ["input"], popover: { selector: '[role="listbox"]', trigger: "input" } }
3782
3845
  },
3783
3846
  modal: {
3784
- set: path12.join(REPO_ROOT, "examples/recordings/carbon-poc-modal"),
3847
+ set: path13.join(REPO_ROOT, "examples/recordings/carbon-poc-modal"),
3785
3848
  entry: "Modal.tsx",
3786
3849
  configs: MODAL_CONFIGS,
3787
3850
  systemApi: MODAL_API,
@@ -3792,15 +3855,15 @@ BEHAVIORAL CONTRACT (machine-verified, gating): the primary action and close con
3792
3855
  }
3793
3856
  });
3794
3857
 
3795
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/behavior.ts
3858
+ // packages/verify/src/behavior.ts
3796
3859
  var behavior_exports = {};
3797
3860
  __export(behavior_exports, {
3798
3861
  checkBehaviors: () => checkBehaviors,
3799
3862
  compileMount: () => compileMount,
3800
3863
  recordingIsDark: () => recordingIsDark
3801
3864
  });
3802
- import { existsSync as existsSync8, readFileSync as readFileSync6 } from "node:fs";
3803
- import path13 from "node:path";
3865
+ import { existsSync as existsSync9, readFileSync as readFileSync6 } from "node:fs";
3866
+ import path14 from "node:path";
3804
3867
  import { build as build3 } from "esbuild";
3805
3868
  import { chromium as chromium3 } from "playwright-core";
3806
3869
  import { PNG as PNG2 } from "pngjs";
@@ -3809,12 +3872,12 @@ function getFontFaces() {
3809
3872
  return _fontFaces;
3810
3873
  }
3811
3874
  async function compileMount(task, bundleDir) {
3812
- const entryTsx = path13.join(bundleDir, task.entry);
3813
- if (!existsSync8(entryTsx)) return { error: `${task.entry} missing` };
3875
+ const entryTsx = path14.join(bundleDir, task.entry);
3876
+ if (!existsSync9(entryTsx)) return { error: `${task.entry} missing` };
3814
3877
  const mountSrc = `
3815
3878
  import { createElement } from "react";
3816
3879
  import { createRoot } from "react-dom/client";
3817
- import * as B from ${JSON.stringify(path13.resolve(entryTsx))};
3880
+ import * as B from ${JSON.stringify(path14.resolve(entryTsx))};
3818
3881
  const cfg = (window as unknown as { __cfg: { component: string; props: Record<string, unknown>; spyProps?: string[] } }).__cfg;
3819
3882
  const C = (B as Record<string, unknown>)[cfg.component] as Parameters<typeof createElement>[0] | undefined;
3820
3883
  // Callbacks cannot ride the JSON config: specs NAME spy props and the
@@ -4066,8 +4129,8 @@ async function runSteps(page, spec, renderPose) {
4066
4129
  function recordingIsDark(task) {
4067
4130
  const rep = task.configs[0]?.rep;
4068
4131
  if (rep === void 0) return false;
4069
- const f = path13.join(task.set, rep, "get_screenshot.json");
4070
- if (!existsSync8(f)) return false;
4132
+ const f = path14.join(task.set, rep, "get_screenshot.json");
4133
+ if (!existsSync9(f)) return false;
4071
4134
  try {
4072
4135
  const env = JSON.parse(readFileSync6(f, "utf8")).content.find((c) => c.type === "image");
4073
4136
  if (env?.data === void 0) return false;
@@ -4141,7 +4204,7 @@ async function checkBehaviors(task, bundleDir, opts = {}) {
4141
4204
  const deadlineMs = timeoutMs + 1e4;
4142
4205
  const js = await compileMount(task, bundleDir);
4143
4206
  if (typeof js !== "string") return task.behaviors.map((b) => ({ id: b.id, pass: false, detail: js.error }));
4144
- const css = ["tokens.css", "styles.css"].map((f) => path13.join(bundleDir, f)).filter((f) => existsSync8(f)).map((f) => readFileSync6(f, "utf8")).join("\n");
4207
+ const css = ["tokens.css", "styles.css"].map((f) => path14.join(bundleDir, f)).filter((f) => existsSync9(f)).map((f) => readFileSync6(f, "utf8")).join("\n");
4145
4208
  const server = await chromium3.launchServer({ executablePath: resolveChrome(), headless: true, args: mountArgs() });
4146
4209
  const browser = await chromium3.connect(server.wsEndpoint());
4147
4210
  const results = [];
@@ -4248,7 +4311,7 @@ body{margin:0;padding:20px}
4248
4311
  }
4249
4312
  var _fontFaces, ANIMATED_PROBE, COMMIT_GAP_CLOSED, POSE_GAP_FLOOR, PRELUDE_ROOT_PROPS;
4250
4313
  var init_behavior = __esm({
4251
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/behavior.ts"() {
4314
+ "packages/verify/src/behavior.ts"() {
4252
4315
  "use strict";
4253
4316
  init_runtime();
4254
4317
  init_browser();
@@ -4283,9 +4346,9 @@ var init_behavior = __esm({
4283
4346
  }
4284
4347
  });
4285
4348
 
4286
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/bundle-quality.ts
4287
- import { readFileSync as readFileSync7, rmSync as rmSync2, writeFileSync as writeFileSync5, existsSync as existsSync9 } from "node:fs";
4288
- import path14 from "node:path";
4349
+ // packages/verify/src/bundle-quality.ts
4350
+ import { readFileSync as readFileSync7, rmSync as rmSync2, writeFileSync as writeFileSync5, existsSync as existsSync10 } from "node:fs";
4351
+ import path15 from "node:path";
4289
4352
  function definedVars(tokensCss) {
4290
4353
  if (tokensCss === void 0) return void 0;
4291
4354
  const names = /* @__PURE__ */ new Set();
@@ -4294,7 +4357,7 @@ function definedVars(tokensCss) {
4294
4357
  }
4295
4358
  function recordedTokenMapEmpty(setDir, reps) {
4296
4359
  const readMap = (file) => {
4297
- if (!existsSync9(file)) return void 0;
4360
+ if (!existsSync10(file)) return void 0;
4298
4361
  try {
4299
4362
  const parsed = JSON.parse(envelopeFirstTextPart(JSON.parse(readFileSync7(file, "utf8"))) || "{}");
4300
4363
  return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
@@ -4302,28 +4365,93 @@ function recordedTokenMapEmpty(setDir, reps) {
4302
4365
  return {};
4303
4366
  }
4304
4367
  };
4305
- const setLevel = readMap(path14.join(setDir, "get_variable_defs.json"));
4368
+ const setLevel = readMap(path15.join(setDir, "get_variable_defs.json"));
4306
4369
  if (setLevel !== void 0) return Object.keys(setLevel).length === 0;
4307
4370
  let recorded = false;
4308
4371
  for (const rep of reps) {
4309
- const m = readMap(path14.join(setDir, rep, "get_variable_defs.json"));
4372
+ const m = readMap(path15.join(setDir, rep, "get_variable_defs.json"));
4310
4373
  if (m === void 0) continue;
4311
4374
  recorded = true;
4312
4375
  if (Object.keys(m).length > 0) return false;
4313
4376
  }
4314
4377
  return recorded;
4315
4378
  }
4316
- async function checkBundleQuality(bundleDir, entry, set) {
4379
+ function scannable(css) {
4380
+ const blank = (m) => m.replace(/[^\n]/g, " ");
4381
+ return css.replace(/\/\*[^]*?\*\//g, blank).replace(/@font-face\s*{[^}]*}/g, blank);
4382
+ }
4383
+ function usedWeights(css) {
4384
+ const out = /* @__PURE__ */ new Set();
4385
+ for (const m of css.matchAll(/font-weight\s*:\s*([^;}]+)/g)) {
4386
+ const v = declValue(m[1]).toLowerCase();
4387
+ if (v === "bold") out.add(700);
4388
+ else if (v === "normal") out.add(400);
4389
+ else if (/^\d{1,4}$/.test(v)) out.add(Number(v));
4390
+ }
4391
+ return [...out].sort((a, b) => a - b);
4392
+ }
4393
+ function fontStacks(css) {
4394
+ const out = [];
4395
+ for (const m of css.matchAll(/font-family\s*:\s*([^;}]+)/g)) {
4396
+ const text = declValue(m[1]);
4397
+ const families = text.split(",").map((f) => f.trim().replace(/^['"]|['"]$/g, "")).filter((f) => f !== "");
4398
+ if (families.length > 0) out.push({ families, line: css.slice(0, m.index).split("\n").length, text });
4399
+ }
4400
+ return out;
4401
+ }
4402
+ function fontStackFindings(sheets, coverage) {
4403
+ if (coverage.size === 0) return [];
4404
+ const scanned = sheets.map((s) => ({ file: s.file, css: scannable(s.css) }));
4405
+ const weights = [...new Set(scanned.flatMap((s) => usedWeights(s.css)))].sort((a, b) => a - b);
4406
+ if (weights.length === 0) return [];
4407
+ const findings = [];
4408
+ const seen = /* @__PURE__ */ new Set();
4409
+ for (const sheet of scanned) {
4410
+ for (const stack of fontStacks(sheet.css)) {
4411
+ if (seen.has(stack.text)) continue;
4412
+ seen.add(stack.text);
4413
+ const family = stack.families[0];
4414
+ const bound = coverage.get(family.toLowerCase());
4415
+ if (bound === void 0) continue;
4416
+ const unserved = weights.filter((w) => !servesWeight(bound, w));
4417
+ if (unserved.length === 0) continue;
4418
+ const rescue = stack.families.slice(1).find((f) => {
4419
+ const c = coverage.get(f.toLowerCase());
4420
+ return c !== void 0 && unserved.every((w) => servesWeight(c, w));
4421
+ });
4422
+ const has = bound.span ? "100\u2013700" : [...bound.weights].sort((a, b) => a - b).join(", ");
4423
+ const list = unserved.join(", ");
4424
+ const renders = !bound.span && bound.weights.size === 1 ? `renders in the ${[...bound.weights][0]} face` : "renders in whichever of those faces is nearest";
4425
+ findings.push({
4426
+ kind: "font-stack",
4427
+ file: sheet.file,
4428
+ line: stack.line,
4429
+ message: `font-family ${stack.text} binds to '${family}', which the font kit provides at ${has} \u2014 CSS matches the FAMILY first and picks a weight only inside it (a later family is never consulted for a missing weight, and the prelude's font-synthesis: none rules out faux-bold), so text at weight ${list} ${renders}, silently. ` + (rescue !== void 0 ? `'${rescue}' in this same stack provides ${list}: list it first.` : `No family in this stack provides ${list} \u2014 if the recording shows ${unserved.length === 1 ? "that weight" : "those weights"}, run \`tendril fonts resolve "${family}" --weights ${unserved.join(" ")}\` and re-score.`) + " ADVISORY: quality feedback only \u2014 it never moves a score, a tier, or the verdict."
4430
+ });
4431
+ }
4432
+ }
4433
+ return findings;
4434
+ }
4435
+ async function checkBundleQuality(bundleDir, entry, set, fontManifest) {
4317
4436
  const findings = [];
4318
- const entryPath = path14.join(bundleDir, entry);
4319
- const cssPath = path14.join(bundleDir, "styles.css");
4320
- const tokensPath = path14.join(bundleDir, "tokens.css");
4321
- const css = existsSync9(cssPath) ? readFileSync7(cssPath, "utf8") : "";
4322
- const tokensCss = existsSync9(tokensPath) ? readFileSync7(tokensPath, "utf8") : void 0;
4323
- if (existsSync9(entryPath)) {
4437
+ const entryPath = path15.join(bundleDir, entry);
4438
+ const cssPath = path15.join(bundleDir, "styles.css");
4439
+ const tokensPath = path15.join(bundleDir, "tokens.css");
4440
+ const css = existsSync10(cssPath) ? readFileSync7(cssPath, "utf8") : "";
4441
+ const tokensCss = existsSync10(tokensPath) ? readFileSync7(tokensPath, "utf8") : void 0;
4442
+ findings.push(
4443
+ ...fontStackFindings(
4444
+ [
4445
+ { file: "styles.css", css },
4446
+ ...tokensCss === void 0 ? [] : [{ file: "tokens.css", css: tokensCss }]
4447
+ ],
4448
+ injectedFamilyWeights(fontManifest)
4449
+ )
4450
+ );
4451
+ if (existsSync10(entryPath)) {
4324
4452
  const workDir = newScratchDir("quality");
4325
4453
  try {
4326
- const tsxPath = path14.join(workDir, entry);
4454
+ const tsxPath = path15.join(workDir, entry);
4327
4455
  writeFileSync5(tsxPath, readFileSync7(entryPath, "utf8"));
4328
4456
  for (const d of runTscStrict([tsxPath]).diagnostics) {
4329
4457
  findings.push({ kind: "tsc", file: entry, ...d.line === void 0 ? {} : { line: d.line }, message: `TS${d.code}: ${d.message}` });
@@ -4340,17 +4468,20 @@ async function checkBundleQuality(bundleDir, entry, set) {
4340
4468
  }
4341
4469
  return { findings, tokensAbsent: tokensCss === void 0 && !/var\(\s*--/.test(css) };
4342
4470
  }
4471
+ var declValue;
4343
4472
  var init_bundle_quality = __esm({
4344
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/bundle-quality.ts"() {
4473
+ "packages/verify/src/bundle-quality.ts"() {
4345
4474
  "use strict";
4346
4475
  init_src();
4476
+ init_font_faces();
4347
4477
  init_runtime();
4348
4478
  init_tsc_check();
4349
4479
  init_token_lint();
4480
+ declValue = (raw) => raw.trim().replace(/\s*!important$/i, "").trim();
4350
4481
  }
4351
4482
  });
4352
4483
 
4353
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/effect-geometry.ts
4484
+ // packages/verify/src/effect-geometry.ts
4354
4485
  function fold(into, dx, dy, radius, spread) {
4355
4486
  const reach = radius + spread;
4356
4487
  into.top = Math.max(into.top, reach - dy);
@@ -4382,15 +4513,15 @@ function extentsExplainPad(near, far, pad, tolerance = 2) {
4382
4513
  }
4383
4514
  var NO_EXTENTS;
4384
4515
  var init_effect_geometry = __esm({
4385
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/effect-geometry.ts"() {
4516
+ "packages/verify/src/effect-geometry.ts"() {
4386
4517
  "use strict";
4387
4518
  NO_EXTENTS = { top: 0, right: 0, bottom: 0, left: 0 };
4388
4519
  }
4389
4520
  });
4390
4521
 
4391
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/bundle-score.ts
4392
- import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "node:fs";
4393
- import path15 from "node:path";
4522
+ // packages/verify/src/bundle-score.ts
4523
+ import { existsSync as existsSync11, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "node:fs";
4524
+ import path16 from "node:path";
4394
4525
  import { build as build4 } from "esbuild";
4395
4526
  import { chromium as chromium4 } from "playwright-core";
4396
4527
  function getFontFaces2() {
@@ -4444,7 +4575,7 @@ function chooseSeat(cropAt, ref, padW, padH, backdrop, origin, extents) {
4444
4575
  }
4445
4576
  function metadataRoot(set, rep) {
4446
4577
  try {
4447
- const text = JSON.parse(readFileSync8(path15.join(set, rep, "get_metadata.json"), "utf8")).content.map((c) => c.text ?? "").join("\n");
4578
+ const text = JSON.parse(readFileSync8(path16.join(set, rep, "get_metadata.json"), "utf8")).content.map((c) => c.text ?? "").join("\n");
4448
4579
  return parseMetadataStructure(text);
4449
4580
  } catch {
4450
4581
  return void 0;
@@ -4499,17 +4630,17 @@ function smallSemanticNodes(set, rep, maxArea = 1024) {
4499
4630
  });
4500
4631
  }
4501
4632
  function repMeta(set, rep) {
4502
- const text = JSON.parse(readFileSync8(path15.join(set, rep, "get_metadata.json"), "utf8")).content.map((c) => c.text ?? "").join("\n");
4633
+ const text = JSON.parse(readFileSync8(path16.join(set, rep, "get_metadata.json"), "utf8")).content.map((c) => c.text ?? "").join("\n");
4503
4634
  const root = parseMetadataStructure(text);
4504
4635
  return { w: Math.round(root.width ?? 100), h: Math.round(root.height ?? 40) };
4505
4636
  }
4506
4637
  function repRef(set, rep) {
4507
- const env = JSON.parse(readFileSync8(path15.join(set, rep, "get_screenshot.json"), "utf8")).content.find((c) => c.type === "image");
4638
+ const env = JSON.parse(readFileSync8(path16.join(set, rep, "get_screenshot.json"), "utf8")).content.find((c) => c.type === "image");
4508
4639
  return Uint8Array.from(Buffer.from(env?.data ?? "", "base64"));
4509
4640
  }
4510
4641
  function repEffectExtents(set, rep) {
4511
- const file = path15.join(set, rep, "get_design_context.json");
4512
- if (!existsSync10(file)) return void 0;
4642
+ const file = path16.join(set, rep, "get_design_context.json");
4643
+ if (!existsSync11(file)) return void 0;
4513
4644
  try {
4514
4645
  const text = JSON.parse(readFileSync8(file, "utf8")).content.map((c) => c.text ?? "").join("\n");
4515
4646
  const extents = shadowExtents(text);
@@ -4522,13 +4653,13 @@ async function scoreBundleForTask(task, bundleDir, bar = BAR, opts = {}) {
4522
4653
  if (opts.evidenceDir !== void 0) mkdirSync3(opts.evidenceDir, { recursive: true });
4523
4654
  const CONFIGS2 = task.configs;
4524
4655
  const timeoutMs = opts.mountDeadlineMs ?? ENGINE_MOUNT_DEADLINE_MS;
4525
- const entryTsx = path15.join(bundleDir, task.entry);
4526
- if (!existsSync10(entryTsx)) return CONFIGS2.map((c) => ({ rep: c.rep, similarity: 0, inkRecall: 0, exact: { similarity: 0, inkRecall: 0 }, pass: false, error: `${task.entry} missing` }));
4527
- const css = ["tokens.css", "styles.css"].map((f) => path15.join(bundleDir, f)).filter((f) => existsSync10(f)).map((f) => readFileSync8(f, "utf8")).join("\n");
4656
+ const entryTsx = path16.join(bundleDir, task.entry);
4657
+ if (!existsSync11(entryTsx)) return CONFIGS2.map((c) => ({ rep: c.rep, similarity: 0, inkRecall: 0, exact: { similarity: 0, inkRecall: 0 }, pass: false, error: `${task.entry} missing` }));
4658
+ const css = ["tokens.css", "styles.css"].map((f) => path16.join(bundleDir, f)).filter((f) => existsSync11(f)).map((f) => readFileSync8(f, "utf8")).join("\n");
4528
4659
  const mountSrc = `
4529
4660
  import { createElement } from "react";
4530
4661
  import { createRoot } from "react-dom/client";
4531
- import * as B from ${JSON.stringify(path15.resolve(entryTsx))};
4662
+ import * as B from ${JSON.stringify(path16.resolve(entryTsx))};
4532
4663
  const cfg = (window as unknown as { __cfg: { component: string; props: Record<string, unknown> } }).__cfg;
4533
4664
  const C = (B as Record<string, unknown>)[cfg.component] as Parameters<typeof createElement>[0] | undefined;
4534
4665
  const root = document.getElementById("root");
@@ -4623,12 +4754,12 @@ body{margin:0;background:rgb(${backdrop.join(",")})}
4623
4754
  return name === void 0 ? c : { ...c, name };
4624
4755
  });
4625
4756
  if (opts.evidenceDir !== void 0) {
4626
- writeFileSync6(path15.join(opts.evidenceDir, `${cfg.rep}-render.png`), scored);
4627
- writeFileSync6(path15.join(opts.evidenceDir, `${cfg.rep}-ref.png`), ref);
4628
- writeFileSync6(path15.join(opts.evidenceDir, `${cfg.rep}-diff.png`), diffPng(scored, ref));
4757
+ writeFileSync6(path16.join(opts.evidenceDir, `${cfg.rep}-render.png`), scored);
4758
+ writeFileSync6(path16.join(opts.evidenceDir, `${cfg.rep}-ref.png`), ref);
4759
+ writeFileSync6(path16.join(opts.evidenceDir, `${cfg.rep}-diff.png`), diffPng(scored, ref));
4629
4760
  for (const [i, c] of absent.slice(0, 3).entries()) {
4630
- writeFileSync6(path15.join(opts.evidenceDir, `${cfg.rep}-absent-${i}-ref.png`), zoomCrop(ref, c));
4631
- writeFileSync6(path15.join(opts.evidenceDir, `${cfg.rep}-absent-${i}-render.png`), zoomCrop(scored, c));
4761
+ writeFileSync6(path16.join(opts.evidenceDir, `${cfg.rep}-absent-${i}-ref.png`), zoomCrop(ref, c));
4762
+ writeFileSync6(path16.join(opts.evidenceDir, `${cfg.rep}-absent-${i}-render.png`), zoomCrop(scored, c));
4632
4763
  }
4633
4764
  }
4634
4765
  return {
@@ -4688,7 +4819,7 @@ body{margin:0;background:rgb(${backdrop.join(",")})}
4688
4819
  }
4689
4820
  var BAR, MARGIN, _fontFaces2, CONFIGS, SEAT_WINDOW, EFFECT_BLEED_MAX;
4690
4821
  var init_bundle_score = __esm({
4691
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/bundle-score.ts"() {
4822
+ "packages/verify/src/bundle-score.ts"() {
4692
4823
  "use strict";
4693
4824
  init_runtime();
4694
4825
  init_browser();
@@ -4706,11 +4837,11 @@ var init_bundle_score = __esm({
4706
4837
  }
4707
4838
  });
4708
4839
 
4709
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/containment.ts
4840
+ // packages/verify/src/containment.ts
4710
4841
  import { build as build5 } from "esbuild";
4711
4842
  import { chromium as chromium5 } from "playwright-core";
4712
4843
  var init_containment = __esm({
4713
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/containment.ts"() {
4844
+ "packages/verify/src/containment.ts"() {
4714
4845
  "use strict";
4715
4846
  init_runtime();
4716
4847
  init_browser();
@@ -4720,14 +4851,14 @@ var init_containment = __esm({
4720
4851
  }
4721
4852
  });
4722
4853
 
4723
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/prelude.ts
4854
+ // packages/verify/src/prelude.ts
4724
4855
  var PRELUDE_CONTRACT;
4725
4856
  var init_prelude = __esm({
4726
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/prelude.ts"() {
4857
+ "packages/verify/src/prelude.ts"() {
4727
4858
  "use strict";
4728
4859
  PRELUDE_CONTRACT = `BUNDLE PRELUDE (machine-verified on computed styles \u2014 the harness page provides NONE of this; your CSS must):
4729
4860
  - 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).
4730
- - Component root: -webkit-font-smoothing: antialiased and -moz-osx-font-smoothing: grayscale (recorded rasterization); font-synthesis: none (a missing font weight must fall back visibly, never fake-bold); color-scheme MATCHING YOUR RECORDING (light for a light capture, dark for a dark one) and direction: ltr \u2014 pin them, so the render cannot follow the viewer OS preference and drift from the capture it is graded against; isolation: isolate (own stacking context; overlay z-indexes never fight the host).
4861
+ - Component root: -webkit-font-smoothing: antialiased and -moz-osx-font-smoothing: grayscale (recorded rasterization); font-synthesis: none (no faux bold or italic \u2014 text renders in the face your stack actually binds, so a weight the kit cannot serve reaches the score instead of being faked; it does NOT fall through to the next family in the stack); color-scheme MATCHING YOUR RECORDING (light for a light capture, dark for a dark one) and direction: ltr \u2014 pin them, so the render cannot follow the viewer OS preference and drift from the capture it is graded against; isolation: isolate (own stacking context; overlay z-indexes never fight the host).
4731
4862
  - Interactive controls (buttons, options): touch-action: manipulation and user-select: none. Text inputs stay selectable (never user-select: none on them).
4732
4863
  - Scrollable popovers/menus: overscroll-behavior: contain.
4733
4864
  - Focus indicators bind to :focus-visible, never bare :focus. If the recording contains a focus pose, style the indicator from that recorded truth. If NO focus pose is recorded, do NOT invent ring colors/widths/offsets \u2014 an invented ring is unrecorded pixels; keep the browser's default indicator for keyboard focus and state the gap in your report. Text inputs match :focus-visible even on mouse click BY SPEC; the ONE permitted refinement is suppressing the indicator on a POSITIVELY OBSERVED pointer press, fail-safe toward showing it (programmatic focus, restored focus, and assistive tech all count as keyboard and keep the ring \u2014 WCAG 2.4.7 binds keyboard operation). Never suppress more broadly than an observed press, and never restyle what you kept.
@@ -4735,9 +4866,9 @@ var init_prelude = __esm({
4735
4866
  }
4736
4867
  });
4737
4868
 
4738
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/parity.ts
4739
- import { existsSync as existsSync11, readFileSync as readFileSync9 } from "node:fs";
4740
- import path16 from "node:path";
4869
+ // packages/verify/src/parity.ts
4870
+ import { existsSync as existsSync12, readFileSync as readFileSync9 } from "node:fs";
4871
+ import path17 from "node:path";
4741
4872
  import { chromium as chromium6 } from "playwright-core";
4742
4873
  function getFontFaces3() {
4743
4874
  _fontFaces3 ??= fontFaceCss();
@@ -4766,7 +4897,7 @@ async function checkHoverParity(task, bundleDir, opts = {}) {
4766
4897
  const deadlineMs = timeoutMs + 1e4;
4767
4898
  const js = await compileMount(task, bundleDir);
4768
4899
  if (typeof js !== "string") return configs.map((c) => ({ id: `parity:${c.rep}`, pass: false, detail: js.error }));
4769
- const css = ["tokens.css", "styles.css"].map((f) => path16.join(bundleDir, f)).filter((f) => existsSync11(f)).map((f) => readFileSync9(f, "utf8")).join("\n");
4900
+ const css = ["tokens.css", "styles.css"].map((f) => path17.join(bundleDir, f)).filter((f) => existsSync12(f)).map((f) => readFileSync9(f, "utf8")).join("\n");
4770
4901
  const server = await chromium6.launchServer({ executablePath: resolveChrome(), headless: true, args: mountArgs() });
4771
4902
  const browser = await chromium6.connect(server.wsEndpoint());
4772
4903
  const results = [];
@@ -4835,7 +4966,7 @@ body{margin:0;padding:20px}
4835
4966
  }
4836
4967
  var _fontFaces3;
4837
4968
  var init_parity = __esm({
4838
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/parity.ts"() {
4969
+ "packages/verify/src/parity.ts"() {
4839
4970
  "use strict";
4840
4971
  init_browser();
4841
4972
  init_behavior();
@@ -4844,10 +4975,10 @@ var init_parity = __esm({
4844
4975
  }
4845
4976
  });
4846
4977
 
4847
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/composition.ts
4978
+ // packages/verify/src/composition.ts
4848
4979
  import { createRequire as createRequire2 } from "node:module";
4849
- import { existsSync as existsSync12, readFileSync as readFileSync10 } from "node:fs";
4850
- import path17 from "node:path";
4980
+ import { existsSync as existsSync13, readFileSync as readFileSync10 } from "node:fs";
4981
+ import path18 from "node:path";
4851
4982
  import { build as build6 } from "esbuild";
4852
4983
  import { chromium as chromium7 } from "playwright-core";
4853
4984
  function getFontFaces4() {
@@ -4855,9 +4986,9 @@ function getFontFaces4() {
4855
4986
  return _fontFaces4;
4856
4987
  }
4857
4988
  async function compileInstrumentedMount(task, bundleDir) {
4858
- const entryTsx = path17.join(bundleDir, task.entry);
4859
- if (!existsSync12(entryTsx)) return { error: `${task.entry} missing` };
4860
- const requireFromVerify = createRequire2(path17.join(VERIFY_PKG_DIR, "package.json"));
4989
+ const entryTsx = path18.join(bundleDir, task.entry);
4990
+ if (!existsSync13(entryTsx)) return { error: `${task.entry} missing` };
4991
+ const requireFromVerify = createRequire2(path18.join(VERIFY_PKG_DIR, "package.json"));
4861
4992
  let realJsxPath;
4862
4993
  try {
4863
4994
  realJsxPath = requireFromVerify.resolve("react/jsx-runtime");
@@ -4868,7 +4999,7 @@ async function compileInstrumentedMount(task, bundleDir) {
4868
4999
  import { createElement } from "react";
4869
5000
  import { createRoot } from "react-dom/client";
4870
5001
  import { __registerParts } from "react/jsx-runtime";
4871
- import * as B from ${JSON.stringify(path17.resolve(entryTsx))};
5002
+ import * as B from ${JSON.stringify(path18.resolve(entryTsx))};
4872
5003
  const cfg = (window as unknown as { __cfg: { component: string; props: Record<string, unknown>; partComponents: string[] } }).__cfg;
4873
5004
  const pairs: Array<[unknown, string]> = [];
4874
5005
  for (const name of cfg.partComponents) {
@@ -4923,7 +5054,7 @@ function expectedParts(task, roles, mainSlug) {
4923
5054
  }
4924
5055
  function interiorRegions(setDir, roles) {
4925
5056
  const mains = roles.main;
4926
- const withInterior = mains.filter((m) => existsSync12(path17.join(setDir, m, "get_metadata_interior.json")));
5057
+ const withInterior = mains.filter((m) => existsSync13(path18.join(setDir, m, "get_metadata_interior.json")));
4927
5058
  if (withInterior.length === 0) {
4928
5059
  return { unavailable: "no interior geometry recorded for any main (pre-obligation set) \u2014 re-record with `tendril record` to enable crop checks" };
4929
5060
  }
@@ -4940,7 +5071,7 @@ async function checkCropComposition(task, bundleDir, regions, opts = {}) {
4940
5071
  if (typeof js !== "string") {
4941
5072
  return regions.map((r) => ({ id: cropId(r), pass: false, similarity: 0, inkRecall: 0, detail: js.error }));
4942
5073
  }
4943
- const css = ["tokens.css", "styles.css"].map((f) => path17.join(bundleDir, f)).filter((f) => existsSync12(f)).map((f) => readFileSync10(f, "utf8")).join("\n");
5074
+ const css = ["tokens.css", "styles.css"].map((f) => path18.join(bundleDir, f)).filter((f) => existsSync13(f)).map((f) => readFileSync10(f, "utf8")).join("\n");
4944
5075
  const server = await chromium7.launchServer({ executablePath: resolveChrome(), headless: true, args: mountArgs() });
4945
5076
  const browser = await chromium7.connect(server.wsEndpoint());
4946
5077
  const PAD = 4;
@@ -5045,7 +5176,7 @@ async function checkStructuralComposition(task, bundleDir, roles, opts = {}) {
5045
5176
  const deadlineMs = timeoutMs + 1e4;
5046
5177
  const js = await compileInstrumentedMount(task, bundleDir);
5047
5178
  if (typeof js !== "string") return [...results, ...mains.map((m) => ({ id: `composition:${m}`, pass: false, detail: js.error }))];
5048
- const css = ["tokens.css", "styles.css"].map((f) => path17.join(bundleDir, f)).filter((f) => existsSync12(f)).map((f) => readFileSync10(f, "utf8")).join("\n");
5179
+ const css = ["tokens.css", "styles.css"].map((f) => path18.join(bundleDir, f)).filter((f) => existsSync13(f)).map((f) => readFileSync10(f, "utf8")).join("\n");
5049
5180
  const server = await chromium7.launchServer({ executablePath: resolveChrome(), headless: true, args: mountArgs() });
5050
5181
  const browser = await chromium7.connect(server.wsEndpoint());
5051
5182
  try {
@@ -5110,7 +5241,7 @@ body{margin:0;padding:20px}
5110
5241
  }
5111
5242
  var _fontFaces4, REAL_JSX_SPEC, JSX_SHIM, CROP_BAR, cropId;
5112
5243
  var init_composition = __esm({
5113
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/composition.ts"() {
5244
+ "packages/verify/src/composition.ts"() {
5114
5245
  "use strict";
5115
5246
  init_runtime();
5116
5247
  init_browser();
@@ -5134,18 +5265,18 @@ export const jsxs = (t, p, k) => real.jsxs(t, inject(t, p), k);
5134
5265
  }
5135
5266
  });
5136
5267
 
5137
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/occlusion.ts
5138
- import { existsSync as existsSync13 } from "node:fs";
5139
- import path18 from "node:path";
5268
+ // packages/verify/src/occlusion.ts
5269
+ import { existsSync as existsSync14 } from "node:fs";
5270
+ import path19 from "node:path";
5140
5271
  import { build as build7 } from "esbuild";
5141
5272
  import { chromium as chromium8 } from "playwright-core";
5142
5273
  async function compileTwoUp(task, bundleDir) {
5143
- const entryTsx = path18.join(bundleDir, task.entry);
5144
- if (!existsSync13(entryTsx)) return { error: `${task.entry} missing` };
5274
+ const entryTsx = path19.join(bundleDir, task.entry);
5275
+ if (!existsSync14(entryTsx)) return { error: `${task.entry} missing` };
5145
5276
  const src = `
5146
5277
  import { createElement } from "react";
5147
5278
  import { createRoot } from "react-dom/client";
5148
- import * as B from ${JSON.stringify(path18.resolve(entryTsx))};
5279
+ import * as B from ${JSON.stringify(path19.resolve(entryTsx))};
5149
5280
  const cfg = (window as unknown as { __cfg: { component: string; props: Record<string, unknown> } }).__cfg;
5150
5281
  const C = (B as Record<string, unknown>)[cfg.component] as Parameters<typeof createElement>[0] | undefined;
5151
5282
  for (const id of ["first", "second"]) {
@@ -5283,7 +5414,7 @@ body{margin:0;padding:16px;display:flex;flex-direction:column;gap:8px;align-item
5283
5414
  }
5284
5415
  var OVERLAY_SELECTOR;
5285
5416
  var init_occlusion = __esm({
5286
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/occlusion.ts"() {
5417
+ "packages/verify/src/occlusion.ts"() {
5287
5418
  "use strict";
5288
5419
  init_runtime();
5289
5420
  init_browser();
@@ -5292,9 +5423,9 @@ var init_occlusion = __esm({
5292
5423
  }
5293
5424
  });
5294
5425
 
5295
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/index.ts
5426
+ // packages/verify/src/index.ts
5296
5427
  var init_src4 = __esm({
5297
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/verify/src/index.ts"() {
5428
+ "packages/verify/src/index.ts"() {
5298
5429
  "use strict";
5299
5430
  init_browser();
5300
5431
  init_runtime();
@@ -5322,22 +5453,22 @@ var init_src4 = __esm({
5322
5453
  }
5323
5454
  });
5324
5455
 
5325
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/environment.ts
5326
- import { existsSync as existsSync14, readFileSync as readFileSync11 } from "node:fs";
5327
- import path19 from "node:path";
5456
+ // packages/cli/src/environment.ts
5457
+ import { existsSync as existsSync15, readFileSync as readFileSync11 } from "node:fs";
5458
+ import path20 from "node:path";
5328
5459
  import { createHash as createHash3 } from "node:crypto";
5329
- import { fileURLToPath as fileURLToPath4 } from "node:url";
5460
+ import { fileURLToPath as fileURLToPath5 } from "node:url";
5330
5461
  function cliVersion() {
5331
5462
  try {
5332
- return JSON.parse(readFileSync11(path19.join(path19.dirname(fileURLToPath4(import.meta.url)), "..", "package.json"), "utf8")).version ?? "dev";
5463
+ return JSON.parse(readFileSync11(path20.join(path20.dirname(fileURLToPath5(import.meta.url)), "..", "package.json"), "utf8")).version ?? "dev";
5333
5464
  } catch {
5334
5465
  return "dev";
5335
5466
  }
5336
5467
  }
5337
5468
  function environmentStamp(taskFamilies) {
5338
- const manifestPath2 = path19.join(fontCacheDir(), "manifest.json");
5469
+ const manifestPath2 = path20.join(fontCacheDir(), "manifest.json");
5339
5470
  let fontsHash = null;
5340
- if (existsSync14(manifestPath2)) {
5471
+ if (existsSync15(manifestPath2)) {
5341
5472
  try {
5342
5473
  const entries = JSON.parse(readFileSync11(manifestPath2, "utf8"));
5343
5474
  const scoped = taskFamilies === void 0 || taskFamilies === null ? entries : entries.filter((f) => taskFamilies.some((fam) => fam.toLowerCase() === f.family.toLowerCase()));
@@ -5357,20 +5488,20 @@ function environmentStamp(taskFamilies) {
5357
5488
  return { chrome, chromeVersion: ver === null ? null : ver + lcdSuffix, fontsManifestSha256: fontsHash };
5358
5489
  }
5359
5490
  var init_environment = __esm({
5360
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/environment.ts"() {
5491
+ "packages/cli/src/environment.ts"() {
5361
5492
  "use strict";
5362
5493
  init_src4();
5363
5494
  }
5364
5495
  });
5365
5496
 
5366
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/describe.ts
5497
+ // packages/cli/src/describe.ts
5367
5498
  function printDescription(description) {
5368
5499
  process.stdout.write(`${JSON.stringify(description, null, 2)}
5369
5500
  `);
5370
5501
  }
5371
5502
  var COMMON_EXIT_CODES;
5372
5503
  var init_describe = __esm({
5373
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/describe.ts"() {
5504
+ "packages/cli/src/describe.ts"() {
5374
5505
  "use strict";
5375
5506
  COMMON_EXIT_CODES = {
5376
5507
  0: "success",
@@ -5382,9 +5513,9 @@ var init_describe = __esm({
5382
5513
  }
5383
5514
  });
5384
5515
 
5385
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/env.ts
5386
- import { existsSync as existsSync15, readFileSync as readFileSync12 } from "node:fs";
5387
- import path20 from "node:path";
5516
+ // packages/cli/src/env.ts
5517
+ import { existsSync as existsSync16, readFileSync as readFileSync12 } from "node:fs";
5518
+ import path21 from "node:path";
5388
5519
  function parseEnv(content) {
5389
5520
  const entries = /* @__PURE__ */ new Map();
5390
5521
  for (const line of content.split("\n")) {
@@ -5396,17 +5527,17 @@ function parseEnv(content) {
5396
5527
  function resolveCredential(name) {
5397
5528
  const fromProcess = process.env[name];
5398
5529
  if (fromProcess) return fromProcess;
5399
- const envPath = path20.resolve(process.env["INIT_CWD"] ?? process.cwd(), ".env");
5400
- if (!existsSync15(envPath)) return void 0;
5530
+ const envPath = path21.resolve(process.env["INIT_CWD"] ?? process.cwd(), ".env");
5531
+ if (!existsSync16(envPath)) return void 0;
5401
5532
  return parseEnv(readFileSync12(envPath, "utf8")).get(name);
5402
5533
  }
5403
5534
  var init_env = __esm({
5404
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/env.ts"() {
5535
+ "packages/cli/src/env.ts"() {
5405
5536
  "use strict";
5406
5537
  }
5407
5538
  });
5408
5539
 
5409
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/output.ts
5540
+ // packages/cli/src/output.ts
5410
5541
  var output_exports = {};
5411
5542
  __export(output_exports, {
5412
5543
  PROGRESS_PREFIX: () => PROGRESS_PREFIX,
@@ -5450,23 +5581,23 @@ function warn(flags, message) {
5450
5581
  }
5451
5582
  var PROGRESS_PREFIX;
5452
5583
  var init_output = __esm({
5453
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/output.ts"() {
5584
+ "packages/cli/src/output.ts"() {
5454
5585
  "use strict";
5455
5586
  init_src3();
5456
5587
  PROGRESS_PREFIX = "@tendril-progress ";
5457
5588
  }
5458
5589
  });
5459
5590
 
5460
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/entitlement.ts
5461
- import { chmodSync, existsSync as existsSync16, mkdirSync as mkdirSync4, readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "node:fs";
5591
+ // packages/cli/src/entitlement.ts
5592
+ import { chmodSync, existsSync as existsSync17, mkdirSync as mkdirSync4, readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "node:fs";
5462
5593
  import crypto from "node:crypto";
5463
5594
  import os3 from "node:os";
5464
- import path21 from "node:path";
5595
+ import path22 from "node:path";
5465
5596
  function entitlementPath() {
5466
- return process.env["TENDRIL_ENTITLEMENT_PATH"] ?? path21.join(os3.homedir(), ".tendril", "entitlement.json");
5597
+ return process.env["TENDRIL_ENTITLEMENT_PATH"] ?? path22.join(os3.homedir(), ".tendril", "entitlement.json");
5467
5598
  }
5468
5599
  function readStoredEntitlement(file = entitlementPath()) {
5469
- if (!existsSync16(file)) return void 0;
5600
+ if (!existsSync17(file)) return void 0;
5470
5601
  try {
5471
5602
  const parsed = JSON.parse(readFileSync13(file, "utf8"));
5472
5603
  if (typeof parsed.token !== "string" || typeof parsed.lastRefreshAt !== "number") return void 0;
@@ -5476,7 +5607,7 @@ function readStoredEntitlement(file = entitlementPath()) {
5476
5607
  }
5477
5608
  }
5478
5609
  function writeStoredEntitlement(stored, file = entitlementPath()) {
5479
- mkdirSync4(path21.dirname(file), { recursive: true });
5610
+ mkdirSync4(path22.dirname(file), { recursive: true });
5480
5611
  writeFileSync7(file, `${JSON.stringify(stored, null, 2)}
5481
5612
  `);
5482
5613
  chmodSync(file, 384);
@@ -5502,11 +5633,11 @@ function checkEntitlement(opts = {}) {
5502
5633
  const now = opts.now ?? Date.now();
5503
5634
  const stored = "stored" in opts ? opts.stored : readStoredEntitlement();
5504
5635
  if (stored === void 0) {
5505
- return { ok: false, code: "entitlement-required", error: "no entitlement on this machine \u2014 record and generate need an active Tendril plan (verify stays free, always)", remediation: ACTIVATE_REMEDIATION };
5636
+ return { ok: false, code: "entitlement-required", error: "no entitlement on this machine \u2014 record and generate need an active Tendril plan (verify stays free, always)", remediation: activateRemediation() };
5506
5637
  }
5507
5638
  const parsed = parseEntitlementToken(stored.token);
5508
5639
  if ("error" in parsed) {
5509
- return { ok: false, code: "entitlement-invalid", error: `stored entitlement is unreadable: ${parsed.error}`, remediation: ACTIVATE_REMEDIATION };
5640
+ return { ok: false, code: "entitlement-invalid", error: `stored entitlement is unreadable: ${parsed.error}`, remediation: activateRemediation() };
5510
5641
  }
5511
5642
  const pem = keys[parsed.claims.kid];
5512
5643
  const valid = pem !== void 0 && (() => {
@@ -5517,14 +5648,14 @@ function checkEntitlement(opts = {}) {
5517
5648
  }
5518
5649
  })();
5519
5650
  if (!valid) {
5520
- return { ok: false, code: "entitlement-invalid", error: "stored entitlement failed signature verification", remediation: ACTIVATE_REMEDIATION };
5651
+ return { ok: false, code: "entitlement-invalid", error: "stored entitlement failed signature verification", remediation: activateRemediation() };
5521
5652
  }
5522
5653
  if (now > parsed.claims.exp + TOLERANCE_MS) {
5523
5654
  return {
5524
5655
  ok: false,
5525
5656
  code: "entitlement-expired",
5526
5657
  error: "entitlement expired (and the offline tolerance window has passed)",
5527
- remediation: `Reconnect and ${ACTIVATE_REMEDIATION}`
5658
+ remediation: `Reconnect and ${activateRemediation()}`
5528
5659
  };
5529
5660
  }
5530
5661
  if (now < stored.lastRefreshAt - CLOCK_ROLLBACK_MS) {
@@ -5532,7 +5663,7 @@ function checkEntitlement(opts = {}) {
5532
5663
  ok: false,
5533
5664
  code: "entitlement-clock",
5534
5665
  error: "system clock sits more than a day before the last entitlement refresh",
5535
- remediation: `Fix the system clock, then ${ACTIVATE_REMEDIATION}`
5666
+ remediation: `Fix the system clock, then ${activateRemediation()}`
5536
5667
  };
5537
5668
  }
5538
5669
  return { ok: true, mode: "active", claims: parsed.claims, stale: now > parsed.claims.exp };
@@ -5543,26 +5674,27 @@ function requireEntitlement(flags) {
5543
5674
  fail(flags, ExitCode.Auth, { error: status.error, code: status.code, remediation: status.remediation });
5544
5675
  }
5545
5676
  }
5546
- var ENT_PREFIX, PUBLIC_KEYS, TOLERANCE_MS, CLOCK_ROLLBACK_MS, b64urlDecode, ACTIVATE_REMEDIATION;
5677
+ var ENT_PREFIX, PUBLIC_KEYS, TOLERANCE_MS, CLOCK_ROLLBACK_MS, b64urlDecode, activateRemediation;
5547
5678
  var init_entitlement = __esm({
5548
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/entitlement.ts"() {
5679
+ "packages/cli/src/entitlement.ts"() {
5549
5680
  "use strict";
5550
5681
  init_src3();
5682
+ init_invocation();
5551
5683
  init_output();
5552
5684
  ENT_PREFIX = "tendril-ent.v1.";
5553
5685
  PUBLIC_KEYS = {};
5554
5686
  TOLERANCE_MS = 24 * 60 * 60 * 1e3;
5555
5687
  CLOCK_ROLLBACK_MS = 24 * 60 * 60 * 1e3;
5556
5688
  b64urlDecode = (s) => Buffer.from(s, "base64url");
5557
- ACTIVATE_REMEDIATION = "Run `tendril activate` in your terminal (a browser approval \u2014 never paste license material into an agent chat).";
5689
+ activateRemediation = () => `Run \`${tendrilCommand("activate")}\` in your terminal (a browser approval \u2014 never paste license material into an agent chat).`;
5558
5690
  }
5559
5691
  });
5560
5692
 
5561
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/doctor.ts
5693
+ // packages/cli/src/commands/doctor.ts
5562
5694
  import { spawnSync } from "node:child_process";
5563
- import { existsSync as existsSync17, readFileSync as readFileSync14, readdirSync as readdirSync3 } from "node:fs";
5695
+ import { existsSync as existsSync18, readFileSync as readFileSync14, readdirSync as readdirSync3 } from "node:fs";
5564
5696
  import os4 from "node:os";
5565
- import path22 from "node:path";
5697
+ import path23 from "node:path";
5566
5698
  async function runDoctorChecks(options) {
5567
5699
  const checks = [];
5568
5700
  const mcpUrl = options.mcpUrl ?? DEFAULT_MCP_URL;
@@ -5592,7 +5724,7 @@ async function runDoctorChecks(options) {
5592
5724
  name: "openrouter-key",
5593
5725
  ok: false,
5594
5726
  detail: "OPENROUTER_API_KEY not set \u2014 optional; only the curated API-model engine needs it",
5595
- remediation: "Run `tendril init` to store your OpenRouter key (BYOK) if you plan to use the curated engine."
5727
+ remediation: `Run \`${tendrilCommand("init")}\` to store your OpenRouter key (BYOK) if you plan to use the curated engine.`
5596
5728
  }
5597
5729
  );
5598
5730
  try {
@@ -5606,17 +5738,17 @@ async function runDoctorChecks(options) {
5606
5738
  remediation: "Install Google Chrome (or Chromium), or set CHROME_PATH to a Chromium-family browser binary."
5607
5739
  });
5608
5740
  }
5609
- const fontManifest = path22.join(fontCacheDir(), "manifest.json");
5741
+ const fontManifest = path23.join(fontCacheDir(), "manifest.json");
5610
5742
  checks.push(
5611
- existsSync17(fontManifest) ? { name: "font-cache", ok: true, detail: `resolved font cache at ${fontCacheDir()} (${JSON.parse(readFileSync14(fontManifest, "utf8")).length} faces)` } : {
5743
+ existsSync18(fontManifest) ? { name: "font-cache", ok: true, detail: `resolved font cache at ${fontCacheDir()} (${JSON.parse(readFileSync14(fontManifest, "utf8")).length} faces)` } : {
5612
5744
  name: "font-cache",
5613
5745
  ok: true,
5614
5746
  detail: `font cache empty at ${fontCacheDir()} \u2014 normal on a fresh machine; faces resolve per design system at first use`,
5615
- remediation: "Nothing to do now: `tendril fonts resolve --set <recording-dir>` fetches exactly what a recording declares, and generate/verify name that command when they need it."
5747
+ remediation: `Nothing to do now: \`${tendrilCommand("fonts resolve --set <recording-dir>")}\` fetches exactly what a recording declares, and generate/verify name that command \u2014 with the set filled in \u2014 when they need it.`
5616
5748
  }
5617
5749
  );
5618
- const pluginRoot = path22.join(os4.homedir(), ".claude", "plugins", "cache", "tendrilapp", "tendril");
5619
- if (existsSync17(pluginRoot)) {
5750
+ const pluginRoot = path23.join(os4.homedir(), ".claude", "plugins", "cache", "tendrilapp", "tendril");
5751
+ if (existsSync18(pluginRoot)) {
5620
5752
  try {
5621
5753
  const versions = readdirSync3(pluginRoot).filter((v) => /^\d+\.\d+\.\d+$/.test(v));
5622
5754
  const newest = versions.sort((a, b) => versionIsNewer(a, b) ? 1 : -1)[0];
@@ -5660,17 +5792,6 @@ async function runDoctorChecks(options) {
5660
5792
  });
5661
5793
  return { ok: checks.filter((c) => c.name !== "figma-pat" && c.name !== "openrouter-key" && c.name !== "path-skew").every((c) => c.ok), checks };
5662
5794
  }
5663
- function findPathTendril(pathEnv, platform) {
5664
- const dirs = pathEnv.split(path22.delimiter).filter((d) => d !== "" && !/node_modules[\\/]\.bin/.test(d) && !/[\\/]_npx[\\/]/.test(d));
5665
- const names = platform === "win32" ? ["tendril.cmd", "tendril.bat"] : ["tendril"];
5666
- for (const dir of dirs) {
5667
- for (const name of names) {
5668
- const candidate = path22.join(dir, name);
5669
- if (existsSync17(candidate)) return candidate;
5670
- }
5671
- }
5672
- return null;
5673
- }
5674
5795
  function probeVersion(binary) {
5675
5796
  const windowsShim = /\.(cmd|bat)$/i.test(binary);
5676
5797
  const res = windowsShim ? spawnSync(`"${binary}" --version`, { shell: true, timeout: 5e3, encoding: "utf8" }) : spawnSync(binary, ["--version"], { timeout: 5e3, encoding: "utf8" });
@@ -5735,13 +5856,14 @@ async function runDoctor(flags) {
5735
5856
  }
5736
5857
  var DEFAULT_MCP_URL, DOCTOR_DESCRIPTION;
5737
5858
  var init_doctor = __esm({
5738
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/doctor.ts"() {
5859
+ "packages/cli/src/commands/doctor.ts"() {
5739
5860
  "use strict";
5740
5861
  init_src4();
5741
5862
  init_src();
5742
5863
  init_describe();
5743
5864
  init_env();
5744
5865
  init_environment();
5866
+ init_invocation();
5745
5867
  init_output();
5746
5868
  init_entitlement();
5747
5869
  DEFAULT_MCP_URL = "http://127.0.0.1:3845/mcp";
@@ -5763,7 +5885,7 @@ var init_doctor = __esm({
5763
5885
  }
5764
5886
  });
5765
5887
 
5766
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/model-config.ts
5888
+ // packages/llm/src/model-config.ts
5767
5889
  import { z as z6 } from "zod";
5768
5890
  function resolveModel(config, requestedId) {
5769
5891
  const entry = config.allowlist.find((m) => m.id === requestedId);
@@ -5784,7 +5906,7 @@ function resolveModel(config, requestedId) {
5784
5906
  }
5785
5907
  var ModelStatusSchema, ModelEntrySchema, ModelConfigSchema, DEFAULT_MODEL_CONFIG;
5786
5908
  var init_model_config = __esm({
5787
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/model-config.ts"() {
5909
+ "packages/llm/src/model-config.ts"() {
5788
5910
  "use strict";
5789
5911
  ModelStatusSchema = z6.enum(["verified", "degraded"]);
5790
5912
  ModelEntrySchema = z6.object({
@@ -5873,10 +5995,10 @@ var init_model_config = __esm({
5873
5995
  }
5874
5996
  });
5875
5997
 
5876
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/openrouter.ts
5998
+ // packages/llm/src/openrouter.ts
5877
5999
  var FALLBACK_KINDS, DEFAULT_REQUEST_TIMEOUT_MS, OpenRouterClient;
5878
6000
  var init_openrouter = __esm({
5879
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/openrouter.ts"() {
6001
+ "packages/llm/src/openrouter.ts"() {
5880
6002
  "use strict";
5881
6003
  FALLBACK_KINDS = /* @__PURE__ */ new Set(["rate-limit", "server", "network", "timeout"]);
5882
6004
  DEFAULT_REQUEST_TIMEOUT_MS = 6e5;
@@ -6003,7 +6125,7 @@ var init_openrouter = __esm({
6003
6125
  }
6004
6126
  });
6005
6127
 
6006
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/semantics.ts
6128
+ // packages/llm/src/semantics.ts
6007
6129
  import { z as z7 } from "zod";
6008
6130
  function portable(node) {
6009
6131
  if (Array.isArray(node)) return node.map(portable);
@@ -6041,7 +6163,7 @@ function docsJsonSchema() {
6041
6163
  }
6042
6164
  var PropTypeSchema, SemanticsSchema, CodegenOutputSchema, DocsOutputSchema;
6043
6165
  var init_semantics = __esm({
6044
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/semantics.ts"() {
6166
+ "packages/llm/src/semantics.ts"() {
6045
6167
  "use strict";
6046
6168
  PropTypeSchema = z7.discriminatedUnion("kind", [
6047
6169
  z7.object({ kind: z7.literal("enum"), values: z7.array(z7.string()).min(1) }),
@@ -6130,10 +6252,10 @@ var init_semantics = __esm({
6130
6252
  }
6131
6253
  });
6132
6254
 
6133
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/golden/button.ts
6255
+ // packages/llm/src/golden/button.ts
6134
6256
  var goldenButtonSemantics, goldenButtonCode, goldenButtonDocs;
6135
6257
  var init_button2 = __esm({
6136
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/golden/button.ts"() {
6258
+ "packages/llm/src/golden/button.ts"() {
6137
6259
  "use strict";
6138
6260
  goldenButtonSemantics = {
6139
6261
  componentName: "Button",
@@ -6291,7 +6413,7 @@ handling come from the platform.
6291
6413
  }
6292
6414
  });
6293
6415
 
6294
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/prompt.ts
6416
+ // packages/llm/src/prompt.ts
6295
6417
  function buildStablePrefix(input) {
6296
6418
  const tokens = [...input.tokenLines].sort().join("\n");
6297
6419
  const golden = `GOLDEN EXAMPLE (canonical quality bar)
@@ -6325,7 +6447,7 @@ ${input.irJson}` });
6325
6447
  }
6326
6448
  var SYSTEM_RULES;
6327
6449
  var init_prompt = __esm({
6328
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/prompt.ts"() {
6450
+ "packages/llm/src/prompt.ts"() {
6329
6451
  "use strict";
6330
6452
  init_button2();
6331
6453
  SYSTEM_RULES = `You generate production React components from a design-system IR.
@@ -6421,10 +6543,10 @@ strictly in the requested JSON shape.`;
6421
6543
  }
6422
6544
  });
6423
6545
 
6424
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/generation-model.ts
6546
+ // packages/llm/src/generation-model.ts
6425
6547
  var MockGenerationModel, MAX_SCHEMA_ATTEMPTS, OpenRouterGenerationModel;
6426
6548
  var init_generation_model = __esm({
6427
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/generation-model.ts"() {
6549
+ "packages/llm/src/generation-model.ts"() {
6428
6550
  "use strict";
6429
6551
  init_openrouter();
6430
6552
  init_prompt();
@@ -6581,9 +6703,9 @@ ${JSON.stringify(semantics)}`,
6581
6703
  }
6582
6704
  });
6583
6705
 
6584
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/index.ts
6706
+ // packages/llm/src/index.ts
6585
6707
  var init_src5 = __esm({
6586
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/llm/src/index.ts"() {
6708
+ "packages/llm/src/index.ts"() {
6587
6709
  "use strict";
6588
6710
  init_model_config();
6589
6711
  init_openrouter();
@@ -6594,11 +6716,11 @@ var init_src5 = __esm({
6594
6716
  }
6595
6717
  });
6596
6718
 
6597
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/metadata/src/component-json.ts
6719
+ // packages/metadata/src/component-json.ts
6598
6720
  import { z as z8 } from "zod";
6599
6721
  var TokenUseSchema, AntiPatternSchema, ComponentJsonSchema;
6600
6722
  var init_component_json = __esm({
6601
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/metadata/src/component-json.ts"() {
6723
+ "packages/metadata/src/component-json.ts"() {
6602
6724
  "use strict";
6603
6725
  TokenUseSchema = z8.object({
6604
6726
  /** DTCG token path, e.g. "color.primary". */
@@ -6650,7 +6772,7 @@ var init_component_json = __esm({
6650
6772
  }
6651
6773
  });
6652
6774
 
6653
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/metadata/src/extract.ts
6775
+ // packages/metadata/src/extract.ts
6654
6776
  import { parse } from "react-docgen";
6655
6777
  function extractProps(tsxSource, filename) {
6656
6778
  const docs = parse(tsxSource, { filename });
@@ -6723,13 +6845,13 @@ function buildComponentJson(input) {
6723
6845
  });
6724
6846
  }
6725
6847
  var init_extract = __esm({
6726
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/metadata/src/extract.ts"() {
6848
+ "packages/metadata/src/extract.ts"() {
6727
6849
  "use strict";
6728
6850
  init_component_json();
6729
6851
  }
6730
6852
  });
6731
6853
 
6732
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/metadata/src/recording-set.ts
6854
+ // packages/metadata/src/recording-set.ts
6733
6855
  import { z as z9 } from "zod";
6734
6856
  function roleLossToken(loss) {
6735
6857
  return loss.kind === "main" ? `main:${loss.main}` : `part:${loss.part}${EDGE_ARROW}${loss.main}`;
@@ -6790,7 +6912,7 @@ function validateRecordingSet(manifest, fileExists) {
6790
6912
  }
6791
6913
  var RECORDING_SET_VERSION, EnvelopeSchema, RepEntrySchema, RolesSchema, EDGE_ARROW, RecordingSetManifestSchema, REQUIRED_REP_FILES;
6792
6914
  var init_recording_set = __esm({
6793
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/metadata/src/recording-set.ts"() {
6915
+ "packages/metadata/src/recording-set.ts"() {
6794
6916
  "use strict";
6795
6917
  RECORDING_SET_VERSION = 1;
6796
6918
  EnvelopeSchema = z9.object({
@@ -6851,7 +6973,7 @@ var init_recording_set = __esm({
6851
6973
  }
6852
6974
  });
6853
6975
 
6854
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/metadata/src/bundle.ts
6976
+ // packages/metadata/src/bundle.ts
6855
6977
  import { z as z10 } from "zod";
6856
6978
  function readBundleManifest(raw) {
6857
6979
  if (Buffer.byteLength(raw, "utf8") > MAX_BUNDLE_MANIFEST_BYTES) {
@@ -6920,7 +7042,7 @@ function hashRecordingSet(relPaths, readFile, sha256) {
6920
7042
  }
6921
7043
  var BUNDLE_VERSION, ConfigStatusSchema, PinnedPropSchema, PropAdapterSchema, RequiredFontSchema, ConfigClaimSchema, BehaviorClaimSchema, BundleProvenanceSchema, BundleComponentJsonSchema, MAX_BUNDLE_MANIFEST_BYTES, MAX_BUNDLE_SOURCE_BYTES;
6922
7044
  var init_bundle = __esm({
6923
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/metadata/src/bundle.ts"() {
7045
+ "packages/metadata/src/bundle.ts"() {
6924
7046
  "use strict";
6925
7047
  init_recording_set();
6926
7048
  BUNDLE_VERSION = 1;
@@ -7018,9 +7140,9 @@ var init_bundle = __esm({
7018
7140
  }
7019
7141
  });
7020
7142
 
7021
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/metadata/src/index.ts
7143
+ // packages/metadata/src/index.ts
7022
7144
  var init_src6 = __esm({
7023
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/metadata/src/index.ts"() {
7145
+ "packages/metadata/src/index.ts"() {
7024
7146
  "use strict";
7025
7147
  init_component_json();
7026
7148
  init_extract();
@@ -7029,7 +7151,7 @@ var init_src6 = __esm({
7029
7151
  }
7030
7152
  });
7031
7153
 
7032
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/activate.ts
7154
+ // packages/cli/src/commands/activate.ts
7033
7155
  var activate_exports = {};
7034
7156
  __export(activate_exports, {
7035
7157
  ENTITLEMENT_SERVICE_URL: () => ENTITLEMENT_SERVICE_URL,
@@ -7054,7 +7176,7 @@ async function runActivate(flags) {
7054
7176
  fail(flags, ExitCode.Auth, {
7055
7177
  error: `could not start activation: ${err instanceof Error ? err.message : String(err)}`,
7056
7178
  code: "entitlement-service-unreachable",
7057
- remediation: "Check your connection and retry `tendril activate`."
7179
+ remediation: `Check your connection and retry \`${tendrilCommand("activate")}\`.`
7058
7180
  });
7059
7181
  }
7060
7182
  process.stderr.write(`To activate Tendril, visit:
@@ -7081,7 +7203,7 @@ Waiting for approval\u2026
7081
7203
  fail(flags, ExitCode.Auth, {
7082
7204
  error: `activation was not approved (HTTP ${res.status})`,
7083
7205
  code: "entitlement-denied",
7084
- remediation: "Retry `tendril activate`; if it persists, check the account's plan in the portal."
7206
+ remediation: `Retry \`${tendrilCommand("activate")}\`; if it persists, check the account's plan in the portal.`
7085
7207
  });
7086
7208
  }
7087
7209
  token = (await res.json()).token;
@@ -7091,7 +7213,7 @@ Waiting for approval\u2026
7091
7213
  fail(flags, ExitCode.Auth, {
7092
7214
  error: "activation timed out before the browser approval arrived",
7093
7215
  code: "entitlement-timeout",
7094
- remediation: "Run `tendril activate` again and complete the browser step within the shown window."
7216
+ remediation: `Run \`${tendrilCommand("activate")}\` again and complete the browser step within the shown window.`
7095
7217
  });
7096
7218
  }
7097
7219
  const parsed = parseEntitlementToken(token);
@@ -7099,7 +7221,7 @@ Waiting for approval\u2026
7099
7221
  fail(flags, ExitCode.Auth, {
7100
7222
  error: `service returned an unusable token: ${parsed.error}`,
7101
7223
  code: "entitlement-invalid",
7102
- remediation: "Retry `tendril activate`; report this if it persists \u2014 it is a service-side fault."
7224
+ remediation: `Retry \`${tendrilCommand("activate")}\`; report this if it persists \u2014 it is a service-side fault.`
7103
7225
  });
7104
7226
  }
7105
7227
  if (Object.keys(PUBLIC_KEYS).length > 0) {
@@ -7114,16 +7236,17 @@ Waiting for approval\u2026
7114
7236
  }
7115
7237
  var ENTITLEMENT_SERVICE_URL;
7116
7238
  var init_activate = __esm({
7117
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/activate.ts"() {
7239
+ "packages/cli/src/commands/activate.ts"() {
7118
7240
  "use strict";
7119
7241
  init_src3();
7120
7242
  init_entitlement();
7243
+ init_invocation();
7121
7244
  init_output();
7122
7245
  ENTITLEMENT_SERVICE_URL = void 0;
7123
7246
  }
7124
7247
  });
7125
7248
 
7126
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/record.ts
7249
+ // packages/cli/src/commands/record.ts
7127
7250
  var record_exports = {};
7128
7251
  __export(record_exports, {
7129
7252
  instanceLeads: () => instanceLeads,
@@ -7140,9 +7263,9 @@ __export(record_exports, {
7140
7263
  runRecordPlan: () => runRecordPlan,
7141
7264
  runRecordStatus: () => runRecordStatus
7142
7265
  });
7143
- import { existsSync as existsSync19, mkdtempSync as mkdtempSync2, readFileSync as readFileSync16, readdirSync as readdirSync5 } from "node:fs";
7266
+ import { existsSync as existsSync20, mkdtempSync as mkdtempSync2, readFileSync as readFileSync16, readdirSync as readdirSync5 } from "node:fs";
7144
7267
  import os5 from "node:os";
7145
- import path25 from "node:path";
7268
+ import path26 from "node:path";
7146
7269
  import { writeFileSync as writeFileSync9 } from "node:fs";
7147
7270
  function symbolsFromMetadataEnvelope(file, sourceFrame) {
7148
7271
  const env = JSON.parse(readFileSync16(file, "utf8"));
@@ -7203,7 +7326,7 @@ function runRecordPlan(opts) {
7203
7326
  if (rawFile !== void 0) {
7204
7327
  try {
7205
7328
  const envelope = rawEnvelopeFromFile(rawFile, opts.metadataRawPartsFile !== void 0);
7206
- const tmp = path25.join(mkdtempSync2(path25.join(os5.tmpdir(), "tendril-plan-meta-")), "get_metadata.json");
7329
+ const tmp = path26.join(mkdtempSync2(path26.join(os5.tmpdir(), "tendril-plan-meta-")), "get_metadata.json");
7207
7330
  writeFileSync9(tmp, JSON.stringify(envelope));
7208
7331
  metadataEntries.push({ file: tmp });
7209
7332
  } catch (err) {
@@ -7225,7 +7348,7 @@ function runRecordPlan(opts) {
7225
7348
  let metadataTruncated = false;
7226
7349
  for (const { file, frame } of metadataEntries) {
7227
7350
  try {
7228
- const parsed = symbolsFromMetadataEnvelope(path25.resolve(file), frame);
7351
+ const parsed = symbolsFromMetadataEnvelope(path26.resolve(file), frame);
7229
7352
  symbols.push(...parsed.symbols);
7230
7353
  if (parsed.truncated) metadataTruncated = true;
7231
7354
  } catch (err) {
@@ -7258,7 +7381,7 @@ function runRecordPlan(opts) {
7258
7381
  if (symbols.length === 0) {
7259
7382
  const leads = metadataEntries.flatMap(({ file }) => {
7260
7383
  try {
7261
- const env = JSON.parse(readFileSync16(path25.resolve(file), "utf8"));
7384
+ const env = JSON.parse(readFileSync16(path26.resolve(file), "utf8"));
7262
7385
  return instanceLeads(env.content.map((c) => c.text ?? "").join("\n"));
7263
7386
  } catch {
7264
7387
  return [];
@@ -7363,7 +7486,7 @@ function nextPayload(setDir) {
7363
7486
  const instruction = nextInstruction(setDir);
7364
7487
  const status = sessionStatus(setDir);
7365
7488
  const progress = { recordedReps: status.reps.filter((x) => x.missing.length === 0).length, totalReps: status.reps.length };
7366
- if (instruction === null && !existsSync19(path25.join(setDir, "get_variable_defs.json"))) {
7489
+ if (instruction === null && !existsSync20(path26.join(setDir, "get_variable_defs.json"))) {
7367
7490
  const manifest = loadManifest(setDir);
7368
7491
  const frameNode = Object.keys(manifest.sourceFrames ?? {})[0] ?? manifest.reps[0]?.nodeId ?? "";
7369
7492
  return { slug: "__set__", nodeId: frameNode, tool: "get_variable_defs", note: `SET-LEVEL: call get_variable_defs on the component frame and ingest with --rep __set__. ${ENVELOPE_HELP}`, progress };
@@ -7380,7 +7503,7 @@ function runRecordNext(opts) {
7380
7503
  const progress = payload["progress"];
7381
7504
  process.stdout.write(`[${progress.recordedReps}/${progress.totalReps} reps] ${payload["tool"]} for ${payload["slug"]} (node ${payload["nodeId"]})
7382
7505
  \u2192 ${payload["note"]}
7383
- \u2192 then: tendril record ingest --set <dir> --rep ${payload["slug"]} --tool ${payload["tool"]} --file <envelope.json>
7506
+ \u2192 then: ${tendrilCommand(`record ingest --set ${path26.resolve(opts.setDir)} --rep ${payload["slug"]} --tool ${payload["tool"]} --file <envelope.json>`)}
7384
7507
  `);
7385
7508
  });
7386
7509
  }
@@ -7454,7 +7577,7 @@ async function autoFetchAssets(setDir, rep, envelopeText2) {
7454
7577
  const skipped = [];
7455
7578
  const failed = [];
7456
7579
  for (const { url, name } of assetUrlsFromEnvelopeText(envelopeText2)) {
7457
- if (existsSync19(path25.join(setDir, rep, name))) {
7580
+ if (existsSync20(path26.join(setDir, rep, name))) {
7458
7581
  skipped.push(name);
7459
7582
  continue;
7460
7583
  }
@@ -7476,16 +7599,16 @@ async function autoFetchAssets(setDir, rep, envelopeText2) {
7476
7599
  }
7477
7600
  function rawEnvelopeFromFile(file, parts) {
7478
7601
  if (parts) {
7479
- const blocks = JSON.parse(readFileSync16(path25.resolve(file), "utf8"));
7602
+ const blocks = JSON.parse(readFileSync16(path26.resolve(file), "utf8"));
7480
7603
  if (!Array.isArray(blocks) || blocks.length === 0 || blocks.some((p) => typeof p !== "string")) throw new Error("parts file must be a non-empty JSON array of strings");
7481
7604
  return { content: blocks.map((text) => ({ type: "text", text })) };
7482
7605
  }
7483
- return { content: [{ type: "text", text: readFileSync16(path25.resolve(file), "utf8") }] };
7606
+ return { content: [{ type: "text", text: readFileSync16(path26.resolve(file), "utf8") }] };
7484
7607
  }
7485
7608
  async function runRecordIngest(opts) {
7486
7609
  let payload;
7487
7610
  try {
7488
- payload = opts.rawParts === true || opts.raw === true ? rawEnvelopeFromFile(opts.file, opts.rawParts === true) : JSON.parse(readFileSync16(path25.resolve(opts.file), "utf8"));
7611
+ payload = opts.rawParts === true || opts.raw === true ? rawEnvelopeFromFile(opts.file, opts.rawParts === true) : JSON.parse(readFileSync16(path26.resolve(opts.file), "utf8"));
7489
7612
  } catch (err) {
7490
7613
  fail(opts, ExitCode.InputValidation, {
7491
7614
  error: `cannot read envelope file: ${err instanceof Error ? err.message : String(err)}`,
@@ -7497,7 +7620,7 @@ async function runRecordIngest(opts) {
7497
7620
  fail(opts, ExitCode.InputValidation, {
7498
7621
  error: "--raw is for text tool responses; screenshots are binary",
7499
7622
  code: "envelope-invalid",
7500
- remediation: "Use `tendril record fetch` with the image_url instead."
7623
+ remediation: `Use \`${tendrilCommand(`record fetch --set ${path26.resolve(opts.setDir)} --rep ${opts.rep} --tool ${opts.tool} --url <image_url>`)}\` instead.`
7501
7624
  });
7502
7625
  }
7503
7626
  if (opts.rep === "__set__" && opts.tool === "get_variable_defs") {
@@ -7509,7 +7632,7 @@ async function runRecordIngest(opts) {
7509
7632
  remediation: "Save the get_variable_defs response verbatim as a text envelope."
7510
7633
  });
7511
7634
  }
7512
- writeFileSync9(path25.join(opts.setDir, "get_variable_defs.json"), `${JSON.stringify(payload, null, 1)}
7635
+ writeFileSync9(path26.join(opts.setDir, "get_variable_defs.json"), `${JSON.stringify(payload, null, 1)}
7513
7636
  `);
7514
7637
  emitData(opts, { ingested: "get_variable_defs", rep: "__set__", setLevel: true, next: nextPayload(opts.setDir) }, () => {
7515
7638
  process.stdout.write("set-level get_variable_defs ingested\n");
@@ -7525,7 +7648,7 @@ async function runRecordIngest(opts) {
7525
7648
  if (assets !== void 0) {
7526
7649
  for (const a of assets.fetched) process.stdout.write(` asset fetched ${a}
7527
7650
  `);
7528
- for (const f of assets.failed) process.stdout.write(` ASSET FAILED ${f.name}: ${f.reason} \u2014 download it and run tendril record asset
7651
+ for (const f of assets.failed) process.stdout.write(` ASSET FAILED ${f.name}: ${f.reason} \u2014 download it, then: ${tendrilCommand(`record asset --set ${path26.resolve(opts.setDir)} --rep ${opts.rep} --name ${f.name} --file <downloaded-file>`)}
7529
7652
  `);
7530
7653
  }
7531
7654
  });
@@ -7598,14 +7721,14 @@ async function runRecordIngestRep(opts) {
7598
7721
  if (assets !== void 0) {
7599
7722
  for (const a of assets.fetched) process.stdout.write(` asset fetched ${a}
7600
7723
  `);
7601
- for (const f of assets.failed) process.stdout.write(` ASSET FAILED ${f.name}: ${f.reason} \u2014 download it and run tendril record asset
7724
+ for (const f of assets.failed) process.stdout.write(` ASSET FAILED ${f.name}: ${f.reason} \u2014 download it, then: ${tendrilCommand(`record asset --set ${path26.resolve(opts.setDir)} --rep ${opts.rep} --name ${f.name} --file <downloaded-file>`)}
7602
7725
  `);
7603
7726
  }
7604
7727
  });
7605
7728
  }
7606
7729
  function runRecordAsset(opts) {
7607
7730
  if (opts.dir !== void 0) {
7608
- const dir = path25.resolve(opts.dir);
7731
+ const dir = path26.resolve(opts.dir);
7609
7732
  const names = readdirSync5(dir).filter((f) => /^asset-[\w.-]+\.(svg|png|jpe?g|webp|gif)$/i.test(f));
7610
7733
  if (names.length === 0) {
7611
7734
  fail(opts, ExitCode.InputValidation, {
@@ -7617,7 +7740,7 @@ function runRecordAsset(opts) {
7617
7740
  const ingested = [];
7618
7741
  try {
7619
7742
  for (const name of names) {
7620
- ingestAsset(opts.setDir, opts.rep, name, readFileSync16(path25.join(dir, name)));
7743
+ ingestAsset(opts.setDir, opts.rep, name, readFileSync16(path26.join(dir, name)));
7621
7744
  ingested.push(name);
7622
7745
  }
7623
7746
  } catch (err) {
@@ -7637,11 +7760,11 @@ function runRecordAsset(opts) {
7637
7760
  fail(opts, ExitCode.InputValidation, {
7638
7761
  error: "pass --name and --file for a single asset, or --dir for a batch",
7639
7762
  code: "asset-rejected",
7640
- remediation: "tendril record asset --set <dir> --rep <slug> --dir <downloads-dir>"
7763
+ remediation: tendrilCommand(`record asset --set ${path26.resolve(opts.setDir)} --rep ${opts.rep} --dir <downloads-dir>`)
7641
7764
  });
7642
7765
  }
7643
7766
  try {
7644
- ingestAsset(opts.setDir, opts.rep, opts.name, readFileSync16(path25.resolve(opts.file)));
7767
+ ingestAsset(opts.setDir, opts.rep, opts.name, readFileSync16(path26.resolve(opts.file)));
7645
7768
  emitData(opts, { rep: opts.rep, asset: opts.name }, () => {
7646
7769
  process.stdout.write(`ingested ${opts.rep}/${opts.name}
7647
7770
  `);
@@ -7677,7 +7800,7 @@ function narrowedRoles(derived, override) {
7677
7800
  function rolesFromFile(opts, file, derived) {
7678
7801
  let json;
7679
7802
  try {
7680
- json = JSON.parse(readFileSync16(path25.resolve(file), "utf8"));
7803
+ json = JSON.parse(readFileSync16(path26.resolve(file), "utf8"));
7681
7804
  } catch (err) {
7682
7805
  fail(opts, ExitCode.InputValidation, {
7683
7806
  error: `cannot read roles file ${file}: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`,
@@ -7715,11 +7838,11 @@ function rolesFromFile(opts, file, derived) {
7715
7838
  };
7716
7839
  }
7717
7840
  function runRecordFinish(opts) {
7718
- if (!existsSync19(path25.join(opts.setDir, "recording-set.json"))) {
7841
+ if (!existsSync20(path26.join(opts.setDir, "recording-set.json"))) {
7719
7842
  fail(opts, ExitCode.InputValidation, {
7720
7843
  error: `no recording-set.json in ${opts.setDir}`,
7721
7844
  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.`
7845
+ remediation: `Run \`${tendrilCommand(`record plan --set ${path26.resolve(opts.setDir)} --component <name> --metadata <envelope.json>`)}\` first \u2014 \`record finish\` closes a set the planner opened.`
7723
7846
  });
7724
7847
  }
7725
7848
  const { manifest, raw } = readManifestFile(opts.setDir);
@@ -7747,17 +7870,17 @@ function runRecordFinish(opts) {
7747
7870
  fail(opts, ExitCode.ConfirmationRequired, {
7748
7871
  error: "--confirm-roles (and --roles-file) require an interactive terminal \u2014 this confirmation is human-only",
7749
7872
  code: "roles-confirmation-not-interactive",
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."
7873
+ remediation: `A human runs \`${tendrilCommand(`record finish --set ${path26.resolve(opts.setDir)} --confirm-roles`)}\` in their own terminal. Agents: show the proposal to your operator instead of confirming it.`
7751
7874
  });
7752
7875
  }
7753
7876
  const merged = { ...raw, roles };
7754
- const { issues } = validateRecordingSet(merged, (rel) => existsSync19(path25.join(opts.setDir, rel)));
7877
+ const { issues } = validateRecordingSet(merged, (rel) => existsSync20(path26.join(opts.setDir, rel)));
7755
7878
  const errors = issues.filter((i) => i.severity === "error");
7756
7879
  if (errors.length > 0) {
7757
7880
  fail(opts, ExitCode.InputValidation, {
7758
7881
  error: `recording set rejected \u2014 roles NOT written: ${errors.map((e) => e.message).join("; ")}`,
7759
7882
  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`."
7883
+ remediation: `Fix the set (\`${tendrilCommand(`record status --set ${path26.resolve(opts.setDir)}`)}\` lists missing envelopes) or the roles graph, then re-run \`record finish\`.`
7761
7884
  });
7762
7885
  }
7763
7886
  for (const issue of issues) if (issue.severity === "warning") warn(opts, issue.message);
@@ -7770,27 +7893,28 @@ function runRecordFinish(opts) {
7770
7893
  }
7771
7894
  var ENVELOPE_HELP, isAutoFetchAssetUrl, describeRoleLoss;
7772
7895
  var init_record = __esm({
7773
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/record.ts"() {
7896
+ "packages/cli/src/commands/record.ts"() {
7774
7897
  "use strict";
7775
7898
  init_src3();
7776
7899
  init_src();
7777
7900
  init_src6();
7778
7901
  init_output();
7779
7902
  init_entitlement();
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.';
7903
+ init_invocation();
7904
+ 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 \`${tendrilCommand("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.`;
7781
7905
  isAutoFetchAssetUrl = (url) => isFigmaAssetUrl(url) || isLocalAssetUrl(url);
7782
7906
  describeRoleLoss = (loss) => loss.kind === "main" ? `drops main "${loss.main}"` : `stops "${loss.part}" being a part of main "${loss.main}"`;
7783
7907
  }
7784
7908
  });
7785
7909
 
7786
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/engine.ts
7910
+ // packages/generate/src/engine.ts
7787
7911
  var init_engine = __esm({
7788
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/engine.ts"() {
7912
+ "packages/generate/src/engine.ts"() {
7789
7913
  "use strict";
7790
7914
  }
7791
7915
  });
7792
7916
 
7793
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/parse.ts
7917
+ // packages/generate/src/parse.ts
7794
7918
  function parseFiles(text, entry) {
7795
7919
  const out = /* @__PURE__ */ new Map();
7796
7920
  const re = /```[a-z]*[^\n]*\n(?:\/\/|\/\*)[ \t]*FILE:[ \t]*([\w.]+)[ \t]*(?:\*\/)?[ \t]*\n([\s\S]*?)```/g;
@@ -7823,15 +7947,15 @@ ${content}\`\`\``);
7823
7947
  return blocks.join("\n");
7824
7948
  }
7825
7949
  var init_parse = __esm({
7826
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/parse.ts"() {
7950
+ "packages/generate/src/parse.ts"() {
7827
7951
  "use strict";
7828
7952
  }
7829
7953
  });
7830
7954
 
7831
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/engine-curated.ts
7955
+ // packages/generate/src/engine-curated.ts
7832
7956
  var CuratedEngine;
7833
7957
  var init_engine_curated = __esm({
7834
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/engine-curated.ts"() {
7958
+ "packages/generate/src/engine-curated.ts"() {
7835
7959
  "use strict";
7836
7960
  init_parse();
7837
7961
  CuratedEngine = class {
@@ -7969,9 +8093,9 @@ var init_engine_curated = __esm({
7969
8093
  }
7970
8094
  });
7971
8095
 
7972
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/loop.ts
7973
- import { existsSync as existsSync20, mkdirSync as mkdirSync6, readFileSync as readFileSync17, renameSync, writeFileSync as writeFileSync10 } from "node:fs";
7974
- import path26 from "node:path";
8096
+ // packages/generate/src/loop.ts
8097
+ import { existsSync as existsSync21, mkdirSync as mkdirSync6, readFileSync as readFileSync17, renameSync, writeFileSync as writeFileSync10 } from "node:fs";
8098
+ import path27 from "node:path";
7975
8099
  import { z as z11 } from "zod";
7976
8100
  function objective(scores, behaviors) {
7977
8101
  const vals = scores.map((s) => Math.min(s.similarity, s.inkRecall));
@@ -8005,12 +8129,12 @@ ${preludeLines.join("\n")}` : ""}${absentLines.length > 0 ? `
8005
8129
  MISSING FEATURES (absent-ink clusters \u2014 recorded marks your render leaves out or paints invisibly; GATING at the cert bar. Fix the named node's ink \u2014 a config carrying one cannot certify):
8006
8130
  ${absentLines.join("\n")}` : ""}
8007
8131
 
8008
- Fix the FAIL configs (region coordinates are in the recorded screenshot's frame; ink<1 means recorded foreground pixels your render does not cover). Reading the pair: ink=1 with LOW sim means nothing is missing \u2014 shapes or positions are wrong, do not chase missing ink; LOW ink with high sim means recorded marks are absent or painted invisibly. Do not regress PASS configs. ${mode === "files" ? "Update the files in your candidate directory and re-run the score." : "Reply with the complete corrected files in the same FILE format."}`;
8132
+ Fix the FAIL configs (region coordinates are in the recorded screenshot's frame; ink<1 means recorded foreground pixels your render does not cover). Reading the pair: ink=1 with LOW sim means nothing is MISSING (do not chase missing ink) \u2014 the same pixels are being painted wrong, and there are TWO causes. GEOMETRY: wrong position/size/radius; the diff shows shifted edges and bands. WRONG TEXT WEIGHT OR FACE: the diff shows a uniform haze over glyph runs; CSS binds the font FAMILY before the weight, a later family in the stack is never consulted for a weight the first one lacks, and font-synthesis: none rules out faux-bold \u2014 so a stack led by a family the kit holds at one weight renders every other weight in that face, silently. Check the font stack against the kit's cached faces before concluding geometry is at fault. LOW ink with high sim means recorded marks are absent or painted invisibly. Do not regress PASS configs. ${mode === "files" ? "Update the files in your candidate directory and re-run the score." : "Reply with the complete corrected files in the same FILE format."}`;
8009
8133
  }
8010
8134
  function archivePriorRun(outDir) {
8011
- if (!existsSync20(path26.join(outDir, "run-log.json")) && !existsSync20(path26.join(outDir, "loop-state.json"))) return void 0;
8135
+ if (!existsSync21(path27.join(outDir, "run-log.json")) && !existsSync21(path27.join(outDir, "loop-state.json"))) return void 0;
8012
8136
  let n = 1;
8013
- while (existsSync20(`${outDir}-prev-${n}`)) n += 1;
8137
+ while (existsSync21(`${outDir}-prev-${n}`)) n += 1;
8014
8138
  renameSync(outDir, `${outDir}-prev-${n}`);
8015
8139
  return `${outDir}-prev-${n}`;
8016
8140
  }
@@ -8019,14 +8143,14 @@ async function runEngineLoop(opts) {
8019
8143
  const plateau = opts.plateau ?? 2;
8020
8144
  const progress = opts.onProgress ?? (() => {
8021
8145
  });
8022
- const statePath = path26.join(opts.outDir, "loop-state.json");
8023
- const resuming = opts.resume === true && existsSync20(statePath);
8146
+ const statePath = path27.join(opts.outDir, "loop-state.json");
8147
+ const resuming = opts.resume === true && existsSync21(statePath);
8024
8148
  if (!resuming) {
8025
8149
  const archived = archivePriorRun(opts.outDir);
8026
8150
  if (archived !== void 0) progress(`previous run archived to ${archived}`);
8027
8151
  }
8028
8152
  mkdirSync6(opts.outDir, { recursive: true });
8029
- const scratch = path26.join(opts.outDir, ".candidate");
8153
+ const scratch = path27.join(opts.outDir, ".candidate");
8030
8154
  let attempts = [];
8031
8155
  let log = [];
8032
8156
  let best;
@@ -8054,7 +8178,7 @@ async function runEngineLoop(opts) {
8054
8178
  };
8055
8179
  const writeCandidate = (files) => {
8056
8180
  mkdirSync6(scratch, { recursive: true });
8057
- for (const [name, content] of Object.entries(files)) writeFileSync10(path26.join(scratch, name), content);
8181
+ for (const [name, content] of Object.entries(files)) writeFileSync10(path27.join(scratch, name), content);
8058
8182
  };
8059
8183
  const scoreCandidate = async (candidate, iter, usd, modelMs) => {
8060
8184
  writeCandidate(candidate.files);
@@ -8112,8 +8236,8 @@ async function runEngineLoop(opts) {
8112
8236
  const usd = candidate.usage?.usd ?? 0;
8113
8237
  spentUsd += usd;
8114
8238
  if (candidate.raw !== void 0) {
8115
- mkdirSync6(path26.join(opts.outDir, "responses"), { recursive: true });
8116
- writeFileSync10(path26.join(opts.outDir, "responses", `iter-${iter}.md`), candidate.raw);
8239
+ mkdirSync6(path27.join(opts.outDir, "responses"), { recursive: true });
8240
+ writeFileSync10(path27.join(opts.outDir, "responses", `iter-${iter}.md`), candidate.raw);
8117
8241
  }
8118
8242
  if (candidate.files[opts.entry] === void 0 || candidate.files["styles.css"] === void 0) {
8119
8243
  const finish = candidate.usage?.finishReason ?? "?";
@@ -8139,10 +8263,10 @@ async function runEngineLoop(opts) {
8139
8263
  }
8140
8264
  }
8141
8265
  }
8142
- if (best !== void 0) for (const [name, content] of Object.entries(best.files)) writeFileSync10(path26.join(opts.outDir, name), content);
8266
+ if (best !== void 0) for (const [name, content] of Object.entries(best.files)) writeFileSync10(path27.join(opts.outDir, name), content);
8143
8267
  const final = best !== void 0 ? await opts.score(opts.outDir) : { scores: [], behaviors: [] };
8144
8268
  writeFileSync10(
8145
- path26.join(opts.outDir, "run-log.json"),
8269
+ path27.join(opts.outDir, "run-log.json"),
8146
8270
  `${JSON.stringify(
8147
8271
  {
8148
8272
  ...opts.meta,
@@ -8163,7 +8287,7 @@ async function runEngineLoop(opts) {
8163
8287
  }
8164
8288
  var better, RegionSchema, ConfigScoreSchema, BehaviorResultSchema, LoopStateSchema;
8165
8289
  var init_loop2 = __esm({
8166
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/loop.ts"() {
8290
+ "packages/generate/src/loop.ts"() {
8167
8291
  "use strict";
8168
8292
  better = (a, b) => a[0] !== b[0] ? a[0] > b[0] : a[1] !== b[1] ? a[1] > b[1] : a[2] > b[2];
8169
8293
  RegionSchema = z11.object({ x0: z11.number(), y0: z11.number(), x1: z11.number(), y1: z11.number(), density: z11.number() });
@@ -8208,9 +8332,9 @@ var init_loop2 = __esm({
8208
8332
  }
8209
8333
  });
8210
8334
 
8211
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/brief.ts
8212
- import { existsSync as existsSync21, readFileSync as readFileSync18 } from "node:fs";
8213
- import path27 from "node:path";
8335
+ // packages/generate/src/brief.ts
8336
+ import { existsSync as existsSync22, readFileSync as readFileSync18 } from "node:fs";
8337
+ import path28 from "node:path";
8214
8338
  function singleAxes2(name) {
8215
8339
  const parsed = parseVariantAxes(name);
8216
8340
  if (parsed === void 0) return void 0;
@@ -8449,8 +8573,8 @@ function envelopeText(file) {
8449
8573
  }
8450
8574
  function dismissEvidence(setDir, repSlugs) {
8451
8575
  for (const slug of repSlugs) {
8452
- const f = path27.join(setDir, slug, "get_design_context.json");
8453
- if (!existsSync21(f)) continue;
8576
+ const f = path28.join(setDir, slug, "get_design_context.json");
8577
+ if (!existsSync22(f)) continue;
8454
8578
  const text = envelopeText(f);
8455
8579
  const propHit = /[{,]\s*(\w*dismiss\w*)\s*=\s*(?:true|false)\b/i.exec(text) ?? /\b(\w*dismiss\w*)\??\s*:\s*boolean\b/i.exec(text);
8456
8580
  if (propHit !== null) return `emission prop "${propHit[1]}"`;
@@ -8494,13 +8618,13 @@ function recordedFontNeeds(setDir, opts = {}) {
8494
8618
  }
8495
8619
  };
8496
8620
  const manifest = loadManifest(setDir);
8497
- const setDefs = path27.join(setDir, "get_variable_defs.json");
8498
- if (existsSync21(setDefs)) fromDefs(envelopeText(setDefs));
8621
+ const setDefs = path28.join(setDir, "get_variable_defs.json");
8622
+ if (existsSync22(setDefs)) fromDefs(envelopeText(setDefs));
8499
8623
  for (const rep of manifest.reps) {
8500
- const ctx = path27.join(setDir, rep.slug, "get_design_context.json");
8501
- if (existsSync21(ctx)) fromEmission(envelopeText(ctx));
8502
- const defs = path27.join(setDir, rep.slug, "get_variable_defs.json");
8503
- if (existsSync21(defs)) fromDefs(envelopeText(defs));
8624
+ const ctx = path28.join(setDir, rep.slug, "get_design_context.json");
8625
+ if (existsSync22(ctx)) fromEmission(envelopeText(ctx));
8626
+ const defs = path28.join(setDir, rep.slug, "get_variable_defs.json");
8627
+ if (existsSync22(defs)) fromDefs(envelopeText(defs));
8504
8628
  }
8505
8629
  return [...byFamily.entries()].map(([family, paired]) => {
8506
8630
  const weights = /* @__PURE__ */ new Set([...paired, ...opts.pairedOnly === true ? [] : unpaired]);
@@ -8511,8 +8635,8 @@ function symbolFontGlyphCount(setDir, reps) {
8511
8635
  const PUA = /[\uE000-\uF8FF\u{F0000}-\u{FFFFD}\u{100000}-\u{10FFFD}]/u;
8512
8636
  const glyphs = /* @__PURE__ */ new Set();
8513
8637
  for (const rep of reps) {
8514
- const file = path27.join(setDir, rep, "get_metadata.json");
8515
- if (!existsSync21(file)) continue;
8638
+ const file = path28.join(setDir, rep, "get_metadata.json");
8639
+ if (!existsSync22(file)) continue;
8516
8640
  try {
8517
8641
  const text = JSON.parse(readFileSync18(file, "utf8")).content.map((c) => c.text ?? "").join("\n");
8518
8642
  for (const m of text.matchAll(/<text\s[^>]*name="([^"]*)"/g)) {
@@ -8540,8 +8664,8 @@ function recordedTextSlots(setDir, repSlugs) {
8540
8664
  const propRep = [];
8541
8665
  const perRep = [];
8542
8666
  for (const slug of repSlugs) {
8543
- const f = path27.join(setDir, slug, "get_design_context.json");
8544
- if (!existsSync21(f)) continue;
8667
+ const f = path28.join(setDir, slug, "get_design_context.json");
8668
+ if (!existsSync22(f)) continue;
8545
8669
  const code = envelopeText(f);
8546
8670
  const props = /* @__PURE__ */ new Map();
8547
8671
  for (const m of code.matchAll(/[{,]\s*(\w+)\s*=\s*"((?:[^"\\]|\\.)*)"/g)) {
@@ -8566,8 +8690,8 @@ function recordedTextSlots(setDir, repSlugs) {
8566
8690
  }
8567
8691
  const axisValuesBySlug = /* @__PURE__ */ new Map();
8568
8692
  for (const slug of repSlugs) {
8569
- const metaFile = path27.join(setDir, slug, "get_metadata.json");
8570
- if (!existsSync21(metaFile)) continue;
8693
+ const metaFile = path28.join(setDir, slug, "get_metadata.json");
8694
+ if (!existsSync22(metaFile)) continue;
8571
8695
  const name = symbolName(envelopeText(metaFile));
8572
8696
  if (name === void 0) continue;
8573
8697
  const values = /* @__PURE__ */ new Set();
@@ -8666,8 +8790,8 @@ function authorTaskFromSet(setDir, opts = {}) {
8666
8790
  const poses = [];
8667
8791
  const missing = [];
8668
8792
  for (const rep of manifest.reps) {
8669
- const metaFile = path27.join(setDir, rep.slug, "get_metadata.json");
8670
- if (!existsSync21(metaFile)) {
8793
+ const metaFile = path28.join(setDir, rep.slug, "get_metadata.json");
8794
+ if (!existsSync22(metaFile)) {
8671
8795
  missing.push(rep.slug);
8672
8796
  continue;
8673
8797
  }
@@ -8681,8 +8805,8 @@ function authorTaskFromSet(setDir, opts = {}) {
8681
8805
  if (missing.length > 0) {
8682
8806
  throw new Error(`recording set ${setDir} is missing metadata for ${missing.length} rep(s): ${missing.slice(0, 5).join(", ")}${missing.length > 5 ? ", \u2026" : ""}`);
8683
8807
  }
8684
- const setMeta = path27.join(setDir, "get_metadata.json");
8685
- const latticeNames = manifest.latticeNames ?? (existsSync21(setMeta) ? [...envelopeText(setMeta).matchAll(/name="([^"]*)"/g)].map((m) => decodeXmlEntities(m[1])) : void 0);
8808
+ const setMeta = path28.join(setDir, "get_metadata.json");
8809
+ const latticeNames = manifest.latticeNames ?? (existsSync22(setMeta) ? [...envelopeText(setMeta).matchAll(/name="([^"]*)"/g)].map((m) => decodeXmlEntities(m[1])) : void 0);
8686
8810
  const defaults = { ...manifest.defaults ?? {}, ...opts.defaults ?? {} };
8687
8811
  const recordedFonts = recordedFontFamilies(setDir);
8688
8812
  const textSlots = recordedTextSlots(setDir, manifest.reps.map((r) => r.slug));
@@ -8801,7 +8925,7 @@ RESOLVED FOR THIS RECORDING: it is ${opts.colorScheme}-mode truth, so pin color-
8801
8925
  }
8802
8926
  var PoseCompletenessError, kebab3, camel, pascal, RESERVED_PROPS, axisPropName, isStateAxis, DISMISS_NAMES, symbolName, STYLE_WEIGHTS2, styleWeight;
8803
8927
  var init_brief = __esm({
8804
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/brief.ts"() {
8928
+ "packages/generate/src/brief.ts"() {
8805
8929
  "use strict";
8806
8930
  init_src();
8807
8931
  init_src4();
@@ -8855,11 +8979,11 @@ var init_brief = __esm({
8855
8979
  }
8856
8980
  });
8857
8981
 
8858
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/segments.ts
8859
- import { existsSync as existsSync22, readFileSync as readFileSync19, readdirSync as readdirSync6 } from "node:fs";
8860
- import path28 from "node:path";
8982
+ // packages/generate/src/segments.ts
8983
+ import { existsSync as existsSync23, readFileSync as readFileSync19, readdirSync as readdirSync6 } from "node:fs";
8984
+ import path29 from "node:path";
8861
8985
  function repText(set, rep, tool) {
8862
- const env = JSON.parse(readFileSync19(path28.join(set, rep, `${tool}.json`), "utf8"));
8986
+ const env = JSON.parse(readFileSync19(path29.join(set, rep, `${tool}.json`), "utf8"));
8863
8987
  return tool === "get_design_context" ? envelopeFirstTextPart(env) : envelopeTextContent(env);
8864
8988
  }
8865
8989
  function stripFigmaInstructions(emission) {
@@ -8920,16 +9044,16 @@ DROPPED from the map, untrustworthy in the source export \u2014 for these, each
8920
9044
  function buildSegments(task, mode = "fenced") {
8921
9045
  const SET = task.set;
8922
9046
  let rawDefs = {};
8923
- if (existsSync22(path28.join(SET, "get_variable_defs.json"))) {
8924
- const text = envelopeFirstTextPart(JSON.parse(readFileSync19(path28.join(SET, "get_variable_defs.json"), "utf8"))) || "{}";
9047
+ if (existsSync23(path29.join(SET, "get_variable_defs.json"))) {
9048
+ const text = envelopeFirstTextPart(JSON.parse(readFileSync19(path29.join(SET, "get_variable_defs.json"), "utf8"))) || "{}";
8925
9049
  try {
8926
9050
  rawDefs = JSON.parse(text);
8927
9051
  } catch {
8928
9052
  }
8929
9053
  } else {
8930
9054
  for (const cfg of task.configs) {
8931
- const f = path28.join(SET, cfg.rep, "get_variable_defs.json");
8932
- if (!existsSync22(f)) continue;
9055
+ const f = path29.join(SET, cfg.rep, "get_variable_defs.json");
9056
+ if (!existsSync23(f)) continue;
8933
9057
  const text = envelopeFirstTextPart(JSON.parse(readFileSync19(f, "utf8"))) || "{}";
8934
9058
  try {
8935
9059
  for (const [k, v] of Object.entries(JSON.parse(text))) rawDefs[k] ??= v;
@@ -8938,8 +9062,8 @@ function buildSegments(task, mode = "fenced") {
8938
9062
  }
8939
9063
  }
8940
9064
  const emissionTexts = task.configs.map((cfg) => {
8941
- const f = path28.join(SET, cfg.rep, "get_design_context.json");
8942
- return existsSync22(f) ? envelopeFirstTextPart(JSON.parse(readFileSync19(f, "utf8"))) : "";
9065
+ const f = path29.join(SET, cfg.rep, "get_design_context.json");
9066
+ return existsSync23(f) ? envelopeFirstTextPart(JSON.parse(readFileSync19(f, "utf8"))) : "";
8943
9067
  });
8944
9068
  const { map, note } = cleanTokenMap(rawDefs, emissionTexts);
8945
9069
  const defs = JSON.stringify(map, null, 1);
@@ -8954,9 +9078,9 @@ ${defs}
8954
9078
  for (const cfg of task.configs) {
8955
9079
  const meta = stripFigmaInstructions(repText(SET, cfg.rep, "get_metadata"));
8956
9080
  const emission = stripFigmaInstructions(repText(SET, cfg.rep, "get_design_context"));
8957
- const assets = readdirSync6(path28.join(SET, cfg.rep)).filter((f) => f.startsWith("asset-") && f.endsWith(".svg")).map((f) => `asset ${f}:
9081
+ const assets = readdirSync6(path29.join(SET, cfg.rep)).filter((f) => f.startsWith("asset-") && f.endsWith(".svg")).map((f) => `asset ${f}:
8958
9082
  \`\`\`svg
8959
- ${readFileSync19(path28.join(SET, cfg.rep, f), "utf8")}
9083
+ ${readFileSync19(path29.join(SET, cfg.rep, f), "utf8")}
8960
9084
  \`\`\``).join("\n");
8961
9085
  parts.push(`
8962
9086
  ## Config ${cfg.rep} \u2192 ${cfg.component} ${JSON.stringify(cfg.props)}
@@ -8981,20 +9105,20 @@ Optionally a third block with \`/* FILE: tokens.css */\`.`);
8981
9105
  } else {
8982
9106
  parts.push(`
8983
9107
  ## Output format
8984
- Write the COMPLETE files (${task.entry}, styles.css, optional tokens.css) into your candidate directory. Do not paste file contents into chat \u2014 the scorer reads the directory.`);
9108
+ Write the COMPLETE files (${task.entry}, styles.css, optional tokens.css) into ONE candidate directory: \`tendril-out/${path29.basename(task.set)}-candidate/\` unless you were handed another path. Pass that same directory to \`tendril engine score\` every round and keep writing into it \u2014 the scorer stamps the bundle there, writes its evidence beside your files, and appends its score-history.jsonl lines there (one when a round starts, one when it scores); a fresh directory each round throws all of that away. Do not paste file contents into chat \u2014 the scorer reads the directory.`);
8985
9109
  }
8986
9110
  return parts.join("\n");
8987
9111
  }
8988
9112
  var cssIdent;
8989
9113
  var init_segments = __esm({
8990
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/segments.ts"() {
9114
+ "packages/generate/src/segments.ts"() {
8991
9115
  "use strict";
8992
9116
  init_src();
8993
9117
  cssIdent = (name) => name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
8994
9118
  }
8995
9119
  });
8996
9120
 
8997
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/consent.ts
9121
+ // packages/generate/src/consent.ts
8998
9122
  function formatConsentLines(e) {
8999
9123
  return [
9000
9124
  `engine=${e.engineId} model=${e.modelId} route=${e.providerRoute}`,
@@ -9004,12 +9128,12 @@ function formatConsentLines(e) {
9004
9128
  ];
9005
9129
  }
9006
9130
  var init_consent = __esm({
9007
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/consent.ts"() {
9131
+ "packages/generate/src/consent.ts"() {
9008
9132
  "use strict";
9009
9133
  }
9010
9134
  });
9011
9135
 
9012
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/adapter.ts
9136
+ // packages/generate/src/adapter.ts
9013
9137
  function resolveAdapterSettings(entry, overrides = {}) {
9014
9138
  const notes = [];
9015
9139
  let maxTokens = DEFAULT_MAX_TOKENS;
@@ -9041,16 +9165,16 @@ function resolveAdapterSettings(entry, overrides = {}) {
9041
9165
  }
9042
9166
  var DEFAULT_MAX_TOKENS;
9043
9167
  var init_adapter = __esm({
9044
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/adapter.ts"() {
9168
+ "packages/generate/src/adapter.ts"() {
9045
9169
  "use strict";
9046
9170
  DEFAULT_MAX_TOKENS = 2e4;
9047
9171
  }
9048
9172
  });
9049
9173
 
9050
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/bundle-emit.ts
9174
+ // packages/generate/src/bundle-emit.ts
9051
9175
  import { createHash as createHash4 } from "node:crypto";
9052
- import { copyFileSync, existsSync as existsSync23, mkdirSync as mkdirSync7, readFileSync as readFileSync20, readdirSync as readdirSync7, rmSync as rmSync3, writeFileSync as writeFileSync11 } from "node:fs";
9053
- import path29 from "node:path";
9176
+ import { copyFileSync, existsSync as existsSync24, mkdirSync as mkdirSync7, readFileSync as readFileSync20, readdirSync as readdirSync7, rmSync as rmSync3, writeFileSync as writeFileSync11 } from "node:fs";
9177
+ import path30 from "node:path";
9054
9178
  function pinFromConfigs(configs) {
9055
9179
  const domains = /* @__PURE__ */ new Map();
9056
9180
  const kinds = /* @__PURE__ */ new Map();
@@ -9119,9 +9243,9 @@ function fontsCssFor(faces, bundleDir, cacheDir = DEFAULT_FONT_CACHE, substitute
9119
9243
  const notices = [];
9120
9244
  const licenseTexts = /* @__PURE__ */ new Map();
9121
9245
  for (const face of faces) {
9122
- const src = path29.join(cacheDir, path29.basename(face.file));
9123
- const target = `./fonts/${path29.basename(face.file)}`;
9124
- const format = FONT_FORMATS[path29.extname(face.file).toLowerCase()] ?? "truetype";
9246
+ const src = path30.join(cacheDir, path30.basename(face.file));
9247
+ const target = `./fonts/${path30.basename(face.file)}`;
9248
+ const format = FONT_FORMATS[path30.extname(face.file).toLowerCase()] ?? "truetype";
9125
9249
  const family = face.family.replace(/['\\]/g, "").replace(/\*\//g, "");
9126
9250
  const decl = `@font-face { font-family: '${family}'; font-weight: ${face.weight}; font-style: normal; src: url(${target}) format('${format}'); }`;
9127
9251
  const license = normalizeFontLicense(face.license);
@@ -9151,14 +9275,14 @@ function fontsCssFor(faces, bundleDir, cacheDir = DEFAULT_FONT_CACHE, substitute
9151
9275
  `/* ${decl} */`
9152
9276
  );
9153
9277
  }
9154
- } else if (existsSync23(src) && createHash4("sha256").update(readFileSync20(src)).digest("hex") === face.sha256) {
9155
- mkdirSync7(path29.join(bundleDir, "fonts"), { recursive: true });
9156
- copyFileSync(src, path29.join(bundleDir, "fonts", path29.basename(face.file)));
9278
+ } else if (existsSync24(src) && createHash4("sha256").update(readFileSync20(src)).digest("hex") === face.sha256) {
9279
+ mkdirSync7(path30.join(bundleDir, "fonts"), { recursive: true });
9280
+ copyFileSync(src, path30.join(bundleDir, "fonts", path30.basename(face.file)));
9157
9281
  licenseTexts.set(terms.file, terms.text);
9158
9282
  const upstream = upstreamAttribution(face);
9159
9283
  notices.push(
9160
9284
  "",
9161
- `${face.family.replace(/[\r\n]+/g, " ")} ${face.weight} \u2014 ./${path29.basename(face.file)}`,
9285
+ `${face.family.replace(/[\r\n]+/g, " ")} ${face.weight} \u2014 ./${path30.basename(face.file)}`,
9162
9286
  ` licence: ${terms.title} \u2014 full text in ./${terms.file}`,
9163
9287
  ` source: ${face.source}`,
9164
9288
  ` sha256: ${face.sha256}`,
@@ -9172,9 +9296,9 @@ function fontsCssFor(faces, bundleDir, cacheDir = DEFAULT_FONT_CACHE, substitute
9172
9296
  }
9173
9297
  if (lines.length === 0) return null;
9174
9298
  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")}
9299
+ const fontsDir = path30.join(bundleDir, "fonts");
9300
+ for (const [file, text] of licenseTexts) writeFileSync11(path30.join(fontsDir, file), text);
9301
+ writeFileSync11(path30.join(fontsDir, "NOTICE.txt"), `${[NOTICE_PREAMBLE, ...notices].join("\n")}
9178
9302
  `);
9179
9303
  header.push(
9180
9304
  "/* REDISTRIBUTION: the face files in ./fonts/ are redistributed under the licences",
@@ -9186,8 +9310,8 @@ function fontsCssFor(faces, bundleDir, cacheDir = DEFAULT_FONT_CACHE, substitute
9186
9310
  `;
9187
9311
  }
9188
9312
  function countLatticeSymbols(setDir) {
9189
- const manifestFile = path29.join(setDir, "recording-set.json");
9190
- if (existsSync23(manifestFile)) {
9313
+ const manifestFile = path30.join(setDir, "recording-set.json");
9314
+ if (existsSync24(manifestFile)) {
9191
9315
  try {
9192
9316
  const lattice = JSON.parse(readFileSync20(manifestFile, "utf8")).latticeNames;
9193
9317
  if (lattice !== void 0 && lattice.length > 0) return lattice.length;
@@ -9195,9 +9319,9 @@ function countLatticeSymbols(setDir) {
9195
9319
  }
9196
9320
  }
9197
9321
  const files = [
9198
- path29.join(setDir, "get_metadata.json"),
9199
- ...existsSync23(setDir) ? readdirSync7(setDir).filter((f) => /^get_metadata-.*\.json$/.test(f)).map((f) => path29.join(setDir, f)) : []
9200
- ].filter((f) => existsSync23(f));
9322
+ path30.join(setDir, "get_metadata.json"),
9323
+ ...existsSync24(setDir) ? readdirSync7(setDir).filter((f) => /^get_metadata-.*\.json$/.test(f)).map((f) => path30.join(setDir, f)) : []
9324
+ ].filter((f) => existsSync24(f));
9201
9325
  if (files.length === 0) return null;
9202
9326
  let count = 0;
9203
9327
  for (const f of files) {
@@ -9209,21 +9333,21 @@ function countLatticeSymbols(setDir) {
9209
9333
  function recordingSetHash(setDir, configs) {
9210
9334
  const relPaths = [];
9211
9335
  for (const name of ["recording-set.json", "completeness-manifest.json", "get_variable_defs.json", "get_metadata.json"]) {
9212
- if (existsSync23(path29.join(setDir, name))) relPaths.push(name);
9336
+ if (existsSync24(path30.join(setDir, name))) relPaths.push(name);
9213
9337
  }
9214
9338
  for (const cfg of configs) {
9215
9339
  for (const f of ["get_design_context.json", "get_metadata.json", "get_screenshot.json", "get_variable_defs.json"]) {
9216
- if (existsSync23(path29.join(setDir, cfg.rep, f))) relPaths.push(`${cfg.rep}/${f}`);
9340
+ if (existsSync24(path30.join(setDir, cfg.rep, f))) relPaths.push(`${cfg.rep}/${f}`);
9217
9341
  }
9218
- if (existsSync23(path29.join(setDir, cfg.rep))) {
9219
- for (const asset of readdirSync7(path29.join(setDir, cfg.rep)).filter((f) => f.startsWith("asset-"))) {
9342
+ if (existsSync24(path30.join(setDir, cfg.rep))) {
9343
+ for (const asset of readdirSync7(path30.join(setDir, cfg.rep)).filter((f) => f.startsWith("asset-"))) {
9220
9344
  relPaths.push(`${cfg.rep}/${asset}`);
9221
9345
  }
9222
9346
  }
9223
9347
  }
9224
9348
  return hashRecordingSet(
9225
9349
  relPaths,
9226
- (p) => new Uint8Array(readFileSync20(path29.join(setDir, p))),
9350
+ (p) => new Uint8Array(readFileSync20(path30.join(setDir, p))),
9227
9351
  (chunks) => {
9228
9352
  const h = createHash4("sha256");
9229
9353
  for (const c of chunks) h.update(c);
@@ -9246,7 +9370,7 @@ function emitBundleV1(opts) {
9246
9370
  const lattice = countLatticeSymbols(opts.task.set);
9247
9371
  const interaction = opts.behaviors.filter((b) => !b.id.startsWith("prelude:"));
9248
9372
  const prelude = opts.behaviors.filter((b) => b.id.startsWith("prelude:"));
9249
- const cssFiles = ["styles.css", "tokens.css"].map((f) => path29.join(opts.bundleDir, f)).filter((f) => existsSync23(f));
9373
+ const cssFiles = ["styles.css", "tokens.css"].map((f) => path30.join(opts.bundleDir, f)).filter((f) => existsSync24(f));
9250
9374
  const families = cssFontFamilies(cssFiles.map((f) => readFileSync20(f, "utf8")).join("\n"));
9251
9375
  const requiredFonts = requiredFontsManifest(families, opts.fontCacheDir).map((f) => ({
9252
9376
  family: f.family,
@@ -9276,7 +9400,7 @@ function emitBundleV1(opts) {
9276
9400
  // resolvable via verify's --set override).
9277
9401
  path: (() => {
9278
9402
  const base = process.env["INIT_CWD"] ?? process.cwd();
9279
- const rel = path29.relative(base, opts.task.set);
9403
+ const rel = path30.relative(base, opts.task.set);
9280
9404
  return rel !== "" && !rel.startsWith("..") ? rel : opts.task.set;
9281
9405
  })(),
9282
9406
  component: opts.componentName,
@@ -9300,12 +9424,12 @@ function emitBundleV1(opts) {
9300
9424
  })
9301
9425
  };
9302
9426
  const written = [];
9303
- const manifestPath2 = path29.join(opts.bundleDir, "component.json");
9427
+ const manifestPath2 = path30.join(opts.bundleDir, "component.json");
9304
9428
  writeFileSync11(manifestPath2, `${JSON.stringify(manifest, null, 2)}
9305
9429
  `);
9306
9430
  written.push(manifestPath2);
9307
- const stylesPath = path29.join(opts.bundleDir, "styles.css");
9308
- if (existsSync23(stylesPath)) {
9431
+ const stylesPath = path30.join(opts.bundleDir, "styles.css");
9432
+ if (existsSync24(stylesPath)) {
9309
9433
  const comment = cssProvenanceComment({ pass, scored: statuses.length, certified, latticeConfigs: lattice });
9310
9434
  const current = readFileSync20(stylesPath, "utf8");
9311
9435
  const stripped = current.replace(/^\/\* tendril bundle v\d+ [^]*?\*\/\n/, "");
@@ -9313,8 +9437,8 @@ function emitBundleV1(opts) {
9313
9437
  ${stripped}`);
9314
9438
  written.push(stylesPath);
9315
9439
  }
9316
- const fontsCssPath = path29.join(opts.bundleDir, "fonts.css");
9317
- rmSync3(path29.join(opts.bundleDir, "fonts"), { recursive: true, force: true });
9440
+ const fontsCssPath = path30.join(opts.bundleDir, "fonts.css");
9441
+ rmSync3(path30.join(opts.bundleDir, "fonts"), { recursive: true, force: true });
9318
9442
  rmSync3(fontsCssPath, { force: true });
9319
9443
  const fontsCss = fontsCssFor(requiredFontsManifest(families, opts.fontCacheDir), opts.bundleDir, opts.fontCacheDir, opts.substitutedFamilies ?? []);
9320
9444
  if (fontsCss !== null) {
@@ -9327,7 +9451,7 @@ ${stripped}`);
9327
9451
  }
9328
9452
  var FONT_FORMATS, BARS, NOTICE_PREAMBLE, OFL_1_1_TEXT, UFL_1_0_TEXT, APACHE_2_0_TEXT, REDISTRIBUTABLE;
9329
9453
  var init_bundle_emit = __esm({
9330
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/bundle-emit.ts"() {
9454
+ "packages/generate/src/bundle-emit.ts"() {
9331
9455
  "use strict";
9332
9456
  init_src6();
9333
9457
  init_src();
@@ -9742,9 +9866,9 @@ DEALINGS IN THE FONT SOFTWARE.
9742
9866
  }
9743
9867
  });
9744
9868
 
9745
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/index.ts
9869
+ // packages/generate/src/index.ts
9746
9870
  var init_src7 = __esm({
9747
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/generate/src/index.ts"() {
9871
+ "packages/generate/src/index.ts"() {
9748
9872
  "use strict";
9749
9873
  init_engine();
9750
9874
  init_engine_curated();
@@ -9758,7 +9882,7 @@ var init_src7 = __esm({
9758
9882
  }
9759
9883
  });
9760
9884
 
9761
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/fonts.ts
9885
+ // packages/cli/src/commands/fonts.ts
9762
9886
  var fonts_exports = {};
9763
9887
  __export(fonts_exports, {
9764
9888
  DEFAULT_FONT_CACHE: () => DEFAULT_FONT_CACHE,
@@ -9768,8 +9892,8 @@ __export(fonts_exports, {
9768
9892
  runFontsResolveSet: () => runFontsResolveSet,
9769
9893
  runFontsStatus: () => runFontsStatus
9770
9894
  });
9771
- import { existsSync as existsSync24, readFileSync as readFileSync21 } from "node:fs";
9772
- import path30 from "node:path";
9895
+ import { existsSync as existsSync25, readFileSync as readFileSync21 } from "node:fs";
9896
+ import path31 from "node:path";
9773
9897
  async function runFontsResolve(opts) {
9774
9898
  const result = await resolveFonts(opts.family, opts.weights, opts.cacheDir);
9775
9899
  emitData(opts, result, () => {
@@ -9784,7 +9908,7 @@ async function runFontsResolve(opts) {
9784
9908
  }
9785
9909
  }
9786
9910
  async function runFontsResolveSet(opts) {
9787
- const setDir = path30.resolve(process.env["INIT_CWD"] ?? process.cwd(), opts.set);
9911
+ const setDir = path31.resolve(process.env["INIT_CWD"] ?? process.cwd(), opts.set);
9788
9912
  let needs = [];
9789
9913
  try {
9790
9914
  needs = recordedFontNeeds(setDir);
@@ -9792,19 +9916,19 @@ async function runFontsResolveSet(opts) {
9792
9916
  fail(opts, ExitCode.InputValidation, {
9793
9917
  error: `cannot read font needs from ${setDir}: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`,
9794
9918
  code: "font-needs-unreadable",
9795
- remediation: 'Point --set at a directory recorded with `tendril record` (it carries recording-set.json), or resolve a family explicitly: tendril fonts resolve "<Family>" --weights 400 500 600.'
9919
+ remediation: `Point --set at a directory recorded with \`${tendrilCommand("record plan")}\` (it carries recording-set.json), or resolve a family explicitly: ${tendrilCommand('fonts resolve "<Family>" --weights 400 500 600')}.`
9796
9920
  });
9797
9921
  }
9798
9922
  if (needs.length === 0) {
9799
9923
  fail(opts, ExitCode.InputValidation, {
9800
9924
  error: `recording set ${setDir} declares no detectable font families`,
9801
9925
  code: "font-needs-empty",
9802
- remediation: 'Resolve the family the design uses explicitly: tendril fonts resolve "<Family>" --weights 400 500 600.'
9926
+ remediation: `Resolve the family the design uses explicitly: ${tendrilCommand('fonts resolve "<Family>" --weights 400 500 600')}.`
9803
9927
  });
9804
9928
  }
9805
9929
  const inCache = new Set(resolvedFontFamilies(opts.cacheDir).flatMap((f) => f.weights.map((w) => `${f.family.toLowerCase()}:${w}`)));
9806
9930
  const unstamped = new Map(facesMissingLicense(opts.cacheDir).map((f) => [`${f.family.toLowerCase()}:${f.weight}`, f.sha256]));
9807
- const cached = [];
9931
+ const cached2 = [];
9808
9932
  const resolved = [];
9809
9933
  const failures = [];
9810
9934
  const relicensed = [];
@@ -9817,7 +9941,7 @@ async function runFontsResolveSet(opts) {
9817
9941
  const key = `${need.family.toLowerCase()}:${w}`;
9818
9942
  if (!inCache.has(key)) missing.push(w);
9819
9943
  else if (unstamped.has(key)) toStamp.push(w);
9820
- else cached.push({ family: need.family, weight: w });
9944
+ else cached2.push({ family: need.family, weight: w });
9821
9945
  }
9822
9946
  if (missing.length > 0) {
9823
9947
  const result = await resolveFonts(need.family, missing, opts.cacheDir);
@@ -9834,10 +9958,10 @@ async function runFontsResolveSet(opts) {
9834
9958
  unlicensed.push(...result.failures);
9835
9959
  }
9836
9960
  }
9837
- emitData(opts, { set: setDir, needs, cached, resolved, relicensed, unlicensed, failures }, () => {
9961
+ emitData(opts, { set: setDir, needs, cached: cached2, resolved, relicensed, unlicensed, failures }, () => {
9838
9962
  process.stdout.write(`set declares: ${needs.map((n) => `${n.family} (${n.weights.join(", ")})`).join(" \xB7 ")}
9839
9963
  `);
9840
- for (const f of cached) process.stdout.write(`cached ${f.family} ${f.weight}
9964
+ for (const f of cached2) process.stdout.write(`cached ${f.family} ${f.weight}
9841
9965
  `);
9842
9966
  for (const f of resolved) process.stdout.write(`resolved ${f.family} ${f.weight} (${f.sha256.slice(0, 12)}\u2026)
9843
9967
  `);
@@ -9857,16 +9981,16 @@ async function runFontsResolveSet(opts) {
9857
9981
  }
9858
9982
  }
9859
9983
  function runFontsStatus(opts) {
9860
- const manifestPath2 = path30.join(opts.cacheDir, "manifest.json");
9861
- if (!existsSync24(manifestPath2)) {
9984
+ const manifestPath2 = path31.join(opts.cacheDir, "manifest.json");
9985
+ if (!existsSync25(manifestPath2)) {
9862
9986
  fail(opts, ExitCode.FontsUnproven, {
9863
9987
  error: `no font cache at ${opts.cacheDir}`,
9864
9988
  code: "fonts-unresolved",
9865
- remediation: 'Run `tendril fonts resolve --set <recording-dir>` (or `tendril fonts resolve "<Family>" --weights 400 500 600`) first.'
9989
+ remediation: `Run \`${tendrilCommand("fonts resolve --set <recording-dir>")}\` (or \`${tendrilCommand('fonts resolve "<Family>" --weights 400 500 600')}\`) first.`
9866
9990
  });
9867
9991
  }
9868
9992
  const faces = JSON.parse(readFileSync21(manifestPath2, "utf8"));
9869
- const lockVerdicts = opts.lock !== void 0 ? checkFontLock(path30.resolve(opts.lock), opts.cacheDir) : null;
9993
+ const lockVerdicts = opts.lock !== void 0 ? checkFontLock(path31.resolve(opts.lock), opts.cacheDir) : null;
9870
9994
  emitData(opts, { faces, lockVerdicts }, () => {
9871
9995
  for (const f of faces) process.stdout.write(`cached ${f.family} ${f.weight} (${f.sha256.slice(0, 12)}\u2026)
9872
9996
  `);
@@ -9897,7 +10021,10 @@ function runFontsAdd(opts) {
9897
10021
  fail(opts, ExitCode.InputValidation, {
9898
10022
  error: err instanceof Error ? err.message : String(err),
9899
10023
  code: "font-add-failed",
9900
- remediation: 'Pass a font file you are licensed to use: tendril fonts add "S\xF6hne" 400 ./fonts/soehne-400.woff2'
10024
+ // The face file is the user's own licensed asset: this command
10025
+ // can name every argument but that one, so it stays a marked
10026
+ // blank rather than a fabricated path that looks real.
10027
+ remediation: `Pass a font file you are licensed to use, by absolute path: ${tendrilCommand(`fonts add "${opts.family}" ${opts.weight} <absolute-path-to-face.woff2>`)}`
9901
10028
  });
9902
10029
  }
9903
10030
  emitData(opts, face, () => {
@@ -9906,28 +10033,32 @@ function runFontsAdd(opts) {
9906
10033
  });
9907
10034
  }
9908
10035
  var init_fonts = __esm({
9909
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/fonts.ts"() {
10036
+ "packages/cli/src/commands/fonts.ts"() {
9910
10037
  "use strict";
9911
10038
  init_src3();
9912
10039
  init_src4();
9913
10040
  init_src7();
9914
10041
  init_output();
10042
+ init_invocation();
9915
10043
  }
9916
10044
  });
9917
10045
 
9918
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/font-guidance.ts
10046
+ // packages/cli/src/font-guidance.ts
10047
+ import path32 from "node:path";
9919
10048
  function fontsUnprovenRemediation(setDir) {
9920
- if (setDir !== void 0) {
10049
+ const set = setDir === void 0 ? void 0 : path32.resolve(setDir);
10050
+ if (set !== void 0) {
9921
10051
  try {
9922
- const needs = recordedFontNeeds(setDir);
10052
+ const needs = recordedFontNeeds(set);
9923
10053
  if (needs.length > 0) {
9924
10054
  const families = needs.map((n) => `"${n.family}"`).join(", ");
9925
- return `Run \`tendril fonts resolve --set ${setDir}\` \u2014 the recording declares ${families}; faces land in ${DEFAULT_FONT_CACHE}.`;
10055
+ return `Run \`${tendrilCommand(`fonts resolve --set ${set}`)}\` \u2014 the recording declares ${families}; faces land in ${DEFAULT_FONT_CACHE}.`;
9926
10056
  }
9927
10057
  } catch {
9928
10058
  }
9929
10059
  }
9930
- return `Run \`tendril fonts resolve --set <recording-dir>\` (or \`tendril fonts resolve "<Family>" --weights 400 500 600\`) to populate the font cache \u2014 the cache read is ${DEFAULT_FONT_CACHE}.`;
10060
+ const target = set ?? "<recording-dir>";
10061
+ return `Run \`${tendrilCommand(`fonts resolve --set ${target}`)}\` (or \`${tendrilCommand('fonts resolve "<Family>" --weights 400 500 600')}\`) to populate the font cache \u2014 the cache read is ${DEFAULT_FONT_CACHE}.`;
9931
10062
  }
9932
10063
  function taskFontFamilies(setDir) {
9933
10064
  try {
@@ -9969,28 +10100,31 @@ function missingWeights(setDir, cacheDir) {
9969
10100
  return gaps;
9970
10101
  }
9971
10102
  var init_font_guidance = __esm({
9972
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/font-guidance.ts"() {
10103
+ "packages/cli/src/font-guidance.ts"() {
9973
10104
  "use strict";
9974
10105
  init_src4();
9975
10106
  init_src7();
10107
+ init_invocation();
9976
10108
  }
9977
10109
  });
9978
10110
 
9979
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/verify.ts
10111
+ // packages/cli/src/commands/verify.ts
9980
10112
  var verify_exports = {};
9981
10113
  __export(verify_exports, {
9982
10114
  NO_ROLE_MANIFEST: () => NO_ROLE_MANIFEST,
9983
10115
  ROLES_NOT_RESOLVED: () => ROLES_NOT_RESOLVED,
9984
10116
  checkSummarySegments: () => checkSummarySegments,
9985
10117
  compositionReport: () => compositionReport,
10118
+ eyeCheck: () => eyeCheck,
9986
10119
  failureTally: () => failureTally,
9987
10120
  foldConfigStatus: () => foldConfigStatus,
9988
10121
  interactionCoverage: () => interactionCoverage,
10122
+ occlusionReport: () => occlusionReport,
9989
10123
  resolveComposition: () => resolveComposition,
9990
10124
  runVerify: () => runVerify
9991
10125
  });
9992
- import { existsSync as existsSync25, readFileSync as readFileSync22 } from "node:fs";
9993
- import path31 from "node:path";
10126
+ import { existsSync as existsSync26, readFileSync as readFileSync22 } from "node:fs";
10127
+ import path33 from "node:path";
9994
10128
  function interactionCoverage(behaviors) {
9995
10129
  const interaction = behaviors.filter((b) => !b.id.startsWith("prelude:"));
9996
10130
  return {
@@ -10038,9 +10172,18 @@ function checkSummarySegments(input) {
10038
10172
  const tally = (rows) => `${rows.filter((r) => r.pass).length}/${rows.length}`;
10039
10173
  const { availability } = input;
10040
10174
  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)}`;
10175
+ const occ = occlusionReport(input.occlusion);
10176
+ const occlusion = "unavailable" in occ ? `occlusion not applicable (${NO_OVERLAY_DECLARED})` : `occlusion ${tally(input.occlusion)}`;
10042
10177
  return ` \xB7 ${composition} \xB7 ${occlusion}`;
10043
10178
  }
10179
+ function occlusionReport(occlusion) {
10180
+ if (occlusion.length === 0) {
10181
+ return {
10182
+ unavailable: "the bundle declares no overlay (no open-state config and no prelude popover) \u2014 the sibling-occlusion check DOES NOT APPLY and nothing about overlay stacking was measured; an empty check list is this state, not a clean bill"
10183
+ };
10184
+ }
10185
+ return { checks: occlusion.length, passed: occlusion.filter((o) => o.pass).length };
10186
+ }
10044
10187
  function compositionReport(input) {
10045
10188
  const { availability, regions } = input;
10046
10189
  if (availability.unavailable !== void 0) return { unavailable: availability.unavailable };
@@ -10057,6 +10200,13 @@ function compositionReport(input) {
10057
10200
  crops: input.crops ?? { unavailable: cropsUnavailable }
10058
10201
  };
10059
10202
  }
10203
+ function eyeCheck(bundleDir) {
10204
+ return {
10205
+ command: tendrilCommand(`inspect "${bundleDir}"`),
10206
+ sheetPath: path33.join(bundleDir, "verify-evidence", "inspect.html"),
10207
+ note: "magnified recorded-vs-rendered crops of every small node; scores cannot see shape. The command WRITES/refreshes the sheet at sheetPath \u2014 re-run it after every verify; an existing sheet may show stale crops."
10208
+ };
10209
+ }
10060
10210
  function failureTally(t) {
10061
10211
  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
10212
  }
@@ -10065,7 +10215,7 @@ function taskFromManifest(opts, manifest, setDir) {
10065
10215
  const adapterSlugs = Object.keys(manifest.propAdapter);
10066
10216
  const unmapped = recordedSlugs.filter((s) => !adapterSlugs.includes(s));
10067
10217
  const adapterOnly = adapterSlugs.filter((s) => !recordedSlugs.includes(s));
10068
- const registry = Object.values(TASKS).find((t) => path31.resolve(t.set) === path31.resolve(setDir));
10218
+ const registry = Object.values(TASKS).find((t) => path33.resolve(t.set) === path33.resolve(setDir));
10069
10219
  const authored = (() => {
10070
10220
  if (registry !== void 0) return void 0;
10071
10221
  try {
@@ -10074,7 +10224,7 @@ function taskFromManifest(opts, manifest, setDir) {
10074
10224
  fail(opts, ExitCode.InputValidation, {
10075
10225
  error: `cannot author the verification task from ${setDir}: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`,
10076
10226
  code: "AUTHORING_FAILED",
10077
- remediation: "Fix the recording set (duplicate/colliding poses fail authoring by design \u2014 check `tendril record status` and the set's variant names)."
10227
+ remediation: `Fix the recording set (duplicate/colliding poses fail authoring by design \u2014 check \`${tendrilCommand(`record status --set ${setDir}`)}\` and the set's variant names).`
10078
10228
  });
10079
10229
  }
10080
10230
  })();
@@ -10097,18 +10247,18 @@ function taskFromManifest(opts, manifest, setDir) {
10097
10247
  }
10098
10248
  async function runVerify(opts) {
10099
10249
  const callerCwd = process.env["INIT_CWD"] ?? process.cwd();
10100
- const setOverride = opts.set !== void 0 ? path31.resolve(callerCwd, opts.set) : void 0;
10101
- opts = { ...opts, bundleDir: path31.resolve(callerCwd, opts.bundleDir), ...setOverride !== void 0 ? { set: setOverride } : {} };
10102
- if (!existsSync25(opts.bundleDir)) {
10250
+ const setOverride = opts.set !== void 0 ? path33.resolve(callerCwd, opts.set) : void 0;
10251
+ opts = { ...opts, bundleDir: path33.resolve(callerCwd, opts.bundleDir), ...setOverride !== void 0 ? { set: setOverride } : {} };
10252
+ if (!existsSync26(opts.bundleDir)) {
10103
10253
  fail(opts, ExitCode.InputValidation, {
10104
10254
  error: `bundle directory not found: ${opts.bundleDir}`,
10105
10255
  code: "bundle-missing",
10106
10256
  remediation: "Point at a generated bundle directory (containing component.json, the entry module, and styles.css)."
10107
10257
  });
10108
10258
  }
10109
- const manifestPath2 = path31.join(opts.bundleDir, "component.json");
10259
+ const manifestPath2 = path33.join(opts.bundleDir, "component.json");
10110
10260
  let manifest;
10111
- if (existsSync25(manifestPath2)) {
10261
+ if (existsSync26(manifestPath2)) {
10112
10262
  const { manifest: parsed, issues } = readBundleManifest(readFileSync22(manifestPath2, "utf8"));
10113
10263
  if (issues.length > 0) {
10114
10264
  fail(opts, ExitCode.InputValidation, {
@@ -10136,21 +10286,21 @@ async function runVerify(opts) {
10136
10286
  task = registry;
10137
10287
  } else if (manifest !== void 0) {
10138
10288
  const resolveSetDir = (p) => {
10139
- if (path31.isAbsolute(p)) return p;
10140
- const fromRepo = path31.resolve(REPO_ROOT, p);
10141
- if (existsSync25(fromRepo)) return fromRepo;
10142
- return path31.resolve(callerCwd, p);
10289
+ if (path33.isAbsolute(p)) return p;
10290
+ const fromRepo = path33.resolve(REPO_ROOT, p);
10291
+ if (existsSync26(fromRepo)) return fromRepo;
10292
+ return path33.resolve(callerCwd, p);
10143
10293
  };
10144
10294
  const setDir = opts.set ?? resolveSetDir(manifest.provenance.recordingSet.path);
10145
- if (!existsSync25(path31.join(setDir, "recording-set.json")) && !Object.values(TASKS).some((t) => path31.resolve(t.set) === path31.resolve(setDir))) {
10295
+ if (!existsSync26(path33.join(setDir, "recording-set.json")) && !Object.values(TASKS).some((t) => path33.resolve(t.set) === path33.resolve(setDir))) {
10146
10296
  fail(opts, ExitCode.RecordingIncomplete, {
10147
10297
  error: `recording set not found or unmanifested: ${setDir}`,
10148
10298
  code: "recording-set-missing",
10149
10299
  remediation: "Pass --set <dir> pointing at the recording set this bundle was generated from."
10150
10300
  });
10151
10301
  }
10152
- const registry = Object.values(TASKS).find((t) => path31.resolve(t.set) === path31.resolve(setDir));
10153
- if (registry !== void 0 && !existsSync25(path31.join(setDir, "recording-set.json"))) {
10302
+ const registry = Object.values(TASKS).find((t) => path33.resolve(t.set) === path33.resolve(setDir));
10303
+ if (registry !== void 0 && !existsSync26(path33.join(setDir, "recording-set.json"))) {
10154
10304
  const recordedSlugs = registry.configs.map((c) => c.rep);
10155
10305
  const adapterSlugs = Object.keys(manifest.propAdapter);
10156
10306
  unmapped = recordedSlugs.filter((s) => !adapterSlugs.includes(s));
@@ -10174,8 +10324,8 @@ async function runVerify(opts) {
10174
10324
  warn(opts, `recording set content differs from the bundle's provenance stamp (${hash.slice(0, 12)}\u2026 vs ${manifest.provenance.recordingSet.hash.slice(0, 12)}\u2026) \u2014 scores apply to the CURRENT set`);
10175
10325
  }
10176
10326
  for (const name of [manifest.entry, "styles.css", "tokens.css"]) {
10177
- const p = path31.join(opts.bundleDir, name);
10178
- if (!existsSync25(p)) continue;
10327
+ const p = path33.join(opts.bundleDir, name);
10328
+ if (!existsSync26(p)) continue;
10179
10329
  const issues = checkBundleSourceFile(name, new Uint8Array(readFileSync22(p)));
10180
10330
  if (issues.length > 0) {
10181
10331
  fail(opts, ExitCode.InputValidation, {
@@ -10214,7 +10364,7 @@ async function runVerify(opts) {
10214
10364
  warn(opts, `font weights (advisory): the recording implies weights ${g.declared.join(", ")} for "${g.family}" \u2014 cache provides ${g.provided.join(", ")}; nearest-weight rendering may shift stroke density (certification stays family-gated; implied weights can leak across families)`);
10215
10365
  }
10216
10366
  const missing = task.configs.filter(
10217
- (c) => !existsSync25(path31.join(task.set, c.rep, "get_screenshot.json")) || !existsSync25(path31.join(task.set, c.rep, "get_metadata.json"))
10367
+ (c) => !existsSync26(path33.join(task.set, c.rep, "get_screenshot.json")) || !existsSync26(path33.join(task.set, c.rep, "get_metadata.json"))
10218
10368
  );
10219
10369
  if (missing.length > 0) {
10220
10370
  fail(opts, ExitCode.RecordingIncomplete, {
@@ -10224,10 +10374,10 @@ async function runVerify(opts) {
10224
10374
  });
10225
10375
  }
10226
10376
  const bar = BARS2[opts.bar];
10227
- const evidenceDir = path31.join(opts.bundleDir, "verify-evidence");
10377
+ const evidenceDir = path33.join(opts.bundleDir, "verify-evidence");
10228
10378
  const scores = await scoreBundleForTask(task, opts.bundleDir, bar, { evidenceDir, onProgress: emitProgress });
10229
10379
  const quality = await checkBundleQuality(opts.bundleDir, task.entry, { dir: task.set, reps: task.configs.map((c) => c.rep) });
10230
- const bundleCss = ["tokens.css", "styles.css"].map((f) => path31.join(opts.bundleDir, f)).filter((f) => existsSync25(f)).map((f) => readFileSync22(f, "utf8")).join("\n");
10380
+ const bundleCss = ["tokens.css", "styles.css"].map((f) => path33.join(opts.bundleDir, f)).filter((f) => existsSync26(f)).map((f) => readFileSync22(f, "utf8")).join("\n");
10231
10381
  const occlusion = await checkSiblingOcclusion(task, opts.bundleDir, bundleCss);
10232
10382
  const parity = await checkHoverParity(task, opts.bundleDir);
10233
10383
  const behaviors = [...await checkBehaviors(task, opts.bundleDir), ...parity];
@@ -10312,6 +10462,10 @@ async function runVerify(opts) {
10312
10462
  // silently inherited neither.
10313
10463
  quality: { findings: quality.findings, tokensAbsent: quality.tokensAbsent },
10314
10464
  occlusion,
10465
+ // The rows' STATE, which the rows alone cannot carry (see
10466
+ // occlusionReport): the agent channel had no counterpart to the
10467
+ // human line's "occlusion not applicable (no overlay declared)".
10468
+ occlusionCheck: occlusionReport(occlusion),
10315
10469
  configs: statuses,
10316
10470
  behaviors,
10317
10471
  evidence: { dir: evidenceDir, files: "per config: <rep>-render.png, <rep>-ref.png, <rep>-diff.png" },
@@ -10323,15 +10477,7 @@ async function runVerify(opts) {
10323
10477
  ...certBlockedByAbsentInk.length > 0 ? { certBlockedByAbsentInk } : {},
10324
10478
  ...weightGaps.length > 0 ? { fontWeightGaps: weightGaps } : {},
10325
10479
  ...lcdTextEnabled() ? { environmentOverrides: ["enable-lcd-text"] } : {},
10326
- // Run 13 finding 1: the eye-check nudge lived only in the human
10327
- // footer, so MCP-driven agents — the documented path — were never
10328
- // told the check exists and shipped without ever opening a sheet.
10329
- // Structured here so every consumer sees it.
10330
- eyeCheck: {
10331
- command: `tendril inspect "${opts.bundleDir}"`,
10332
- sheetPath: path31.join(opts.bundleDir, "verify-evidence", "inspect.html"),
10333
- note: "magnified recorded-vs-rendered crops of every small node; scores cannot see shape. The command WRITES/refreshes the sheet at sheetPath \u2014 re-run it after every verify; an existing sheet may show stale crops."
10334
- }
10480
+ eyeCheck: eyeCheck(opts.bundleDir)
10335
10481
  };
10336
10482
  emitData(opts, report, () => {
10337
10483
  for (const s of statuses) {
@@ -10425,18 +10571,20 @@ ${certified}/${statuses.length} certified \xB7 ${report.coverage.pass}/${statuse
10425
10571
  }
10426
10572
  process.stdout.write(`environment: chrome=${report.environment.chromeVersion ?? report.environment.chrome} fonts=${report.environment.fontsManifestSha256 ?? "UNRESOLVED"}
10427
10573
  `);
10428
- const shippedFonts = requiredFontsManifest(cssFontFamilies(["styles.css", "tokens.css"].map((f) => path31.join(opts.bundleDir, f)).filter((f) => existsSync25(f)).map((f) => readFileSync22(f, "utf8")).join("\n")));
10574
+ const shippedFonts = requiredFontsManifest(cssFontFamilies(["styles.css", "tokens.css"].map((f) => path33.join(opts.bundleDir, f)).filter((f) => existsSync26(f)).map((f) => readFileSync22(f, "utf8")).join("\n")));
10429
10575
  if (shippedFonts.length > 0 && substitutedFamilies.length === 0) {
10430
10576
  process.stdout.write(`fonts: scored with Tendril-cache faces \u2014 a consuming app must provision the same families (the bundle ships fonts.css when faces are shippable; sha-pinned list in component.json requiredFonts)
10431
10577
  `);
10432
10578
  }
10433
10579
  for (const g of weightGaps) {
10434
- process.stdout.write(`fonts (weight gap): "${g.family}" declares ${g.declared.join(", ")} \u2014 cache provides ${g.provided.join(", ")}; nearest-weight rendering may shift stroke density (advisory, never a gate). Fix: tendril fonts resolve --set ${task.set}
10435
- `);
10580
+ process.stdout.write(
10581
+ `fonts (weight gap): "${g.family}" declares ${g.declared.join(", ")} \u2014 cache provides ${g.provided.join(", ")}; nearest-weight rendering may shift stroke density (advisory, never a gate). Fix: ${tendrilCommand(`fonts resolve --set ${task.set}`)}
10582
+ `
10583
+ );
10436
10584
  }
10437
10585
  process.stdout.write(`evidence: ${evidenceDir} (render/ref/diff per config)
10438
10586
  `);
10439
- process.stdout.write(`eye check: tendril inspect "${opts.bundleDir}" \u2014 magnified recorded-vs-rendered crops of every small node; scores cannot see shape (re-run after every verify)
10587
+ process.stdout.write(`eye check: ${report.eyeCheck.command} \u2014 magnified recorded-vs-rendered crops of every small node; scores cannot see shape (re-run after every verify)
10440
10588
  `);
10441
10589
  });
10442
10590
  if (opts.bar === "cert" && substitutedFamilies.length > 0) {
@@ -10476,9 +10624,9 @@ ${certified}/${statuses.length} certified \xB7 ${report.coverage.pass}/${statuse
10476
10624
  process.exitCode = ExitCode.VerificationFailed;
10477
10625
  }
10478
10626
  }
10479
- var BARS2, NO_ROLE_MANIFEST, ROLES_NOT_RESOLVED, UNSTAMPED_ROLES;
10627
+ var BARS2, NO_ROLE_MANIFEST, ROLES_NOT_RESOLVED, UNSTAMPED_ROLES, NO_OVERLAY_DECLARED;
10480
10628
  var init_verify = __esm({
10481
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/verify.ts"() {
10629
+ "packages/cli/src/commands/verify.ts"() {
10482
10630
  "use strict";
10483
10631
  init_src3();
10484
10632
  init_src6();
@@ -10487,6 +10635,7 @@ var init_verify = __esm({
10487
10635
  init_src4();
10488
10636
  init_environment();
10489
10637
  init_font_guidance();
10638
+ init_invocation();
10490
10639
  init_output();
10491
10640
  BARS2 = {
10492
10641
  pass: { sim: 0.95, ink: 0.95 },
@@ -10501,45 +10650,46 @@ var init_verify = __esm({
10501
10650
  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
10651
  });
10503
10652
  UNSTAMPED_ROLES = "unstamped";
10653
+ NO_OVERLAY_DECLARED = "no overlay declared";
10504
10654
  }
10505
10655
  });
10506
10656
 
10507
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/engine.ts
10657
+ // packages/cli/src/commands/engine.ts
10508
10658
  var engine_exports = {};
10509
10659
  __export(engine_exports, {
10510
10660
  runEngineBrief: () => runEngineBrief,
10511
10661
  runEngineScore: () => runEngineScore
10512
10662
  });
10513
- import { appendFileSync, existsSync as existsSync26, mkdirSync as mkdirSync8, readFileSync as readFileSync23, writeFileSync as writeFileSync12 } from "node:fs";
10514
- import path32 from "node:path";
10663
+ import { appendFileSync, existsSync as existsSync27, mkdirSync as mkdirSync8, readFileSync as readFileSync23, writeFileSync as writeFileSync12 } from "node:fs";
10664
+ import path34 from "node:path";
10515
10665
  function resolveEngineTask(opts, callerCwd) {
10516
- const asPath = path32.resolve(callerCwd, opts.taskOrSet);
10517
- const isSet = existsSync26(path32.join(asPath, "recording-set.json"));
10666
+ const asPath = path34.resolve(callerCwd, opts.taskOrSet);
10667
+ const isSet = existsSync27(path34.join(asPath, "recording-set.json"));
10518
10668
  const registry = TASKS[opts.taskOrSet];
10519
- if (registry !== void 0 && !isSet) return { task: registry, name: opts.taskOrSet, disclosures: [], interactionEvidence: [] };
10669
+ if (registry !== void 0 && !isSet) return { task: registry, name: opts.taskOrSet, ref: opts.taskOrSet, disclosures: [], interactionEvidence: [] };
10520
10670
  if (isSet) {
10521
10671
  try {
10522
10672
  const authored = authorTaskFromSet(asPath);
10523
10673
  for (const d of authored.disclosures) warn(opts, d);
10524
- return { task: authored.task, name: path32.basename(asPath), disclosures: authored.disclosures, interactionEvidence: authored.api.interactionEvidence, apiPin: { props: authored.api.apiPin.props, forcedStates: authored.api.apiPin.forcedStates } };
10674
+ return { task: authored.task, name: path34.basename(asPath), ref: asPath, disclosures: authored.disclosures, interactionEvidence: authored.api.interactionEvidence, apiPin: { props: authored.api.apiPin.props, forcedStates: authored.api.apiPin.forcedStates } };
10525
10675
  } catch (err) {
10526
10676
  fail(opts, ExitCode.InputValidation, {
10527
10677
  error: `cannot author a task from ${asPath}: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`,
10528
10678
  code: "AUTHORING_FAILED",
10529
- remediation: "Complete the recording set (tendril record status) or use a reference task name."
10679
+ remediation: `Complete the recording set (${tendrilCommand(`record status --set ${asPath}`)}) or use a reference task name.`
10530
10680
  });
10531
10681
  }
10532
10682
  }
10533
10683
  fail(opts, ExitCode.InputValidation, {
10534
10684
  error: `"${opts.taskOrSet}" is neither a reference task nor a recorded set`,
10535
10685
  code: "UNKNOWN_RECORDED_INPUT",
10536
- remediation: `Pick a task (${Object.keys(TASKS).join(", ")}) or point at a set recorded with \`tendril record\`.`
10686
+ remediation: `Pick a task (${Object.keys(TASKS).join(", ")}) or point at a set recorded with \`${tendrilCommand("record plan")}\`.`
10537
10687
  });
10538
10688
  }
10539
10689
  function runEngineBrief(opts) {
10540
10690
  requireEntitlement(opts);
10541
10691
  const callerCwd = process.env["INIT_CWD"] ?? process.cwd();
10542
- const { task, name, disclosures } = resolveEngineTask(opts, callerCwd);
10692
+ const { task, name, ref, disclosures } = resolveEngineTask(opts, callerCwd);
10543
10693
  const bar = BARS3[opts.bar];
10544
10694
  const disclosureBlock = disclosures.length > 0 ? `
10545
10695
 
@@ -10548,8 +10698,8 @@ ${disclosures.map((d) => `- ${d}`).join("\n")}` : "";
10548
10698
  const brief = buildBrief(task.systemApi, bar, { colorScheme: recordingIsDark(task) ? "dark" : "light" }) + disclosureBlock;
10549
10699
  const segments = buildSegments(task, "files");
10550
10700
  let notRecorded;
10551
- const manifestPath2 = path32.join(task.set, "recording-set.json");
10552
- if (existsSync26(manifestPath2)) {
10701
+ const manifestPath2 = path34.join(task.set, "recording-set.json");
10702
+ if (existsSync27(manifestPath2)) {
10553
10703
  notRecorded = JSON.parse(readFileSync23(manifestPath2, "utf8")).notRecorded;
10554
10704
  }
10555
10705
  const unverified = notRecorded !== void 0 && notRecorded !== "" ? `
@@ -10558,7 +10708,7 @@ ${disclosures.map((d) => `- ${d}`).join("\n")}` : "";
10558
10708
  DO NOT INVENT PIXELS FOR THESE POSES. Implement them ONLY as the composition of recorded per-axis truth (the custom-property composition rule: one paint axis sets variables, the other consumes) and list every such pose in your report as UNRECORDED-COMPOSED. Recording them is the real fix: re-plan the set (full matrix is the default) and record the missing poses.
10559
10709
  ${notRecorded}` : "";
10560
10710
  let fontProvisioning;
10561
- if (existsSync26(manifestPath2)) {
10711
+ if (existsSync27(manifestPath2)) {
10562
10712
  const missingFams = unprovisionedFamilies(task.set);
10563
10713
  const unprovided = unprovisionedFaces(task.set);
10564
10714
  const weightOnly = missingFams.length === 0;
@@ -10566,16 +10716,17 @@ ${notRecorded}` : "";
10566
10716
  const names = unprovided.map((f) => `'${f}'`).join(", ");
10567
10717
  const PROPRIETARY = /^(sf pro|sf compact|sf mono|new york|pingfang|segoe ui|helvetica neue|proxima nova|avenir)/i;
10568
10718
  const allProprietary = unprovided.every((f) => PROPRIETARY.test(f.trim()));
10719
+ const resolveCommand = tendrilCommand(`fonts resolve --set ${task.set}`);
10569
10720
  fontProvisioning = {
10570
10721
  unprovided,
10571
10722
  question: {
10572
10723
  prompt: weightOnly ? `This design implies font ${unprovided.length === 1 ? "weight" : "weights"} the local kit lacks: ${names} (the ${missingFams.length === 0 && unprovided.length === 1 ? "family itself is" : "families themselves are"} provisioned). How should it be handled?` : `This design's text uses ${names}, which is not in the local font kit. How should it be handled?`,
10573
10724
  options: [
10574
- allProprietary && !weightOnly ? `(Recommended) ${names} ${unprovided.length === 1 ? "is a proprietary face" : "are proprietary faces"} \u2014 Google Fonts cannot serve ${unprovided.length === 1 ? "it" : "them"}, so skip \`fonts resolve\`: run \`tendril fonts add "<Family>" <weight> <file>\` with the .woff2/.ttf/.otf you hold a licence for (the file never leaves this machine), then re-run this brief \u2014 exact text fidelity.` : `(Recommended) Run \`tendril fonts resolve --set ${task.set}\` \u2014 open-source families are fetched automatically. Any face that fails there is one you license privately: run \`tendril fonts add "<Family>" <weight> <file>\` with the .woff2/.ttf/.otf you hold (the file never leaves this machine). Then re-run this brief \u2014 exact text fidelity.`,
10725
+ allProprietary && !weightOnly ? `(Recommended) ${names} ${unprovided.length === 1 ? "is a proprietary face" : "are proprietary faces"} \u2014 Google Fonts cannot serve ${unprovided.length === 1 ? "it" : "them"}, so skip \`fonts resolve\`: run \`${tendrilCommand('fonts add "<Family>" <weight> <file>')}\` with the .woff2/.ttf/.otf you hold a licence for (the file never leaves this machine), then re-run this brief \u2014 exact text fidelity.` : `(Recommended) Run \`${resolveCommand}\` \u2014 open-source families are fetched automatically. Any face that fails there is one you license privately: run \`${tendrilCommand('fonts add "<Family>" <weight> <file>')}\` with the .woff2/.ttf/.otf you hold (the file never leaves this machine). Then re-run this brief \u2014 exact text fidelity.`,
10575
10726
  weightOnly ? "Continue with nearest-weight rendering: the family is provisioned, certification remains possible, and the gap rides the report as an advisory (fontWeightGaps); resolving removes it." : 'Continue with a substitute face: generation proceeds in a provided family, no config can score "certified" under it (cert-bar runs exit fonts-unproven after their report), the substitution is disclosed, and small text differences are expected and not fixable from CSS.'
10576
10727
  ]
10577
10728
  },
10578
- nonInteractive: weightOnly ? `Run \`tendril fonts resolve --set ${task.set}\` if quick, or continue \u2014 the weight gap is an advisory, never a gate.` : opts.bar === "cert" ? `Resolve the families first (\`tendril fonts resolve --set ${task.set}\`) \u2014 this loop targets the cert bar, and scoring exits fonts-unproven under a substitute, so continuing without resolving is a dead end.` : "Continue with the substitute and state the substitution in your report."
10729
+ nonInteractive: weightOnly ? `Run \`${resolveCommand}\` if quick, or continue \u2014 the weight gap is an advisory, never a gate.` : opts.bar === "cert" ? `Resolve the families first (\`${resolveCommand}\`) \u2014 this loop targets the cert bar, and scoring exits fonts-unproven under a substitute, so continuing without resolving is a dead end.` : "Continue with the substitute and state the substitution in your report."
10579
10730
  };
10580
10731
  }
10581
10732
  }
@@ -10583,8 +10734,8 @@ ${notRecorded}` : "";
10583
10734
 
10584
10735
  === TASK PAYLOAD (recorded truth, verbatim) ===
10585
10736
  ${segments}`;
10586
- const payloadFile = path32.resolve(callerCwd, opts.out ?? `tendril-out/${name}-brief.md`);
10587
- mkdirSync8(path32.dirname(payloadFile), { recursive: true });
10737
+ const payloadFile = path34.resolve(callerCwd, opts.out ?? `tendril-out/${name}-brief.md`);
10738
+ mkdirSync8(path34.dirname(payloadFile), { recursive: true });
10588
10739
  writeFileSync12(payloadFile, payload);
10589
10740
  emitData(
10590
10741
  opts,
@@ -10613,7 +10764,7 @@ ${segments}`;
10613
10764
  "Settle the proposer model (see modelSelection \u2014 ask the user when one is present), then:",
10614
10765
  `Read ${payloadFile} completely \u2014 it is the system brief plus every recorded config's emission, box, and assets.`,
10615
10766
  `Write the complete bundle files (${task.entry}, styles.css, optional tokens.css) into a candidate directory.`,
10616
- `Run \`tendril engine score ${name} <candidateDir> --bar ${opts.bar} --model ${opts.model ?? "<declared-model>"} --json\` \u2014 the CLI is the sole judge, and it refuses to score an undeclared model.`,
10767
+ `Run \`${tendrilCommand(`engine score ${ref} <candidateDir> --bar ${opts.bar} --model ${opts.model ?? "<declared-model>"} --json`)}\` \u2014 the CLI is the sole judge, and it refuses to score an undeclared model.`,
10617
10768
  "Apply the returned feedback and re-score. Stop when all checks pass or two consecutive scores fail to improve.",
10618
10769
  "Never edit recording sets; never claim scores yourself \u2014 only the score command's output counts."
10619
10770
  ]
@@ -10626,18 +10777,23 @@ ${segments}`;
10626
10777
  }
10627
10778
  );
10628
10779
  }
10780
+ function appendScoreHistory(candidateDir, entry) {
10781
+ appendFileSync(path34.join(candidateDir, "score-history.jsonl"), `${JSON.stringify({ at: (/* @__PURE__ */ new Date()).toISOString(), ...entry })}
10782
+ `);
10783
+ }
10629
10784
  async function runEngineScore(opts) {
10630
10785
  requireEntitlement(opts);
10631
10786
  const callerCwd = process.env["INIT_CWD"] ?? process.cwd();
10632
- const candidateDir = path32.resolve(callerCwd, opts.candidateDir);
10787
+ const candidateDir = path34.resolve(callerCwd, opts.candidateDir);
10633
10788
  const { task, name, apiPin, interactionEvidence } = resolveEngineTask(opts, callerCwd);
10634
- if (!existsSync26(candidateDir)) {
10789
+ if (!existsSync27(candidateDir)) {
10635
10790
  fail(opts, ExitCode.InputValidation, {
10636
10791
  error: `candidate directory not found: ${candidateDir}`,
10637
10792
  code: "candidate-missing",
10638
10793
  remediation: `Write ${task.entry} and styles.css into a directory and pass it.`
10639
10794
  });
10640
10795
  }
10796
+ appendScoreHistory(candidateDir, { event: "round-start", bar: opts.bar });
10641
10797
  if (!fontsResolved()) {
10642
10798
  fail(opts, ExitCode.FontsUnproven, {
10643
10799
  error: "resolved font cache absent \u2014 scoring under system font substitution is refused",
@@ -10655,10 +10811,10 @@ async function runEngineScore(opts) {
10655
10811
  for (const g of missingWeights(task.set)) {
10656
10812
  warn(opts, `font weights (advisory): the recording implies weights ${g.declared.join(", ")} for "${g.family}" \u2014 cache provides ${g.provided.join(", ")}; nearest-weight rendering may shift stroke density (certification stays family-gated; implied weights can leak across families)`);
10657
10813
  }
10658
- if (opts.rebind !== true && existsSync26(path32.join(candidateDir, "component.json"))) {
10814
+ if (opts.rebind !== true && existsSync27(path34.join(candidateDir, "component.json"))) {
10659
10815
  const prior = (() => {
10660
10816
  try {
10661
- const read = readBundleManifest(readFileSync23(path32.join(candidateDir, "component.json"), "utf8"));
10817
+ const read = readBundleManifest(readFileSync23(path34.join(candidateDir, "component.json"), "utf8"));
10662
10818
  return read.manifest === void 0 ? { unreadable: true } : { hash: read.manifest.provenance.recordingSet.hash, path: read.manifest.provenance.recordingSet.path };
10663
10819
  } catch {
10664
10820
  return { unreadable: true };
@@ -10680,7 +10836,7 @@ async function runEngineScore(opts) {
10680
10836
  }
10681
10837
  }
10682
10838
  const bar = BARS3[opts.bar];
10683
- const evidenceDir = path32.join(candidateDir, "verify-evidence");
10839
+ const evidenceDir = path34.join(candidateDir, "verify-evidence");
10684
10840
  const scores = await scoreBundleForTask(task, candidateDir, bar, { evidenceDir, onProgress: emitProgress });
10685
10841
  const parity = await checkHoverParity(task, candidateDir);
10686
10842
  const behaviors = [...await checkBehaviors(task, candidateDir), ...parity];
@@ -10723,11 +10879,7 @@ METRIC DEADBAND (read before iterating on near-misses): the scored similarity/in
10723
10879
  environment: environmentStamp(taskFontFamilies(task.set)),
10724
10880
  substitutedFamilies
10725
10881
  });
10726
- appendFileSync(
10727
- path32.join(candidateDir, "score-history.jsonl"),
10728
- `${JSON.stringify({ at: (/* @__PURE__ */ new Date()).toISOString(), bar: opts.bar, pass: obj[0], total, certified: certifiedReps.length, floor: obj[1], mean: obj[2] })}
10729
- `
10730
- );
10882
+ appendScoreHistory(candidateDir, { event: "round-scored", bar: opts.bar, pass: obj[0], total, certified: certifiedReps.length, floor: obj[1], mean: obj[2] });
10731
10883
  emitData(
10732
10884
  opts,
10733
10885
  {
@@ -10793,7 +10945,7 @@ ${obj[0]}/${total} \xB7 certified ${certifiedReps.length}/${total} \xB7 floor=${
10793
10945
  }
10794
10946
  var BARS3;
10795
10947
  var init_engine2 = __esm({
10796
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/engine.ts"() {
10948
+ "packages/cli/src/commands/engine.ts"() {
10797
10949
  "use strict";
10798
10950
  init_src3();
10799
10951
  init_src7();
@@ -10802,6 +10954,7 @@ var init_engine2 = __esm({
10802
10954
  init_font_guidance();
10803
10955
  init_src4();
10804
10956
  init_output();
10957
+ init_invocation();
10805
10958
  init_entitlement();
10806
10959
  init_verify();
10807
10960
  init_src4();
@@ -10812,16 +10965,16 @@ var init_engine2 = __esm({
10812
10965
  }
10813
10966
  });
10814
10967
 
10815
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/codeconnect.ts
10968
+ // packages/cli/src/commands/codeconnect.ts
10816
10969
  var codeconnect_exports = {};
10817
10970
  __export(codeconnect_exports, {
10818
10971
  runCodeConnect: () => runCodeConnect
10819
10972
  });
10820
- import { existsSync as existsSync27, readFileSync as readFileSync24, writeFileSync as writeFileSync13 } from "node:fs";
10821
- import path33 from "node:path";
10973
+ import { existsSync as existsSync28, readFileSync as readFileSync24, writeFileSync as writeFileSync13 } from "node:fs";
10974
+ import path35 from "node:path";
10822
10975
  function runCodeConnect(opts) {
10823
10976
  const callerCwd = process.env["INIT_CWD"] ?? process.cwd();
10824
- const bundleDir = path33.resolve(callerCwd, opts.bundleDir);
10977
+ const bundleDir = path35.resolve(callerCwd, opts.bundleDir);
10825
10978
  let url;
10826
10979
  try {
10827
10980
  url = new URL(opts.figmaUrl);
@@ -10837,7 +10990,7 @@ function runCodeConnect(opts) {
10837
10990
  }
10838
10991
  let manifest;
10839
10992
  try {
10840
- const read = readBundleManifest(readFileSync24(path33.join(bundleDir, "component.json"), "utf8"));
10993
+ const read = readBundleManifest(readFileSync24(path35.join(bundleDir, "component.json"), "utf8"));
10841
10994
  if (read.manifest === void 0) throw new Error(read.issues.map((i) => i.message).join("; ") || "no component.json");
10842
10995
  manifest = read.manifest;
10843
10996
  } catch (err) {
@@ -10847,8 +11000,8 @@ function runCodeConnect(opts) {
10847
11000
  remediation: "Point at a bundle produced by the Tendril pipeline (it carries component.json), and verify it first."
10848
11001
  });
10849
11002
  }
10850
- const setDir = path33.resolve(callerCwd, opts.set ?? manifest.provenance.recordingSet.path);
10851
- if (!existsSync27(path33.join(setDir, "recording-set.json"))) {
11003
+ const setDir = path35.resolve(callerCwd, opts.set ?? manifest.provenance.recordingSet.path);
11004
+ if (!existsSync28(path35.join(setDir, "recording-set.json"))) {
10852
11005
  fail(opts, ExitCode.InputValidation, {
10853
11006
  error: `recording set not found at ${setDir}`,
10854
11007
  code: "codeconnect-no-set",
@@ -10862,15 +11015,15 @@ function runCodeConnect(opts) {
10862
11015
  fail(opts, ExitCode.InputValidation, {
10863
11016
  error: `cannot author the API from ${setDir}: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`,
10864
11017
  code: "codeconnect-authoring-failed",
10865
- remediation: "The set must be a complete protocol recording (tendril record status)."
11018
+ remediation: `The set must be a complete protocol recording (${tendrilCommand(`record status --set ${setDir}`)}).`
10866
11019
  });
10867
11020
  }
10868
11021
  const api = authored.api;
10869
11022
  const component = api.component;
10870
11023
  const recManifest = loadManifest(setDir);
10871
11024
  const poseNames = recManifest.latticeNames ?? recManifest.reps.map((r) => {
10872
- const meta = path33.join(setDir, r.slug, "get_metadata.json");
10873
- if (!existsSync27(meta)) return void 0;
11025
+ const meta = path35.join(setDir, r.slug, "get_metadata.json");
11026
+ if (!existsSync28(meta)) return void 0;
10874
11027
  try {
10875
11028
  return /name="([^"]*)"/.exec(envelopeFirstTextPart(JSON.parse(readFileSync24(meta, "utf8"))))?.[1];
10876
11029
  } catch {
@@ -10889,7 +11042,7 @@ function runCodeConnect(opts) {
10889
11042
  fail(opts, ExitCode.InputValidation, {
10890
11043
  error: "the recording set's content no longer matches the hash this bundle was scored against \u2014 its verification claims describe a different recording",
10891
11044
  code: "codeconnect-set-drift",
10892
- remediation: "Re-run `tendril verify` (or engine score) against the current set, then re-emit."
11045
+ remediation: `Re-run \`${tendrilCommand(`verify ${bundleDir} --set ${setDir}`)}\` (or engine score) against the current set, then re-emit.`
10893
11046
  });
10894
11047
  }
10895
11048
  const boolProps = api.props.filter((p) => p.kind === "boolean");
@@ -10930,7 +11083,7 @@ function runCodeConnect(opts) {
10930
11083
  axisLines.push(`const ${varName} = instance.getEnum(${q(axis)}, { ${entries.join(", ")} })`);
10931
11084
  fragmentVars.push(varName);
10932
11085
  }
10933
- const entryRel = path33.relative(callerCwd, path33.join(bundleDir, manifest.entry));
11086
+ const entryRel = path35.relative(callerCwd, path35.join(bundleDir, manifest.entry));
10934
11087
  const trust = manifest.trustStatement.split("\n")[0] ?? "";
10935
11088
  const lines = [
10936
11089
  `// url=${opts.figmaUrl}`,
@@ -10951,7 +11104,7 @@ function runCodeConnect(opts) {
10951
11104
  `}`,
10952
11105
  ``
10953
11106
  ].join("\n");
10954
- const outFile = path33.resolve(callerCwd, opts.out ?? path33.join(bundleDir, `${component}.figma.ts`));
11107
+ const outFile = path35.resolve(callerCwd, opts.out ?? path35.join(bundleDir, `${component}.figma.ts`));
10955
11108
  writeFileSync13(outFile, lines);
10956
11109
  emitData(
10957
11110
  opts,
@@ -10976,42 +11129,43 @@ function runCodeConnect(opts) {
10976
11129
  }
10977
11130
  var kebab4, q;
10978
11131
  var init_codeconnect = __esm({
10979
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/codeconnect.ts"() {
11132
+ "packages/cli/src/commands/codeconnect.ts"() {
10980
11133
  "use strict";
10981
11134
  init_src3();
10982
11135
  init_src7();
10983
11136
  init_src();
10984
11137
  init_src6();
11138
+ init_invocation();
10985
11139
  init_output();
10986
11140
  kebab4 = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
10987
11141
  q = (s) => `'${s.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029")}'`;
10988
11142
  }
10989
11143
  });
10990
11144
 
10991
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/mcp/src/server.ts
11145
+ // packages/mcp/src/server.ts
10992
11146
  import { createHash as createHash5 } from "node:crypto";
10993
- import { existsSync as existsSync28, mkdtempSync as mkdtempSync3, readFileSync as readFileSync25, readdirSync as readdirSync8, writeFileSync as writeFileSync14 } from "node:fs";
11147
+ import { existsSync as existsSync29, mkdtempSync as mkdtempSync3, readFileSync as readFileSync25, readdirSync as readdirSync8, writeFileSync as writeFileSync14 } from "node:fs";
10994
11148
  import os6 from "node:os";
10995
- import path34 from "node:path";
10996
- import { fileURLToPath as fileURLToPath5 } from "node:url";
11149
+ import path36 from "node:path";
11150
+ import { fileURLToPath as fileURLToPath6 } from "node:url";
10997
11151
  import { z as z12 } from "zod";
10998
11152
  function sourceHash() {
10999
- const dir = path34.dirname(fileURLToPath5(import.meta.url));
11153
+ const dir = path36.dirname(fileURLToPath6(import.meta.url));
11000
11154
  const h = createHash5("sha256");
11001
11155
  for (const f of readdirSync8(dir).filter((n) => n.endsWith(".ts")).sort()) {
11002
11156
  h.update(f);
11003
- h.update(readFileSync25(path34.join(dir, f)));
11157
+ h.update(readFileSync25(path36.join(dir, f)));
11004
11158
  }
11005
11159
  return h.digest("hex").slice(0, 16);
11006
11160
  }
11007
11161
  var REPO_ROOT3, CLI_BIN, BUNDLED_CLI, CLI_SPAWN, str, optStr, TOOLS, BOOT_HASH;
11008
11162
  var init_server = __esm({
11009
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/mcp/src/server.ts"() {
11163
+ "packages/mcp/src/server.ts"() {
11010
11164
  "use strict";
11011
- REPO_ROOT3 = path34.resolve(path34.dirname(fileURLToPath5(import.meta.url)), "..", "..", "..");
11012
- CLI_BIN = path34.join(REPO_ROOT3, "packages", "cli", "src", "bin.ts");
11013
- BUNDLED_CLI = path34.join(path34.dirname(fileURLToPath5(import.meta.url)), "tendril.js");
11014
- CLI_SPAWN = existsSync28(BUNDLED_CLI) ? { cmd: process.execPath, prefix: [BUNDLED_CLI] } : { cmd: "npx", prefix: ["tsx", CLI_BIN] };
11165
+ REPO_ROOT3 = path36.resolve(path36.dirname(fileURLToPath6(import.meta.url)), "..", "..", "..");
11166
+ CLI_BIN = path36.join(REPO_ROOT3, "packages", "cli", "src", "bin.ts");
11167
+ BUNDLED_CLI = path36.join(path36.dirname(fileURLToPath6(import.meta.url)), "tendril.js");
11168
+ CLI_SPAWN = existsSync29(BUNDLED_CLI) ? { cmd: process.execPath, prefix: [BUNDLED_CLI] } : { cmd: "npx", prefix: ["tsx", CLI_BIN] };
11015
11169
  str = (d) => z12.string().describe(d);
11016
11170
  optStr = (d) => z12.string().optional().describe(d);
11017
11171
  TOOLS = [
@@ -11041,7 +11195,7 @@ var init_server = __esm({
11041
11195
  const single = i["metadata"];
11042
11196
  const parts = i["metadataParts"];
11043
11197
  if (single !== void 0 || parts !== void 0) {
11044
- const tmp = path34.join(mkdtempSync3(path34.join(os6.tmpdir(), "tendril-envelope-")), "response.txt");
11198
+ const tmp = path36.join(mkdtempSync3(path36.join(os6.tmpdir(), "tendril-envelope-")), "response.txt");
11045
11199
  if (single !== void 0) {
11046
11200
  writeFileSync14(tmp, single);
11047
11201
  argvOut.push("--metadata-raw-file", tmp);
@@ -11112,7 +11266,7 @@ var init_server = __esm({
11112
11266
  const bridge = (label, single, parts) => {
11113
11267
  if (single !== void 0 && parts !== void 0) throw new Error(`pass at most one of \`${label}\` and \`${label}Parts\``);
11114
11268
  if (single === void 0 && parts === void 0) return;
11115
- const tmp = path34.join(mkdtempSync3(path34.join(os6.tmpdir(), "tendril-envelope-")), "response.txt");
11269
+ const tmp = path36.join(mkdtempSync3(path36.join(os6.tmpdir(), "tendril-envelope-")), "response.txt");
11116
11270
  if (single !== void 0) {
11117
11271
  writeFileSync14(tmp, single);
11118
11272
  argvOut.push(`--${label}-file`, tmp);
@@ -11155,7 +11309,7 @@ var init_server = __esm({
11155
11309
  const file = i["file"];
11156
11310
  if ([text, texts, file].filter((x) => x !== void 0).length !== 1) throw new Error("pass exactly one of `text` (single-block response), `texts` (multi-block response), or `file` (a saved envelope)");
11157
11311
  if (file !== void 0) return [...base, "--file", file];
11158
- const tmp = path34.join(mkdtempSync3(path34.join(os6.tmpdir(), "tendril-envelope-")), "response.txt");
11312
+ const tmp = path36.join(mkdtempSync3(path36.join(os6.tmpdir(), "tendril-envelope-")), "response.txt");
11159
11313
  if (text !== void 0) {
11160
11314
  writeFileSync14(tmp, text);
11161
11315
  return [...base, "--file", tmp, "--raw"];
@@ -11302,7 +11456,7 @@ var init_server = __esm({
11302
11456
  }
11303
11457
  });
11304
11458
 
11305
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/permissions.ts
11459
+ // packages/cli/src/commands/permissions.ts
11306
11460
  var permissions_exports = {};
11307
11461
  __export(permissions_exports, {
11308
11462
  PERMISSIONS_DESCRIPTION: () => PERMISSIONS_DESCRIPTION,
@@ -11310,12 +11464,12 @@ __export(permissions_exports, {
11310
11464
  mergeAllowlist: () => mergeAllowlist,
11311
11465
  runPermissions: () => runPermissions
11312
11466
  });
11313
- import { existsSync as existsSync29, mkdirSync as mkdirSync9, readFileSync as readFileSync26, writeFileSync as writeFileSync15 } from "node:fs";
11467
+ import { existsSync as existsSync30, mkdirSync as mkdirSync9, readFileSync as readFileSync26, writeFileSync as writeFileSync15 } from "node:fs";
11314
11468
  import os7 from "node:os";
11315
- import path35 from "node:path";
11469
+ import path37 from "node:path";
11316
11470
  function mergeAllowlist(file, entries) {
11317
11471
  let settings = {};
11318
- if (existsSync29(file) && readFileSync26(file, "utf8").trim() !== "") {
11472
+ if (existsSync30(file) && readFileSync26(file, "utf8").trim() !== "") {
11319
11473
  settings = JSON.parse(readFileSync26(file, "utf8"));
11320
11474
  if (settings === null || typeof settings !== "object" || Array.isArray(settings)) throw new Error("settings root is not an object");
11321
11475
  }
@@ -11328,7 +11482,7 @@ function mergeAllowlist(file, entries) {
11328
11482
  const alreadyPresent = entries.filter((e) => present.has(e));
11329
11483
  if (added.length > 0) {
11330
11484
  allow.push(...added);
11331
- mkdirSync9(path35.dirname(file), { recursive: true });
11485
+ mkdirSync9(path37.dirname(file), { recursive: true });
11332
11486
  writeFileSync15(file, `${JSON.stringify(settings, null, 2)}
11333
11487
  `);
11334
11488
  }
@@ -11364,7 +11518,7 @@ async function runPermissions(flags) {
11364
11518
  const result = await buildPermissions({ ...flags.mcpUrl ? { mcpUrl: flags.mcpUrl } : {} });
11365
11519
  if (flags.write) {
11366
11520
  const base = process.env["INIT_CWD"] ?? process.cwd();
11367
- const file = flags.user ? path35.join(os7.homedir(), ".claude", "settings.json") : path35.join(base, ".claude", "settings.local.json");
11521
+ const file = flags.user ? path37.join(os7.homedir(), ".claude", "settings.json") : path37.join(base, ".claude", "settings.local.json");
11368
11522
  if (flags.dryRun) {
11369
11523
  emitData(flags, { file, wouldAdd: result.toolEntries }, () => {
11370
11524
  process.stdout.write(`dry-run: would merge ${result.toolEntries.length} per-tool entries into ${file}
@@ -11397,7 +11551,7 @@ async function runPermissions(flags) {
11397
11551
  `Claude Code allowlist for the Tendril pipeline.
11398
11552
  One command installs it (project-local, idempotent):
11399
11553
 
11400
- tendril permissions --claude --write
11554
+ ${tendrilCommand("permissions --claude --write")}
11401
11555
 
11402
11556
  Or paste into .claude/settings.json under permissions.allow:
11403
11557
 
@@ -11416,12 +11570,13 @@ ${result.directConfigNote}
11416
11570
  }
11417
11571
  var FIGMA_TOOL_FALLBACK, PERMISSIONS_DESCRIPTION, TENDRIL_PLUGIN_PREFIX, FIGMA_PLUGIN_PREFIX;
11418
11572
  var init_permissions = __esm({
11419
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/permissions.ts"() {
11573
+ "packages/cli/src/commands/permissions.ts"() {
11420
11574
  "use strict";
11421
11575
  init_src3();
11422
11576
  init_src();
11423
11577
  init_server();
11424
11578
  init_describe();
11579
+ init_invocation();
11425
11580
  init_output();
11426
11581
  init_doctor();
11427
11582
  FIGMA_TOOL_FALLBACK = ["get_metadata", "get_design_context", "get_screenshot", "get_variable_defs", "get_motion_context", "get_figjam"];
@@ -11451,27 +11606,27 @@ var init_permissions = __esm({
11451
11606
  }
11452
11607
  });
11453
11608
 
11454
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/inspect.ts
11609
+ // packages/cli/src/commands/inspect.ts
11455
11610
  var inspect_exports = {};
11456
11611
  __export(inspect_exports, {
11457
11612
  INSPECT_DESCRIPTION: () => INSPECT_DESCRIPTION,
11458
11613
  runInspect: () => runInspect
11459
11614
  });
11460
- import { existsSync as existsSync30, readFileSync as readFileSync27, writeFileSync as writeFileSync16 } from "node:fs";
11461
- import path36 from "node:path";
11615
+ import { existsSync as existsSync31, readFileSync as readFileSync27, writeFileSync as writeFileSync16 } from "node:fs";
11616
+ import path38 from "node:path";
11462
11617
  async function runInspect(opts) {
11463
11618
  if (opts.describe) {
11464
11619
  printDescription(INSPECT_DESCRIPTION);
11465
11620
  return;
11466
11621
  }
11467
- const bundleDir = path36.resolve(opts.bundleDir);
11468
- const evidenceDir = path36.join(bundleDir, "verify-evidence");
11469
- const manifestPath2 = path36.join(bundleDir, "component.json");
11470
- if (!existsSync30(evidenceDir) || !existsSync30(manifestPath2)) {
11622
+ const bundleDir = path38.resolve(opts.bundleDir);
11623
+ const evidenceDir = path38.join(bundleDir, "verify-evidence");
11624
+ const manifestPath2 = path38.join(bundleDir, "component.json");
11625
+ if (!existsSync31(evidenceDir) || !existsSync31(manifestPath2)) {
11471
11626
  fail(opts, ExitCode.InputValidation, {
11472
- error: `nothing to inspect in ${bundleDir} \u2014 ${existsSync30(manifestPath2) ? "no verify-evidence directory" : "no component.json"}`,
11627
+ error: `nothing to inspect in ${bundleDir} \u2014 ${existsSync31(manifestPath2) ? "no verify-evidence directory" : "no component.json"}`,
11473
11628
  code: "no-evidence",
11474
- remediation: "Run `tendril verify <bundleDir>` first \u2014 inspect reads the ref/render evidence that run writes."
11629
+ remediation: `Run \`${tendrilCommand(`verify ${bundleDir}`)}\` first \u2014 inspect reads the ref/render evidence that run writes.`
11475
11630
  });
11476
11631
  }
11477
11632
  const { manifest } = readBundleManifest(readFileSync27(manifestPath2, "utf8"));
@@ -11482,27 +11637,27 @@ async function runInspect(opts) {
11482
11637
  remediation: "Re-emit the bundle (score/verify rewrite component.json), then re-run inspect."
11483
11638
  });
11484
11639
  }
11485
- const setDir = path36.resolve(opts.set ?? manifest.provenance.recordingSet.path);
11486
- const reps = Object.keys(manifest.propAdapter).filter((rep) => existsSync30(path36.join(evidenceDir, `${rep}-ref.png`)) && existsSync30(path36.join(evidenceDir, `${rep}-render.png`)));
11640
+ const setDir = path38.resolve(opts.set ?? manifest.provenance.recordingSet.path);
11641
+ const reps = Object.keys(manifest.propAdapter).filter((rep) => existsSync31(path38.join(evidenceDir, `${rep}-ref.png`)) && existsSync31(path38.join(evidenceDir, `${rep}-render.png`)));
11487
11642
  if (reps.length === 0) {
11488
11643
  fail(opts, ExitCode.InputValidation, {
11489
11644
  error: "verify-evidence holds no ref/render pairs for this bundle's configs",
11490
11645
  code: "no-evidence",
11491
- remediation: "Run `tendril verify <bundleDir>` first \u2014 inspect reads the ref/render evidence that run writes."
11646
+ remediation: `Run \`${tendrilCommand(`verify ${bundleDir}`)}\` first \u2014 inspect reads the ref/render evidence that run writes.`
11492
11647
  });
11493
11648
  }
11494
11649
  let crops = 0;
11495
11650
  const sections = [];
11496
11651
  for (const rep of reps) {
11497
- const ref = new Uint8Array(readFileSync27(path36.join(evidenceDir, `${rep}-ref.png`)));
11498
- const render = new Uint8Array(readFileSync27(path36.join(evidenceDir, `${rep}-render.png`)));
11652
+ const ref = new Uint8Array(readFileSync27(path38.join(evidenceDir, `${rep}-ref.png`)));
11653
+ const render = new Uint8Array(readFileSync27(path38.join(evidenceDir, `${rep}-render.png`)));
11499
11654
  const nodes = smallSemanticNodes(setDir, rep, opts.maxArea ?? 1024).slice(0, 12);
11500
11655
  const cells = [];
11501
11656
  for (const [i, n] of nodes.entries()) {
11502
11657
  const rect = { x: n.x, y: n.y, w: n.w, h: n.h };
11503
11658
  try {
11504
- writeFileSync16(path36.join(evidenceDir, `${rep}-inspect-${i}-ref.png`), zoomCrop(ref, rect));
11505
- writeFileSync16(path36.join(evidenceDir, `${rep}-inspect-${i}-render.png`), zoomCrop(render, rect));
11659
+ writeFileSync16(path38.join(evidenceDir, `${rep}-inspect-${i}-ref.png`), zoomCrop(ref, rect));
11660
+ writeFileSync16(path38.join(evidenceDir, `${rep}-inspect-${i}-render.png`), zoomCrop(render, rect));
11506
11661
  } catch {
11507
11662
  continue;
11508
11663
  }
@@ -11515,7 +11670,7 @@ async function runInspect(opts) {
11515
11670
  `<section><h2>${esc(rep)}</h2><div class="full"><span><em>recorded</em><img src="./${rep}-ref.png"></span><span><em>rendered</em><img src="./${rep}-render.png"></span><span><em>diff</em><img src="./${rep}-diff.png"></span></div>` + (cells.length > 0 ? `<div class="grid">${cells.join("")}</div>` : `<p class="none">no small recorded nodes in this config's sweep</p>`) + `</section>`
11516
11671
  );
11517
11672
  }
11518
- const sheet = path36.join(evidenceDir, "inspect.html");
11673
+ const sheet = path38.join(evidenceDir, "inspect.html");
11519
11674
  writeFileSync16(
11520
11675
  sheet,
11521
11676
  `<!doctype html><meta charset="utf-8"><title>${esc(manifest.name)} \u2014 tendril inspect</title><style>
@@ -11540,12 +11695,13 @@ ${reps.length} config(s), ${crops} detail crop pair(s) \u2014 open the sheet and
11540
11695
  }
11541
11696
  var INSPECT_DESCRIPTION, esc;
11542
11697
  var init_inspect = __esm({
11543
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/inspect.ts"() {
11698
+ "packages/cli/src/commands/inspect.ts"() {
11544
11699
  "use strict";
11545
11700
  init_src3();
11546
11701
  init_src6();
11547
11702
  init_src4();
11548
11703
  init_describe();
11704
+ init_invocation();
11549
11705
  init_output();
11550
11706
  INSPECT_DESCRIPTION = {
11551
11707
  name: "inspect",
@@ -11568,7 +11724,7 @@ var init_inspect = __esm({
11568
11724
  }
11569
11725
  });
11570
11726
 
11571
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/generate-route.ts
11727
+ // packages/cli/src/commands/generate-route.ts
11572
11728
  var generate_route_exports = {};
11573
11729
  __export(generate_route_exports, {
11574
11730
  routeGenerate: () => routeGenerate
@@ -11581,28 +11737,28 @@ function routeGenerate(input) {
11581
11737
  return { path: "facts", ...input.url !== void 0 ? { url: input.url } : {} };
11582
11738
  }
11583
11739
  var init_generate_route = __esm({
11584
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/generate-route.ts"() {
11740
+ "packages/cli/src/commands/generate-route.ts"() {
11585
11741
  "use strict";
11586
11742
  }
11587
11743
  });
11588
11744
 
11589
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/generate-recorded.ts
11745
+ // packages/cli/src/commands/generate-recorded.ts
11590
11746
  var generate_recorded_exports = {};
11591
11747
  __export(generate_recorded_exports, {
11592
11748
  runGenerateRecorded: () => runGenerateRecorded
11593
11749
  });
11594
11750
  import { confirm as confirm3, isCancel as isCancel3 } from "@clack/prompts";
11595
- import { existsSync as existsSync31, readFileSync as readFileSync28 } from "node:fs";
11596
- import path37 from "node:path";
11751
+ import { existsSync as existsSync32, readFileSync as readFileSync28 } from "node:fs";
11752
+ import path39 from "node:path";
11597
11753
  async function runGenerateRecorded(opts) {
11598
11754
  const callerCwd = process.env["INIT_CWD"] ?? process.cwd();
11599
- const outDirAbs = path37.resolve(callerCwd, opts.out);
11600
- const recordedAsPath = path37.resolve(callerCwd, opts.recorded);
11755
+ const outDirAbs = path39.resolve(callerCwd, opts.out);
11756
+ const recordedAsPath = path39.resolve(callerCwd, opts.recorded);
11601
11757
  let task;
11602
11758
  let taskName;
11603
11759
  let authoredApi;
11604
11760
  let composition;
11605
- const isSet = existsSync31(path37.join(recordedAsPath, "recording-set.json"));
11761
+ const isSet = existsSync32(path39.join(recordedAsPath, "recording-set.json"));
11606
11762
  const registry = TASKS[opts.recorded];
11607
11763
  if (registry !== void 0 && !isSet) {
11608
11764
  task = registry;
@@ -11611,7 +11767,7 @@ async function runGenerateRecorded(opts) {
11611
11767
  try {
11612
11768
  const authored = authorTaskFromSet(recordedAsPath);
11613
11769
  task = authored.task;
11614
- taskName = path37.basename(recordedAsPath);
11770
+ taskName = path39.basename(recordedAsPath);
11615
11771
  authoredApi = authored.api;
11616
11772
  const roles = RolesSchema.safeParse(loadManifest(recordedAsPath).roles);
11617
11773
  if (roles.success) composition = roles.data;
@@ -11620,14 +11776,14 @@ async function runGenerateRecorded(opts) {
11620
11776
  fail(opts, ExitCode.InputValidation, {
11621
11777
  error: `cannot author a task from ${recordedAsPath}: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`,
11622
11778
  code: "AUTHORING_FAILED",
11623
- remediation: "Complete the recording set (tendril record status) or use a reference-corpus task name."
11779
+ remediation: `Complete the recording set (${tendrilCommand(`record status --set ${recordedAsPath}`)}) or use a reference-corpus task name.`
11624
11780
  });
11625
11781
  }
11626
11782
  } else {
11627
11783
  fail(opts, ExitCode.InputValidation, {
11628
11784
  error: `"${opts.recorded}" is neither a reference task nor a recorded set (no recording-set.json found)`,
11629
11785
  code: "UNKNOWN_RECORDED_INPUT",
11630
- remediation: `Pick a task (${Object.keys(TASKS).join(", ")}) or point at a set recorded with \`tendril record\`.`
11786
+ remediation: `Pick a task (${Object.keys(TASKS).join(", ")}) or point at a set recorded with \`${tendrilCommand("record plan")}\`.`
11631
11787
  });
11632
11788
  }
11633
11789
  if (!fontsResolved()) {
@@ -11645,13 +11801,13 @@ async function runGenerateRecorded(opts) {
11645
11801
  warn(opts, `font weights (advisory): the recording implies weights ${g.declared.join(", ")} for "${g.family}" \u2014 cache provides ${g.provided.join(", ")}; nearest-weight rendering may shift stroke density (certification stays family-gated; implied weights can leak across families)`);
11646
11802
  }
11647
11803
  const missing = task.configs.filter(
11648
- (c) => !existsSync31(path37.join(task.set, c.rep, "get_screenshot.json")) || !existsSync31(path37.join(task.set, c.rep, "get_metadata.json")) || !existsSync31(path37.join(task.set, c.rep, "get_design_context.json"))
11804
+ (c) => !existsSync32(path39.join(task.set, c.rep, "get_screenshot.json")) || !existsSync32(path39.join(task.set, c.rep, "get_metadata.json")) || !existsSync32(path39.join(task.set, c.rep, "get_design_context.json"))
11649
11805
  );
11650
11806
  if (missing.length > 0) {
11651
11807
  fail(opts, ExitCode.RecordingIncomplete, {
11652
11808
  error: `recording set ${task.set} is missing envelopes for ${missing.length} rep(s): ${missing.slice(0, 3).map((c) => c.rep).join(", ")}${missing.length > 3 ? ", \u2026" : ""}`,
11653
11809
  code: "recording-incomplete",
11654
- remediation: "Resume the recording session (`tendril record next`) until `tendril record status` reports the set complete."
11810
+ remediation: `Resume the recording session (\`${tendrilCommand(`record next --set ${task.set}`)}\`) until \`${tendrilCommand(`record status --set ${task.set}`)}\` reports the set complete.`
11655
11811
  });
11656
11812
  }
11657
11813
  const modelId = opts.model ?? DEFAULT_MODEL_CONFIG.curatedDefault ?? DEFAULT_MODEL_CONFIG.bulk;
@@ -11672,7 +11828,7 @@ async function runGenerateRecorded(opts) {
11672
11828
  fail(opts, ExitCode.Auth, {
11673
11829
  error: "OPENROUTER_API_KEY is not configured \u2014 the curated engine needs an OpenRouter-compatible key.",
11674
11830
  code: "MISSING_OPENROUTER_KEY",
11675
- remediation: "Two paths: run `tendril init` to store your OpenRouter key (BYOK \u2014 your key, your inference), or drive the agent-harness engine explicitly with your own agent host."
11831
+ remediation: `Two paths: run \`${tendrilCommand("init")}\` to store your OpenRouter key (BYOK \u2014 your key, your inference), or drive the agent-harness engine explicitly with your own agent host.`
11676
11832
  });
11677
11833
  }
11678
11834
  const bar = BARS4[opts.bar];
@@ -11715,8 +11871,8 @@ async function runGenerateRecorded(opts) {
11715
11871
  ` : `${line}
11716
11872
  `);
11717
11873
  if (opts.dryRun) {
11718
- emitData(opts, { dryRun: true, task: taskName, model: modelId, consent, wouldWrite: path37.join(outDirAbs, taskName) }, () => {
11719
- process.stdout.write(`dry-run: nothing sent, nothing written (would write ${path37.join(outDirAbs, taskName)})
11874
+ emitData(opts, { dryRun: true, task: taskName, model: modelId, consent, wouldWrite: path39.join(outDirAbs, taskName) }, () => {
11875
+ process.stdout.write(`dry-run: nothing sent, nothing written (would write ${path39.join(outDirAbs, taskName)})
11720
11876
  `);
11721
11877
  });
11722
11878
  return;
@@ -11739,10 +11895,10 @@ async function runGenerateRecorded(opts) {
11739
11895
  });
11740
11896
  }
11741
11897
  }
11742
- const bundleDir = path37.join(outDirAbs, taskName);
11743
- if (existsSync31(path37.join(bundleDir, "component.json"))) {
11898
+ const bundleDir = path39.join(outDirAbs, taskName);
11899
+ if (existsSync32(path39.join(bundleDir, "component.json"))) {
11744
11900
  try {
11745
- const prior = readBundleManifest(readFileSync28(path37.join(bundleDir, "component.json"), "utf8")).manifest;
11901
+ const prior = readBundleManifest(readFileSync28(path39.join(bundleDir, "component.json"), "utf8")).manifest;
11746
11902
  if (prior !== void 0 && prior.provenance.recordingSet.hash !== recordingSetHash(task.set, task.configs)) {
11747
11903
  fail(opts, ExitCode.InputValidation, {
11748
11904
  error: `${bundleDir} already holds a bundle bound to recording set "${prior.provenance.recordingSet.path}" \u2014 generating here against a different set would silently rewrite its verification identity`,
@@ -11868,7 +12024,7 @@ ${certified}/${statuses.length} certified \xB7 ${statuses.length - pixelFailures
11868
12024
  }
11869
12025
  var BARS4;
11870
12026
  var init_generate_recorded = __esm({
11871
- "../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/generate-recorded.ts"() {
12027
+ "packages/cli/src/commands/generate-recorded.ts"() {
11872
12028
  "use strict";
11873
12029
  init_src3();
11874
12030
  init_src5();
@@ -11879,6 +12035,7 @@ var init_generate_recorded = __esm({
11879
12035
  init_env();
11880
12036
  init_environment();
11881
12037
  init_font_guidance();
12038
+ init_invocation();
11882
12039
  init_output();
11883
12040
  BARS4 = {
11884
12041
  pass: { sim: 0.95, ink: 0.95 },
@@ -11887,24 +12044,27 @@ var init_generate_recorded = __esm({
11887
12044
  }
11888
12045
  });
11889
12046
 
11890
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/bin.ts
12047
+ // packages/cli/src/bin.ts
11891
12048
  init_src3();
12049
+ init_invocation();
11892
12050
  import { CommanderError } from "commander";
11893
12051
 
11894
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/program.ts
12052
+ // packages/cli/src/program.ts
11895
12053
  init_src3();
11896
12054
  init_environment();
12055
+ init_invocation();
11897
12056
  init_doctor();
11898
12057
  import { Command } from "commander";
11899
12058
 
11900
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/init.ts
12059
+ // packages/cli/src/commands/init.ts
11901
12060
  init_src3();
11902
12061
  init_describe();
11903
12062
  init_env();
12063
+ init_invocation();
11904
12064
  init_output();
11905
12065
  import { intro, isCancel, outro, password } from "@clack/prompts";
11906
12066
  import fs from "node:fs";
11907
- import path23 from "node:path";
12067
+ import path24 from "node:path";
11908
12068
  var INIT_DESCRIPTION = {
11909
12069
  name: "init",
11910
12070
  summary: "Configure Figma and OpenRouter credentials in .env (idempotent).",
@@ -11941,7 +12101,7 @@ async function runInit(flags) {
11941
12101
  printDescription(INIT_DESCRIPTION);
11942
12102
  return;
11943
12103
  }
11944
- const envPath = path23.resolve(process.cwd(), ".env");
12104
+ const envPath = path24.resolve(process.cwd(), ".env");
11945
12105
  const existing = fs.existsSync(envPath) ? parseEnv(fs.readFileSync(envPath, "utf8")) : /* @__PURE__ */ new Map();
11946
12106
  let figmaToken = flags.figmaToken ?? existing.get(ENV_KEYS.figma);
11947
12107
  let openrouterKey = flags.openrouterKey ?? existing.get(ENV_KEYS.openrouter);
@@ -11950,7 +12110,7 @@ async function runInit(flags) {
11950
12110
  fail(flags, ExitCode.InputValidation, {
11951
12111
  error: "Missing credentials and prompts are disabled.",
11952
12112
  code: "MISSING_CREDENTIALS",
11953
- remediation: "Pass --figma-token <token> and --openrouter-key <key>, or run `tendril init` in an interactive terminal."
12113
+ remediation: `Pass --figma-token <token> and --openrouter-key <key>, or run \`${tendrilCommand("init")}\` in an interactive terminal.`
11954
12114
  });
11955
12115
  }
11956
12116
  if (interactive) {
@@ -11962,7 +12122,7 @@ async function runInit(flags) {
11962
12122
  next.set(ENV_KEYS.figma, figmaToken);
11963
12123
  next.set(ENV_KEYS.openrouter, openrouterKey);
11964
12124
  const changed = existing.get(ENV_KEYS.figma) !== next.get(ENV_KEYS.figma) || existing.get(ENV_KEYS.openrouter) !== next.get(ENV_KEYS.openrouter);
11965
- const gitignorePath = path23.resolve(process.cwd(), ".gitignore");
12125
+ const gitignorePath = path24.resolve(process.cwd(), ".gitignore");
11966
12126
  const gitignore = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, "utf8") : "";
11967
12127
  const gitignoreCoversEnv = gitignore.split("\n").some((line) => [".env", ".env", ".env*"].includes(line.trim()));
11968
12128
  if (flags.dryRun) {
@@ -12007,26 +12167,27 @@ async function runInit(flags) {
12007
12167
  });
12008
12168
  }
12009
12169
 
12010
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/generate.ts
12170
+ // packages/cli/src/commands/generate.ts
12011
12171
  init_src3();
12012
12172
  init_src();
12013
12173
  init_src5();
12014
12174
  init_src2();
12015
12175
  init_describe();
12016
12176
  init_env();
12177
+ init_invocation();
12017
12178
  init_output();
12018
12179
  init_entitlement();
12019
12180
  import { confirm as confirm2, isCancel as isCancel2 } from "@clack/prompts";
12020
- import { readFileSync as readFileSync15, readdirSync as readdirSync4, existsSync as existsSync18 } from "node:fs";
12181
+ import { readFileSync as readFileSync15, readdirSync as readdirSync4, existsSync as existsSync19 } from "node:fs";
12021
12182
 
12022
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/pipeline.ts
12183
+ // packages/cli/src/pipeline.ts
12023
12184
  init_src2();
12024
12185
  init_src4();
12025
12186
  init_src6();
12026
12187
  import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync8 } from "node:fs";
12027
- import path24 from "node:path";
12188
+ import path25 from "node:path";
12028
12189
 
12029
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/assets-module.ts
12190
+ // packages/cli/src/assets-module.ts
12030
12191
  init_src();
12031
12192
  var KEBAB_ATTRS = {
12032
12193
  "fill-rule": "fillRule",
@@ -12137,7 +12298,7 @@ function buildAssetsModule(assets, aliases = {}) {
12137
12298
  return { source, flags };
12138
12299
  }
12139
12300
 
12140
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/pipeline.ts
12301
+ // packages/cli/src/pipeline.ts
12141
12302
  var VerifyFailedError = class extends Error {
12142
12303
  constructor(loop) {
12143
12304
  super(
@@ -12360,7 +12521,7 @@ async function runGenerationPipeline(input) {
12360
12521
  });
12361
12522
  const written = [];
12362
12523
  if (!input.dryRun) {
12363
- const dir = path24.resolve(input.outDir, semantics.componentName);
12524
+ const dir = path25.resolve(input.outDir, semantics.componentName);
12364
12525
  mkdirSync5(dir, { recursive: true });
12365
12526
  const files = {
12366
12527
  // Bundle-local tokens: THE emission the component's CSS resolves
@@ -12384,13 +12545,13 @@ async function runGenerationPipeline(input) {
12384
12545
  `
12385
12546
  };
12386
12547
  for (const [name, content] of Object.entries(files)) {
12387
- const filePath = path24.join(dir, name);
12548
+ const filePath = path25.join(dir, name);
12388
12549
  writeFileSync8(filePath, content);
12389
12550
  written.push(filePath);
12390
12551
  }
12391
12552
  for (const artifact of emitTokenArtifacts(input.mapping)) {
12392
- const filePath = path24.resolve(input.outDir, artifact.path);
12393
- mkdirSync5(path24.dirname(filePath), { recursive: true });
12553
+ const filePath = path25.resolve(input.outDir, artifact.path);
12554
+ mkdirSync5(path25.dirname(filePath), { recursive: true });
12394
12555
  writeFileSync8(filePath, artifact.content);
12395
12556
  written.push(filePath);
12396
12557
  }
@@ -12398,7 +12559,7 @@ async function runGenerationPipeline(input) {
12398
12559
  return { semantics, loop: finalLoop, report, componentJson, usageMd: docs.usageMd, written };
12399
12560
  }
12400
12561
 
12401
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/commands/generate.ts
12562
+ // packages/cli/src/commands/generate.ts
12402
12563
  var TOOL_VERSION = "0.0.0";
12403
12564
  var GENERATE_DESCRIPTION = {
12404
12565
  name: "generate",
@@ -12454,7 +12615,7 @@ function resolveProvidedSource(flags, contextFile) {
12454
12615
  fail(flags, ExitCode.InputValidation, {
12455
12616
  error: `Cannot read context file "${contextFile}".`,
12456
12617
  code: "CONTEXT_UNREADABLE",
12457
- remediation: "Pass a readable JSON file via --context; run `tendril generate --describe` for the payload shape."
12618
+ remediation: `Pass a readable JSON file via --context; run \`${tendrilCommand("generate --describe")}\` for the payload shape.`
12458
12619
  });
12459
12620
  }
12460
12621
  try {
@@ -12463,7 +12624,7 @@ function resolveProvidedSource(flags, contextFile) {
12463
12624
  fail(flags, ExitCode.InputValidation, {
12464
12625
  error: `Context file "${contextFile}" is not a valid design-context payload: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`,
12465
12626
  code: "CONTEXT_INVALID",
12466
- remediation: "The payload must match { nodeTree, variables[], metadata, screenshotBase64? } \u2014 see `tendril generate --describe` and docs/adr/003-figma-access-strategy.md."
12627
+ remediation: `The payload must match { nodeTree, variables[], metadata, screenshotBase64? } \u2014 see \`${tendrilCommand("generate --describe")}\` and docs/adr/003-figma-access-strategy.md.`
12467
12628
  });
12468
12629
  }
12469
12630
  }
@@ -12473,7 +12634,7 @@ function resolveSource(flags, url) {
12473
12634
  fail(flags, ExitCode.General, {
12474
12635
  error: "Live Figma transports (desktop MCP / REST) are not wired up yet.",
12475
12636
  code: "NOT_IMPLEMENTED",
12476
- remediation: "Use `tendril generate --context <file>` with an agent-fetched payload, or mock://button for the offline fixture; live transports are task 1.2 in docs/PLAN.md."
12637
+ remediation: `Use \`${tendrilCommand("generate --context <file>")}\` with an agent-fetched payload, or mock://button for the offline fixture; live transports are task 1.2 in docs/PLAN.md.`
12477
12638
  });
12478
12639
  }
12479
12640
  fail(flags, ExitCode.InputValidation, {
@@ -12492,7 +12653,7 @@ async function runGenerate(url, flags) {
12492
12653
  fail(flags, ExitCode.InputValidation, {
12493
12654
  error: "Missing input: pass a recording set or reference task (recorded truth, the default), mock://button, or --context <file>.",
12494
12655
  code: "MISSING_ARGUMENT",
12495
- remediation: "Run `tendril generate --describe` to see arguments and examples."
12656
+ remediation: `Run \`${tendrilCommand("generate --describe")}\` to see arguments and examples.`
12496
12657
  });
12497
12658
  }
12498
12659
  url ??= `provided://${flags.context}`;
@@ -12569,10 +12730,10 @@ token mapping (${mapping.flat.length} variables):
12569
12730
  let initialCode;
12570
12731
  let initialSemantics;
12571
12732
  try {
12572
- if (existsSync18(flags.out)) {
12733
+ if (existsSync19(flags.out)) {
12573
12734
  for (const entry of readdirSync4(flags.out)) {
12574
12735
  const cjPath = `${flags.out}/${entry}/component.json`;
12575
- if (!existsSync18(cjPath)) continue;
12736
+ if (!existsSync19(cjPath)) continue;
12576
12737
  const cj = JSON.parse(readFileSync15(cjPath, "utf8"));
12577
12738
  if (cj.name !== void 0 && Array.isArray(cj.props)) {
12578
12739
  previousApi = JSON.stringify({
@@ -12581,13 +12742,13 @@ token mapping (${mapping.flat.length} variables):
12581
12742
  });
12582
12743
  const tsxPath = `${flags.out}/${entry}/${cj.name}.tsx`;
12583
12744
  const cssPath = `${flags.out}/${entry}/${cj.name}.css`;
12584
- if (flags.refine && existsSync18(tsxPath) && existsSync18(cssPath)) {
12745
+ if (flags.refine && existsSync19(tsxPath) && existsSync19(cssPath)) {
12585
12746
  initialCode = {
12586
12747
  tsx: readFileSync15(tsxPath, "utf8"),
12587
12748
  css: readFileSync15(cssPath, "utf8")
12588
12749
  };
12589
12750
  const semPath = `${flags.out}/${entry}/semantics.json`;
12590
- if (existsSync18(semPath)) {
12751
+ if (existsSync19(semPath)) {
12591
12752
  initialSemantics = JSON.parse(readFileSync15(semPath, "utf8"));
12592
12753
  }
12593
12754
  }
@@ -12617,7 +12778,7 @@ token mapping (${mapping.flat.length} variables):
12617
12778
  fail(flags, ExitCode.Auth, {
12618
12779
  error: "OPENROUTER_API_KEY is not configured.",
12619
12780
  code: "MISSING_OPENROUTER_KEY",
12620
- remediation: "Run `tendril init` to store your OpenRouter key in .env (BYOK \u2014 your key, your inference)."
12781
+ remediation: `Run \`${tendrilCommand("init")}\` to store your OpenRouter key in .env (BYOK \u2014 your key, your inference).`
12621
12782
  });
12622
12783
  }
12623
12784
  genModel = new OpenRouterGenerationModel(new OpenRouterClient({ apiKey }), model.id, {
@@ -12726,7 +12887,7 @@ bundle written to ${flags.out}/${result.semantics.componentName}/:
12726
12887
  );
12727
12888
  }
12728
12889
 
12729
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/program.ts
12890
+ // packages/cli/src/program.ts
12730
12891
  init_src4();
12731
12892
  function globalFlags(cmd) {
12732
12893
  const opts = cmd.optsWithGlobals();
@@ -12840,7 +13001,7 @@ function buildProgram() {
12840
13001
  fail2(flags, ExitCode.InputValidation, {
12841
13002
  error: family === void 0 ? "nothing to resolve \u2014 pass a family name or --set <recording-dir>" : "pass a family name OR --set, not both \u2014 --set derives families from the recording itself",
12842
13003
  code: "INPUT_VALIDATION",
12843
- remediation: 'tendril fonts resolve --set <recording-dir>, or tendril fonts resolve "<Family>" --weights 400 500 600'
13004
+ remediation: `${tendrilCommand("fonts resolve --set <recording-dir>")}, or ${tendrilCommand('fonts resolve "<Family>" --weights 400 500 600')}`
12844
13005
  });
12845
13006
  }
12846
13007
  if (set !== void 0) {
@@ -12983,7 +13144,7 @@ function buildProgram() {
12983
13144
  return program;
12984
13145
  }
12985
13146
 
12986
- // ../../../../../../Users/jordyarnoldussen/Desktop/Tendril/packages/cli/src/bin.ts
13147
+ // packages/cli/src/bin.ts
12987
13148
  try {
12988
13149
  await buildProgram().parseAsync(process.argv);
12989
13150
  } catch (err) {
@@ -12994,7 +13155,7 @@ try {
12994
13155
  const cliError2 = {
12995
13156
  error: err.message,
12996
13157
  code: "INPUT_VALIDATION",
12997
- remediation: "Run `tendril --help` or `<command> --describe` for usage."
13158
+ remediation: `Run \`${tendrilCommand("--help")}\` or \`${tendrilCommand("<command> --describe")}\` for usage.`
12998
13159
  };
12999
13160
  process.stderr.write(`${JSON.stringify(cliError2)}
13000
13161
  `);