@astryxdesign/cli 0.6.3-canary.f22695a → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/README.md +1 -2
  2. package/api/build/build.type.d.mts +2 -2
  3. package/api/build/build.type.mjs +2 -2
  4. package/api/component/component.type.d.mts +6 -6
  5. package/api/component/component.type.mjs +19 -19
  6. package/api/discover/discover.type.d.mts +4 -4
  7. package/api/discover/discover.type.mjs +10 -10
  8. package/api/docs/_adapter.d.mts +24 -37
  9. package/api/docs/_adapter.mjs +83 -169
  10. package/api/docs/detail/detail.mjs +63 -14
  11. package/api/docs/detail/section/section.d.mts +1 -1
  12. package/api/docs/detail/section/section.mjs +20 -44
  13. package/api/docs/detail/section/section.test.mjs +0 -41
  14. package/api/docs/docs.d.mts +2 -7
  15. package/api/docs/docs.doc.mjs +10 -27
  16. package/api/docs/docs.mjs +9 -16
  17. package/api/docs/docs.test.mjs +0 -6
  18. package/api/docs/docs.type.d.mts +3 -40
  19. package/api/docs/docs.type.mjs +8 -36
  20. package/api/docs/integrationDocs.test.mjs +0 -106
  21. package/api/doctor/doctor.d.mts +0 -48
  22. package/api/doctor/doctor.mjs +0 -232
  23. package/api/doctor/doctor.test.mjs +0 -196
  24. package/api/hook/hook.type.d.mts +3 -3
  25. package/api/hook/hook.type.mjs +11 -11
  26. package/api/hook/list/list.d.mts +1 -1
  27. package/api/integration/add-contribution.mjs +3 -5
  28. package/api/integration/add-contribution.test.mjs +4 -4
  29. package/api/integration/integration-authoring.type.d.mts +1 -1
  30. package/api/integration/pack-check.mjs +7 -49
  31. package/api/integration/pack-check.test.mjs +0 -249
  32. package/api/search/search.d.mts +1 -1
  33. package/api/search/search.mjs +5 -5
  34. package/api/search/search.type.d.mts +2 -2
  35. package/api/search/search.type.mjs +1 -1
  36. package/api/swizzle/swizzle.type.d.mts +2 -2
  37. package/api/swizzle/swizzle.type.mjs +2 -2
  38. package/api/template/template.d.mts +1 -1
  39. package/api/template/template.type.d.mts +6 -6
  40. package/api/template/template.type.mjs +12 -12
  41. package/api/theme/build/build.mjs +6 -20
  42. package/api/theme/build/build.test.mjs +0 -127
  43. package/api/theme/palette/generate/generate.mjs +1 -1
  44. package/api/theme/palette/generate/generator.d.mts +13 -10
  45. package/api/theme/palette/generate/generator.mjs +3 -7
  46. package/api/theme/theme.type.d.mts +11 -170
  47. package/api/theme/theme.type.mjs +27 -94
  48. package/api/upgrade/_adapter.mjs +5 -71
  49. package/api/upgrade/upgrade.doc.mjs +3 -4
  50. package/api/upgrade/upgrade.type.d.mts +5 -5
  51. package/api/upgrade/upgrade.type.mjs +11 -11
  52. package/assets/codemods/integration-discovery.mjs +2 -40
  53. package/assets/codemods/integration-discovery.test.mjs +0 -58
  54. package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +5 -27
  55. package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +5 -20
  56. package/assets/docs/README.md +0 -9
  57. package/assets/docs/cli-integrations.doc.mjs +15 -86
  58. package/assets/docs/styling-libraries.doc.mjs +1 -1
  59. package/assets/docs/working-with-ai.doc.mjs +1 -1
  60. package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.doc.mjs +3 -19
  61. package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +65 -383
  62. package/authoring/_shared/contract.ts +0 -22
  63. package/authoring/codemod/codemod.doc.mjs +1 -6
  64. package/authoring/codemod/parse.d.mts +8 -8
  65. package/authoring/codemod/parse.mjs +6 -8
  66. package/authoring/config/parse.d.mts +13 -13
  67. package/authoring/config/parse.mjs +8 -8
  68. package/authoring/config/type.ts +3 -3
  69. package/authoring/debug/parse.d.mts +5 -5
  70. package/authoring/debug/parse.mjs +3 -3
  71. package/authoring/doctypes/_schema.d.mts +23 -788
  72. package/authoring/doctypes/_schema.mjs +39 -492
  73. package/authoring/doctypes/base/type.ts +0 -40
  74. package/authoring/doctypes/command/command.doc.mjs +2 -3
  75. package/authoring/doctypes/command/parse.d.mts +2 -2
  76. package/authoring/doctypes/command/parse.mjs +1 -1
  77. package/authoring/doctypes/command/type.ts +2 -3
  78. package/authoring/doctypes/component/component.doc.mjs +3 -6
  79. package/authoring/doctypes/component/parse.d.mts +2 -2
  80. package/authoring/doctypes/component/parse.mjs +1 -1
  81. package/authoring/doctypes/component/type.ts +3 -4
  82. package/authoring/doctypes/enum/parse.d.mts +2 -2
  83. package/authoring/doctypes/enum/parse.mjs +1 -1
  84. package/authoring/doctypes/enum/type.ts +1 -3
  85. package/authoring/doctypes/function/function.doc.mjs +0 -4
  86. package/authoring/doctypes/function/parse.d.mts +2 -2
  87. package/authoring/doctypes/function/parse.mjs +1 -1
  88. package/authoring/doctypes/function/type.ts +2 -6
  89. package/authoring/doctypes/hook/hook.doc.mjs +0 -4
  90. package/authoring/doctypes/hook/parse.d.mts +2 -2
  91. package/authoring/doctypes/hook/parse.mjs +1 -1
  92. package/authoring/doctypes/hook/type.ts +2 -3
  93. package/authoring/doctypes/legacy.d.mts +6 -8
  94. package/authoring/doctypes/legacy.mjs +4 -5
  95. package/authoring/doctypes/parse.d.mts +18 -20
  96. package/authoring/doctypes/parse.mjs +10 -16
  97. package/authoring/doctypes/parse.test.mjs +3 -77
  98. package/authoring/doctypes/reference/parse.d.mts +2 -2
  99. package/authoring/doctypes/reference/parse.mjs +5 -8
  100. package/authoring/doctypes/reference/reference.doc.mjs +4 -17
  101. package/authoring/doctypes/reference/type.ts +5 -51
  102. package/authoring/doctypes/schema/parse.d.mts +2 -2
  103. package/authoring/doctypes/schema/parse.mjs +1 -1
  104. package/authoring/doctypes/schema/type.ts +2 -3
  105. package/authoring/doctypes/template/parse.d.mts +1 -92
  106. package/authoring/doctypes/template/parse.mjs +2 -36
  107. package/authoring/doctypes/template/parse.test.mjs +2 -8
  108. package/authoring/doctypes/template/template.doc.mjs +0 -4
  109. package/authoring/doctypes/template/type.ts +2 -5
  110. package/authoring/doctypes/types.ts +9 -10
  111. package/authoring/gap-report/parse.d.mts +10 -10
  112. package/authoring/gap-report/parse.mjs +6 -6
  113. package/authoring/gap-report/type.ts +1 -1
  114. package/authoring/index.d.mts +0 -1
  115. package/authoring/index.d.ts +17 -49
  116. package/authoring/index.mjs +0 -1
  117. package/authoring/integration/integration.doc.mjs +6 -13
  118. package/authoring/integration/parse.d.mts +2 -2
  119. package/authoring/integration/parse.mjs +1 -1
  120. package/authoring/integration/parse.test.mjs +1 -10
  121. package/authoring/integration/schema.d.mts +4 -6
  122. package/authoring/integration/schema.mjs +3 -9
  123. package/authoring/integration/type.ts +6 -23
  124. package/authoring/shadcn/receipt.d.mts +6 -6
  125. package/clients/cli/commands/docs.doc.mjs +3 -13
  126. package/clients/cli/commands/docs.mjs +21 -121
  127. package/clients/cli/commands/docs.test.mjs +0 -88
  128. package/clients/cli/commands/integration-authoring.test.mjs +9 -13
  129. package/clients/cli/commands/theme-palette-generate.doc.mjs +4 -8
  130. package/clients/cli/commands/upgrade.doc.mjs +2 -2
  131. package/clients/cli/formatters/index.mjs +1 -162
  132. package/clients/cli/formatters/index.test.mjs +0 -91
  133. package/clients/cli/lib/manifest.mjs +2 -7
  134. package/foundation/config/project.mjs +6 -21
  135. package/foundation/discovery/component-discovery.d.mts +1 -1
  136. package/foundation/discovery/component-discovery.mjs +1 -2
  137. package/foundation/discovery/docs-discovery.d.mts +4 -11
  138. package/foundation/discovery/docs-discovery.mjs +88 -208
  139. package/foundation/discovery/docs-discovery.test.mjs +13 -279
  140. package/foundation/discovery/template-adapter.mjs +1 -2
  141. package/foundation/integrations/autolink.mjs +5 -12
  142. package/foundation/integrations/integration-warnings.mjs +0 -6
  143. package/foundation/integrations/integrations.d.mts +2 -46
  144. package/foundation/integrations/integrations.mjs +8 -167
  145. package/foundation/integrations/integrations.test.mjs +1 -384
  146. package/foundation/integrations/validate-contributions.d.mts +0 -2
  147. package/foundation/integrations/validate-contributions.mjs +0 -10
  148. package/foundation/response/json-contract.test.mjs +17 -46
  149. package/foundation/response/response-types.doc.mjs +1 -6
  150. package/package.json +11 -9
  151. package/api/docs/compiled-topics.test.mjs +0 -78
  152. package/api/docs/index/index.d.mts +0 -18
  153. package/api/docs/index/index.mjs +0 -32
  154. package/api/docs/index/index.test.mjs +0 -62
  155. package/api/upgrade/project-context.test.mjs +0 -272
  156. package/assets/docs/authoring.doc.mjs +0 -14
  157. package/assets/templates/blocks/components/Timer/TimerFormats.doc.mjs +0 -14
  158. package/assets/templates/blocks/components/Timer/TimerFormats.tsx +0 -34
  159. package/assets/templates/blocks/components/Timer/TimerInline.doc.mjs +0 -14
  160. package/assets/templates/blocks/components/Timer/TimerInline.tsx +0 -14
  161. package/assets/templates/blocks/components/Timer/TimerShowcase.doc.mjs +0 -13
  162. package/assets/templates/blocks/components/Timer/TimerShowcase.tsx +0 -47
  163. package/assets/templates/blocks/components/Timer/TimerTypography.doc.mjs +0 -14
  164. package/assets/templates/blocks/components/Timer/TimerTypography.tsx +0 -31
  165. package/authoring/doctypes/base/graph-fields.doc.d.mts +0 -9
  166. package/authoring/doctypes/base/graph-fields.doc.mjs +0 -62
  167. package/authoring/doctypes/load-contract.test.mjs +0 -207
  168. package/authoring/doctypes/namespace/namespace.doc.d.mts +0 -9
  169. package/authoring/doctypes/namespace/namespace.doc.mjs +0 -132
  170. package/authoring/doctypes/namespace/parse.d.mts +0 -12
  171. package/authoring/doctypes/namespace/parse.mjs +0 -25
  172. package/authoring/doctypes/namespace/parse.test.mjs +0 -165
  173. package/authoring/doctypes/namespace/type.ts +0 -71
  174. package/authoring/identity/identity.doc.d.mts +0 -9
  175. package/authoring/identity/identity.doc.mjs +0 -61
  176. package/authoring/identity/type.ts +0 -132
  177. package/foundation/discovery/authoring-self-docs.d.mts +0 -69
  178. package/foundation/discovery/authoring-self-docs.mjs +0 -214
  179. package/foundation/discovery/authoring-self-docs.test.mjs +0 -154
  180. package/foundation/discovery/docs-output-budget.d.mts +0 -28
  181. package/foundation/discovery/docs-output-budget.mjs +0 -50
  182. package/foundation/discovery/docs-section-key.d.mts +0 -98
  183. package/foundation/discovery/docs-section-key.mjs +0 -221
  184. package/foundation/discovery/docs-section-key.test.mjs +0 -224
  185. package/foundation/doc-compiler/compile.d.mts +0 -162
  186. package/foundation/doc-compiler/compile.mjs +0 -262
  187. package/foundation/doc-compiler/doc-compiler.test.mjs +0 -687
  188. package/foundation/doc-compiler/ir.d.mts +0 -9
  189. package/foundation/doc-compiler/ir.mjs +0 -287
  190. package/foundation/doc-compiler/lenses.d.mts +0 -33
  191. package/foundation/doc-compiler/lenses.mjs +0 -127
  192. package/foundation/identity/provider-identity.d.mts +0 -90
  193. package/foundation/identity/provider-identity.mjs +0 -320
  194. package/foundation/identity/provider-identity.test.mjs +0 -254
  195. package/foundation/identity/providers.d.mts +0 -7
  196. package/foundation/identity/providers.mjs +0 -16
  197. package/foundation/integrations/provider-conflicts.test.mjs +0 -125
@@ -388,14 +388,6 @@ async function validatePackedComponentExports(integration, scratchBase) {
388
388
  components.map(component => component.specifier),
389
389
  scratchBase,
390
390
  );
391
- issues.push(
392
- ...validateSpecifierExtensions(
393
- components.map(({name, specifier}) => ({
394
- label: `Component "${name}"`,
395
- specifier,
396
- })),
397
- ),
398
- );
399
391
  for (const {name, specifier} of components) {
400
392
  const result = resolved.get(specifier);
401
393
  if (!result?.url || result.error) {
@@ -435,27 +427,19 @@ async function validatePackedComponentExports(integration, scratchBase) {
435
427
  */
436
428
  async function validatePackedTemplateExports(integration, scratchBase) {
437
429
  const {templates} = await discoverIntegrationTemplatesForOne(integration);
438
- const entries = templates.map(template => {
439
- const relPath = path
430
+ const entries = templates.map(template => ({
431
+ id: template.dirName,
432
+ specifier: `${integration.name}/${path
440
433
  .relative(integration.__packageDir, template.filePath)
441
434
  .split(path.sep)
442
- .join('/');
443
- const extensionless = relPath.replace(/\.tsx?$/u, '');
444
- return {
445
- id: template.dirName,
446
- specifier: `${integration.name}/${extensionless}`,
447
- };
448
- });
435
+ .join('/')}`,
436
+ }));
449
437
  const resolved = resolveConsumerSpecifiers(
450
438
  entries.map(entry => entry.specifier),
451
439
  scratchBase,
452
440
  );
453
- const issues = validateSpecifierExtensions(
454
- entries.map(({id, specifier}) => ({
455
- label: `Template "${id}"`,
456
- specifier,
457
- })),
458
- );
441
+ /** @type {Issue[]} */
442
+ const issues = [];
459
443
  for (const {id, specifier} of entries) {
460
444
  const result = resolved.get(specifier);
461
445
  if (!result?.url || result.error) {
@@ -485,32 +469,6 @@ async function validatePackedTemplateExports(integration, scratchBase) {
485
469
  return issues;
486
470
  }
487
471
 
488
- const TS_EXTENSION_RE = /\.tsx?$/u;
489
-
490
- /**
491
- * Reject specifiers that end in a TypeScript extension — they fail under
492
- * default `moduleResolution` with TS5097/TS2307 unless the consumer enables
493
- * `allowImportingTsExtensions`.
494
- *
495
- * @param {Array<{label: string, specifier: string}>} entries
496
- * @returns {Issue[]}
497
- */
498
- function validateSpecifierExtensions(entries) {
499
- /** @type {Issue[]} */
500
- const issues = [];
501
- for (const {label, specifier} of entries) {
502
- if (TS_EXTENSION_RE.test(specifier)) {
503
- issues.push(
504
- error(
505
- 'typescript_extension_in_specifier',
506
- `${label} advertises import "${specifier}", which ends in a TypeScript extension. A consumer with default moduleResolution will reject it (TS5097). Use an extensionless specifier mapped through the package exports.`,
507
- ),
508
- );
509
- }
510
- }
511
- return issues;
512
- }
513
-
514
472
  /**
515
473
  * Verify an integration package is ready to publish.
516
474
  *
@@ -567,252 +567,3 @@ describe('pack-check mutation tests', () => {
567
567
  }
568
568
  });
569
569
  });
570
-
571
- describe('extensionless subpath resolution', () => {
572
- it('rejects .tsx public specifiers before publishing', async () => {
573
- // Manually construct a package with OLD-style .tsx exports keys
574
- writePackage({
575
- manifest: "export default {components: './components'};\n",
576
- files: ['astryx.integration.mjs', 'components', 'index.mjs'],
577
- themes: false,
578
- });
579
- const pkgFile = path.join(tmpDir, 'package.json');
580
- const pkg = JSON.parse(fs.readFileSync(pkgFile, 'utf-8'));
581
- pkg.exports = {
582
- '.': './index.mjs',
583
- './components/AcmeWidget.tsx': './components/AcmeWidget.tsx',
584
- };
585
- fs.writeFileSync(pkgFile, `${JSON.stringify(pkg, null, 2)}\n`);
586
- fs.writeFileSync(
587
- path.join(tmpDir, 'index.mjs'),
588
- 'export const existing = 1;\n',
589
- );
590
- fs.mkdirSync(path.join(tmpDir, 'components'));
591
- fs.writeFileSync(
592
- path.join(tmpDir, 'components', 'AcmeWidget.doc.mjs'),
593
- `export default {type: 'component', name: 'AcmeWidget', import: '@acme/widgets/components/AcmeWidget.tsx', description: 'Widget.', props: []};\n`,
594
- );
595
- fs.writeFileSync(
596
- path.join(tmpDir, 'components', 'AcmeWidget.tsx'),
597
- 'export function AcmeWidget() { return null; }\n',
598
- );
599
-
600
- const result = await integrationPackCheck({cwd: tmpDir});
601
-
602
- // The .tsx extension in the specifier must be caught
603
- expect(result.data.packable).toBe(false);
604
- expect(result.data.issues).toContainEqual(
605
- expect.objectContaining({
606
- code: 'typescript_extension_in_specifier',
607
- message: expect.stringContaining('.tsx'),
608
- }),
609
- );
610
- });
611
-
612
- it('generated extensionless component specifier resolves through exports map', async () => {
613
- fs.writeFileSync(
614
- path.join(tmpDir, 'package.json'),
615
- `${JSON.stringify({
616
- name: '@acme/widgets',
617
- version: '1.0.0',
618
- files: ['index.mjs'],
619
- exports: {'.': './index.mjs'},
620
- })}\n`,
621
- );
622
- fs.writeFileSync(
623
- path.join(tmpDir, 'index.mjs'),
624
- 'export const existing = 1;\n',
625
- );
626
- await integrationAddComponent('AcmeWidget', {cwd: tmpDir});
627
-
628
- // Verify the exports map has extensionless key → .tsx target
629
- const pkg = JSON.parse(
630
- fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf-8'),
631
- );
632
- expect(pkg.exports['./components/AcmeWidget']).toBe(
633
- './components/AcmeWidget.tsx',
634
- );
635
- expect(pkg.exports['./components/AcmeWidget.tsx']).toBeUndefined();
636
-
637
- const result = await integrationPackCheck({cwd: tmpDir});
638
-
639
- expect(result.data.packable).toBe(true);
640
- expect(result.data.issues).not.toContainEqual(
641
- expect.objectContaining({code: 'typescript_extension_in_specifier'}),
642
- );
643
- expect(result.data.issues).not.toContainEqual(
644
- expect.objectContaining({code: 'component_import_unresolvable'}),
645
- );
646
- });
647
-
648
- it('validates generated imports without project-local TypeScript', async () => {
649
- fs.rmSync(tmpDir, {recursive: true, force: true});
650
- tmpDir = fs.mkdtempSync(
651
- path.join(os.tmpdir(), 'astryx-pack-check-no-typescript-'),
652
- );
653
- fs.writeFileSync(
654
- path.join(tmpDir, 'package.json'),
655
- `${JSON.stringify({
656
- name: '@acme/widgets',
657
- version: '1.0.0',
658
- files: ['index.mjs'],
659
- exports: {'.': './index.mjs'},
660
- })}\n`,
661
- );
662
- fs.writeFileSync(
663
- path.join(tmpDir, 'index.mjs'),
664
- 'export const existing = 1;\n',
665
- );
666
- await integrationAddComponent('AcmeWidget', {cwd: tmpDir});
667
-
668
- const result = await integrationPackCheck({cwd: tmpDir});
669
-
670
- expect(result.data.packable).toBe(true);
671
- expect(result.data.issues).not.toContainEqual(
672
- expect.objectContaining({code: 'component_import_unresolvable'}),
673
- );
674
- });
675
-
676
- it('generated extensionless template specifiers resolve for page and block types', async () => {
677
- fs.writeFileSync(
678
- path.join(tmpDir, 'package.json'),
679
- `${JSON.stringify({
680
- name: '@acme/widgets',
681
- version: '1.0.0',
682
- files: ['index.mjs'],
683
- exports: {'.': './index.mjs'},
684
- })}\n`,
685
- );
686
- fs.writeFileSync(
687
- path.join(tmpDir, 'index.mjs'),
688
- 'export const existing = 1;\n',
689
- );
690
- await integrationAddTemplate('account-page', {cwd: tmpDir, type: 'page'});
691
- await integrationAddTemplate('info-card', {cwd: tmpDir, type: 'block'});
692
-
693
- const pkg = JSON.parse(
694
- fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf-8'),
695
- );
696
- expect(pkg.exports['./templates/account-page']).toBe(
697
- './templates/account-page.tsx',
698
- );
699
- expect(pkg.exports['./templates/info-card']).toBe(
700
- './templates/info-card.tsx',
701
- );
702
-
703
- const result = await integrationPackCheck({cwd: tmpDir});
704
-
705
- expect(result.data.packable).toBe(true);
706
- expect(result.data.issues).not.toContainEqual(
707
- expect.objectContaining({code: 'template_import_unresolvable'}),
708
- );
709
- expect(result.data.issues).not.toContainEqual(
710
- expect.objectContaining({code: 'typescript_extension_in_specifier'}),
711
- );
712
- });
713
-
714
- it('preserves condition-style exports sugar without creating a map', async () => {
715
- // Package with condition-only exports (sugar, no subpaths)
716
- fs.writeFileSync(
717
- path.join(tmpDir, 'package.json'),
718
- `${JSON.stringify({
719
- name: '@acme/widgets',
720
- version: '1.0.0',
721
- files: ['index.mjs'],
722
- exports: {import: './index.mjs', require: './index.cjs'},
723
- })}\n`,
724
- );
725
- fs.writeFileSync(
726
- path.join(tmpDir, 'index.mjs'),
727
- 'export const existing = 1;\n',
728
- );
729
- fs.writeFileSync(path.join(tmpDir, 'index.cjs'), 'exports.existing = 1;\n');
730
- fs.writeFileSync(
731
- path.join(tmpDir, 'astryx.integration.mjs'),
732
- 'export default {};\n',
733
- );
734
-
735
- await integrationAddComponent('AcmeWidget', {cwd: tmpDir});
736
-
737
- const pkg = JSON.parse(
738
- fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf-8'),
739
- );
740
- // Condition sugar wrapped into subpath map with the component added
741
- expect(pkg.exports['.']).toEqual({
742
- import: './index.mjs',
743
- require: './index.cjs',
744
- });
745
- expect(pkg.exports['./components/AcmeWidget']).toBe(
746
- './components/AcmeWidget.tsx',
747
- );
748
- });
749
-
750
- it('no-map: pack-check fails when generated component has no exports map', async () => {
751
- fs.writeFileSync(
752
- path.join(tmpDir, 'package.json'),
753
- `${JSON.stringify({
754
- name: '@acme/widgets',
755
- version: '1.0.0',
756
- files: ['dist'],
757
- })}\n`,
758
- );
759
- fs.writeFileSync(
760
- path.join(tmpDir, 'astryx.integration.mjs'),
761
- 'export default {};\n',
762
- );
763
-
764
- await integrationAddComponent('AcmeWidget', {cwd: tmpDir});
765
- await integrationAddTemplate('hero-page', {cwd: tmpDir, type: 'page'});
766
-
767
- const pkg = JSON.parse(
768
- fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf-8'),
769
- );
770
- // No exports map created
771
- expect(pkg.exports).toBeUndefined();
772
-
773
- const result = await integrationPackCheck({cwd: tmpDir});
774
-
775
- // The extensionless import cannot resolve without an exports map —
776
- // pack-check must fail closed, not false-green.
777
- expect(result.data.packable).toBe(false);
778
- expect(result.data.issues).toContainEqual(
779
- expect.objectContaining({
780
- severity: 'error',
781
- message: expect.stringContaining('AcmeWidget'),
782
- }),
783
- );
784
- });
785
-
786
- it('idempotent when extensionless export already exists', async () => {
787
- fs.writeFileSync(
788
- path.join(tmpDir, 'package.json'),
789
- `${JSON.stringify({
790
- name: '@acme/widgets',
791
- version: '1.0.0',
792
- files: ['index.mjs'],
793
- exports: {
794
- '.': './index.mjs',
795
- './components/AcmeWidget': './components/AcmeWidget.tsx',
796
- },
797
- })}\n`,
798
- );
799
- fs.writeFileSync(
800
- path.join(tmpDir, 'index.mjs'),
801
- 'export const existing = 1;\n',
802
- );
803
- fs.writeFileSync(
804
- path.join(tmpDir, 'astryx.integration.mjs'),
805
- 'export default {};\n',
806
- );
807
-
808
- await integrationAddComponent('AcmeWidget', {cwd: tmpDir});
809
-
810
- const pkg = JSON.parse(
811
- fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf-8'),
812
- );
813
- // Export preserved, no duplicate
814
- expect(
815
- Object.keys(pkg.exports).filter(k => k.includes('AcmeWidget')),
816
- ).toEqual(['./components/AcmeWidget']);
817
- });
818
- });
@@ -99,5 +99,5 @@ export type Candidate = {
99
99
  _import?: string | undefined;
100
100
  _title?: string | undefined;
101
101
  _displayName?: string | undefined;
102
- _kind?: "page" | "block" | undefined;
102
+ _kind?: "block" | "page" | undefined;
103
103
  };
@@ -66,7 +66,7 @@ import {
66
66
  import {loadIntegrationsSafely} from '../component/_adapter.mjs';
67
67
  import {levenshteinDistance} from '../../foundation/text/string-utils.mjs';
68
68
  import {discoverTemplates, extractComponents} from '../template/template.mjs';
69
- import {loadDocsCatalog, lowerTopic} from '../docs/_adapter.mjs';
69
+ import {loadDocsCatalog, loadTopicDoc} from '../docs/_adapter.mjs';
70
70
  import {AstryxError} from '../error.mjs';
71
71
  import {ERROR_CODES} from '../../foundation/response/error-codes.mjs';
72
72
  import {setResultCoverage} from './coverage.mjs';
@@ -732,16 +732,16 @@ async function gatherHooks(coreDir) {
732
732
  async function gatherDocs(cwd) {
733
733
  /** @type {Candidate[]} */
734
734
  const candidates = [];
735
- let catalog;
735
+ let entries;
736
736
  try {
737
- catalog = await loadDocsCatalog(cwd);
737
+ entries = (await loadDocsCatalog(cwd)).entries();
738
738
  } catch {
739
739
  return candidates;
740
740
  }
741
- for (const entry of catalog.entries()) {
741
+ for (const entry of entries) {
742
742
  let doc = null;
743
743
  try {
744
- doc = (await lowerTopic(catalog, entry)).doc;
744
+ doc = await loadTopicDoc(entry);
745
745
  } catch {
746
746
  // A topic that cannot be loaded is reported by the commands that own
747
747
  // integration issues; search just cannot index it.
@@ -48,10 +48,10 @@ export type SearchResultEntry = {
48
48
  /**
49
49
  * - Template kind (`page` | `block`) — present for template results.
50
50
  */
51
- kind?: "page" | "block" | undefined;
51
+ kind?: "block" | "page" | undefined;
52
52
  };
53
53
  /**
54
- * astryx --json search <query>
54
+ * xds --json search <query>
55
55
  */
56
56
  export type SearchResponse = {
57
57
  type: "search";
@@ -28,7 +28,7 @@
28
28
  */
29
29
 
30
30
  /**
31
- * astryx --json search <query>
31
+ * xds --json search <query>
32
32
  * @typedef {object} SearchResponse
33
33
  * @property {'search'} type
34
34
  * @property {object} data
@@ -2,7 +2,7 @@
2
2
  // DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
3
3
 
4
4
  /**
5
- * astryx --json swizzle [--list]
5
+ * xds --json swizzle [--list]
6
6
  */
7
7
  export type SwizzleListResponse = {
8
8
  type: "swizzle.list";
@@ -22,7 +22,7 @@ export type SwizzleFeedback = {
22
22
  ghCommand?: string | undefined;
23
23
  };
24
24
  /**
25
- * astryx --json swizzle <component>
25
+ * xds --json swizzle <component>
26
26
  */
27
27
  export type SwizzleCopyResponse = {
28
28
  type: "swizzle.copy";
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  /**
10
- * astryx --json swizzle [--list]
10
+ * xds --json swizzle [--list]
11
11
  *
12
12
  * @typedef {object} SwizzleListResponse
13
13
  * @property {'swizzle.list'} type
@@ -23,7 +23,7 @@
23
23
  */
24
24
 
25
25
  /**
26
- * astryx --json swizzle <component>
26
+ * xds --json swizzle <component>
27
27
  *
28
28
  * @typedef {object} SwizzleCopyResponse
29
29
  * @property {'swizzle.copy'} type
@@ -31,7 +31,7 @@ export function template(name?: string, options?: {
31
31
  skeleton?: boolean | undefined;
32
32
  cdn?: string | boolean | undefined;
33
33
  show?: boolean | undefined;
34
- type?: "page" | "block" | undefined;
34
+ type?: "block" | "page" | undefined;
35
35
  package?: string | undefined;
36
36
  cwd?: string | undefined;
37
37
  }): Promise<{
@@ -2,7 +2,7 @@
2
2
  // DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
3
3
 
4
4
  /**
5
- * astryx --json template [--list]
5
+ * xds --json template [--list]
6
6
  */
7
7
  export type TemplateListResponse = {
8
8
  type: "template.list";
@@ -53,7 +53,7 @@ export type TemplateListEntry = {
53
53
  scaffold?: boolean | undefined;
54
54
  };
55
55
  /**
56
- * astryx --json template <name>
56
+ * xds --json template <name>
57
57
  */
58
58
  export type TemplateShowResponse = {
59
59
  type: "template.show";
@@ -66,7 +66,7 @@ export type TemplateShowResponse = {
66
66
  };
67
67
  };
68
68
  /**
69
- * astryx --json template <name> --skeleton
69
+ * xds --json template <name> --skeleton
70
70
  */
71
71
  export type TemplateSkeletonResponse = {
72
72
  type: "template.skeleton";
@@ -78,7 +78,7 @@ export type TemplateSkeletonResponse = {
78
78
  };
79
79
  };
80
80
  /**
81
- * astryx --json template <name> [path]
81
+ * xds --json template <name> [path]
82
82
  */
83
83
  export type TemplateCopyResponse = {
84
84
  type: "template.copy";
@@ -90,7 +90,7 @@ export type TemplateCopyResponse = {
90
90
  };
91
91
  };
92
92
  /**
93
- * astryx --json template --cdn [path]
93
+ * xds --json template --cdn [path]
94
94
  * `written: false` with `reason: 'exists'` is a success: the command is safe to
95
95
  * re-run, and an edited page is the consumer's file to keep. `version` is the
96
96
  * Astryx version every CDN URL in the file was pinned to.
@@ -118,7 +118,7 @@ export type TemplateOptions = {
118
118
  /**
119
119
  * Filter templates by kind: 'page' or 'block'. Only applies to list views.
120
120
  */
121
- type?: "page" | "block" | undefined;
121
+ type?: "block" | "page" | undefined;
122
122
  /**
123
123
  * Narrow to templates from a specific package (id-only lookups across packages are ambiguous).
124
124
  */
@@ -6,18 +6,18 @@
6
6
  *
7
7
  * Each template is exactly two files: page.tsx (code) + template.doc.mjs (metadata).
8
8
  *
9
- * Invocation -> type discriminator
9
+ * Invocation -> type discriminator
10
10
  * ------------------------------------------------------------------
11
- * astryx --json template [--list] -> template.list
12
- * astryx --json template <name> -> template.show
13
- * astryx --json template <name> --skeleton -> template.skeleton
14
- * astryx --json template <name> [path] -> template.copy
15
- * astryx --json template --cdn [path] -> template.cdn
16
- * (unknown template) -> CLIError
11
+ * xds --json template [--list] -> template.list
12
+ * xds --json template <name> -> template.show
13
+ * xds --json template <name> --skeleton -> template.skeleton
14
+ * xds --json template <name> [path] -> template.copy
15
+ * xds --json template --cdn [path] -> template.cdn
16
+ * (unknown template) -> CLIError
17
17
  */
18
18
 
19
19
  /**
20
- * astryx --json template [--list]
20
+ * xds --json template [--list]
21
21
  * @typedef {object} TemplateListResponse
22
22
  * @property {'template.list'} type
23
23
  * @property {TemplateListEntry[]} data
@@ -43,7 +43,7 @@
43
43
  */
44
44
 
45
45
  /**
46
- * astryx --json template <name>
46
+ * xds --json template <name>
47
47
  * @typedef {object} TemplateShowResponse
48
48
  * @property {'template.show'} type
49
49
  * @property {object} data
@@ -55,7 +55,7 @@
55
55
  */
56
56
 
57
57
  /**
58
- * astryx --json template <name> --skeleton
58
+ * xds --json template <name> --skeleton
59
59
  * @typedef {object} TemplateSkeletonResponse
60
60
  * @property {'template.skeleton'} type
61
61
  * @property {object} data
@@ -66,7 +66,7 @@
66
66
  */
67
67
 
68
68
  /**
69
- * astryx --json template <name> [path]
69
+ * xds --json template <name> [path]
70
70
  * @typedef {object} TemplateCopyResponse
71
71
  * @property {'template.copy'} type
72
72
  * @property {object} data
@@ -77,7 +77,7 @@
77
77
  */
78
78
 
79
79
  /**
80
- * astryx --json template --cdn [path]
80
+ * xds --json template --cdn [path]
81
81
  * `written: false` with `reason: 'exists'` is a success: the command is safe to
82
82
  * re-run, and an edited page is the consumer's file to keep. `version` is the
83
83
  * Astryx version every CDN URL in the file was pinned to.
@@ -12,10 +12,9 @@
12
12
  * - A .d.ts (plus an optional .variants.d.ts for custom prop values)
13
13
  *
14
14
  * It performs the writes and returns a `theme.build` receipt — its `warnings`
15
- * carry override problems, every declaration core's generator dropped because
16
- * its value could not stay one CSS declaration, and any fonts the theme names
17
- * but does not load (font-warning.mjs) — or `null` when the theme produced no
18
- * CSS (nothing to build). Errors throw AstryxError (with
15
+ * carry override problems and any fonts the theme names but does not load
16
+ * (font-warning.mjs) — or `null` when the theme produced no CSS (nothing to
17
+ * build). Errors throw AstryxError (with
19
18
  * a stable code). Human progress is emitted through the shared `logger`
20
19
  * (silent by default), so the CLI keeps its exact output while a programmatic
21
20
  * caller stays quiet.
@@ -2304,15 +2303,7 @@ async function themeBuildInternal(
2304
2303
  const scopeSelector = themeScopeStart(themeDef.name);
2305
2304
  const scopeTo = THEME_SCOPE_TO;
2306
2305
 
2307
- // Older cores ignore this optional collector. Current core writes the same
2308
- // warning text here that runtime callers receive on the console.
2309
- /** @type {string[]} */
2310
- const droppedDeclarations = [];
2311
-
2312
- const {component, prose} = _generateThemeRulesSplit(
2313
- resolvedTheme,
2314
- droppedDeclarations,
2315
- );
2306
+ const {component, prose} = _generateThemeRulesSplit(resolvedTheme);
2316
2307
  const cssParts = [];
2317
2308
  // Prose element defaults always ship — the `<Theme>` runtime
2318
2309
  // (generateThemeCSS) always emits them, so the build must too, or the
@@ -2331,7 +2322,7 @@ async function themeBuildInternal(
2331
2322
  let adaptationCss;
2332
2323
  try {
2333
2324
  adaptationCss = _generateAdaptationCSS
2334
- ? _generateAdaptationCSS(resolvedTheme, droppedDeclarations)
2325
+ ? _generateAdaptationCSS(resolvedTheme)
2335
2326
  : {component: '', prose: ''};
2336
2327
  } catch (error) {
2337
2328
  const message =
@@ -2377,16 +2368,11 @@ async function themeBuildInternal(
2377
2368
  // adaptations on the same resolved leaf.
2378
2369
  let onMediaCss = '';
2379
2370
  if (_generateOnMediaCSS) {
2380
- onMediaCss = _generateOnMediaCSS(resolvedTheme, droppedDeclarations);
2371
+ onMediaCss = _generateOnMediaCSS(resolvedTheme);
2381
2372
  if (onMediaCss) {
2382
2373
  cssParts.push(`@layer astryx-theme {\n${onMediaCss}\n}`);
2383
2374
  }
2384
2375
  }
2385
- for (const message of droppedDeclarations) {
2386
- const w = `Declaration ${message}. The generated CSS omits it; fix the value in the theme source.`;
2387
- warningMessages.push(w);
2388
- logger.warn(` ⚠ ${w}`);
2389
- }
2390
2376
  if (cssParts.length === 0) {
2391
2377
  logger.log('No overrides found — nothing to build.');
2392
2378
  return null;