@contentful/experience-design-system-cli 2.37.1-dev-build-2582b468.0 → 2.37.1-dev-build-41b62bf7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/app.js CHANGED
@@ -9648,8 +9648,8 @@ function extractAccessorProperties(classDecl, applyRuntimeFieldDenylist = false)
9648
9648
  accessors.set(name, entry);
9649
9649
  }
9650
9650
  for (const [name, { getter, setter }] of accessors) {
9651
- const hasPropertyDecorator2 = getter?.getDecorators().some((decorator) => decorator.getName() === "property") || setter?.getDecorators().some((decorator) => decorator.getName() === "property");
9652
- if (!hasPropertyDecorator2 && !(getter && setter))
9651
+ const hasPropertyDecorator = getter?.getDecorators().some((decorator) => decorator.getName() === "property") || setter?.getDecorators().some((decorator) => decorator.getName() === "property");
9652
+ if (!hasPropertyDecorator && !(getter && setter))
9653
9653
  continue;
9654
9654
  const type = getter?.getReturnTypeNode()?.getText() ?? setter?.getParameters()[0]?.getTypeNode()?.getText() ?? "any";
9655
9655
  const accessorNode = getter ?? setter;
@@ -12919,9 +12919,9 @@ function generateUlid(now = Date.now()) {
12919
12919
  tsBytes[i] = n & 255;
12920
12920
  n = Math.floor(n / 256);
12921
12921
  }
12922
- const ts6 = encodeBase32(tsBytes, 10);
12922
+ const ts3 = encodeBase32(tsBytes, 10);
12923
12923
  const rand = encodeBase32(randomBytes2(10), 16);
12924
- return (ts6 + rand).toUpperCase();
12924
+ return (ts3 + rand).toUpperCase();
12925
12925
  }
12926
12926
 
12927
12927
  // packages/experience-design-system-backend-pipeline/dist/src/persistence/src/runs/repositories/read-runs-file.js
@@ -15335,610 +15335,7 @@ async function runMapTokens(request) {
15335
15335
  import { mkdir as mkdir4 } from "node:fs/promises";
15336
15336
  import { relative as relative2 } from "node:path";
15337
15337
 
15338
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/astro/helpers/collect-astro-props-bindings.js
15339
- import { Node as Node10, Project as Project7 } from "ts-morph";
15340
-
15341
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/shared/helpers/tsx-shared.js
15342
- import { Project as Project8 } from "ts-morph";
15343
-
15344
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/shared/helpers/tsx-node-utils.js
15345
- import { Node as Node12, SyntaxKind as SyntaxKind7 } from "ts-morph";
15346
-
15347
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/shared/helpers/resolve-tsx-workspace-imports.js
15348
- import { Node as Node11 } from "ts-morph";
15349
-
15350
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/shared/helpers/resolve-tsx-tsconfig-path.js
15351
- import ts3 from "typescript";
15352
-
15353
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/shared/helpers/tsx-renderable-exports.js
15354
- import { Node as Node13 } from "ts-morph";
15355
-
15356
- // packages/experience-design-system-extraction/dist/src/extract/helpers/evidence/collect-jsx-component-references.js
15357
- import { Node as Node15, SyntaxKind as SyntaxKind9 } from "ts-morph";
15358
-
15359
- // packages/experience-design-system-extraction/dist/src/extract/helpers/evidence/ast/get-jsx-ast-data.js
15360
- import { Node as Node14 } from "ts-morph";
15361
-
15362
- // packages/experience-design-system-extraction/dist/src/extract/helpers/evidence/ast/collect-structural-jsx-evidence.js
15363
- import { SyntaxKind as SyntaxKind8 } from "ts-morph";
15364
-
15365
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/extract-from-react-source-file.js
15366
- import { SyntaxKind as SyntaxKind14 } from "ts-morph";
15367
-
15368
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/extract-react-component-from-export.js
15369
- import { Node as Node32 } from "ts-morph";
15370
-
15371
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/collect-prop-dataflow.js
15372
- import { Node as Node17, SyntaxKind as SyntaxKind10 } from "ts-morph";
15373
-
15374
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/resolve-component-function.js
15375
- import { Node as Node16 } from "ts-morph";
15376
-
15377
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/extract-react-props-from-type.js
15378
- import { Node as Node24 } from "ts-morph";
15379
-
15380
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/dom-attribute-surfaces.js
15381
- import { Node as Node18 } from "ts-morph";
15382
- function createTextControlSurface2(onChangeType, specificProps) {
15383
- return [
15384
- { name: "autoComplete", type: "string", required: false },
15385
- ...specificProps,
15386
- { name: "disabled", type: "boolean", required: false },
15387
- { name: "name", type: "string", required: false },
15388
- { name: "onChange", type: onChangeType, required: false },
15389
- { name: "placeholder", type: "string", required: false },
15390
- { name: "readOnly", type: "boolean", required: false },
15391
- { name: "required", type: "boolean", required: false },
15392
- {
15393
- name: "value",
15394
- type: "string | number | readonly string[]",
15395
- required: false
15396
- }
15397
- ];
15398
- }
15399
- var DOM_ATTRIBUTE_PROP_SURFACES2 = {
15400
- HTMLProps: [],
15401
- HTMLAttributes: [
15402
- { name: "className", type: "string", required: false },
15403
- { name: "hidden", type: "boolean", required: false },
15404
- { name: "id", type: "string", required: false },
15405
- {
15406
- name: "onClick",
15407
- type: "MouseEventHandler<HTMLElement>",
15408
- required: false
15409
- },
15410
- { name: "style", type: "CSSProperties", required: false },
15411
- { name: "tabIndex", type: "number", required: false },
15412
- { name: "title", type: "string", required: false }
15413
- ],
15414
- ImgHTMLAttributes: [
15415
- { name: "alt", type: "string", required: false },
15416
- { name: "crossOrigin", type: "string", required: false },
15417
- { name: "height", type: "number | string", required: false },
15418
- {
15419
- name: "loading",
15420
- type: "string",
15421
- required: false,
15422
- allowedValues: ["eager", "lazy"]
15423
- },
15424
- { name: "sizes", type: "string", required: false },
15425
- { name: "src", type: "string", required: false },
15426
- { name: "srcSet", type: "string", required: false },
15427
- { name: "width", type: "number | string", required: false }
15428
- ],
15429
- LiHTMLAttributes: [],
15430
- AnchorHTMLAttributes: [
15431
- { name: "download", type: "boolean | string", required: false },
15432
- { name: "href", type: "string", required: false },
15433
- { name: "hrefLang", type: "string", required: false },
15434
- { name: "referrerPolicy", type: "string", required: false },
15435
- { name: "rel", type: "string", required: false },
15436
- {
15437
- name: "target",
15438
- type: "string",
15439
- required: false,
15440
- allowedValues: ["_blank", "_parent", "_self", "_top"]
15441
- }
15442
- ],
15443
- ButtonHTMLAttributes: [
15444
- { name: "autoFocus", type: "boolean", required: false },
15445
- { name: "disabled", type: "boolean", required: false },
15446
- { name: "form", type: "string", required: false },
15447
- { name: "formAction", type: "string", required: false },
15448
- { name: "formMethod", type: "string", required: false },
15449
- { name: "formNoValidate", type: "boolean", required: false },
15450
- { name: "formTarget", type: "string", required: false },
15451
- { name: "name", type: "string", required: false },
15452
- {
15453
- name: "type",
15454
- type: "string",
15455
- required: false,
15456
- allowedValues: ["button", "reset", "submit"]
15457
- },
15458
- {
15459
- name: "value",
15460
- type: "string | number | readonly string[]",
15461
- required: false
15462
- }
15463
- ],
15464
- InputHTMLAttributes: createTextControlSurface2("ChangeEventHandler<HTMLInputElement>", [
15465
- { name: "checked", type: "boolean", required: false },
15466
- { name: "max", type: "number | string", required: false },
15467
- { name: "maxLength", type: "number", required: false },
15468
- { name: "min", type: "number | string", required: false },
15469
- { name: "minLength", type: "number", required: false },
15470
- { name: "type", type: "string", required: false }
15471
- ]),
15472
- FieldsetHTMLAttributes: [
15473
- { name: "disabled", type: "boolean", required: false },
15474
- { name: "form", type: "string", required: false },
15475
- { name: "name", type: "string", required: false }
15476
- ],
15477
- LabelHTMLAttributes: [
15478
- { name: "form", type: "string", required: false },
15479
- { name: "htmlFor", type: "string", required: false }
15480
- ],
15481
- SelectHTMLAttributes: [
15482
- { name: "autoComplete", type: "string", required: false },
15483
- { name: "disabled", type: "boolean", required: false },
15484
- { name: "form", type: "string", required: false },
15485
- { name: "multiple", type: "boolean", required: false },
15486
- { name: "name", type: "string", required: false },
15487
- {
15488
- name: "onChange",
15489
- type: "ChangeEventHandler<HTMLSelectElement>",
15490
- required: false
15491
- },
15492
- { name: "required", type: "boolean", required: false },
15493
- { name: "size", type: "number", required: false },
15494
- {
15495
- name: "value",
15496
- type: "string | number | readonly string[]",
15497
- required: false
15498
- }
15499
- ],
15500
- SVGAttributes: [
15501
- {
15502
- name: "focusable",
15503
- type: 'boolean | "auto"',
15504
- required: false,
15505
- allowedValues: ["auto"]
15506
- },
15507
- { name: "height", type: "number | string", required: false },
15508
- { name: "viewBox", type: "string", required: false },
15509
- { name: "width", type: "number | string", required: false }
15510
- ],
15511
- SVGProps: [],
15512
- TextareaHTMLAttributes: createTextControlSurface2("ChangeEventHandler<HTMLTextAreaElement>", [
15513
- { name: "cols", type: "number", required: false },
15514
- { name: "rows", type: "number", required: false },
15515
- { name: "wrap", type: "string", required: false }
15516
- ]),
15517
- TdHTMLAttributes: [
15518
- {
15519
- name: "align",
15520
- type: "string",
15521
- required: false,
15522
- allowedValues: ["center", "char", "justify", "left", "right"]
15523
- },
15524
- { name: "colSpan", type: "number", required: false },
15525
- { name: "headers", type: "string", required: false },
15526
- { name: "rowSpan", type: "number", required: false },
15527
- { name: "scope", type: "string", required: false }
15528
- ]
15529
- };
15530
-
15531
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/collect-dom-wrapper-contexts.js
15532
- import { Node as Node19 } from "ts-morph";
15533
-
15534
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/detect-dom-is-pure-wrapper.js
15535
- import { Node as Node20 } from "ts-morph";
15536
-
15537
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/detect-omit-wrapped-custom-props.js
15538
- import { Node as Node21 } from "ts-morph";
15539
-
15540
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/detect-pick-type-patterns.js
15541
- import { Node as Node22 } from "ts-morph";
15542
-
15543
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/detect-react-polymorphic.js
15544
- import { Node as Node23 } from "ts-morph";
15545
-
15546
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/resolve-react-props-type.js
15547
- import { Node as Node25 } from "ts-morph";
15548
-
15549
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/extract-react-binding-defaults.js
15550
- import { Node as Node28 } from "ts-morph";
15551
-
15552
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/filter-impl-alias-props.js
15553
- import { Node as Node26 } from "ts-morph";
15554
-
15555
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/extract-binding-fallback-props.js
15556
- import { Node as Node27, SyntaxKind as SyntaxKind11 } from "ts-morph";
15557
-
15558
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/collect-react-impl-hints.js
15559
- import { Node as Node30, SyntaxKind as SyntaxKind13 } from "ts-morph";
15560
-
15561
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/infer-primitive-dom-props.js
15562
- import { Node as Node29, SyntaxKind as SyntaxKind12 } from "ts-morph";
15563
-
15564
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/extract-react-prop-types.js
15565
- import { Node as Node31 } from "ts-morph";
15566
-
15567
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/stencil/extractor.js
15568
- import { Project as Project9, Node as Node37 } from "ts-morph";
15569
-
15570
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/stencil/helpers/detect-stencil-class.js
15571
- import { Node as Node33 } from "ts-morph";
15572
-
15573
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/stencil/helpers/extract-stencil-props.js
15574
- import { Node as Node35 } from "ts-morph";
15575
-
15576
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/stencil/helpers/stencil-prop-helpers.js
15577
- import { Node as Node34, SyntaxKind as SyntaxKind15 } from "ts-morph";
15578
-
15579
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/stencil/helpers/extract-stencil-slots.js
15580
- import { Node as Node36 } from "ts-morph";
15581
-
15582
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/svelte/helpers/resolve-svelte-unresolved-retry.js
15583
- import { Project as Project12, ScriptTarget as ScriptTarget4, ModuleKind as ModuleKind4, ts as ts5 } from "ts-morph";
15584
-
15585
- // packages/experience-design-system-extraction/dist/src/extract/services/quality/helpers/scoring/collect-scoring-inputs.js
15586
- var OPAQUE_TYPES2 = /* @__PURE__ */ new Set(["any", "unknown", "object", "Record<string, unknown>", "Record<string, any>"]);
15587
- var OBVIOUS_PROP_NAMES2 = /* @__PURE__ */ new Set([
15588
- "className",
15589
- "style",
15590
- "id",
15591
- "children",
15592
- "disabled",
15593
- "hidden",
15594
- "onClick",
15595
- "onChange",
15596
- "onSubmit",
15597
- "onBlur",
15598
- "onFocus",
15599
- "href",
15600
- "src",
15601
- "alt",
15602
- "type",
15603
- "value",
15604
- "checked",
15605
- "placeholder",
15606
- "label",
15607
- "title",
15608
- "name",
15609
- "required",
15610
- "readOnly",
15611
- "autoFocus",
15612
- "tabIndex",
15613
- "role",
15614
- "aria-label",
15615
- "aria-describedby"
15616
- ]);
15617
- function isWidePrimitiveUnion2(type) {
15618
- const parts = type.split("|").map((p) => p.trim());
15619
- if (parts.length < 3)
15620
- return false;
15621
- const basePrimitives = /* @__PURE__ */ new Set(["string", "number", "boolean"]);
15622
- const nullability = /* @__PURE__ */ new Set(["null", "undefined"]);
15623
- const baseCount = parts.filter((p) => basePrimitives.has(p)).length;
15624
- const nullabilityCount = parts.filter((p) => nullability.has(p)).length;
15625
- return baseCount >= 3 || baseCount >= 2 && nullabilityCount > 0 && baseCount + nullabilityCount >= 3;
15626
- }
15627
- function countExtractionIssues(component, options = {}) {
15628
- let count = 0;
15629
- const reasons = [];
15630
- if (component.props.length === 0 && component.slots.length === 0) {
15631
- count++;
15632
- reasons.push("no-props-or-slots");
15633
- }
15634
- if (component.props.length > 50) {
15635
- count++;
15636
- reasons.push(`high-prop-count:${component.props.length}`);
15637
- }
15638
- for (const prop of component.props) {
15639
- if (OPAQUE_TYPES2.has(prop.type.trim())) {
15640
- count++;
15641
- reasons.push(`opaque-type:${prop.name}`);
15642
- break;
15643
- }
15644
- if (isWidePrimitiveUnion2(prop.type)) {
15645
- count++;
15646
- reasons.push(`wide-union:${prop.name}`);
15647
- break;
15648
- }
15649
- if (!prop.description && !OBVIOUS_PROP_NAMES2.has(prop.name)) {
15650
- count++;
15651
- reasons.push("props-missing-description");
15652
- break;
15653
- }
15654
- }
15655
- count += options.additionalIssueCount ?? 0;
15656
- if (options.additionalReasons && options.additionalReasons.length > 0) {
15657
- reasons.push(...options.additionalReasons);
15658
- }
15659
- return { count, reasons: [...new Set(reasons)] };
15660
- }
15661
- function mapIssueCountToConfidence(count) {
15662
- if (count === 0)
15663
- return 5;
15664
- if (count === 1)
15665
- return 4;
15666
- if (count === 2)
15667
- return 3;
15668
- if (count === 3)
15669
- return 2;
15670
- return 1;
15671
- }
15672
-
15673
- // packages/experience-design-system-extraction/dist/src/extract/services/quality/helpers/scoring/compute-extraction-score.js
15674
- function computeExtractionScore2(component, options = {}) {
15675
- const { count, reasons } = countExtractionIssues(component, options);
15676
- return {
15677
- confidence: mapIssueCountToConfidence(count),
15678
- reasons
15679
- };
15680
- }
15681
- function deriveNeedsReview2(confidence) {
15682
- return confidence <= 2;
15683
- }
15684
-
15685
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/svelte/helpers/resolve-svelte-type-checker.js
15686
- import { Project as Project10, ScriptTarget as ScriptTarget2, ModuleKind as ModuleKind2, ts as ts4 } from "ts-morph";
15687
-
15688
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/svelte/helpers/extract-svelte-declaration-data.js
15689
- import { Node as Node38 } from "ts-morph";
15690
-
15691
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/svelte/helpers/resolve-svelte-external-type-readers.js
15692
- import { Node as Node40, Project as Project11, ScriptTarget as ScriptTarget3, ModuleKind as ModuleKind3 } from "ts-morph";
15693
-
15694
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/svelte/helpers/extract-svelte-external-type-members.js
15695
- import { Node as Node39 } from "ts-morph";
15696
-
15697
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/svelte/helpers/extract-from-svelte-file.js
15698
- import { parse as parseSvelte2 } from "svelte/compiler";
15699
-
15700
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/vue-tsx/extractor.js
15701
- import { Node as Node44 } from "ts-morph";
15702
-
15703
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/vue-tsx/helpers/extract-vue-tsx-props.js
15704
- import { Node as Node42 } from "ts-morph";
15705
-
15706
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/vue-tsx/helpers/resolve-ast-object.js
15707
- import { Node as Node41, SyntaxKind as SyntaxKind16 } from "ts-morph";
15708
-
15709
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/vue-tsx/helpers/extract-vue-tsx-slots.js
15710
- import { Node as Node43, SyntaxKind as SyntaxKind17 } from "ts-morph";
15711
-
15712
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/vue/extractor.js
15713
- import { parse as parseSFC3 } from "@vue/compiler-sfc";
15714
-
15715
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/vue/helpers/extract-vue-setup-props.js
15716
- import { Project as Project14, Node as Node47 } from "ts-morph";
15717
-
15718
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/vue/helpers/extract-vue-setup-object-props.js
15719
- import { Project as Project13, Node as Node46 } from "ts-morph";
15720
-
15721
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/vue/helpers/extract-vue-object-props.js
15722
- import { Node as Node45 } from "ts-morph";
15723
-
15724
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/vue/helpers/extract-vue-options-props.js
15725
- import { parse as parseSFC2 } from "@vue/compiler-sfc";
15726
- import { Node as Node48, Project as Project15 } from "ts-morph";
15727
-
15728
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/web-components/extractor.js
15729
- import { Project as Project16 } from "ts-morph";
15730
-
15731
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/web-components/helpers/extract-wc-observed-attrs.js
15732
- import { Node as Node49 } from "ts-morph";
15733
-
15734
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/web-components/helpers/extract-wc-class-properties.js
15735
- import { Node as Node50 } from "ts-morph";
15736
-
15737
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-decorator-tag.js
15738
- import { Node as Node51 } from "ts-morph";
15739
-
15740
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-sibling-definition.js
15741
- import { Node as Node54, SyntaxKind as SyntaxKind19 } from "ts-morph";
15742
-
15743
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-import.js
15744
- import { Node as Node53, SyntaxKind as SyntaxKind18 } from "ts-morph";
15745
-
15746
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-import-source.js
15747
- import { Node as Node52 } from "ts-morph";
15748
-
15749
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/web-components/helpers/extract-wc-template-content.js
15750
- import { Node as Node56 } from "ts-morph";
15751
-
15752
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/web-components/helpers/collect-wc-html-templates.js
15753
- import { Node as Node55 } from "ts-morph";
15754
-
15755
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-base-class.js
15756
- import { Node as Node57, SyntaxKind as SyntaxKind20 } from "ts-morph";
15757
-
15758
- // packages/experience-design-system-extraction/dist/src/extract/services/classification/helpers/check-prop-types.js
15759
- function isStringLiteralUnion(type) {
15760
- return type.includes("|") && type.includes("'");
15761
- }
15762
- function isSimpleType(type) {
15763
- const t = type.trim();
15764
- if (t === "string" || t === "boolean" || t === "number")
15765
- return true;
15766
- return isStringLiteralUnion(t);
15767
- }
15768
- function isBooleanType(type) {
15769
- return type.trim() === "boolean";
15770
- }
15771
- function isStringType(type) {
15772
- return type.trim() === "string";
15773
- }
15774
- function isNumberType(type) {
15775
- return type.trim() === "number";
15776
- }
15777
- function isComplexType(type) {
15778
- return !isSimpleType(type);
15779
- }
15780
-
15781
- // packages/experience-design-system-extraction/dist/src/extract/services/classification/helpers/detect-dom-props.js
15782
- var DOM_PASS_THROUGH_PROPS = /* @__PURE__ */ new Set([
15783
- // Bare HTML / framework styling pass-through
15784
- "className",
15785
- "class",
15786
- "classes",
15787
- "classNames",
15788
- "rootClassName",
15789
- "prefixCls",
15790
- "style",
15791
- "styles",
15792
- // Bare HTML attributes
15793
- "id",
15794
- "role",
15795
- "tabIndex",
15796
- "tabindex",
15797
- "htmlFor",
15798
- "for",
15799
- "slot",
15800
- "is",
15801
- "lang",
15802
- "dir",
15803
- "hidden",
15804
- "draggable",
15805
- "spellCheck",
15806
- "spellcheck",
15807
- "contentEditable",
15808
- "contenteditable",
15809
- "inputMode",
15810
- "inputmode",
15811
- "autoComplete",
15812
- "autocomplete",
15813
- "autoFocus",
15814
- "autofocus",
15815
- "translate",
15816
- "part",
15817
- "exportparts",
15818
- "aria",
15819
- // Framework theming / pass-through escape hatches — dev-facing, never marketer-configurable
15820
- "dt",
15821
- "pt",
15822
- "ptOptions",
15823
- "unstyled",
15824
- "sx",
15825
- // Polymorphic component props — change rendered HTML/component, not marketer-visible behavior
15826
- "as",
15827
- "element",
15828
- "component",
15829
- // QA / vendor test attributes
15830
- "dataQa",
15831
- "data-qa",
15832
- // Vue v-model internals — framework wiring, never marketer-configurable
15833
- "modelValue",
15834
- "modelModifiers"
15835
- ]);
15836
- function isDomPassThroughProp(name) {
15837
- if (DOM_PASS_THROUGH_PROPS.has(name))
15838
- return true;
15839
- if (/^aria[-A-Z]/.test(name))
15840
- return true;
15841
- return name.startsWith("data-");
15842
- }
15843
-
15844
- // packages/experience-design-system-extraction/dist/src/extract/services/classification/classify-component-props.js
15845
- function preClassifyProp(prop) {
15846
- const { name, type } = prop;
15847
- if (/^on[A-Z]/.test(name) || type.includes("=> void") || type.includes("EventHandler")) {
15848
- return { category: "exclude" };
15849
- }
15850
- if (name === "ref" || name === "innerRef" || type.includes("Ref<") || type.includes("RefObject<")) {
15851
- return { category: "exclude" };
15852
- }
15853
- if (name === "testId" || name === "data-testid" || name === "dataTestId") {
15854
- return { category: "exclude" };
15855
- }
15856
- if (name === "key") {
15857
- return { category: "exclude" };
15858
- }
15859
- if (type.includes("Dispatch<") || type.includes("SetStateAction")) {
15860
- return { category: "exclude" };
15861
- }
15862
- if (isDomPassThroughProp(name)) {
15863
- return { category: "exclude" };
15864
- }
15865
- if (name === "name" && prop.domAttribute) {
15866
- return { category: "exclude" };
15867
- }
15868
- if (isStringLiteralUnion(type)) {
15869
- return { category: "design", cdfTypeHint: "enum" };
15870
- }
15871
- if (!isComplexType(type)) {
15872
- const designNameStart = /^(variant|size|spacing|gap|color|bg|theme|align|layout|orientation|position)/i;
15873
- const designNameEnd = /(Color|Size|Variant|Style)$/;
15874
- if (designNameStart.test(name) || designNameEnd.test(name)) {
15875
- return { category: "design", cdfTypeHint: "string" };
15876
- }
15877
- }
15878
- if (isBooleanType(type)) {
15879
- const stateNames = ["disabled", "loading", "expanded", "isOpen", "selected", "checked", "active", "preview"];
15880
- if (stateNames.includes(name)) {
15881
- return { category: "state", cdfTypeHint: "boolean" };
15882
- }
15883
- }
15884
- if (isBooleanType(type)) {
15885
- const visualToggle = /^(hide|show|enable|disable|vertical|horizontal|reverse|bold|italic|imageOn|with)/i;
15886
- if (visualToggle.test(name)) {
15887
- return { category: "design", cdfTypeHint: "boolean" };
15888
- }
15889
- }
15890
- if (name === "componentId" || name === "sectionKey" || name === "locale" || name === "variantIndex") {
15891
- return { category: "state", cdfTypeHint: "string" };
15892
- }
15893
- if (isStringType(type)) {
15894
- const urlNameStart = /^(href|url|link|src)/i;
15895
- const urlNameEnd = /(Url|Href|Link|Src)$/;
15896
- if (urlNameStart.test(name) || urlNameEnd.test(name)) {
15897
- return { category: "content", cdfTypeHint: "string" };
15898
- }
15899
- }
15900
- if (isStringType(type)) {
15901
- const textNameStart = /^(label|title|text|description|caption|heading|subheading|body|alt|name|placeholder|summary)/i;
15902
- const textNameEnd = /(Text|Label|Title|Name)$/;
15903
- if (textNameStart.test(name) || textNameEnd.test(name)) {
15904
- return { category: "content", cdfTypeHint: "string" };
15905
- }
15906
- }
15907
- if (isStringType(type)) {
15908
- return { category: "content", cdfTypeHint: "string" };
15909
- }
15910
- if (isBooleanType(type)) {
15911
- return { category: "design", cdfTypeHint: "boolean" };
15912
- }
15913
- if (isNumberType(type)) {
15914
- return { category: "design", cdfTypeHint: "string" };
15915
- }
15916
- return void 0;
15917
- }
15918
- function preClassifyComponent(component) {
15919
- const props = component.props.flatMap((prop) => {
15920
- const result = preClassifyProp(prop);
15921
- if (result?.category === "exclude") {
15922
- return [];
15923
- }
15924
- const { domAttribute: _domAttribute, ...authorableProp } = prop;
15925
- if (prop.category) {
15926
- return [authorableProp];
15927
- }
15928
- if (!result) {
15929
- return [authorableProp];
15930
- }
15931
- return [
15932
- {
15933
- ...authorableProp,
15934
- category: result.category
15935
- }
15936
- ];
15937
- });
15938
- return { ...component, props };
15939
- }
15940
-
15941
- // packages/experience-design-system-extraction/dist/src/extract/services/quality/helpers/authorability/evaluate-authorability.js
15338
+ // packages/experience-design-system-backend-pipeline/dist/src/steps/extraction/src/helpers/quality/non-authorable-filter.js
15942
15339
  var HANDLER_TYPE_PATTERN = /=>|EventHandler|Dispatch<|SetStateAction/;
15943
15340
  var REF_TYPE_PATTERN = /Ref<|RefObject<|MutableRefObject/;
15944
15341
  function isHandlerOrRefProp(prop) {
@@ -15991,10 +15388,15 @@ function hasNoAuthoringSurface(component) {
15991
15388
  return { skip: false };
15992
15389
  }
15993
15390
 
15994
- // packages/experience-design-system-extraction/dist/src/extract/services/quality/helpers/inspection/inspect-component-source.js
15391
+ // packages/experience-design-system-backend-pipeline/dist/src/steps/extraction/src/helpers/evidence/source-inspection.js
15995
15392
  import { readFile as readFile15 } from "node:fs/promises";
15996
15393
 
15997
- // packages/experience-design-system-extraction/dist/src/extract/helpers/evidence/parse-source-imports.js
15394
+ // packages/experience-design-system-backend-pipeline/dist/src/steps/extraction/src/constants/review-reasons.js
15395
+ var HIGH_CONFIDENCE_DATA_FETCH_WRAPPER_REASON = "data-fetch-wrapper";
15396
+ var POSSIBLE_DATA_FETCH_WRAPPER_REASON = "possible-data-fetch-wrapper";
15397
+ var ZERO_SURFACE_RENDERED_UI_REASON = "zero-surface:rendered-ui";
15398
+
15399
+ // packages/experience-design-system-backend-pipeline/dist/src/steps/extraction/src/framework-adapters/shared/parse-imported-names.js
15998
15400
  function parseImportedNames(importClause) {
15999
15401
  const trimmed = importClause.trim();
16000
15402
  if (!trimmed)
@@ -16019,7 +15421,7 @@ function parseImportedNames(importClause) {
16019
15421
  return names;
16020
15422
  }
16021
15423
 
16022
- // packages/experience-design-system-extraction/dist/src/extract/services/quality/helpers/inspection/detect-data-wrapper-patterns.js
15424
+ // packages/experience-design-system-backend-pipeline/dist/src/steps/extraction/src/helpers/evidence/source-inspection.js
16023
15425
  var INFRA_PROP_NAMES = /* @__PURE__ */ new Set(["id", "locale", "preview", "slug", "topic", "previousComponent", "__typename"]);
16024
15426
  var VISIBLE_UI_TAG_PATTERN = /<(?:[A-Z][A-Za-z0-9_.]*|div|span|section|main|article|header|footer|nav|aside|img|video|p|h[1-6]|ul|ol|li|button|input|textarea|select|form|label|table|tbody|thead|tr|td|th)\b/;
16025
15427
  var GENERATED_IMPORT_PATTERN = /from\s+['"][^'"]*__generated[^'"]*['"]/;
@@ -16061,11 +15463,11 @@ function hasSiblingForwardRender(sourceText, siblingImports) {
16061
15463
  function hasVisibleUiRender(sourceText) {
16062
15464
  return /return\s*(?:\(|<)/.test(sourceText) && VISIBLE_UI_TAG_PATTERN.test(sourceText);
16063
15465
  }
16064
- function collectInfraPropNames(component) {
15466
+ function infraPropNames(component) {
16065
15467
  const props = component.props.map((prop) => prop.name);
16066
15468
  return props.length > 0 && props.every((prop) => INFRA_PROP_NAMES.has(prop)) ? props : [];
16067
15469
  }
16068
- function mapScoreToWrapperConfidence(score) {
15470
+ function scoreToConfidence(score) {
16069
15471
  if (score <= 0)
16070
15472
  return 0;
16071
15473
  if (score <= 2)
@@ -16076,14 +15478,9 @@ function mapScoreToWrapperConfidence(score) {
16076
15478
  return 4;
16077
15479
  return 5;
16078
15480
  }
16079
- function dedupeStrings(values) {
16080
- return [...new Set(values)];
15481
+ function dedupeReasons(reasons) {
15482
+ return [...new Set(reasons)];
16081
15483
  }
16082
-
16083
- // packages/experience-design-system-extraction/dist/src/extract/services/quality/helpers/inspection/inspect-component-source.js
16084
- var HIGH_CONFIDENCE_DATA_FETCH_WRAPPER_REASON = "data-fetch-wrapper";
16085
- var POSSIBLE_DATA_FETCH_WRAPPER_REASON = "possible-data-fetch-wrapper";
16086
- var ZERO_SURFACE_RENDERED_UI_REASON = "zero-surface:rendered-ui";
16087
15484
  async function inspectComponentSource(component) {
16088
15485
  let sourceText = "";
16089
15486
  try {
@@ -16098,7 +15495,7 @@ async function inspectComponentSource(component) {
16098
15495
  const reviewReasons = [];
16099
15496
  let wrapperScore = 0;
16100
15497
  const hasGeneratedQueryHook = GENERATED_IMPORT_PATTERN.test(sourceText) && GENERATED_QUERY_HOOK_PATTERN.test(sourceText);
16101
- const infraProps = collectInfraPropNames(component);
15498
+ const infraProps = infraPropNames(component);
16102
15499
  const siblingImports = collectSiblingRendererImports(sourceText);
16103
15500
  if (GQL_FILENAME_PATTERN.test(component.source)) {
16104
15501
  reviewReasons.push("data-wrapper:gql-filename");
@@ -16128,7 +15525,7 @@ async function inspectComponentSource(component) {
16128
15525
  reviewReasons.push("data-wrapper:loading-null-guard");
16129
15526
  wrapperScore += 1;
16130
15527
  }
16131
- const wrapperConfidence = mapScoreToWrapperConfidence(wrapperScore);
15528
+ const wrapperConfidence = scoreToConfidence(wrapperScore);
16132
15529
  if (wrapperConfidence >= 4) {
16133
15530
  reviewReasons.unshift(HIGH_CONFIDENCE_DATA_FETCH_WRAPPER_REASON);
16134
15531
  } else if (wrapperConfidence === 3) {
@@ -16140,7 +15537,7 @@ async function inspectComponentSource(component) {
16140
15537
  }
16141
15538
  return {
16142
15539
  wrapperConfidence,
16143
- reviewReasons: dedupeStrings(reviewReasons),
15540
+ reviewReasons: dedupeReasons(reviewReasons),
16144
15541
  keepDespiteZeroSurface
16145
15542
  };
16146
15543
  }
@@ -16171,123 +15568,235 @@ function describeReviewReason(reason) {
16171
15568
  }
16172
15569
  }
16173
15570
  function describeReviewReasons(reasons) {
16174
- return dedupeStrings(reasons.map(describeReviewReason));
15571
+ return dedupeReasons(reasons.map(describeReviewReason));
16175
15572
  }
16176
15573
 
16177
- // packages/experience-design-system-extraction/dist/src/extract/services/quality/helpers/inspection/validate-extracted-components.js
16178
- function validateExtractedComponents2(components) {
16179
- const nameCounts = /* @__PURE__ */ new Map();
16180
- for (const component of components) {
16181
- const key = component.name.trim();
16182
- nameCounts.set(key, (nameCounts.get(key) ?? 0) + 1);
16183
- }
16184
- return components.map((component) => {
16185
- const issues = [];
16186
- if (!component.name.trim()) {
16187
- issues.push({
16188
- severity: "error",
16189
- code: "EMPTY_COMPONENT_NAME",
16190
- message: "Component name must not be empty"
16191
- });
15574
+ // packages/experience-design-system-backend-pipeline/dist/src/steps/extraction/src/helpers/quality/evaluate-extraction-quality.js
15575
+ function wrapperConfidenceToIssueCount(confidence) {
15576
+ if (confidence >= 4)
15577
+ return 2;
15578
+ if (confidence === 3)
15579
+ return 1;
15580
+ return 0;
15581
+ }
15582
+ async function evaluateExtractionQuality(components, initialWarnings = []) {
15583
+ const inspectedComponents = await Promise.all(components.map(async (component) => ({
15584
+ component,
15585
+ inspection: await inspectComponentSource(component)
15586
+ })));
15587
+ const scoredComponents = [];
15588
+ const warnings = [...initialWarnings];
15589
+ for (const { component, inspection } of inspectedComponents) {
15590
+ const verdict = hasNoAuthoringSurface(component);
15591
+ const keepDespiteZeroSurface = verdict.skip && verdict.reason === "component has no props and no slots" && inspection.keepDespiteZeroSurface;
15592
+ const retainedForReview = verdict.skip && !keepDespiteZeroSurface;
15593
+ if (retainedForReview) {
15594
+ warnings.push(`${component.name}: requires operator review (${verdict.reason})`);
16192
15595
  }
16193
- for (let i = 0; i < component.props.length; i++) {
16194
- if (!component.props[i].name.trim()) {
16195
- issues.push({
16196
- severity: "error",
16197
- code: "EMPTY_PROP_NAME",
16198
- message: `Prop at index ${i} has an empty name`,
16199
- field: `props[${i}].name`
16200
- });
16201
- }
15596
+ if (keepDespiteZeroSurface) {
15597
+ warnings.push(`${component.name}: retained despite 0 props/slots because the source renders visible or compositional UI`);
16202
15598
  }
16203
- for (let i = 0; i < component.slots.length; i++) {
16204
- if (!component.slots[i].name.trim()) {
16205
- issues.push({
16206
- severity: "warning",
16207
- code: "EMPTY_SLOT_NAME",
16208
- message: `Slot at index ${i} has an empty name`,
16209
- field: `slots[${i}].name`
16210
- });
16211
- }
15599
+ if (inspection.reviewReasons.length > 0) {
15600
+ const reviewNotes = describeReviewReasons(inspection.reviewReasons).filter((note) => note !== "high-confidence data-fetch wrapper").join("; ");
15601
+ if (reviewNotes)
15602
+ warnings.push(`${component.name}: ${reviewNotes}`);
16212
15603
  }
16213
- const propNames = new Set(component.props.map((p) => p.name.trim()).filter(Boolean));
16214
- for (let i = 0; i < component.slots.length; i++) {
16215
- const slotName = component.slots[i].name.trim();
16216
- if (slotName && propNames.has(slotName)) {
16217
- issues.push({
16218
- severity: "error",
16219
- code: "PROP_SLOT_NAME_COLLISION",
16220
- message: `"${slotName}" is used as both a prop name and a slot name`,
16221
- field: `slots[${i}].name`
16222
- });
16223
- }
15604
+ const extractorReasons = component.reviewReasons ?? [];
15605
+ const nonAuthorableReason = retainedForReview ? [`non-authorable:${verdict.reason}`] : [];
15606
+ const { confidence, reasons } = computeExtractionScore(component, {
15607
+ additionalIssueCount: wrapperConfidenceToIssueCount(inspection.wrapperConfidence) + extractorReasons.length + nonAuthorableReason.length,
15608
+ additionalReasons: [...extractorReasons, ...inspection.reviewReasons, ...nonAuthorableReason]
15609
+ });
15610
+ scoredComponents.push({
15611
+ ...component,
15612
+ extractionConfidence: confidence,
15613
+ reviewReasons: reasons,
15614
+ needsReview: deriveNeedsReview(confidence) || inspection.wrapperConfidence >= 4 || inspection.keepDespiteZeroSurface || retainedForReview || extractorReasons.includes("props-type-unresolved") || (component.needsReview ?? false)
15615
+ });
15616
+ }
15617
+ return {
15618
+ components: validateExtractedComponents(scoredComponents),
15619
+ warnings
15620
+ };
15621
+ }
15622
+
15623
+ // packages/experience-design-system-backend-pipeline/dist/src/steps/extraction/src/helpers/pre-classify.js
15624
+ function isStringLiteralUnion(type) {
15625
+ return type.includes("|") && type.includes("'");
15626
+ }
15627
+ function isSimpleType(type) {
15628
+ const t = type.trim();
15629
+ if (t === "string" || t === "boolean" || t === "number")
15630
+ return true;
15631
+ return isStringLiteralUnion(t);
15632
+ }
15633
+ function isBooleanType(type) {
15634
+ return type.trim() === "boolean";
15635
+ }
15636
+ function isStringType(type) {
15637
+ return type.trim() === "string";
15638
+ }
15639
+ function isNumberType(type) {
15640
+ return type.trim() === "number";
15641
+ }
15642
+ function isComplexType(type) {
15643
+ return !isSimpleType(type);
15644
+ }
15645
+ var DOM_PASS_THROUGH_PROPS = /* @__PURE__ */ new Set([
15646
+ // Bare HTML / framework styling pass-through
15647
+ "className",
15648
+ "class",
15649
+ "classes",
15650
+ "classNames",
15651
+ "rootClassName",
15652
+ "prefixCls",
15653
+ "style",
15654
+ "styles",
15655
+ // Bare HTML attributes
15656
+ "id",
15657
+ "role",
15658
+ "tabIndex",
15659
+ "tabindex",
15660
+ "htmlFor",
15661
+ "for",
15662
+ "slot",
15663
+ "is",
15664
+ "lang",
15665
+ "dir",
15666
+ "hidden",
15667
+ "draggable",
15668
+ "spellCheck",
15669
+ "spellcheck",
15670
+ "contentEditable",
15671
+ "contenteditable",
15672
+ "inputMode",
15673
+ "inputmode",
15674
+ "autoComplete",
15675
+ "autocomplete",
15676
+ "autoFocus",
15677
+ "autofocus",
15678
+ "translate",
15679
+ "part",
15680
+ "exportparts",
15681
+ "aria",
15682
+ // Framework theming / pass-through escape hatches — dev-facing, never marketer-configurable
15683
+ "dt",
15684
+ "pt",
15685
+ "ptOptions",
15686
+ "unstyled",
15687
+ "sx",
15688
+ // Polymorphic component props — change rendered HTML/component, not marketer-visible behavior
15689
+ "as",
15690
+ "element",
15691
+ "component",
15692
+ // QA / vendor test attributes
15693
+ "dataQa",
15694
+ "data-qa",
15695
+ // Vue v-model internals — framework wiring, never marketer-configurable
15696
+ "modelValue",
15697
+ "modelModifiers"
15698
+ ]);
15699
+ function isDomPassThroughProp(name) {
15700
+ if (DOM_PASS_THROUGH_PROPS.has(name))
15701
+ return true;
15702
+ if (/^aria[-A-Z]/.test(name))
15703
+ return true;
15704
+ return name.startsWith("data-");
15705
+ }
15706
+ function preClassifyProp(prop) {
15707
+ const { name, type } = prop;
15708
+ if (/^on[A-Z]/.test(name) || type.includes("=> void") || type.includes("EventHandler")) {
15709
+ return { category: "exclude" };
15710
+ }
15711
+ if (name === "ref" || name === "innerRef" || type.includes("Ref<") || type.includes("RefObject<")) {
15712
+ return { category: "exclude" };
15713
+ }
15714
+ if (name === "testId" || name === "data-testid" || name === "dataTestId") {
15715
+ return { category: "exclude" };
15716
+ }
15717
+ if (name === "key") {
15718
+ return { category: "exclude" };
15719
+ }
15720
+ if (type.includes("Dispatch<") || type.includes("SetStateAction")) {
15721
+ return { category: "exclude" };
15722
+ }
15723
+ if (isDomPassThroughProp(name)) {
15724
+ return { category: "exclude" };
15725
+ }
15726
+ if (name === "name" && prop.domAttribute) {
15727
+ return { category: "exclude" };
15728
+ }
15729
+ if (isStringLiteralUnion(type)) {
15730
+ return { category: "design", cdfTypeHint: "enum" };
15731
+ }
15732
+ if (!isComplexType(type)) {
15733
+ const designNameStart = /^(variant|size|spacing|gap|color|bg|theme|align|layout|orientation|position)/i;
15734
+ const designNameEnd = /(Color|Size|Variant|Style)$/;
15735
+ if (designNameStart.test(name) || designNameEnd.test(name)) {
15736
+ return { category: "design", cdfTypeHint: "string" };
16224
15737
  }
16225
- const nameKey = component.name.trim();
16226
- if (nameKey && (nameCounts.get(nameKey) ?? 0) > 1) {
16227
- issues.push({
16228
- severity: "error",
16229
- code: "DUPLICATE_COMPONENT_NAME",
16230
- message: `Component name "${component.name}" appears more than once in the extracted set`
16231
- });
15738
+ }
15739
+ if (isBooleanType(type)) {
15740
+ const stateNames = ["disabled", "loading", "expanded", "isOpen", "selected", "checked", "active", "preview"];
15741
+ if (stateNames.includes(name)) {
15742
+ return { category: "state", cdfTypeHint: "boolean" };
15743
+ }
15744
+ }
15745
+ if (isBooleanType(type)) {
15746
+ const visualToggle = /^(hide|show|enable|disable|vertical|horizontal|reverse|bold|italic|imageOn|with)/i;
15747
+ if (visualToggle.test(name)) {
15748
+ return { category: "design", cdfTypeHint: "boolean" };
16232
15749
  }
16233
- if (component.props.length === 0 && component.slots.length === 0) {
16234
- issues.push({
16235
- severity: "warning",
16236
- code: "EMPTY_COMPONENT",
16237
- message: "Component has no props or slots and will be filtered out during generation"
16238
- });
15750
+ }
15751
+ if (name === "componentId" || name === "sectionKey" || name === "locale" || name === "variantIndex") {
15752
+ return { category: "state", cdfTypeHint: "string" };
15753
+ }
15754
+ if (isStringType(type)) {
15755
+ const urlNameStart = /^(href|url|link|src)/i;
15756
+ const urlNameEnd = /(Url|Href|Link|Src)$/;
15757
+ if (urlNameStart.test(name) || urlNameEnd.test(name)) {
15758
+ return { category: "content", cdfTypeHint: "string" };
16239
15759
  }
16240
- return { ...component, validationIssues: issues };
16241
- });
16242
- }
16243
-
16244
- // packages/experience-design-system-extraction/dist/src/extract/services/quality/evaluate-extraction-quality.js
16245
- function wrapperConfidenceToIssueCount(confidence) {
16246
- if (confidence >= 4)
16247
- return 2;
16248
- if (confidence === 3)
16249
- return 1;
16250
- return 0;
15760
+ }
15761
+ if (isStringType(type)) {
15762
+ const textNameStart = /^(label|title|text|description|caption|heading|subheading|body|alt|name|placeholder|summary)/i;
15763
+ const textNameEnd = /(Text|Label|Title|Name)$/;
15764
+ if (textNameStart.test(name) || textNameEnd.test(name)) {
15765
+ return { category: "content", cdfTypeHint: "string" };
15766
+ }
15767
+ }
15768
+ if (isStringType(type)) {
15769
+ return { category: "content", cdfTypeHint: "string" };
15770
+ }
15771
+ if (isBooleanType(type)) {
15772
+ return { category: "design", cdfTypeHint: "boolean" };
15773
+ }
15774
+ if (isNumberType(type)) {
15775
+ return { category: "design", cdfTypeHint: "string" };
15776
+ }
15777
+ return void 0;
16251
15778
  }
16252
- async function evaluateExtractionQuality(components, initialWarnings = []) {
16253
- const inspectedComponents = await Promise.all(components.map(async (component) => ({
16254
- component,
16255
- inspection: await inspectComponentSource(component)
16256
- })));
16257
- const scoredComponents = [];
16258
- const warnings = [...initialWarnings];
16259
- for (const { component, inspection } of inspectedComponents) {
16260
- const verdict = hasNoAuthoringSurface(component);
16261
- const keepDespiteZeroSurface = verdict.skip && verdict.reason === "component has no props and no slots" && inspection.keepDespiteZeroSurface;
16262
- const retainedForReview = verdict.skip && !keepDespiteZeroSurface;
16263
- if (retainedForReview) {
16264
- warnings.push(`${component.name}: requires operator review (${verdict.reason})`);
15779
+ function preClassifyComponent(component) {
15780
+ const props = component.props.flatMap((prop) => {
15781
+ const result = preClassifyProp(prop);
15782
+ if (result?.category === "exclude") {
15783
+ return [];
16265
15784
  }
16266
- if (keepDespiteZeroSurface) {
16267
- warnings.push(`${component.name}: retained despite 0 props/slots because the source renders visible or compositional UI`);
15785
+ const { domAttribute: _domAttribute, ...authorableProp } = prop;
15786
+ if (prop.category) {
15787
+ return [authorableProp];
16268
15788
  }
16269
- if (inspection.reviewReasons.length > 0) {
16270
- const reviewNotes = describeReviewReasons(inspection.reviewReasons).filter((note) => note !== "high-confidence data-fetch wrapper").join("; ");
16271
- if (reviewNotes)
16272
- warnings.push(`${component.name}: ${reviewNotes}`);
15789
+ if (!result) {
15790
+ return [authorableProp];
16273
15791
  }
16274
- const extractorReasons = component.reviewReasons ?? [];
16275
- const nonAuthorableReason = retainedForReview ? [`non-authorable:${verdict.reason}`] : [];
16276
- const { confidence, reasons } = computeExtractionScore2(component, {
16277
- additionalIssueCount: wrapperConfidenceToIssueCount(inspection.wrapperConfidence) + extractorReasons.length + nonAuthorableReason.length,
16278
- additionalReasons: [...extractorReasons, ...inspection.reviewReasons, ...nonAuthorableReason]
16279
- });
16280
- scoredComponents.push({
16281
- ...component,
16282
- extractionConfidence: confidence,
16283
- reviewReasons: reasons,
16284
- needsReview: deriveNeedsReview2(confidence) || inspection.wrapperConfidence >= 4 || inspection.keepDespiteZeroSurface || retainedForReview || extractorReasons.includes("props-type-unresolved") || (component.needsReview ?? false)
16285
- });
16286
- }
16287
- return {
16288
- components: validateExtractedComponents2(scoredComponents),
16289
- warnings
16290
- };
15792
+ return [
15793
+ {
15794
+ ...authorableProp,
15795
+ category: result.category
15796
+ }
15797
+ ];
15798
+ });
15799
+ return { ...component, props };
16291
15800
  }
16292
15801
 
16293
15802
  // packages/experience-design-system-backend-pipeline/dist/src/orchestrators/run-extract-and-compose-session/helpers/emit-pre-classification-exclusions.js
@@ -28565,68 +28074,44 @@ function SettingsScreen({
28565
28074
 
28566
28075
  // packages/experience-design-system-cli/src/tui/settings/configuration/ConfigurationScreen.tsx
28567
28076
  import { useState as useState33 } from "react";
28568
- import { Box as Box48, Text as Text51, useInput as useInput13 } from "ink";
28077
+ import { Box as Box48, Text as Text51, useInput as useInput14 } from "ink";
28569
28078
 
28570
28079
  // packages/experience-design-system-cli/src/tui/settings/configuration/agents/AgentsScreen.tsx
28571
- import { useEffect as useEffect23, useState as useState31 } from "react";
28080
+ import { useEffect as useEffect23, useRef as useRef13, useState as useState31 } from "react";
28572
28081
  import { Box as Box46, Text as Text49, useInput as useInput12 } from "ink";
28573
28082
  init_debug_store();
28574
28083
 
28575
- // packages/experience-design-system-cli/src/tui/settings/shared/v1-store.ts
28084
+ // packages/experience-design-system-cli/src/tui/settings/shared/debug-trail.ts
28576
28085
  init_config();
28577
- var readV1Store = readSettings2;
28578
- var writeV1Store = writeSettings2;
28579
-
28580
- // packages/experience-design-system-cli/src/tui/settings/configuration/agents/agent-store.ts
28581
- var AGENT_LABELS = {
28582
- claude: "Claude Code",
28583
- codex: "OpenAI Codex",
28584
- opencode: "OpenCode",
28585
- cursor: "Cursor",
28586
- copilot: "GitHub Copilot"
28587
- };
28588
- var asString = (value) => typeof value === "string" ? value : "";
28589
- function emptyAgents() {
28590
- return Object.fromEntries(AGENT_NAMES.map((name) => [name, { model: "", binary: "" }]));
28086
+ import { existsSync as existsSync10 } from "node:fs";
28087
+ function diffSnapshots(before, after) {
28088
+ const names = [.../* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)])];
28089
+ const changed_fields = names.filter((name) => before[name] !== after[name]);
28090
+ return { changed: changed_fields.length > 0, changed_fields };
28091
+ }
28092
+ var DEFAULT_TRAIL_LIMIT = 30;
28093
+ function createTrail(limit = DEFAULT_TRAIL_LIMIT) {
28094
+ const actions = [];
28095
+ return {
28096
+ record(action) {
28097
+ actions.push(action);
28098
+ if (actions.length > limit) actions.shift();
28099
+ },
28100
+ entries: () => [...actions]
28101
+ };
28591
28102
  }
28592
- async function readAgentConfig() {
28593
- const store = await readV1Store();
28594
- const stored = asString(store["agent"]);
28595
- const defaultChosen = isAgentName(stored);
28596
- const defaultAgent = defaultChosen ? stored : DEFAULT_AGENT_NAME;
28597
- const agents = emptyAgents();
28598
- const saved = store["agents"];
28599
- if (saved && typeof saved === "object") {
28600
- for (const name of AGENT_NAMES) {
28601
- const entry = saved[name];
28602
- if (entry && typeof entry === "object") {
28603
- const fields2 = entry;
28604
- agents[name] = { model: asString(fields2["model"]), binary: asString(fields2["binary"]) };
28605
- }
28606
- }
28103
+ var MIN_SECRET_LENGTH = 6;
28104
+ function scrubError(error, secrets) {
28105
+ let message = error instanceof Error ? error.message : String(error);
28106
+ for (const secret of secrets) {
28107
+ if (secret.length < MIN_SECRET_LENGTH) continue;
28108
+ for (const form of /* @__PURE__ */ new Set([secret, encodeURIComponent(secret)])) message = message.split(form).join("[redacted]");
28607
28109
  }
28608
- const legacyModel = asString(store["agentModel"]);
28609
- if (legacyModel && !agents[defaultAgent].model)
28610
- agents[defaultAgent] = { ...agents[defaultAgent], model: legacyModel };
28611
- return { defaultAgent, defaultChosen, agents };
28110
+ return message;
28612
28111
  }
28613
- async function writeAgentConfig(config) {
28614
- const existing = await readV1Store();
28615
- const merged = { ...existing };
28616
- const agents = {};
28617
- for (const name of AGENT_NAMES) {
28618
- const model = config.agents[name].model.trim();
28619
- const binary = config.agents[name].binary.trim();
28620
- if (model || binary) agents[name] = { ...model ? { model } : {}, ...binary ? { binary } : {} };
28621
- }
28622
- const defaultModel = config.defaultChosen ? agents[config.defaultAgent]?.model : void 0;
28623
- if (config.defaultChosen) merged["agent"] = config.defaultAgent;
28624
- else delete merged["agent"];
28625
- if (defaultModel) merged["agentModel"] = defaultModel;
28626
- else delete merged["agentModel"];
28627
- if (Object.keys(agents).length > 0) merged["agents"] = agents;
28628
- else delete merged["agents"];
28629
- await writeV1Store(merged);
28112
+ function describeSettingsFile() {
28113
+ const path5 = configFilePath2();
28114
+ return { path: path5, eds_home_set: Boolean(process.env["EDS_HOME"]), exists: existsSync10(path5) };
28630
28115
  }
28631
28116
 
28632
28117
  // packages/experience-design-system-cli/src/tui/settings/configuration/agents/agent-status.ts
@@ -28832,6 +28317,94 @@ async function withBinaryEnv(name, binary, run) {
28832
28317
  }
28833
28318
  }
28834
28319
 
28320
+ // packages/experience-design-system-cli/src/tui/settings/configuration/agents/agent-debug.ts
28321
+ function agentSnapshot(config) {
28322
+ const snapshot = { default_agent: config.defaultAgent };
28323
+ for (const name of AGENT_NAMES) {
28324
+ snapshot[`${name}.model`] = config.agents[name].model;
28325
+ snapshot[`${name}.binary`] = config.agents[name].binary;
28326
+ }
28327
+ return snapshot;
28328
+ }
28329
+ function environmentFrom(checks, savedBinary, envValue) {
28330
+ const path5 = checks.find((check) => check.step === "path");
28331
+ const version = checks.find((check) => check.step === "version");
28332
+ const overridden = envValue !== void 0 && envValue !== "" && envValue !== savedBinary.trim();
28333
+ return {
28334
+ found: path5?.ok === true,
28335
+ resolved_path: path5?.ok ? path5.detail : "",
28336
+ version: version?.ok ? version.detail : "",
28337
+ env_override: overridden ? envValue : ""
28338
+ };
28339
+ }
28340
+ async function describeAgents(config) {
28341
+ const entries = await Promise.all(
28342
+ AGENT_NAMES.map(async (name) => {
28343
+ const saved = config.agents[name].binary;
28344
+ const checks = await inspectAgent(name, saved);
28345
+ return [name, environmentFrom(checks, saved, process.env[`EDS_AGENT_BINARY_${name.toUpperCase()}`])];
28346
+ })
28347
+ );
28348
+ return Object.fromEntries(entries);
28349
+ }
28350
+
28351
+ // packages/experience-design-system-cli/src/tui/settings/shared/v1-store.ts
28352
+ init_config();
28353
+ var readV1Store = readSettings2;
28354
+ var writeV1Store = writeSettings2;
28355
+
28356
+ // packages/experience-design-system-cli/src/tui/settings/configuration/agents/agent-store.ts
28357
+ var AGENT_LABELS = {
28358
+ claude: "Claude Code",
28359
+ codex: "OpenAI Codex",
28360
+ opencode: "OpenCode",
28361
+ cursor: "Cursor",
28362
+ copilot: "GitHub Copilot"
28363
+ };
28364
+ var asString = (value) => typeof value === "string" ? value : "";
28365
+ function emptyAgents() {
28366
+ return Object.fromEntries(AGENT_NAMES.map((name) => [name, { model: "", binary: "" }]));
28367
+ }
28368
+ async function readAgentConfig() {
28369
+ const store = await readV1Store();
28370
+ const stored = asString(store["agent"]);
28371
+ const defaultChosen = isAgentName(stored);
28372
+ const defaultAgent = defaultChosen ? stored : DEFAULT_AGENT_NAME;
28373
+ const agents = emptyAgents();
28374
+ const saved = store["agents"];
28375
+ if (saved && typeof saved === "object") {
28376
+ for (const name of AGENT_NAMES) {
28377
+ const entry = saved[name];
28378
+ if (entry && typeof entry === "object") {
28379
+ const fields2 = entry;
28380
+ agents[name] = { model: asString(fields2["model"]), binary: asString(fields2["binary"]) };
28381
+ }
28382
+ }
28383
+ }
28384
+ const legacyModel = asString(store["agentModel"]);
28385
+ if (legacyModel && !agents[defaultAgent].model)
28386
+ agents[defaultAgent] = { ...agents[defaultAgent], model: legacyModel };
28387
+ return { defaultAgent, defaultChosen, agents };
28388
+ }
28389
+ async function writeAgentConfig(config) {
28390
+ const existing = await readV1Store();
28391
+ const merged = { ...existing };
28392
+ const agents = {};
28393
+ for (const name of AGENT_NAMES) {
28394
+ const model = config.agents[name].model.trim();
28395
+ const binary = config.agents[name].binary.trim();
28396
+ if (model || binary) agents[name] = { ...model ? { model } : {}, ...binary ? { binary } : {} };
28397
+ }
28398
+ const defaultModel = config.defaultChosen ? agents[config.defaultAgent]?.model : void 0;
28399
+ if (config.defaultChosen) merged["agent"] = config.defaultAgent;
28400
+ else delete merged["agent"];
28401
+ if (defaultModel) merged["agentModel"] = defaultModel;
28402
+ else delete merged["agentModel"];
28403
+ if (Object.keys(agents).length > 0) merged["agents"] = agents;
28404
+ else delete merged["agents"];
28405
+ await writeV1Store(merged);
28406
+ }
28407
+
28835
28408
  // packages/experience-design-system-cli/src/tui/settings/configuration/agents/AgentDetail.tsx
28836
28409
  import { useEffect as useEffect22, useState as useState30 } from "react";
28837
28410
  import { Box as Box45, Text as Text48 } from "ink";
@@ -29033,7 +28606,8 @@ function AgentDetail({
29033
28606
  name,
29034
28607
  config,
29035
28608
  setConfig,
29036
- onBack
28609
+ onBack,
28610
+ record: record3
29037
28611
  }) {
29038
28612
  const settings = config.agents[name];
29039
28613
  const [saving, setSaving] = useState30(false);
@@ -29056,10 +28630,12 @@ function AgentDetail({
29056
28630
  setNotice(null);
29057
28631
  writeAgentConfig(config).then(() => {
29058
28632
  applyBinaryOverrides(config);
28633
+ record3(`saved ${name}`);
29059
28634
  setNotice({ kind: "success", text: `Saved: ${AGENT_LABELS[name]} settings are written to config.json` });
29060
- }).catch(
29061
- (err) => setNotice({ kind: "error", text: `Not saved: ${err instanceof Error ? err.message : String(err)}` })
29062
- ).finally(() => setSaving(false));
28635
+ }).catch((err) => {
28636
+ record3(`saving ${name} failed`, err);
28637
+ setNotice({ kind: "error", text: `Not saved: ${err instanceof Error ? err.message : String(err)}` });
28638
+ }).finally(() => setSaving(false));
29063
28639
  };
29064
28640
  const runTest = () => {
29065
28641
  setTesting(true);
@@ -29067,12 +28643,15 @@ function AgentDetail({
29067
28643
  testAgent(name, settings.binary, settings.model).then((result) => {
29068
28644
  setChecks(result);
29069
28645
  const outcome = testOutcome(result);
28646
+ if (!outcome || !outcome.ok)
28647
+ record3(`test of ${name} failed: ${outcome?.text ?? "the agent could not be started"}`);
29070
28648
  setNotice(
29071
28649
  outcome ? { kind: outcome.ok ? "success" : "error", text: outcome.text } : { kind: "error", text: "Test not run: the agent could not be started (see Status)" }
29072
28650
  );
29073
- }).catch(
29074
- (err) => setNotice({ kind: "error", text: `Test could not run: ${err instanceof Error ? err.message : String(err)}` })
29075
- ).finally(() => setTesting(false));
28651
+ }).catch((err) => {
28652
+ record3(`test of ${name} could not run`, err);
28653
+ setNotice({ kind: "error", text: `Test could not run: ${err instanceof Error ? err.message : String(err)}` });
28654
+ }).finally(() => setTesting(false));
29076
28655
  };
29077
28656
  const action = {
29078
28657
  label: "Run test",
@@ -29093,6 +28672,7 @@ function AgentDetail({
29093
28672
  onChange: (key, value) => {
29094
28673
  setConfig({ ...config, agents: { ...config.agents, [name]: { ...settings, [key]: value } } });
29095
28674
  setNotice(null);
28675
+ record3(`edited ${name}.${key}`);
29096
28676
  },
29097
28677
  onSave: save,
29098
28678
  onQuit: onBack,
@@ -29119,6 +28699,12 @@ function AgentsScreen({ onDone }) {
29119
28699
  const [saving, setSaving] = useState31(false);
29120
28700
  const [loadError, setLoadError] = useState31(null);
29121
28701
  const [checks, setChecks] = useState31({});
28702
+ const visit = useRef13({
28703
+ trail: createTrail(),
28704
+ before: void 0,
28705
+ environment: void 0,
28706
+ error: ""
28707
+ }).current;
29122
28708
  const inspectAll = (loaded) => {
29123
28709
  for (const name of AGENT_NAMES) {
29124
28710
  void inspectAgent(name, loaded.agents[name].binary).then(
@@ -29130,14 +28716,38 @@ function AgentsScreen({ onDone }) {
29130
28716
  readAgentConfig().then((loaded) => {
29131
28717
  setConfig(loaded);
29132
28718
  inspectAll(loaded);
28719
+ visit.before = agentSnapshot(loaded);
29133
28720
  startDebugRun({
29134
28721
  flow: "settings/agents",
29135
28722
  step: "01-agents",
29136
28723
  menuOption: "Configuration > Agents",
29137
- inputs: { default_agent: loaded.defaultAgent }
28724
+ inputs: { ...visit.before, default_chosen: loaded.defaultChosen ?? false }
29138
28725
  });
29139
- }).catch((err) => setLoadError(err instanceof Error ? err.message : String(err)));
28726
+ void describeAgents(loaded).then((found) => {
28727
+ visit.environment = found;
28728
+ });
28729
+ }).catch((err) => {
28730
+ visit.error = scrubError(err, []);
28731
+ startDebugRun({ flow: "settings/agents", step: "01-agents", menuOption: "Configuration > Agents", inputs: {} });
28732
+ setLoadError(visit.error);
28733
+ });
29140
28734
  }, []);
28735
+ const endVisit = (current) => {
28736
+ const after = current ? agentSnapshot(current) : void 0;
28737
+ const change = visit.before && after ? diffSnapshots(visit.before, after) : { changed: false, changed_fields: [] };
28738
+ void finishDebugRun({
28739
+ outputs: {
28740
+ ...after ?? {},
28741
+ ...change,
28742
+ actions: visit.trail.entries(),
28743
+ // Missing only when the user left before the probes finished.
28744
+ ...visit.environment ? { agents: visit.environment } : {},
28745
+ ...visit.error ? { error: visit.error } : {}
28746
+ },
28747
+ status: visit.error ? "error" : "success",
28748
+ exitMethod: change.changed ? "saved" : "discarded"
28749
+ });
28750
+ };
29141
28751
  const makeDefault = (name) => {
29142
28752
  if (!config || saving) return;
29143
28753
  if (name === config.defaultAgent) {
@@ -29149,15 +28759,16 @@ function AgentsScreen({ onDone }) {
29149
28759
  writeAgentConfig({ ...config, defaultAgent: name, defaultChosen: true }).then(() => {
29150
28760
  setConfig((current) => current ? { ...current, defaultAgent: name, defaultChosen: true } : current);
29151
28761
  setNotice({ kind: "success", text: `Default agent is now ${AGENT_LABELS[name]}` });
29152
- }).catch(
29153
- (err) => setNotice({
29154
- kind: "error",
29155
- text: `Default agent not changed: ${err instanceof Error ? err.message : String(err)}`
29156
- })
29157
- ).finally(() => setSaving(false));
28762
+ visit.trail.record(`made ${name} the default`);
28763
+ }).catch((err) => {
28764
+ visit.error = scrubError(err, []);
28765
+ visit.trail.record(`making ${name} the default failed`);
28766
+ setNotice({ kind: "error", text: `Default agent not changed: ${visit.error}` });
28767
+ }).finally(() => setSaving(false));
29158
28768
  };
29159
28769
  useInput12((input, key) => {
29160
28770
  if (loadError && (key.escape || input === "q")) {
28771
+ endVisit(null);
29161
28772
  onDone();
29162
28773
  return;
29163
28774
  }
@@ -29182,7 +28793,7 @@ function AgentsScreen({ onDone }) {
29182
28793
  return;
29183
28794
  }
29184
28795
  if (key.escape || input === "q") {
29185
- void finishDebugRun({ outputs: { default_agent: config.defaultAgent }, status: "success", exitMethod: "saved" });
28796
+ endVisit(config);
29186
28797
  onDone();
29187
28798
  }
29188
28799
  });
@@ -29207,6 +28818,10 @@ function AgentsScreen({ onDone }) {
29207
28818
  name: open,
29208
28819
  config,
29209
28820
  setConfig,
28821
+ record: (action, error) => {
28822
+ visit.trail.record(action);
28823
+ if (error !== void 0) visit.error = scrubError(error, []);
28824
+ },
29210
28825
  onBack: () => {
29211
28826
  setOpen(null);
29212
28827
  void readAgentConfig().then((saved) => {
@@ -29273,8 +28888,8 @@ function AgentsScreen({ onDone }) {
29273
28888
  }
29274
28889
 
29275
28890
  // packages/experience-design-system-cli/src/tui/settings/configuration/project/ProjectScreen.tsx
29276
- import { useEffect as useEffect24, useState as useState32 } from "react";
29277
- import { Box as Box47, Text as Text50 } from "ink";
28891
+ import { useEffect as useEffect24, useRef as useRef14, useState as useState32 } from "react";
28892
+ import { Box as Box47, Text as Text50, useInput as useInput13 } from "ink";
29278
28893
  init_debug_store();
29279
28894
 
29280
28895
  // packages/experience-design-system-cli/src/tui/settings/configuration/project/project-store.ts
@@ -29303,7 +28918,7 @@ async function writeCredentials(config) {
29303
28918
  }
29304
28919
 
29305
28920
  // packages/experience-design-system-cli/src/tui/settings/configuration/project/ProjectScreen.tsx
29306
- import { jsx as jsx59, jsxs as jsxs48 } from "react/jsx-runtime";
28921
+ import { Fragment as Fragment19, jsx as jsx59, jsxs as jsxs48 } from "react/jsx-runtime";
29307
28922
  var FIELDS2 = [
29308
28923
  { key: "spaceId", label: "Space ID" },
29309
28924
  { key: "environmentId", label: "Environment ID" },
@@ -29324,45 +28939,94 @@ function debugFields(config) {
29324
28939
  contentful_base_dir: config?.contentfulBaseDir ?? ""
29325
28940
  };
29326
28941
  }
28942
+ var snapshotOf = (config) => Object.fromEntries(FIELDS2.map(({ key }) => [key, config[key] || ""]));
29327
28943
  var valuesOf = (config) => Object.fromEntries(FIELDS2.map(({ key }) => [key, config[key] || ""]));
29328
28944
  function ProjectScreen({ onDone }) {
29329
28945
  const [config, setConfig] = useState32(null);
29330
28946
  const [saving, setSaving] = useState32(false);
29331
28947
  const [notice, setNotice] = useState32(null);
29332
- const [lastSaved, setLastSaved] = useState32(null);
28948
+ const [loadError, setLoadError] = useState32(null);
28949
+ const visit = useRef14({
28950
+ trail: createTrail(),
28951
+ before: void 0,
28952
+ persisted: void 0,
28953
+ error: ""
28954
+ }).current;
28955
+ const scrub = (err) => scrubError(err, [config?.cmaToken ?? ""]);
29333
28956
  useEffect24(() => {
29334
- void readCredentials().then((cfg) => {
28957
+ readCredentials().then((cfg) => {
29335
28958
  setConfig(cfg);
28959
+ visit.before = snapshotOf(cfg);
28960
+ visit.persisted = visit.before;
28961
+ startDebugRun({
28962
+ flow: "settings/contentful-configuration",
28963
+ step: "01-configuration",
28964
+ menuOption: "Configuration > Project",
28965
+ inputs: { ...debugFields(cfg), settings_file: describeSettingsFile() }
28966
+ });
28967
+ }).catch((err) => {
28968
+ visit.error = scrubError(err, []);
29336
28969
  startDebugRun({
29337
28970
  flow: "settings/contentful-configuration",
29338
28971
  step: "01-configuration",
29339
28972
  menuOption: "Configuration > Project",
29340
- inputs: debugFields(cfg)
28973
+ inputs: { settings_file: describeSettingsFile() }
29341
28974
  });
28975
+ setLoadError(visit.error);
29342
28976
  });
29343
28977
  }, []);
28978
+ const endVisit = (current) => {
28979
+ const onScreen = current ? snapshotOf(current) : void 0;
28980
+ const change = visit.before && visit.persisted ? diffSnapshots(visit.before, visit.persisted) : { changed: false, changed_fields: [] };
28981
+ const unsaved = visit.persisted && onScreen ? diffSnapshots(visit.persisted, onScreen) : { changed: false, changed_fields: [] };
28982
+ void finishDebugRun({
28983
+ outputs: {
28984
+ ...debugFields(current),
28985
+ ...change,
28986
+ unsaved_edits: unsaved.changed_fields,
28987
+ actions: visit.trail.entries(),
28988
+ ...visit.error ? { error: visit.error } : {}
28989
+ },
28990
+ status: visit.error ? "error" : "success",
28991
+ exitMethod: change.changed ? "saved" : "discarded"
28992
+ });
28993
+ };
28994
+ useInput13((input, key) => {
28995
+ if (!config && loadError && (key.escape || input === "q")) {
28996
+ endVisit(null);
28997
+ onDone();
28998
+ }
28999
+ });
29344
29000
  if (!config) {
29345
29001
  return /* @__PURE__ */ jsxs48(Box47, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
29346
29002
  /* @__PURE__ */ jsx59(Text50, { bold: true, children: "Project" }),
29347
29003
  /* @__PURE__ */ jsx59(Text50, { children: " " }),
29348
- /* @__PURE__ */ jsx59(Text50, { color: PALETTE.accent, children: "Loading..." })
29004
+ loadError ? /* @__PURE__ */ jsxs48(Fragment19, { children: [
29005
+ /* @__PURE__ */ jsxs48(Text50, { color: PALETTE.error, children: [
29006
+ "\u2717 Could not read the settings: ",
29007
+ loadError
29008
+ ] }),
29009
+ /* @__PURE__ */ jsx59(Text50, { children: " " }),
29010
+ /* @__PURE__ */ jsx59(ControlHints, { hints: [{ keys: "Esc/q", label: "back" }] })
29011
+ ] }) : /* @__PURE__ */ jsx59(Text50, { color: PALETTE.accent, children: "Loading..." })
29349
29012
  ] });
29350
29013
  }
29351
29014
  const save = () => {
29352
29015
  setSaving(true);
29353
29016
  setNotice(null);
29354
29017
  writeCredentials(config).then(() => {
29355
- setLastSaved(config);
29018
+ visit.persisted = snapshotOf(config);
29019
+ visit.trail.record("saved");
29356
29020
  if (config.contentfulBaseDir) void startDebugSessionIn(config.contentfulBaseDir, { replace: true });
29357
29021
  setNotice({ kind: "success", text: "Project settings saved" });
29358
29022
  }).catch((err) => {
29023
+ visit.error = scrub(err);
29024
+ visit.trail.record("save failed");
29359
29025
  setNotice({ kind: "error", text: err instanceof Error ? err.message : "Failed to save" });
29360
29026
  }).finally(() => setSaving(false));
29361
29027
  };
29362
29028
  const quit = () => {
29363
- void finishDebugRun(
29364
- lastSaved ? { outputs: debugFields(lastSaved), status: "success", exitMethod: "saved" } : { outputs: {}, status: "success", exitMethod: "discarded" }
29365
- );
29029
+ endVisit(config);
29366
29030
  onDone();
29367
29031
  };
29368
29032
  return /* @__PURE__ */ jsx59(
@@ -29375,6 +29039,7 @@ function ProjectScreen({ onDone }) {
29375
29039
  onChange: (key, value) => {
29376
29040
  setConfig({ ...config, [key]: value });
29377
29041
  setNotice(null);
29042
+ visit.trail.record(`edited ${key}`);
29378
29043
  },
29379
29044
  onSave: save,
29380
29045
  onQuit: quit,
@@ -29398,7 +29063,7 @@ function ConfigurationScreen({ onDone }) {
29398
29063
  const [focus, setFocus] = useState33(0);
29399
29064
  const [open, setOpen] = useState33(null);
29400
29065
  const close = () => setOpen(null);
29401
- useInput13((input, key) => {
29066
+ useInput14((input, key) => {
29402
29067
  if (open) return;
29403
29068
  if (key.upArrow) {
29404
29069
  setFocus((i) => (i - 1 + SECTIONS.length) % SECTIONS.length);
@@ -29440,7 +29105,7 @@ function ConfigurationScreen({ onDone }) {
29440
29105
 
29441
29106
  // packages/experience-design-system-cli/src/tui/settings/opt-in-analytics/screen.tsx
29442
29107
  import { useEffect as useEffect25, useState as useState34 } from "react";
29443
- import { Box as Box49, Text as Text52, useInput as useInput14 } from "ink";
29108
+ import { Box as Box49, Text as Text52, useInput as useInput15 } from "ink";
29444
29109
 
29445
29110
  // packages/experience-design-system-cli/src/tui/settings/opt-in-analytics/analytics-store.ts
29446
29111
  async function readAnalyticsSetting() {
@@ -29459,7 +29124,7 @@ async function writeAnalyticsSetting(setting) {
29459
29124
 
29460
29125
  // packages/experience-design-system-cli/src/tui/settings/opt-in-analytics/screen.tsx
29461
29126
  init_debug_store();
29462
- import { Fragment as Fragment19, jsx as jsx61, jsxs as jsxs50 } from "react/jsx-runtime";
29127
+ import { Fragment as Fragment20, jsx as jsx61, jsxs as jsxs50 } from "react/jsx-runtime";
29463
29128
  function OptInAnalyticsScreen({ onDone }) {
29464
29129
  const [loading, setLoading] = useState34(true);
29465
29130
  const [enabled, setEnabled] = useState34(true);
@@ -29475,7 +29140,7 @@ function OptInAnalyticsScreen({ onDone }) {
29475
29140
  });
29476
29141
  });
29477
29142
  }, []);
29478
- useInput14((input, key) => {
29143
+ useInput15((input, key) => {
29479
29144
  if (loading) return;
29480
29145
  if (key.return || input === " ") {
29481
29146
  setEnabled((current) => {
@@ -29493,7 +29158,7 @@ function OptInAnalyticsScreen({ onDone }) {
29493
29158
  return /* @__PURE__ */ jsxs50(Box49, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
29494
29159
  /* @__PURE__ */ jsx61(Text52, { bold: true, children: "Settings \u203A Opt-in Analytics" }),
29495
29160
  /* @__PURE__ */ jsx61(Text52, { children: " " }),
29496
- loading ? /* @__PURE__ */ jsx61(Text52, { color: PALETTE.muted, children: "Loading\u2026" }) : /* @__PURE__ */ jsxs50(Fragment19, { children: [
29161
+ loading ? /* @__PURE__ */ jsx61(Text52, { color: PALETTE.muted, children: "Loading\u2026" }) : /* @__PURE__ */ jsxs50(Fragment20, { children: [
29497
29162
  /* @__PURE__ */ jsxs50(Text52, { children: [
29498
29163
  "Share anonymous usage data:",
29499
29164
  " ",
@@ -29518,7 +29183,7 @@ function OptInAnalyticsScreen({ onDone }) {
29518
29183
 
29519
29184
  // packages/experience-design-system-cli/src/tui/settings/debug-mode/screen.tsx
29520
29185
  import { useEffect as useEffect26, useState as useState35 } from "react";
29521
- import { Box as Box50, Text as Text53, useInput as useInput15 } from "ink";
29186
+ import { Box as Box50, Text as Text53, useInput as useInput16 } from "ink";
29522
29187
  init_debug_mode_store();
29523
29188
  init_debug_store();
29524
29189
  import { jsx as jsx62, jsxs as jsxs51 } from "react/jsx-runtime";
@@ -29537,7 +29202,7 @@ function DebugModeScreen({ onDone }) {
29537
29202
  });
29538
29203
  });
29539
29204
  }, []);
29540
- useInput15((input, key) => {
29205
+ useInput16((input, key) => {
29541
29206
  if (loading) return;
29542
29207
  if (key.return || input === " ") {
29543
29208
  setEnabled((current) => {
@@ -29574,7 +29239,7 @@ function DebugModeScreen({ onDone }) {
29574
29239
  }
29575
29240
 
29576
29241
  // packages/experience-design-system-cli/app.tsx
29577
- import { Fragment as Fragment20, jsx as jsx63 } from "react/jsx-runtime";
29242
+ import { Fragment as Fragment21, jsx as jsx63 } from "react/jsx-runtime";
29578
29243
  function App({ importOptions, inkClear }) {
29579
29244
  const [screen, setScreen] = useState36("start");
29580
29245
  const [importExitCode, setImportExitCode] = useState36();
@@ -29743,7 +29408,7 @@ function App({ importOptions, inkClear }) {
29743
29408
  }
29744
29409
  );
29745
29410
  }
29746
- if (importDefaults === void 0) return /* @__PURE__ */ jsx63(Fragment20, {});
29411
+ if (importDefaults === void 0) return /* @__PURE__ */ jsx63(Fragment21, {});
29747
29412
  if (projectPath === void 0) {
29748
29413
  return /* @__PURE__ */ jsx63(WelcomeScreen, { onContinue: setProjectPath, onQuit: leaveImport, initialPath: importDefaults.componentDir });
29749
29414
  }
@@ -29782,7 +29447,7 @@ function App({ importOptions, inkClear }) {
29782
29447
  }
29783
29448
  );
29784
29449
  }
29785
- return /* @__PURE__ */ jsx63(Fragment20, {});
29450
+ return /* @__PURE__ */ jsx63(Fragment21, {});
29786
29451
  }
29787
29452
  if (scopeRun && scopeFlow) {
29788
29453
  if (scopeFlow.status === "failed") {
@@ -29819,7 +29484,7 @@ function App({ importOptions, inkClear }) {
29819
29484
  }
29820
29485
  );
29821
29486
  }
29822
- return /* @__PURE__ */ jsx63(Fragment20, {});
29487
+ return /* @__PURE__ */ jsx63(Fragment21, {});
29823
29488
  }
29824
29489
  if (pendingLaunch?.cached) {
29825
29490
  return /* @__PURE__ */ jsx63(