@astryxdesign/cli 0.1.7 → 0.1.8-canary.07362a9

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 (389) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +115 -19
  3. package/{src/api → api/blog}/blog.mjs +42 -6
  4. package/{src/api → api/blog}/blog.test.mjs +2 -2
  5. package/api/build/build.mjs +92 -0
  6. package/api/build/build.test.mjs +92 -0
  7. package/{src/api → api/component}/component.mjs +49 -26
  8. package/{src/api → api/discover}/discover.mjs +55 -18
  9. package/{src/api → api/docs}/docs.mjs +47 -21
  10. package/{src/api → api/doctor}/doctor.mjs +13 -10
  11. package/{src/api → api}/error.mjs +2 -2
  12. package/{src/api → api/hook}/hook.mjs +11 -11
  13. package/{src/api → api}/index.mjs +16 -9
  14. package/{src/api → api/integration}/validate-integration.mjs +48 -15
  15. package/{src/api → api/integration}/validate-integration.test.mjs +1 -1
  16. package/{src/api → api/layout}/layout.mjs +66 -17
  17. package/{src/api → api/layout}/layout.test.mjs +1 -1
  18. package/{src/api → api/search}/search.mjs +71 -12
  19. package/api/swizzle/swizzle.mjs +283 -0
  20. package/{src/commands → api/swizzle}/swizzle.test.mjs +26 -1
  21. package/{src/api → api/template}/template-integration.test.mjs +2 -2
  22. package/{src/api → api/template}/template-suffix.test.mjs +3 -3
  23. package/{src/api → api/template}/template.mjs +96 -19
  24. package/{src/api → api/theme}/theme-add.mjs +35 -7
  25. package/{src → authoring}/codemod.mjs +6 -6
  26. package/{src → authoring}/config.test.mjs +1 -1
  27. package/{src → authoring}/doc.mjs +1 -1
  28. package/{src → authoring}/doc.test.mjs +1 -1
  29. package/{src → authoring}/template.mjs +1 -1
  30. package/bin/astryx.mjs +12 -10
  31. package/{src → cli}/commands/blog.mjs +48 -7
  32. package/{src → cli}/commands/build-theme.mjs +133 -115
  33. package/cli/commands/build.mjs +172 -0
  34. package/cli/commands/cli-postinstall.test.mjs +42 -0
  35. package/{src → cli}/commands/component/index.mjs +52 -25
  36. package/{src → cli}/commands/component-ownership.test.mjs +3 -3
  37. package/{src → cli}/commands/component-package.test.mjs +1 -1
  38. package/{src → cli}/commands/component-resolution.test.mjs +2 -2
  39. package/{src → cli}/commands/discover.mjs +23 -12
  40. package/{src → cli}/commands/docs.mjs +42 -10
  41. package/{src → cli}/commands/docs.test.mjs +1 -1
  42. package/{src → cli}/commands/doctor.mjs +3 -3
  43. package/{src → cli}/commands/doctor.test.mjs +2 -2
  44. package/{src → cli}/commands/ensure-core-built.mjs +3 -2
  45. package/{src → cli}/commands/external-showcase.test.mjs +1 -1
  46. package/{src → cli}/commands/hook/index.mjs +40 -17
  47. package/{src → cli}/commands/import-hint-correctness.test.mjs +1 -1
  48. package/cli/commands/init.mjs +195 -0
  49. package/{src → cli}/commands/init.next-steps.test.mjs +1 -1
  50. package/cli/commands/interactive-guard.test.mjs +66 -0
  51. package/{src → cli}/commands/json-contract.test.mjs +2 -2
  52. package/{src → cli}/commands/layout.mjs +59 -19
  53. package/{src → cli}/commands/search.mjs +22 -15
  54. package/{src → cli}/commands/search.test.mjs +1 -1
  55. package/cli/commands/setup-nudge.test.mjs +108 -0
  56. package/cli/commands/swizzle.mjs +103 -0
  57. package/{src → cli}/commands/template.mjs +84 -53
  58. package/{src → cli}/commands/template.path-safety.test.mjs +2 -2
  59. package/{src → cli}/commands/upgrade.integration-policy.test.mjs +1 -1
  60. package/{src → cli}/commands/upgrade.mjs +291 -77
  61. package/cli/commands/upgrade.test.mjs +314 -0
  62. package/{src → cli}/commands/validate-integration.mjs +17 -37
  63. package/{src → cli}/index.mjs +55 -19
  64. package/{src/codemods → codemods}/__tests__/registry.test.mjs +1 -0
  65. package/{src/codemods → codemods}/ensure-jscodeshift.mjs +12 -28
  66. package/{src/codemods → codemods}/integration-discovery.mjs +6 -3
  67. package/{src/codemods → codemods}/integration-discovery.test.mjs +1 -1
  68. package/{src/codemods → codemods}/integration-runner.mjs +8 -3
  69. package/{src/codemods → codemods}/registry.mjs +4 -1
  70. package/{src/codemods → codemods}/run-codemod.mjs +18 -11
  71. package/{src/codemods → codemods}/runner.mjs +24 -14
  72. package/{src/codemods → codemods}/transforms/v0.0.10/remove-size-props.mjs +9 -4
  73. package/{src/codemods → codemods}/transforms/v0.0.12/add-is-icon-only.mjs +27 -22
  74. package/{src/codemods → codemods}/transforms/v0.0.13/icon-name-deprecations.mjs +12 -5
  75. package/{src/codemods → codemods}/transforms/v0.0.13/rename-attachments-to-drawer.mjs +15 -8
  76. package/{src/codemods → codemods}/transforms/v0.0.13/toolbar-density-to-size.mjs +10 -4
  77. package/{src/codemods → codemods}/transforms/v0.0.14/rename-action-props.mjs +11 -5
  78. package/{src/codemods → codemods}/transforms/v0.0.14/rename-section-wash-to-muted.mjs +11 -6
  79. package/{src/codemods → codemods}/transforms/v0.0.14/rename-status-variants.mjs +15 -10
  80. package/{src/codemods → codemods}/transforms/v0.0.15/migrate-item-children-to-endcontent.mjs +13 -8
  81. package/{src/codemods → codemods}/transforms/v0.0.15/migrate-selector-children-to-render-option.mjs +18 -13
  82. package/{src/codemods → codemods}/transforms/v0.0.15/migrate-theme-selectors-to-data-attrs.mjs +8 -4
  83. package/{src/codemods → codemods}/transforms/v0.0.15/rename-date-picker-to-input.mjs +11 -6
  84. package/{src/codemods → codemods}/transforms/v0.0.15/rename-imperative-ref-to-handleRef.mjs +6 -1
  85. package/{src/codemods → codemods}/transforms/v0.0.15/rename-isStreaming-to-isStopShown.mjs +6 -1
  86. package/{src/codemods → codemods}/transforms/v0.0.15/rename-stack-element-to-as.mjs +8 -3
  87. package/{src/codemods → codemods}/transforms/v0.0.2/migrate-badge-dot-to-statusdot.mjs +17 -10
  88. package/{src/codemods → codemods}/transforms/v0.0.2/migrate-gap-to-numeric.mjs +7 -1
  89. package/{src/codemods → codemods}/transforms/v0.0.2/migrate-isFullBleed-to-padding.mjs +9 -4
  90. package/{src/codemods → codemods}/transforms/v0.0.2/migrate-useXDSIcon-to-getIcon.mjs +12 -7
  91. package/{src/codemods → codemods}/transforms/v0.0.2/rename-banner-endButton-to-endContent.mjs +7 -2
  92. package/{src/codemods → codemods}/transforms/v0.0.2/rename-form-tooltip-startIcon.mjs +8 -2
  93. package/{src/codemods → codemods}/transforms/v0.0.2/rename-isShown-to-isOpen.mjs +7 -2
  94. package/{src/codemods → codemods}/transforms/v0.0.2/rename-selector-items-to-options.mjs +7 -2
  95. package/{src/codemods → codemods}/transforms/v0.0.2/rename-sidenav-header-to-heading.mjs +11 -4
  96. package/{src/codemods → codemods}/transforms/v0.0.2/rename-topnav-title-to-heading.mjs +10 -4
  97. package/{src/codemods → codemods}/transforms/v0.0.2/unify-uncontrolled-to-defaultX.mjs +7 -2
  98. package/{src/codemods → codemods}/transforms/v0.0.2/unify-visibility-to-onOpenChange.mjs +10 -5
  99. package/{src/codemods → codemods}/transforms/v0.0.6/migrate-badge-children-to-label.mjs +7 -2
  100. package/{src/codemods → codemods}/transforms/v0.0.6/migrate-collapse-to-collapsible.mjs +9 -3
  101. package/{src/codemods → codemods}/transforms/v0.0.6/migrate-radius-tokens.mjs +11 -5
  102. package/{src/codemods → codemods}/transforms/v0.0.6/migrate-shadow-tokens.mjs +13 -6
  103. package/{src/codemods → codemods}/transforms/v0.0.6/migrate-skeleton-radius.mjs +7 -1
  104. package/{src/codemods → codemods}/transforms/v0.0.6/migrate-token-names.mjs +11 -5
  105. package/{src/codemods → codemods}/transforms/v0.0.7/rename-banner-variant-to-container.mjs +8 -3
  106. package/{src/codemods → codemods}/transforms/v0.0.8/migrate-token-renames.mjs +15 -8
  107. package/{src/codemods → codemods}/transforms/v0.0.8/rename-endslot-to-endcontent.mjs +7 -2
  108. package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/drop-xds-prefix-imports.test.mjs +42 -7
  109. package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/migrate-xds-module-specifiers.test.mjs +43 -0
  110. package/{src/codemods → codemods}/transforms/v0.1.0/drop-xds-prefix-imports.mjs +117 -13
  111. package/{src/codemods → codemods}/transforms/v0.1.0/migrate-xds-css-surfaces.mjs +21 -17
  112. package/{src/codemods → codemods}/transforms/v0.1.0/migrate-xds-declare-module.mjs +7 -2
  113. package/{src/codemods → codemods}/transforms/v0.1.0/migrate-xds-module-specifiers.mjs +86 -15
  114. package/{src/codemods → codemods}/transforms/v0.1.2/rename-text-color-active-to-accent.mjs +15 -9
  115. package/{src/codemods → codemods}/transforms/v0.1.3/migrate-layout-components-to-experimental.mjs +17 -12
  116. package/{src/codemods → codemods}/transforms/v0.1.5/rename-switch-label-spacing-default-to-hug.mjs +15 -9
  117. package/{src/codemods → codemods}/transforms/v0.1.7/migrate-table-tableprops-to-direct-props.mjs +17 -10
  118. package/{src/codemods → codemods}/transforms/v0.1.7/rename-table-renderprops-styles-to-xstyle.mjs +18 -13
  119. package/codemods/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +161 -0
  120. package/codemods/transforms/v0.1.8/index.mjs +19 -0
  121. package/codemods/transforms/v0.1.8/rename-avatar-size-scale.mjs +239 -0
  122. package/docs/cli-integrations.doc.mjs +150 -0
  123. package/docs/elevation.doc.mjs +79 -1
  124. package/docs/getting-started.doc.mjs +9 -9
  125. package/docs/internationalization.doc.mjs +92 -46
  126. package/docs/migration.doc.mjs +18 -18
  127. package/docs/principles.doc.dense.mjs +1 -1
  128. package/docs/principles.doc.mjs +6 -6
  129. package/docs/principles.doc.zh.mjs +1 -1
  130. package/docs/styling-libraries.doc.mjs +3 -3
  131. package/docs/styling.doc.mjs +4 -4
  132. package/docs/theme.doc.dense.mjs +2 -2
  133. package/docs/theme.doc.mjs +7 -7
  134. package/docs/theme.doc.zh.mjs +1 -1
  135. package/docs/tokens.doc.mjs +1 -1
  136. package/docs/working-with-ai.doc.mjs +19 -19
  137. package/{src/commands → lib/agent-docs}/agent-docs.mjs +164 -29
  138. package/{src/commands → lib/agent-docs}/agent-docs.path-safety.test.mjs +1 -1
  139. package/{src/commands → lib/agent-docs}/agent-docs.test.mjs +123 -10
  140. package/{src/lib → lib}/cli-error.mjs +2 -2
  141. package/{src/lib → lib}/component-discovery.mjs +44 -2
  142. package/{src/lib → lib}/component-format.mjs +67 -25
  143. package/{src/lib → lib}/component-loader.mjs +27 -13
  144. package/{src/lib → lib}/componentDocOverlay.test.mjs +0 -1
  145. package/{src/lib → lib}/error-codes.test.mjs +1 -1
  146. package/{src/lib → lib}/hook-discovery.mjs +14 -1
  147. package/{src/lib → lib}/hook-format.mjs +29 -5
  148. package/{src/lib → lib}/integration-warnings.mjs +2 -2
  149. package/{src/lib → lib}/integrations.mjs +20 -0
  150. package/{src/lib → lib}/integrations.test.mjs +1 -1
  151. package/{src/lib → lib}/json-contract.test.mjs +1 -1
  152. package/{src/lib → lib}/json-shim.mjs +11 -6
  153. package/{src/lib → lib}/json-shim.test.mjs +1 -1
  154. package/{src/lib → lib}/json.mjs +3 -3
  155. package/{src/lib → lib}/levenshtein.mjs +6 -0
  156. package/{src/lib → lib}/manifest.mjs +7 -5
  157. package/{src/lib → lib}/manifest.test.mjs +2 -2
  158. package/{src/lib → lib}/module-loader.mjs +1 -0
  159. package/{src/lib → lib}/package-scanner.mjs +47 -0
  160. package/{src/lib → lib}/project.mjs +48 -18
  161. package/{src/lib → lib}/project.test.mjs +1 -1
  162. package/{src/lib → lib}/resolve-theme.mjs +5 -0
  163. package/{src/lib → lib}/string-utils.mjs +15 -0
  164. package/lib/term-log.mjs +57 -0
  165. package/{src/lib → lib}/xle/browser.mjs +18 -8
  166. package/{src/lib → lib}/xle/expand.mjs +155 -22
  167. package/{src/lib → lib}/xle/parse.mjs +119 -13
  168. package/{src/lib → lib}/xle/print.mjs +54 -14
  169. package/{src/lib → lib}/xle/registry-core.mjs +28 -3
  170. package/{src/lib → lib}/xle/registry.mjs +9 -4
  171. package/{src/lib → lib}/xle/splice.mjs +13 -2
  172. package/{src/lib → lib}/xle/validate.mjs +95 -14
  173. package/lib/xle/xle-ast.d.ts +214 -0
  174. package/package.json +37 -28
  175. package/scripts/postinstall.mjs +74 -0
  176. package/templates/blocks/components/Avatar/AvatarFallbackChain.tsx +4 -4
  177. package/templates/blocks/components/Avatar/AvatarGroup.tsx +2 -2
  178. package/templates/blocks/components/Avatar/AvatarInitialsFallback.tsx +1 -1
  179. package/templates/blocks/components/Avatar/AvatarShowcase.tsx +5 -5
  180. package/templates/blocks/components/Avatar/AvatarUserCard.tsx +1 -1
  181. package/templates/blocks/components/Avatar/AvatarWithImage.tsx +4 -4
  182. package/templates/blocks/components/Avatar/AvatarWithStatus.tsx +3 -3
  183. package/templates/blocks/components/AvatarGroup/AvatarGroupShowcase.tsx +2 -2
  184. package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowCustomText.tsx +1 -1
  185. package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowDefault.tsx +1 -1
  186. package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowShowcase.tsx +2 -2
  187. package/templates/blocks/components/AvatarStatusDot/AvatarStatusDotShowcase.tsx +3 -3
  188. package/templates/blocks/components/AvatarStatusDot/AvatarStatusDotVariants.tsx +3 -3
  189. package/templates/blocks/components/Banner/BannerFloating.doc.mjs +14 -0
  190. package/templates/blocks/components/Banner/BannerFloating.tsx +16 -0
  191. package/templates/blocks/components/Button/ButtonFloating.doc.mjs +14 -0
  192. package/templates/blocks/components/Button/ButtonFloating.tsx +37 -0
  193. package/templates/blocks/components/ButtonGroup/ButtonGroupFloating.doc.mjs +14 -0
  194. package/templates/blocks/components/ButtonGroup/ButtonGroupFloating.tsx +23 -0
  195. package/templates/blocks/components/Card/CardElevations.doc.mjs +14 -0
  196. package/templates/blocks/components/Card/CardElevations.tsx +32 -0
  197. package/templates/blocks/components/Card/ClickableCardElevated.doc.mjs +14 -0
  198. package/templates/blocks/components/Card/ClickableCardElevated.tsx +21 -0
  199. package/templates/blocks/components/Card/SelectableCardElevated.doc.mjs +14 -0
  200. package/templates/blocks/components/Card/SelectableCardElevated.tsx +37 -0
  201. package/templates/blocks/components/Carousel/CarouselSnap.tsx +1 -1
  202. package/templates/blocks/components/ChatComposer/ChatComposerFlat.doc.mjs +14 -0
  203. package/templates/blocks/components/ChatComposer/ChatComposerFlat.tsx +75 -0
  204. package/templates/blocks/components/ChatMessage/ChatMessageAvatarName.tsx +2 -2
  205. package/templates/blocks/components/ChatMessage/ChatMessageMultiBubble.tsx +1 -1
  206. package/templates/blocks/components/ChatMessageBubble/ChatMessageBubbleGrouping.tsx +1 -1
  207. package/templates/blocks/components/ChatMessageBubble/ChatMessageBubbleMetadata.tsx +1 -1
  208. package/templates/blocks/components/ChatMessageList/ChatMessageListDensity.tsx +5 -9
  209. package/templates/blocks/components/ChatMessageList/ChatMessageListFullFeatured.tsx +1 -1
  210. package/templates/blocks/components/CodeBlock/CodeBlockTerminal.tsx +1 -1
  211. package/templates/blocks/components/HoverCard/HoverCardShowcase.tsx +1 -1
  212. package/templates/blocks/components/IconButton/IconButtonFloating.doc.mjs +14 -0
  213. package/templates/blocks/components/IconButton/IconButtonFloating.tsx +37 -0
  214. package/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.doc.mjs +19 -0
  215. package/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.tsx +46 -0
  216. package/templates/blocks/components/InternationalizationProvider/InternationalizationProvider02Overrides.doc.mjs +14 -0
  217. package/templates/blocks/components/InternationalizationProvider/InternationalizationProvider02Overrides.tsx +33 -0
  218. package/templates/blocks/components/Item/ItemWithMedia.tsx +2 -2
  219. package/templates/blocks/components/ListItem/ListItemWithMedia.tsx +2 -2
  220. package/templates/blocks/components/OverflowList/OverflowListCappedToolbar.doc.mjs +14 -0
  221. package/templates/blocks/components/OverflowList/OverflowListCappedToolbar.tsx +39 -0
  222. package/templates/blocks/components/OverflowList/OverflowListMultiRowTags.doc.mjs +14 -0
  223. package/templates/blocks/components/OverflowList/OverflowListMultiRowTags.tsx +44 -0
  224. package/templates/blocks/components/Pagination/PaginationDotsCarousel.tsx +2 -6
  225. package/templates/blocks/components/Stack/StackFillItem.tsx +2 -6
  226. package/templates/blocks/components/TabList/TabListTabsWithActions.doc.mjs +1 -1
  227. package/templates/blocks/components/TabList/TabListTabsWithActions.tsx +2 -7
  228. package/templates/blocks/components/Table/TableRowStatusTable.doc.mjs +14 -0
  229. package/templates/blocks/components/Table/TableRowStatusTable.tsx +59 -0
  230. package/templates/blocks/components/Thumbnail/ThumbnailDisabled.tsx +6 -1
  231. package/templates/blocks/components/Thumbnail/ThumbnailGallery.tsx +1 -0
  232. package/templates/blocks/components/Thumbnail/ThumbnailRemovable.tsx +1 -0
  233. package/templates/blocks/components/TypeaheadItem/TypeaheadItemShowcase.tsx +1 -1
  234. package/templates/pages/ai-chat/page.tsx +4 -4
  235. package/templates/pages/dashboard-portfolio/page.tsx +3 -11
  236. package/templates/pages/detail-page/page.tsx +5 -12
  237. package/templates/pages/documentation-design/page.tsx +1 -1
  238. package/templates/pages/messaging-shell/page.tsx +6 -8
  239. package/templates/pages/table-grouped/page.tsx +9 -14
  240. package/templates/pages/table-page/page.tsx +7 -9
  241. package/templates/pages/table-page-heatmap-status/page.tsx +5 -13
  242. package/{src/types → types}/api.contract.assert.ts +17 -8
  243. package/{src/types → types}/api.d.ts +110 -9
  244. package/{src/types → types}/base.d.ts +40 -4
  245. package/types/build.d.ts +53 -0
  246. package/types/codemod.d.ts +166 -0
  247. package/{src/types → types}/component.d.ts +1 -1
  248. package/{src/types → types}/discover.d.ts +1 -1
  249. package/{src/types → types}/docs.d.ts +1 -4
  250. package/{src/types → types}/hook.d.ts +1 -1
  251. package/{src/types → types}/index.d.ts +1 -0
  252. package/types/jscodeshift.d.ts +19 -0
  253. package/types/layout.d.ts +74 -0
  254. package/{src/types → types}/swizzle.d.ts +4 -0
  255. package/{src/types → types}/template-api.d.ts +4 -1
  256. package/types/theme.d.ts +53 -0
  257. package/types/upgrade.d.ts +108 -0
  258. package/utils/package-manager.mjs +178 -0
  259. package/utils/package-manager.test.mjs +220 -0
  260. package/{src/utils → utils}/path-safety.mjs +0 -18
  261. package/{src/utils → utils}/paths.mjs +4 -1
  262. package/{src/utils → utils}/update-check.mjs +5 -4
  263. package/{src/utils → utils}/update-check.test.mjs +3 -3
  264. package/docs/integration-authoring.md +0 -105
  265. package/src/commands/build.mjs +0 -196
  266. package/src/commands/init.mjs +0 -288
  267. package/src/commands/interactive-guard.test.mjs +0 -69
  268. package/src/commands/swizzle.mjs +0 -440
  269. package/src/commands/upgrade.test.mjs +0 -160
  270. package/src/types/codemod.d.ts +0 -81
  271. package/src/types/theme.d.ts +0 -23
  272. package/src/types/upgrade.d.ts +0 -64
  273. package/src/utils/interactive.mjs +0 -76
  274. package/src/utils/interactive.test.mjs +0 -70
  275. package/src/utils/package-manager.mjs +0 -74
  276. package/src/utils/package-manager.test.mjs +0 -113
  277. /package/{src/api → api/docs}/docOverlays.test.mjs +0 -0
  278. /package/{src/api → api/integration}/integration-block-exports.test.mjs +0 -0
  279. /package/{src/api → api/template}/template.test.mjs +0 -0
  280. /package/{src → authoring}/codemod.test.mjs +0 -0
  281. /package/{src → authoring}/config.mjs +0 -0
  282. /package/{src → authoring}/integration.mjs +0 -0
  283. /package/{src → authoring}/template.test.mjs +0 -0
  284. /package/{src → cli}/cli-exit-codes.test.mjs +0 -0
  285. /package/{src → cli}/commands/build-theme.color-scheme.test.mjs +0 -0
  286. /package/{src → cli}/commands/build-theme.import-path.test.mjs +0 -0
  287. /package/{src → cli}/commands/build-theme.path-safety.test.mjs +0 -0
  288. /package/{src → cli}/commands/build-theme.prose.test.mjs +0 -0
  289. /package/{src → cli}/commands/build-theme.variants.test.mjs +0 -0
  290. /package/{src → cli}/commands/build-theme.watch.test.mjs +0 -0
  291. /package/{src → cli}/commands/component.test.mjs +0 -0
  292. /package/{src → cli}/commands/detail-levels.test.mjs +0 -0
  293. /package/{src → cli}/commands/swizzle.path-safety.test.mjs +0 -0
  294. /package/{src → cli}/commands/swizzle.routing.test.mjs +0 -0
  295. /package/{src → cli}/commands/template.test.mjs +0 -0
  296. /package/{src → cli}/commands/upgrade.config-ordering.test.mjs +0 -0
  297. /package/{src → cli}/commands/validate-integration.test.mjs +0 -0
  298. /package/{src → cli}/update-hint-commands.test.mjs +0 -0
  299. /package/{src/codemods → codemods}/__tests__/rename-imperative-ref-to-handleRef.test.mjs +0 -0
  300. /package/{src/codemods → codemods}/__tests__/rename-isStreaming-to-isStopShown.test.mjs +0 -0
  301. /package/{src/codemods → codemods}/__tests__/rename-section-wash-to-muted.test.mjs +0 -0
  302. /package/{src/codemods → codemods}/__tests__/runner.test.mjs +0 -0
  303. /package/{src/codemods → codemods}/__tests__/toolbar-density-to-size.test.mjs +0 -0
  304. /package/{src/codemods → codemods}/__tests__/validation.test.mjs +0 -0
  305. /package/{src/codemods → codemods}/transforms/v0.0.10/__tests__/remove-size-props.test.mjs +0 -0
  306. /package/{src/codemods → codemods}/transforms/v0.0.10/index.mjs +0 -0
  307. /package/{src/codemods → codemods}/transforms/v0.0.12/__tests__/add-is-icon-only.test.mjs +0 -0
  308. /package/{src/codemods → codemods}/transforms/v0.0.12/index.mjs +0 -0
  309. /package/{src/codemods → codemods}/transforms/v0.0.13/__tests__/icon-name-deprecations.test.mjs +0 -0
  310. /package/{src/codemods → codemods}/transforms/v0.0.13/__tests__/rename-attachments-to-drawer.test.mjs +0 -0
  311. /package/{src/codemods → codemods}/transforms/v0.0.13/index.mjs +0 -0
  312. /package/{src/codemods → codemods}/transforms/v0.0.14/__tests__/rename-action-props.test.mjs +0 -0
  313. /package/{src/codemods → codemods}/transforms/v0.0.14/__tests__/rename-status-variants.test.mjs +0 -0
  314. /package/{src/codemods → codemods}/transforms/v0.0.14/index.mjs +0 -0
  315. /package/{src/codemods → codemods}/transforms/v0.0.15/__tests__/migrate-item-children-to-endcontent.test.mjs +0 -0
  316. /package/{src/codemods → codemods}/transforms/v0.0.15/__tests__/migrate-selector-children-to-render-option.test.mjs +0 -0
  317. /package/{src/codemods → codemods}/transforms/v0.0.15/__tests__/migrate-theme-selectors-to-data-attrs.test.mjs +0 -0
  318. /package/{src/codemods → codemods}/transforms/v0.0.15/__tests__/rename-date-picker-to-input.test.mjs +0 -0
  319. /package/{src/codemods → codemods}/transforms/v0.0.15/__tests__/rename-stack-element-to-as.test.mjs +0 -0
  320. /package/{src/codemods → codemods}/transforms/v0.0.15/index.mjs +0 -0
  321. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/migrate-badge-dot-to-statusdot.test.mjs +0 -0
  322. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/migrate-gap-to-numeric.test.mjs +0 -0
  323. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/migrate-isFullBleed-to-padding.test.mjs +0 -0
  324. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/migrate-useXDSIcon-to-getIcon.test.mjs +0 -0
  325. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-banner-endButton-to-endContent.test.mjs +0 -0
  326. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-form-tooltip-startIcon.test.mjs +0 -0
  327. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-isShown-to-isOpen.test.mjs +0 -0
  328. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-selector-items-to-options.test.mjs +0 -0
  329. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-sidenav-header-to-heading.test.mjs +0 -0
  330. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-topnav-title-to-heading.test.mjs +0 -0
  331. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/unify-uncontrolled-to-defaultX.test.mjs +0 -0
  332. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/unify-visibility-to-onOpenChange.test.mjs +0 -0
  333. /package/{src/codemods → codemods}/transforms/v0.0.2/index.mjs +0 -0
  334. /package/{src/codemods → codemods}/transforms/v0.0.6/__tests__/migrate-collapse-to-collapsible.test.mjs +0 -0
  335. /package/{src/codemods → codemods}/transforms/v0.0.6/__tests__/migrate-radius-tokens.test.mjs +0 -0
  336. /package/{src/codemods → codemods}/transforms/v0.0.6/__tests__/migrate-shadow-tokens.test.mjs +0 -0
  337. /package/{src/codemods → codemods}/transforms/v0.0.6/__tests__/migrate-skeleton-radius.test.mjs +0 -0
  338. /package/{src/codemods → codemods}/transforms/v0.0.6/__tests__/migrate-token-names.test.mjs +0 -0
  339. /package/{src/codemods → codemods}/transforms/v0.0.6/index.mjs +0 -0
  340. /package/{src/codemods → codemods}/transforms/v0.0.7/__tests__/rename-banner-variant-to-container.test.mjs +0 -0
  341. /package/{src/codemods → codemods}/transforms/v0.0.7/index.mjs +0 -0
  342. /package/{src/codemods → codemods}/transforms/v0.0.8/__tests__/migrate-token-renames.test.mjs +0 -0
  343. /package/{src/codemods → codemods}/transforms/v0.0.8/__tests__/rename-endslot-to-endcontent.test.mjs +0 -0
  344. /package/{src/codemods → codemods}/transforms/v0.0.8/index.mjs +0 -0
  345. /package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/migrate-xds-css-surfaces.test.mjs +0 -0
  346. /package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/migrate-xds-declare-module.test.mjs +0 -0
  347. /package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/v0.1.0-ordering.test.mjs +0 -0
  348. /package/{src/codemods → codemods}/transforms/v0.1.0/index.mjs +0 -0
  349. /package/{src/codemods → codemods}/transforms/v0.1.2/__tests__/rename-text-color-active-to-accent.test.mjs +0 -0
  350. /package/{src/codemods → codemods}/transforms/v0.1.2/index.mjs +0 -0
  351. /package/{src/codemods → codemods}/transforms/v0.1.3/__tests__/migrate-layout-components-to-experimental.test.mjs +0 -0
  352. /package/{src/codemods → codemods}/transforms/v0.1.3/index.mjs +0 -0
  353. /package/{src/codemods → codemods}/transforms/v0.1.5/__tests__/rename-switch-label-spacing-default-to-hug.test.mjs +0 -0
  354. /package/{src/codemods → codemods}/transforms/v0.1.5/index.mjs +0 -0
  355. /package/{src/codemods → codemods}/transforms/v0.1.7/__tests__/migrate-table-tableprops-to-direct-props.test.mjs +0 -0
  356. /package/{src/codemods → codemods}/transforms/v0.1.7/__tests__/rename-table-renderprops-styles-to-xstyle.test.mjs +0 -0
  357. /package/{src/codemods → codemods}/transforms/v0.1.7/index.mjs +0 -0
  358. /package/{src/lib → lib}/cli-error.test.mjs +0 -0
  359. /package/{src/lib → lib}/component-discovery.importpath.test.mjs +0 -0
  360. /package/{src/lib → lib}/component-format.test.mjs +0 -0
  361. /package/{src/lib → lib}/component-loader.test.mjs +0 -0
  362. /package/{src/lib → lib}/config-cache.mjs +0 -0
  363. /package/{src/lib → lib}/config-cache.test.mjs +0 -0
  364. /package/{src/lib → lib}/config-schema.mjs +0 -0
  365. /package/{src/lib → lib}/error-codes.mjs +0 -0
  366. /package/{src/lib → lib}/integration-warnings.test.mjs +0 -0
  367. /package/{src/lib → lib}/module-loader.test.mjs +0 -0
  368. /package/{src/lib → lib}/node-version.mjs +0 -0
  369. /package/{src/lib → lib}/node-version.test.mjs +0 -0
  370. /package/{src/lib → lib}/parse.mjs +0 -0
  371. /package/{src/lib → lib}/site.mjs +0 -0
  372. /package/{src/lib → lib}/xle/browser.d.ts +0 -0
  373. /package/{src/lib → lib}/xle/xle.test.mjs +0 -0
  374. /package/{src/schemas → schemas}/doc-schema.mjs +0 -0
  375. /package/{src/schemas → schemas}/template-schema.mjs +0 -0
  376. /package/{src/types → types}/config.d.ts +0 -0
  377. /package/{src/types → types}/doc.d.ts +0 -0
  378. /package/{src/types → types}/doctor.d.ts +0 -0
  379. /package/{src/types → types}/error-codes.d.ts +0 -0
  380. /package/{src/types → types}/integration.d.ts +0 -0
  381. /package/{src/types → types}/manifest.d.ts +0 -0
  382. /package/{src/types → types}/search.d.ts +0 -0
  383. /package/{src/types → types}/template.d.ts +0 -0
  384. /package/{src/types → types}/validate-integration.d.ts +0 -0
  385. /package/{src/utils → utils}/github.mjs +0 -0
  386. /package/{src/utils → utils}/path-safety.test.mjs +0 -0
  387. /package/{src/utils → utils}/paths.test.mjs +0 -0
  388. /package/{src/utils → utils}/semver.mjs +0 -0
  389. /package/{src/utils → utils}/semver.test.mjs +0 -0
@@ -8,8 +8,8 @@
8
8
  * - An updated JS module that references the built className
9
9
  *
10
10
  * Usage:
11
- * npx astryx theme build ./src/themes/ocean.ts
12
- * npx astryx theme build ./src/themes/ocean.ts --out ./dist/ocean.css
11
+ * astryx theme build ./src/themes/ocean.ts
12
+ * astryx theme build ./src/themes/ocean.ts --out ./dist/ocean.css
13
13
  */
14
14
 
15
15
  import * as fs from 'node:fs';
@@ -17,26 +17,27 @@ import * as path from 'node:path';
17
17
  import {pathToFileURL, fileURLToPath} from 'node:url';
18
18
  import {spawn} from 'node:child_process';
19
19
  import {createJiti} from 'jiti';
20
- import {getRunPrefix} from '../utils/package-manager.mjs';
20
+ import {getCliInvocation} from '../../utils/package-manager.mjs';
21
21
  import {
22
22
  sanitizeName,
23
23
  PathSafetyError,
24
- isNonInteractive,
25
- } from '../utils/path-safety.mjs';
26
- import {jsonOut, humanLog} from '../lib/json.mjs';
27
- import {cliError} from '../lib/cli-error.mjs';
28
- import {ERROR_CODES} from '../lib/error-codes.mjs';
29
- import {themeAdd, listThemes} from '../api/theme-add.mjs';
24
+ } from '../../utils/path-safety.mjs';
25
+ import {jsonOut, humanLog} from '../../lib/json.mjs';
26
+ import {cliError} from '../../lib/cli-error.mjs';
27
+ import {ERROR_CODES} from '../../lib/error-codes.mjs';
28
+ import {themeAdd} from '../../api/theme/theme-add.mjs';
30
29
 
31
30
  // Import shared theme processing from core. `astryx theme build` MUST produce the
32
31
  // exact same CSS as the `<Theme>` runtime, so it has exactly one generation
33
32
  // path: core's generator. There is no in-CLI fallback implementation — if this
34
33
  // import fails, the build fails (see the ERR_CORE_NOT_FOUND guard in the theme
35
34
  // action). A built, resolvable `@astryxdesign/core` is a hard requirement.
36
- let _defineTheme = null;
37
- let _generateThemeRulesSplit = null;
38
- let _generateOnMediaCSS = null;
39
- let _coreImportError = null;
35
+ // A built, resolvable `@astryxdesign/core` is a hard requirement. These are
36
+ // populated from a dynamic import (a runtime boundary), so `any` is intentional.
37
+ /** @type {any} */ let _defineTheme = null;
38
+ /** @type {any} */ let _generateThemeRulesSplit = null;
39
+ /** @type {any} */ let _generateOnMediaCSS = null;
40
+ /** @type {any} */ let _coreImportError = null;
40
41
  try {
41
42
  const coreTheme = await import('@astryxdesign/core/theme');
42
43
  _defineTheme = coreTheme.defineTheme;
@@ -76,9 +77,11 @@ function generatedHeader(sourceFile, lang = 'js', command) {
76
77
  /**
77
78
  * Convert a theme name to a valid JS identifier.
78
79
  * e.g. 'default-minimal' → 'defaultMinimal', 'ocean' → 'ocean'
80
+ * @param {string} name
81
+ * @returns {string}
79
82
  */
80
83
  function toIdentifier(name) {
81
- return name.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
84
+ return name.replace(/-([a-z])/g, (/** @type {string} */ _, /** @type {string} */ c) => c.toUpperCase());
82
85
  }
83
86
 
84
87
  /**
@@ -86,6 +89,9 @@ function toIdentifier(name) {
86
89
  * from the cwd-relative dir (most consumers import from a file under src/) but
87
90
  * keeps the rest of the path (e.g. `themes/gothic`). Callers note the path is
88
91
  * relative to the consumer's file.
92
+ * @param {string} relDir
93
+ * @param {string} base
94
+ * @returns {string}
89
95
  */
90
96
  function importSpecifier(relDir, base) {
91
97
  const normalized = relDir === '.' ? '' : relDir;
@@ -96,11 +102,13 @@ function importSpecifier(relDir, base) {
96
102
  /**
97
103
  * Convert a kebab-case component name to PascalCase.
98
104
  * e.g. 'button' → 'Button', 'progress-bar' → 'ProgressBar', 'avatar-status-dot' → 'AvatarStatusDot'
105
+ * @param {string} name
106
+ * @returns {string}
99
107
  */
100
108
  function toPascalCase(name) {
101
109
  return name
102
110
  .split('-')
103
- .map(part => part.charAt(0).toUpperCase() + part.slice(1))
111
+ .map((/** @type {string} */ part) => part.charAt(0).toUpperCase() + part.slice(1))
104
112
  .join('');
105
113
  }
106
114
 
@@ -108,6 +116,8 @@ function toPascalCase(name) {
108
116
  * Load known built-in values for a component's visual props from its .doc.mjs file.
109
117
  * Parses the type string (e.g. "'info' | 'warning' | 'error' | 'success'") to extract values.
110
118
  * Returns a map of { propName: string[] } for props that are visual (listed in theming targets).
119
+ * @param {string} componentName
120
+ * @returns {Promise<Record<string, string[]>>}
111
121
  */
112
122
  async function loadKnownValues(componentName) {
113
123
  // Resolve core src relative to the CLI package, not cwd (which may be a theme package)
@@ -141,6 +151,7 @@ async function loadKnownValues(componentName) {
141
151
  if (allProps.length === 0) return {};
142
152
 
143
153
  // Collect visual prop names from theming targets
154
+ /** @type {Set<string>} */
144
155
  const visualProps = new Set();
145
156
  for (const target of doc.theming.targets) {
146
157
  if (target.visualProps) {
@@ -149,6 +160,7 @@ async function loadKnownValues(componentName) {
149
160
  }
150
161
 
151
162
  // Extract values from prop type strings
163
+ /** @type {Record<string, string[]>} */
152
164
  const result = {};
153
165
  for (const prop of allProps) {
154
166
  if (!visualProps.has(prop.name)) continue;
@@ -157,7 +169,7 @@ async function loadKnownValues(componentName) {
157
169
  // Parse union type: "'info' | 'warning' | 'error' | 'success'" → ['info', 'warning', 'error', 'success']
158
170
  const matches = prop.type.match(/'([^']+)'/g);
159
171
  if (matches) {
160
- result[prop.name] = matches.map(m => m.replace(/'/g, ''));
172
+ result[prop.name] = matches.map((/** @type {string} */ m) => m.replace(/'/g, ''));
161
173
  }
162
174
  }
163
175
  return result;
@@ -167,12 +179,17 @@ async function loadKnownValues(componentName) {
167
179
  }
168
180
 
169
181
  // Cache for loaded known values
182
+ /** @type {Map<string, Record<string, string[]>>} */
170
183
  const _knownValuesCache = new Map();
184
+ /**
185
+ * @param {string} componentName
186
+ * @returns {Promise<Record<string, string[]>>}
187
+ */
171
188
  async function getKnownValues(componentName) {
172
189
  if (!_knownValuesCache.has(componentName)) {
173
190
  _knownValuesCache.set(componentName, await loadKnownValues(componentName));
174
191
  }
175
- return _knownValuesCache.get(componentName);
192
+ return _knownValuesCache.get(componentName) ?? {};
176
193
  }
177
194
 
178
195
  /**
@@ -196,10 +213,15 @@ function resolveCoreRoot() {
196
213
  * actually sees), falling back to the `src/<Component>/index.ts` in the
197
214
  * monorepo. Returns the file contents, or '' if nothing is found.
198
215
  */
216
+ /** @type {Map<string, string>} */
199
217
  const _componentDeclCache = new Map();
218
+ /**
219
+ * @param {string} pascalName
220
+ * @returns {string}
221
+ */
200
222
  function readComponentDeclarations(pascalName) {
201
223
  if (_componentDeclCache.has(pascalName)) {
202
- return _componentDeclCache.get(pascalName);
224
+ return _componentDeclCache.get(pascalName) ?? '';
203
225
  }
204
226
  let contents = '';
205
227
  const coreRoot = resolveCoreRoot();
@@ -231,6 +253,9 @@ function readComponentDeclarations(pascalName) {
231
253
  * `HeadingType`, `ButtonSize`) are NOT augmentable, so a generated augmentation
232
254
  * against them is dead code. We check that the name is exported (directly or
233
255
  * re-exported) as a type/interface.
256
+ * @param {string} pascalName
257
+ * @param {string} interfaceName
258
+ * @returns {boolean}
234
259
  */
235
260
  function componentHasAugmentableInterface(pascalName, interfaceName) {
236
261
  const decl = readComponentDeclarations(pascalName);
@@ -255,7 +280,7 @@ function componentHasAugmentableInterface(pascalName, interfaceName) {
255
280
  * generating a `declare module` block for them would be dead code — those are
256
281
  * skipped.
257
282
  *
258
- * @param {object} themeDef - Theme definition (resolved by defineTheme)
283
+ * @param {{components?: Record<string, Record<string, Record<string, unknown>>>}} themeDef - Theme definition (resolved by defineTheme)
259
284
  * @returns {Promise<string|null>} TypeScript declaration content, or null if no augmentations needed
260
285
  */
261
286
  async function generateVariantDeclarationsAsync(themeDef) {
@@ -264,6 +289,7 @@ async function generateVariantDeclarationsAsync(themeDef) {
264
289
  }
265
290
 
266
291
  // Collect custom values: { component: { prop: [value, ...] } }
292
+ /** @type {Record<string, Record<string, Set<string>>>} */
267
293
  const customValues = {};
268
294
 
269
295
  for (const [component, rules] of Object.entries(themeDef.components)) {
@@ -337,6 +363,8 @@ async function generateVariantDeclarationsAsync(themeDef) {
337
363
 
338
364
  /**
339
365
  * Resolve a token value — [light, dark] tuple becomes light-dark()
366
+ * @param {unknown} value
367
+ * @returns {unknown}
340
368
  */
341
369
  function resolveTokenValue(value) {
342
370
  if (Array.isArray(value)) {
@@ -348,12 +376,14 @@ function resolveTokenValue(value) {
348
376
  // Theme @scope selector helpers. Keep the `astryx` literal in sync with
349
377
  // packages/core/src/naming.ts (NAMESPACE) and generateThemeRules.ts.
350
378
  // Theme scopes to data-astryx-theme; the static build path must match.
351
- const themeScopeStart = name => `[data-astryx-theme="${name}"]`;
379
+ const themeScopeStart = (/** @type {string} */ name) => `[data-astryx-theme="${name}"]`;
352
380
  const THEME_SCOPE_TO = `[data-astryx-theme]`;
353
381
 
354
382
  /**
355
383
  * Import a theme module using jiti and find the defineTheme() result.
356
384
  * Returns the resolved DefinedTheme object.
385
+ * @param {string} filePath
386
+ * @returns {Promise<any>}
357
387
  */
358
388
  async function importThemeModule(filePath) {
359
389
  const jiti = createJiti(import.meta.url, {
@@ -377,6 +407,10 @@ async function importThemeModule(filePath) {
377
407
  );
378
408
  }
379
409
 
410
+ /**
411
+ * @param {any} value
412
+ * @returns {boolean}
413
+ */
380
414
  function isThemeObject(value) {
381
415
  return (
382
416
  value &&
@@ -390,6 +424,8 @@ function isThemeObject(value) {
390
424
  /**
391
425
  * Extract the theme definition from a JS/TS file.
392
426
  * Tries jiti first (full TS support), falls back to regex+eval.
427
+ * @param {string} filePath
428
+ * @returns {Promise<any>}
393
429
  */
394
430
  async function extractThemeDefinition(filePath) {
395
431
  try {
@@ -398,8 +434,9 @@ async function extractThemeDefinition(filePath) {
398
434
  try {
399
435
  return extractThemeDefinitionLegacy(filePath);
400
436
  } catch {
437
+ const je = /** @type {Error} */ (jitiError);
401
438
  throw new Error(
402
- `Failed to load theme from ${filePath}: ${jitiError.message}\n` +
439
+ `Failed to load theme from ${filePath}: ${je.message}\n` +
403
440
  `Make sure all imports in the theme file are resolvable.`,
404
441
  );
405
442
  }
@@ -409,6 +446,8 @@ async function extractThemeDefinition(filePath) {
409
446
  /**
410
447
  * Fallback extraction via regex + eval.
411
448
  * Only works for plain object literals — can't follow imports or variables.
449
+ * @param {string} filePath
450
+ * @returns {any}
412
451
  */
413
452
  function extractThemeDefinitionLegacy(filePath) {
414
453
  const content = fs.readFileSync(filePath, 'utf8');
@@ -434,8 +473,9 @@ function extractThemeDefinitionLegacy(filePath) {
434
473
 
435
474
  return eval(`(${objStr})`);
436
475
  } catch (e) {
476
+ const err = /** @type {Error} */ (e);
437
477
  throw new Error(
438
- `Failed to parse theme definition in ${filePath}: ${e.message}\n` +
478
+ `Failed to parse theme definition in ${filePath}: ${err.message}\n` +
439
479
  `Make sure the defineTheme() argument is a plain object literal.`,
440
480
  {cause: e},
441
481
  );
@@ -449,6 +489,8 @@ function extractThemeDefinitionLegacy(filePath) {
449
489
  * Looks for patterns like:
450
490
  * import { defaultIconRegistry } from './icons';
451
491
  * icons: defaultIconRegistry,
492
+ * @param {string} filePath
493
+ * @returns {{exportName: string, importPath: string} | null}
452
494
  */
453
495
  function extractIconInfo(filePath) {
454
496
  const content = fs.readFileSync(filePath, 'utf8');
@@ -457,7 +499,7 @@ function extractIconInfo(filePath) {
457
499
  const iconsMatch = content.match(/icons:\s*([a-zA-Z_][a-zA-Z0-9_]*)/);
458
500
  if (!iconsMatch) return null;
459
501
 
460
- const varName = iconsMatch[1];
502
+ const varName = /** @type {string} */ (iconsMatch[1]);
461
503
 
462
504
  // Find the import for that variable
463
505
  const importRegex = new RegExp(
@@ -468,7 +510,7 @@ function extractIconInfo(filePath) {
468
510
 
469
511
  return {
470
512
  exportName: varName,
471
- importPath: importMatch[1],
513
+ importPath: /** @type {string} */ (importMatch[1]),
472
514
  };
473
515
  }
474
516
 
@@ -476,6 +518,9 @@ function extractIconInfo(filePath) {
476
518
  * Generate a minimal JS module for a built theme.
477
519
  * Includes the theme name, marker, and re-exports the icon registry.
478
520
  * All styling is in the CSS file.
521
+ * @param {any} themeDef
522
+ * @param {{exportName: string, importPath: string} | null} iconInfo
523
+ * @returns {string}
479
524
  */
480
525
  function generateBuiltModule(themeDef, iconInfo) {
481
526
  const iconImport = iconInfo
@@ -487,6 +532,7 @@ function generateBuiltModule(themeDef, iconInfo) {
487
532
  : '';
488
533
 
489
534
  // Resolve token values — tuples become light-dark() strings
535
+ /** @type {Record<string, unknown>} */
490
536
  const resolvedTokens = {};
491
537
  if (themeDef.tokens) {
492
538
  for (const [key, value] of Object.entries(themeDef.tokens)) {
@@ -500,7 +546,7 @@ function generateBuiltModule(themeDef, iconInfo) {
500
546
  .join('\n');
501
547
 
502
548
  return `${iconImport}/**
503
- * ${themeDef.name} theme — built by \`${getRunPrefix()} astryx theme build\`
549
+ * ${themeDef.name} theme — built by \`${getCliInvocation()} theme build\`
504
550
  * Import the CSS file alongside this module:
505
551
  *
506
552
  * import { ${toIdentifier(themeDef.name)}Theme } from './${themeDef.name}';
@@ -517,6 +563,10 @@ ${iconReExport}`;
517
563
 
518
564
  /**
519
565
  * Generate TypeScript declarations for a built theme module.
566
+ * @param {any} themeDef
567
+ * @param {{exportName: string, importPath: string} | null} iconInfo
568
+ * @param {string | null} variantsFileName
569
+ * @returns {string}
520
570
  */
521
571
  function generateBuiltTypes(themeDef, iconInfo, variantsFileName) {
522
572
  const iconType = iconInfo
@@ -544,6 +594,7 @@ ${iconType}export declare const ${toIdentifier(themeDef.name)}Theme: DefinedThem
544
594
  /**
545
595
  * Known Astryx component names and their visual props.
546
596
  * Used to warn on typos in defineTheme component overrides.
597
+ * @type {Record<string, string[]>}
547
598
  */
548
599
  const KNOWN_COMPONENTS = {
549
600
  appshell: ['position'],
@@ -605,8 +656,11 @@ const KNOWN_COMPONENTS = {
605
656
  * Validate component overrides in a theme definition.
606
657
  * Warns on unknown component names and unknown prop names.
607
658
  * Returns array of warning strings.
659
+ * @param {{components?: Record<string, Record<string, unknown>>}} themeDef
660
+ * @returns {string[]}
608
661
  */
609
662
  function validateComponentOverrides(themeDef) {
663
+ /** @type {string[]} */
610
664
  const warnings = [];
611
665
  if (!themeDef.components) return warnings;
612
666
 
@@ -669,8 +723,11 @@ function validateComponentOverrides(themeDef) {
669
723
  * (e.g. borderRadius, padding) instead.
670
724
  *
671
725
  * Returns array of error strings.
726
+ * @param {{components?: Record<string, Record<string, Record<string, unknown>>>}} themeDef
727
+ * @returns {string[]}
672
728
  */
673
729
  function validatePrivateVars(themeDef) {
730
+ /** @type {string[]} */
674
731
  const errors = [];
675
732
  if (!themeDef.components) return errors;
676
733
 
@@ -707,14 +764,14 @@ function resolveCliBin() {
707
764
  * Resolves with the child's exit code; never rejects.
708
765
  *
709
766
  * @param {string} file - The theme file argument, as the user passed it.
710
- * @param {object} options - Parsed command options (only `out` is forwarded).
767
+ * @param {{out?: string}} options - Parsed command options (only `out` is forwarded).
711
768
  * @returns {Promise<number>}
712
769
  */
713
770
  function runThemeBuildOnceChild(file, options) {
714
771
  const cliBin = resolveCliBin();
715
772
  const args = [cliBin, 'theme', 'build', file];
716
773
  if (options.out) args.push('--out', options.out);
717
- return new Promise(resolve => {
774
+ return new Promise((/** @type {(code: number) => void} */ resolve) => {
718
775
  const child = spawn(process.execPath, args, {
719
776
  stdio: 'inherit',
720
777
  env: process.env,
@@ -733,7 +790,7 @@ function runThemeBuildOnceChild(file, options) {
733
790
  *
734
791
  * @param {string} file - The theme file argument, as the user passed it.
735
792
  * @param {string} filePath - Absolute path to the theme file.
736
- * @param {object} options - Parsed command options.
793
+ * @param {{out?: string}} options - Parsed command options.
737
794
  * @returns {Promise<void>} Resolves when the watcher is stopped (Ctrl-C).
738
795
  */
739
796
  async function runThemeBuildWatch(file, filePath, options) {
@@ -746,7 +803,8 @@ async function runThemeBuildWatch(file, filePath, options) {
746
803
 
747
804
  let building = false;
748
805
  let queued = false;
749
- let debounce = null;
806
+ /** @type {ReturnType<typeof setTimeout> | undefined} */
807
+ let debounce;
750
808
 
751
809
  const rebuild = async () => {
752
810
  if (building) {
@@ -777,7 +835,7 @@ async function runThemeBuildWatch(file, filePath, options) {
777
835
  debounce = setTimeout(rebuild, 100);
778
836
  });
779
837
 
780
- await new Promise(resolve => {
838
+ await new Promise((/** @type {(value?: void) => void} */ resolve) => {
781
839
  const stop = () => {
782
840
  clearTimeout(debounce);
783
841
  watcher.close();
@@ -789,11 +847,14 @@ async function runThemeBuildWatch(file, filePath, options) {
789
847
  });
790
848
  }
791
849
 
850
+ /**
851
+ * @param {import('commander').Command} program
852
+ */
792
853
  export function registerTheme(program) {
793
854
  const theme = program
794
855
  .command('theme')
795
856
  .description('Theme tools — build, export, and manage themes')
796
- .action((options, cmd) => {
857
+ .action((/** @type {unknown} */ options, /** @type {import('commander').Command} */ cmd) => {
797
858
  // Parent group has no default behaviour. If the user passed an
798
859
  // unknown subcommand (e.g. `astryx theme bogus`), Commander hands it to
799
860
  // us as a positional in cmd.args — exit 1 with a clear error.
@@ -817,7 +878,7 @@ export function registerTheme(program) {
817
878
  '-w, --watch',
818
879
  'Rebuild automatically when the theme file changes (Ctrl-C to stop)',
819
880
  )
820
- .action(async (file, options) => {
881
+ .action(async (/** @type {string} */ file, /** @type {{out?: string, watch?: boolean}} */ options) => {
821
882
  const filePath = path.resolve(process.cwd(), file);
822
883
  const json = program.opts().json || false;
823
884
 
@@ -847,7 +908,8 @@ export function registerTheme(program) {
847
908
  try {
848
909
  themeDef = await extractThemeDefinition(filePath);
849
910
  } catch (e) {
850
- cliError(e.message, {code: ERROR_CODES.ERR_THEME_LOAD});
911
+ const err = /** @type {Error} */ (e);
912
+ cliError(err.message, {code: ERROR_CODES.ERR_THEME_LOAD});
851
913
  return;
852
914
  }
853
915
 
@@ -993,7 +1055,10 @@ export function registerTheme(program) {
993
1055
  const augmentationSource = resolvedTheme || themeDef;
994
1056
  const variantDecl = await generateVariantDeclarationsAsync(augmentationSource);
995
1057
  const variantsFileName = variantDecl ? `${baseName}.variants.d.ts` : null;
996
- const variantDtsPath = variantDecl ? path.join(outDir, variantsFileName) : null;
1058
+ const variantDtsPath =
1059
+ variantDecl && variantsFileName
1060
+ ? path.join(outDir, variantsFileName)
1061
+ : null;
997
1062
  const variantContent = variantDecl
998
1063
  ? generatedHeader(sourceRelative, 'ts', buildCommand) + variantDecl
999
1064
  : null;
@@ -1014,11 +1079,12 @@ export function registerTheme(program) {
1014
1079
  {dest: jsPath, content: jsContent},
1015
1080
  {dest: dtsPath, content: dtsContent},
1016
1081
  ];
1017
- if (variantDtsPath) {
1082
+ if (variantDtsPath && variantContent) {
1018
1083
  writes.push({dest: variantDtsPath, content: variantContent});
1019
1084
  }
1020
1085
 
1021
1086
  fs.mkdirSync(outDir, {recursive: true});
1087
+ /** @type {Array<{tmp: string, dest: string}>} */
1022
1088
  const staged = [];
1023
1089
  try {
1024
1090
  for (const w of writes) {
@@ -1034,7 +1100,7 @@ export function registerTheme(program) {
1034
1100
  for (const s of staged) {
1035
1101
  try { fs.rmSync(s.tmp, {force: true}); } catch { /* best-effort */ }
1036
1102
  }
1037
- const msg = `Failed to write theme outputs: ${err.message}`;
1103
+ const msg = `Failed to write theme outputs: ${/** @type {Error} */ (err).message}`;
1038
1104
  cliError(msg, {code: ERROR_CODES.ERR_WRITE_FAILED});
1039
1105
  return;
1040
1106
  }
@@ -1045,7 +1111,7 @@ export function registerTheme(program) {
1045
1111
  humanLog(` ${size} KB`);
1046
1112
  humanLog(`✓ ${path.relative(process.cwd(), jsPath)}`);
1047
1113
  humanLog(`✓ ${path.relative(process.cwd(), dtsPath)}`);
1048
- if (variantDtsPath) {
1114
+ if (variantDtsPath && variantDecl) {
1049
1115
  const augCount = (variantDecl.match(/': true;/g) || []).length;
1050
1116
  humanLog(`✓ ${path.relative(process.cwd(), variantDtsPath)} (${augCount} type augmentations)`);
1051
1117
  }
@@ -1061,7 +1127,7 @@ export function registerTheme(program) {
1061
1127
  css: path.relative(process.cwd(), outPath),
1062
1128
  js: path.relative(process.cwd(), jsPath),
1063
1129
  dts: path.relative(process.cwd(), dtsPath),
1064
- ...(variantDecl ? {variantsDts: path.relative(process.cwd(), variantDtsPath)} : {}),
1130
+ ...(variantDecl && variantDtsPath ? {variantsDts: path.relative(process.cwd(), variantDtsPath)} : {}),
1065
1131
  },
1066
1132
  warnings: warningMessages,
1067
1133
  });
@@ -1108,15 +1174,21 @@ Or with a <link> tag:
1108
1174
  .description('List themes available to add')
1109
1175
  .action(async () => {
1110
1176
  const json = program.opts().json || false;
1177
+ /** @type {import('../../types/theme').ThemeListResponse} */
1111
1178
  let result;
1112
1179
  try {
1113
- result = await themeAdd(undefined, {list: true, cwd: process.cwd()});
1180
+ result = /** @type {import('../../types/theme').ThemeListResponse} */ (
1181
+ await themeAdd(undefined, {list: true, cwd: process.cwd()})
1182
+ );
1114
1183
  } catch (e) {
1115
- cliError(e.message, {suggestions: e.suggestions || [], code: e.code});
1184
+ const err = /** @type {import('../../api/error.mjs').AstryxError} */ (e);
1185
+ cliError(err.message, {suggestions: err.suggestions || [], code: err.code});
1116
1186
  return;
1117
1187
  }
1118
1188
 
1119
- if (json) return jsonOut(result.type, result.data);
1189
+ // theme.list is not registered in CLIResponseType (base.d.ts, owned by the
1190
+ // coordinator) — cast the discriminant until it is added there.
1191
+ if (json) return jsonOut(/** @type {any} */ (result.type), result.data);
1120
1192
 
1121
1193
  const themes = result.data;
1122
1194
  if (themes.length === 0) {
@@ -1130,7 +1202,7 @@ Or with a <link> tag:
1130
1202
  if (t.description) humanLog(` ${t.description}`);
1131
1203
  }
1132
1204
  humanLog('\nUsage:');
1133
- humanLog(' astryx theme add <slug> [target-path] Scaffold a theme file you own\n');
1205
+ humanLog(` ${getCliInvocation()} theme add <slug> [target-path] Scaffold a theme file you own\n`);
1134
1206
  });
1135
1207
 
1136
1208
  theme
@@ -1138,49 +1210,32 @@ Or with a <link> tag:
1138
1210
  .description('Scaffold a theme into your project as editable source')
1139
1211
  .option('-f, --overwrite', 'Overwrite existing files without prompting')
1140
1212
  .option('--list', 'List available themes')
1141
- .action(async (slug, targetPath, options) => {
1213
+ .action(async (/** @type {string | undefined} */ slug, /** @type {string | undefined} */ targetPath, /** @type {{list?: boolean, overwrite?: boolean}} */ options) => {
1142
1214
  const json = program.opts().json || false;
1143
1215
 
1144
- // Only prompt with a real TTY on stdin — a piped/redirected stdin would
1145
- // make clack hang. Non-interactive callers fall through to the API's
1146
- // ERR_FILE_EXISTS guard.
1147
- const interactive =
1148
- !json && !isNonInteractive({json}) && Boolean(process.stdin.isTTY);
1149
- if (slug && !options.list && !options.overwrite && interactive) {
1150
- const collision = await detectThemeCollision(slug, targetPath);
1151
- if (collision) {
1152
- const rel = path.relative(process.cwd(), collision) || collision;
1153
- const p = await import('@clack/prompts');
1154
- const confirmed = await p.confirm({
1155
- message: `Overwrite existing file ${rel}?`,
1156
- initialValue: false,
1157
- });
1158
- if (p.isCancel(confirmed)) {
1159
- p.cancel('Cancelled.');
1160
- return;
1161
- }
1162
- if (!confirmed) {
1163
- humanLog('Aborted. Re-run with --overwrite to replace the file.');
1164
- return;
1165
- }
1166
- options.overwrite = true;
1167
- }
1168
- }
1169
-
1216
+ // The CLI is non-interactive: never prompt to confirm an overwrite.
1217
+ // Existing files require an explicit --overwrite; otherwise themeAdd's
1218
+ // ERR_FILE_EXISTS guard rejects the write.
1219
+ /** @type {import('../../types/theme').ThemeListResponse | import('../../types/theme').ThemeAddResponse} */
1170
1220
  let result;
1171
1221
  try {
1172
- result = await themeAdd(slug, {
1173
- list: options.list,
1174
- targetPath,
1175
- overwrite: options.overwrite,
1176
- cwd: process.cwd(),
1177
- });
1222
+ result = /** @type {import('../../types/theme').ThemeListResponse | import('../../types/theme').ThemeAddResponse} */ (
1223
+ await themeAdd(slug, {
1224
+ list: options.list,
1225
+ targetPath,
1226
+ overwrite: options.overwrite,
1227
+ cwd: process.cwd(),
1228
+ })
1229
+ );
1178
1230
  } catch (e) {
1179
- cliError(e.message, {suggestions: e.suggestions || [], code: e.code});
1231
+ const err = /** @type {import('../../api/error.mjs').AstryxError} */ (e);
1232
+ cliError(err.message, {suggestions: err.suggestions || [], code: err.code});
1180
1233
  return;
1181
1234
  }
1182
1235
 
1183
- if (json) return jsonOut(result.type, result.data);
1236
+ // theme.list/theme.add are not registered in CLIResponseType (base.d.ts,
1237
+ // owned by the coordinator) — cast the discriminant until they are added.
1238
+ if (json) return jsonOut(/** @type {any} */ (result.type), result.data);
1184
1239
 
1185
1240
  if (result.type === 'theme.list') {
1186
1241
  const themes = result.data;
@@ -1191,7 +1246,7 @@ Or with a <link> tag:
1191
1246
  if (t.description) humanLog(` ${t.description}`);
1192
1247
  }
1193
1248
  humanLog('\nUsage:');
1194
- humanLog(' astryx theme add <slug> [target-path] Scaffold a theme file you own\n');
1249
+ humanLog(` ${getCliInvocation()} theme add <slug> [target-path] Scaffold a theme file you own\n`);
1195
1250
  return;
1196
1251
  }
1197
1252
 
@@ -1219,40 +1274,3 @@ This is your copy of the ${displayName} theme — edit ${entry} to make it your
1219
1274
  });
1220
1275
  }
1221
1276
 
1222
- /**
1223
- * First existing file that scaffolding <slug> into <targetPath> would clobber,
1224
- * or null. Used to prompt before invoking the API; the API re-validates and
1225
- * owns any authoritative error.
1226
- *
1227
- * @param {string} slug
1228
- * @param {string} [targetPath]
1229
- * @returns {Promise<string|null>}
1230
- */
1231
- async function detectThemeCollision(slug, targetPath) {
1232
- let themes;
1233
- try {
1234
- themes = listThemes();
1235
- } catch {
1236
- return null;
1237
- }
1238
- const match = themes.find(t => t.slug.toLowerCase() === slug.toLowerCase());
1239
- if (!match) return null;
1240
-
1241
- const rawTarget = targetPath || path.join('src', 'themes', match.slug);
1242
- let resolvedDir;
1243
- try {
1244
- // Fail soft (null) on traversal; the API surfaces the real error.
1245
- const {assertWithin} = await import('../utils/path-safety.mjs');
1246
- resolvedDir = assertWithin(rawTarget, process.cwd(), {
1247
- label: 'theme target path',
1248
- });
1249
- } catch {
1250
- return null;
1251
- }
1252
-
1253
- for (const name of match.files) {
1254
- const dest = path.join(resolvedDir, name);
1255
- if (fs.existsSync(dest)) return dest;
1256
- }
1257
- return null;
1258
- }