@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
@@ -0,0 +1,178 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Detect the project's package manager from lockfiles.
5
+ *
6
+ * Returns the correct command prefix for running package binaries
7
+ * (e.g. 'npx astryx', 'yarn astryx', 'pnpm exec astryx').
8
+ */
9
+
10
+ import * as fs from 'node:fs';
11
+ import * as path from 'node:path';
12
+
13
+ /**
14
+ * A package manager we can install with and run binaries through.
15
+ * @typedef {'yarn' | 'pnpm' | 'bun' | 'npm'} PackageManager
16
+ */
17
+
18
+ /**
19
+ * Result of package-manager detection. `'npx'` is the sentinel for "nothing
20
+ * detected" — no lockfile, no `packageManager` field, no runner user-agent —
21
+ * so callers fall back to npm/npx. It is a distinct value from {@link PackageManager}
22
+ * because it means "undetected", not "npm was chosen".
23
+ * @typedef {PackageManager | 'npx'} DetectedPackageManager
24
+ */
25
+
26
+ /** @type {readonly PackageManager[]} */
27
+ const KNOWN_PMS = ['yarn', 'pnpm', 'bun', 'npm'];
28
+
29
+ /**
30
+ * Narrow an arbitrary string to a known {@link PackageManager}.
31
+ * @param {string} name
32
+ * @returns {name is PackageManager}
33
+ */
34
+ function isKnownPackageManager(name) {
35
+ return /** @type {readonly string[]} */ (KNOWN_PMS).includes(name);
36
+ }
37
+
38
+ /**
39
+ * Detect the package manager used in a project directory.
40
+ * Walks up from targetDir looking for lockfiles.
41
+ *
42
+ * Returns `'npx'` when nothing can be detected — see {@link DetectedPackageManager}.
43
+ *
44
+ * @param {string} [targetDir=process.cwd()]
45
+ * @returns {DetectedPackageManager}
46
+ */
47
+ export function detectPackageManager(targetDir = process.cwd()) {
48
+ let dir = path.resolve(targetDir);
49
+ const root = path.parse(dir).root;
50
+
51
+ while (dir !== root) {
52
+ // 1. Lockfiles (highest priority)
53
+ if (fs.existsSync(path.join(dir, 'yarn.lock'))) return 'yarn';
54
+ if (fs.existsSync(path.join(dir, 'pnpm-lock.yaml'))) return 'pnpm';
55
+ if (fs.existsSync(path.join(dir, 'bun.lockb')) || fs.existsSync(path.join(dir, 'bun.lock'))) return 'bun';
56
+ if (fs.existsSync(path.join(dir, 'package-lock.json'))) return 'npm';
57
+
58
+ // 2. packageManager field in package.json
59
+ const pkgPath = path.join(dir, 'package.json');
60
+ if (fs.existsSync(pkgPath)) {
61
+ try {
62
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
63
+ if (pkg.packageManager) {
64
+ const name = pkg.packageManager.split('@')[0];
65
+ if (isKnownPackageManager(name)) return name;
66
+ }
67
+ } catch {
68
+ // Best-effort: unreadable/invalid package.json — keep walking up.
69
+ }
70
+ }
71
+
72
+ dir = path.dirname(dir);
73
+ }
74
+
75
+ // 3. npm_config_user_agent env var (set by all PMs when running scripts)
76
+ const ua = process.env.npm_config_user_agent;
77
+ if (ua) {
78
+ const name = ua.split('/')[0];
79
+ if (isKnownPackageManager(name)) return name;
80
+ }
81
+
82
+ return 'npx';
83
+ }
84
+
85
+ /**
86
+ * Get the command prefix for running a package binary.
87
+ *
88
+ * @param {string} [targetDir]
89
+ * @returns {string} e.g. 'npx', 'yarn', 'pnpm exec', 'bunx'
90
+ */
91
+ export function getRunPrefix(targetDir) {
92
+ const pm = detectPackageManager(targetDir);
93
+ switch (pm) {
94
+ case 'yarn': return 'yarn';
95
+ case 'pnpm': return 'pnpm exec';
96
+ case 'bun': return 'bunx';
97
+ case 'npm':
98
+ default: return 'npx';
99
+ }
100
+ }
101
+
102
+ /** The published CLI package name — used for one-off (uninstalled) invocations. */
103
+ export const CLI_PACKAGE = '@astryxdesign/cli';
104
+
105
+ /** The CLI binary name — only resolves once the CLI is installed (or run via CLI_PACKAGE). */
106
+ export const CLI_BIN = 'astryx';
107
+
108
+ /**
109
+ * Get the one-off ("dlx") runner for the detected package manager.
110
+ *
111
+ * Unlike {@link getRunPrefix} (which runs an *installed* binary), this fetches
112
+ * and runs a package on demand — so it is always paired with the scoped
113
+ * {@link CLI_PACKAGE}, never the bare `astryx` bin. Running bare `npx astryx`
114
+ * without the CLI installed resolves to an unrelated package on the registry.
115
+ *
116
+ * @param {string} [targetDir]
117
+ * @returns {string} e.g. 'npx', 'pnpm dlx', 'yarn dlx', 'bunx'
118
+ */
119
+ export function getDlxPrefix(targetDir) {
120
+ const pm = detectPackageManager(targetDir);
121
+ switch (pm) {
122
+ case 'yarn': return 'yarn dlx';
123
+ case 'pnpm': return 'pnpm dlx';
124
+ case 'bun': return 'bunx';
125
+ case 'npm':
126
+ default: return 'npx';
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Heuristic: was the running CLI launched one-off via a package runner
132
+ * (npx / pnpm dlx / yarn dlx / bunx) rather than from an installed dependency?
133
+ *
134
+ * We sniff the entry path (`process.argv[1]`) for well-known runner-cache
135
+ * markers. This errs safe in both directions: a false negative falls back to
136
+ * the installed form (`<prefix> astryx`, the historical behavior), and a false
137
+ * positive emits the always-valid scoped form (`<dlx> @astryxdesign/cli`).
138
+ *
139
+ * @returns {boolean}
140
+ */
141
+ export function isCliOneOff() {
142
+ const entry = String(process.argv[1] || '').replace(/\\/g, '/');
143
+ return /\/_npx\/|\/dlx[-/]|\/\.bun\/install\/cache\/|\/bunx-/.test(entry);
144
+ }
145
+
146
+ /**
147
+ * The safe, install-aware CLI invocation stem to suggest to users.
148
+ *
149
+ * - Installed / global / dev: `<run-prefix> astryx` (e.g. `pnpm exec astryx`).
150
+ * Bare `astryx` resolves to the local (or global) binary.
151
+ * - One-off (npx/dlx cache): `<dlx-prefix> @astryxdesign/cli` — the bare
152
+ * `astryx` name isn't on disk, so npm would fetch an unrelated registry
153
+ * package; the scoped package always resolves to us.
154
+ *
155
+ * @param {string} [targetDir]
156
+ * @returns {string}
157
+ */
158
+ export function getCliInvocation(targetDir) {
159
+ if (isCliOneOff()) return `${getDlxPrefix(targetDir)} ${CLI_PACKAGE}`;
160
+ return `${getRunPrefix(targetDir)} ${CLI_BIN}`;
161
+ }
162
+
163
+ /**
164
+ * Format a full, runnable CLI command from a subcommand string.
165
+ *
166
+ * Accepts either `astryx component Button` or `component Button` (a leading
167
+ * `astryx` token is stripped) and prepends the install-aware invocation stem
168
+ * from {@link getCliInvocation}.
169
+ *
170
+ * @param {string} command e.g. 'astryx component Button' | 'docs tokens'
171
+ * @param {string} [targetDir]
172
+ * @returns {string}
173
+ */
174
+ export function formatCliCommand(command, targetDir) {
175
+ const sub = String(command).replace(/^\s*astryx\b\s*/, '').trim();
176
+ const stem = getCliInvocation(targetDir);
177
+ return sub ? `${stem} ${sub}` : stem;
178
+ }
@@ -0,0 +1,220 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ import {describe, it, expect, afterEach, vi} from 'vitest';
4
+ import * as fs from 'node:fs';
5
+ import * as path from 'node:path';
6
+ import * as os from 'node:os';
7
+ import {
8
+ detectPackageManager,
9
+ getDlxPrefix,
10
+ isCliOneOff,
11
+ getCliInvocation,
12
+ formatCliCommand,
13
+ } from './package-manager.mjs';
14
+
15
+ let tmpDir;
16
+ const ORIGINAL_ARGV1 = process.argv[1];
17
+
18
+ afterEach(() => {
19
+ if (tmpDir) {
20
+ fs.rmSync(tmpDir, {recursive: true, force: true});
21
+ tmpDir = null;
22
+ }
23
+ vi.restoreAllMocks();
24
+ delete process.env.npm_config_user_agent;
25
+ process.argv[1] = ORIGINAL_ARGV1;
26
+ });
27
+
28
+ function makeTmpDir() {
29
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-pm-test-'));
30
+ return tmpDir;
31
+ }
32
+
33
+ describe('detectPackageManager', () => {
34
+ it('detects yarn from yarn.lock', () => {
35
+ const dir = makeTmpDir();
36
+ fs.writeFileSync(path.join(dir, 'yarn.lock'), '');
37
+ expect(detectPackageManager(dir)).toBe('yarn');
38
+ });
39
+
40
+ it('detects pnpm from pnpm-lock.yaml', () => {
41
+ const dir = makeTmpDir();
42
+ fs.writeFileSync(path.join(dir, 'pnpm-lock.yaml'), '');
43
+ expect(detectPackageManager(dir)).toBe('pnpm');
44
+ });
45
+
46
+ it('detects npm from package-lock.json', () => {
47
+ const dir = makeTmpDir();
48
+ fs.writeFileSync(path.join(dir, 'package-lock.json'), '{}');
49
+ expect(detectPackageManager(dir)).toBe('npm');
50
+ });
51
+
52
+ it('detects bun from bun.lockb', () => {
53
+ const dir = makeTmpDir();
54
+ fs.writeFileSync(path.join(dir, 'bun.lockb'), '');
55
+ expect(detectPackageManager(dir)).toBe('bun');
56
+ });
57
+
58
+ it('detects from packageManager field in package.json (no lockfile)', () => {
59
+ const dir = makeTmpDir();
60
+ fs.writeFileSync(
61
+ path.join(dir, 'package.json'),
62
+ JSON.stringify({packageManager: 'yarn@4.1.0'}),
63
+ );
64
+ expect(detectPackageManager(dir)).toBe('yarn');
65
+ });
66
+
67
+ it('detects pnpm from packageManager field', () => {
68
+ const dir = makeTmpDir();
69
+ fs.writeFileSync(
70
+ path.join(dir, 'package.json'),
71
+ JSON.stringify({packageManager: 'pnpm@8.0.0'}),
72
+ );
73
+ expect(detectPackageManager(dir)).toBe('pnpm');
74
+ });
75
+
76
+ it('ignores unknown packageManager values', () => {
77
+ const dir = makeTmpDir();
78
+ fs.writeFileSync(
79
+ path.join(dir, 'package.json'),
80
+ JSON.stringify({packageManager: 'unknown@1.0.0'}),
81
+ );
82
+ expect(detectPackageManager(dir)).toBe('npx');
83
+ });
84
+
85
+ it('lockfile takes priority over packageManager field', () => {
86
+ const dir = makeTmpDir();
87
+ fs.writeFileSync(path.join(dir, 'yarn.lock'), '');
88
+ fs.writeFileSync(
89
+ path.join(dir, 'package.json'),
90
+ JSON.stringify({packageManager: 'pnpm@8.0.0'}),
91
+ );
92
+ expect(detectPackageManager(dir)).toBe('yarn');
93
+ });
94
+
95
+ it('detects from npm_config_user_agent env var', () => {
96
+ const dir = makeTmpDir();
97
+ process.env.npm_config_user_agent = 'yarn/1.22.22 node/v20.0.0';
98
+ expect(detectPackageManager(dir)).toBe('yarn');
99
+ });
100
+
101
+ it('detects pnpm from npm_config_user_agent env var', () => {
102
+ const dir = makeTmpDir();
103
+ process.env.npm_config_user_agent = 'pnpm/8.15.0 node/v20.0.0';
104
+ expect(detectPackageManager(dir)).toBe('pnpm');
105
+ });
106
+
107
+ it('falls back to npx when no signals present', () => {
108
+ const dir = makeTmpDir();
109
+ expect(detectPackageManager(dir)).toBe('npx');
110
+ });
111
+
112
+ it('packageManager field takes priority over npm_config_user_agent', () => {
113
+ const dir = makeTmpDir();
114
+ fs.writeFileSync(
115
+ path.join(dir, 'package.json'),
116
+ JSON.stringify({packageManager: 'bun@1.0.0'}),
117
+ );
118
+ process.env.npm_config_user_agent = 'npm/10.0.0 node/v20.0.0';
119
+ expect(detectPackageManager(dir)).toBe('bun');
120
+ });
121
+ });
122
+
123
+ describe('getDlxPrefix', () => {
124
+ it('returns "pnpm dlx" for pnpm projects', () => {
125
+ const dir = makeTmpDir();
126
+ fs.writeFileSync(path.join(dir, 'pnpm-lock.yaml'), '');
127
+ expect(getDlxPrefix(dir)).toBe('pnpm dlx');
128
+ });
129
+
130
+ it('returns "yarn dlx" for yarn projects', () => {
131
+ const dir = makeTmpDir();
132
+ fs.writeFileSync(path.join(dir, 'yarn.lock'), '');
133
+ expect(getDlxPrefix(dir)).toBe('yarn dlx');
134
+ });
135
+
136
+ it('returns "bunx" for bun projects', () => {
137
+ const dir = makeTmpDir();
138
+ fs.writeFileSync(path.join(dir, 'bun.lockb'), '');
139
+ expect(getDlxPrefix(dir)).toBe('bunx');
140
+ });
141
+
142
+ it('falls back to "npx" with no signals', () => {
143
+ const dir = makeTmpDir();
144
+ delete process.env.npm_config_user_agent;
145
+ expect(getDlxPrefix(dir)).toBe('npx');
146
+ });
147
+ });
148
+
149
+ describe('isCliOneOff', () => {
150
+ it('detects an npm npx cache entry', () => {
151
+ process.argv[1] = '/home/u/.npm/_npx/a1b2/node_modules/.bin/astryx';
152
+ expect(isCliOneOff()).toBe(true);
153
+ });
154
+
155
+ it('detects a pnpm dlx cache entry', () => {
156
+ process.argv[1] = '/home/u/.cache/pnpm/dlx/9f/node_modules/@astryxdesign/cli/bin/astryx.mjs';
157
+ expect(isCliOneOff()).toBe(true);
158
+ });
159
+
160
+ it('detects a bunx cache entry', () => {
161
+ process.argv[1] = '/home/u/.bun/install/cache/@astryxdesign/cli/bin/astryx.mjs';
162
+ expect(isCliOneOff()).toBe(true);
163
+ });
164
+
165
+ it('is false for an installed node_modules entry', () => {
166
+ process.argv[1] = '/proj/node_modules/@astryxdesign/cli/bin/astryx.mjs';
167
+ expect(isCliOneOff()).toBe(false);
168
+ });
169
+
170
+ it('is false for a source checkout (dev) entry', () => {
171
+ process.argv[1] = '/repo/packages/cli/bin/astryx.mjs';
172
+ expect(isCliOneOff()).toBe(false);
173
+ });
174
+ });
175
+
176
+ describe('getCliInvocation', () => {
177
+ it('uses the run-prefix + bare bin when installed (not one-off)', () => {
178
+ process.argv[1] = '/proj/node_modules/@astryxdesign/cli/bin/astryx.mjs';
179
+ const dir = makeTmpDir();
180
+ fs.writeFileSync(path.join(dir, 'pnpm-lock.yaml'), '');
181
+ expect(getCliInvocation(dir)).toBe('pnpm exec astryx');
182
+ });
183
+
184
+ it('uses the dlx runner + scoped package when run one-off', () => {
185
+ process.argv[1] = '/home/u/.npm/_npx/a1b2/node_modules/.bin/astryx';
186
+ const dir = makeTmpDir();
187
+ delete process.env.npm_config_user_agent;
188
+ expect(getCliInvocation(dir)).toBe('npx @astryxdesign/cli');
189
+ });
190
+
191
+ it('pairs the dlx runner with the scoped package for pnpm one-off', () => {
192
+ process.argv[1] = '/home/u/.cache/pnpm/dlx/9f/node_modules/@astryxdesign/cli/bin/astryx.mjs';
193
+ const dir = makeTmpDir();
194
+ fs.writeFileSync(path.join(dir, 'pnpm-lock.yaml'), '');
195
+ expect(getCliInvocation(dir)).toBe('pnpm dlx @astryxdesign/cli');
196
+ });
197
+ });
198
+
199
+ describe('formatCliCommand', () => {
200
+ it('strips a leading "astryx" token and prepends the invocation stem', () => {
201
+ process.argv[1] = '/proj/node_modules/@astryxdesign/cli/bin/astryx.mjs';
202
+ const dir = makeTmpDir();
203
+ fs.writeFileSync(path.join(dir, 'pnpm-lock.yaml'), '');
204
+ expect(formatCliCommand('astryx component Button', dir)).toBe('pnpm exec astryx component Button');
205
+ });
206
+
207
+ it('accepts a bare subcommand (no leading astryx)', () => {
208
+ process.argv[1] = '/proj/node_modules/@astryxdesign/cli/bin/astryx.mjs';
209
+ const dir = makeTmpDir();
210
+ fs.writeFileSync(path.join(dir, 'package-lock.json'), '{}');
211
+ expect(formatCliCommand('docs tokens', dir)).toBe('npx astryx docs tokens');
212
+ });
213
+
214
+ it('rewrites to the scoped package for one-off invocations', () => {
215
+ process.argv[1] = '/home/u/.npm/_npx/a1b2/node_modules/.bin/astryx';
216
+ const dir = makeTmpDir();
217
+ fs.writeFileSync(path.join(dir, 'package-lock.json'), '{}');
218
+ expect(formatCliCommand('astryx component Button', dir)).toBe('npx @astryxdesign/cli component Button');
219
+ });
220
+ });
@@ -165,21 +165,3 @@ export function isFilePathArg(pathArg) {
165
165
  const ext = path.extname(base).toLowerCase();
166
166
  return ext.length > 0 && FILE_EXTENSIONS.has(ext);
167
167
  }
168
-
169
- /**
170
- * True when the process is running non-interactively (no TTY) or when the
171
- * caller has signaled JSON / scripted use. Commands consult this before
172
- * prompting for confirmation; in scripted mode they require an explicit
173
- * `--overwrite` flag instead.
174
- *
175
- * @param {object} [options]
176
- * @param {boolean} [options.json] - Caller's --json flag.
177
- * @returns {boolean}
178
- */
179
- export function isNonInteractive({json = false} = {}) {
180
- if (json) return true;
181
- // stdin not a TTY means piped input or scripted execution.
182
- if (process.stdin && process.stdin.isTTY === false) return true;
183
- if (process.stdout && process.stdout.isTTY === false) return true;
184
- return false;
185
- }
@@ -13,7 +13,7 @@ import {fileURLToPath} from 'node:url';
13
13
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
14
14
 
15
15
  /** Root of the @astryxdesign/cli package */
16
- export const CLI_ROOT = path.resolve(__dirname, '..', '..');
16
+ export const CLI_ROOT = path.resolve(__dirname, '..');
17
17
 
18
18
  /**
19
19
  * Find packages/core directory by walking up from startDir.
@@ -78,6 +78,7 @@ export function findProjectRoot(startDir = process.cwd()) {
78
78
  * Returns array of { name, category, docsDir, blocksDir }.
79
79
  */
80
80
  export function discoverExternalPackages(startDir = process.cwd()) {
81
+ /** @type {Array<{name: string, category: string, docsDir: string, blocksDir: string | null}>} */
81
82
  const externals = [];
82
83
  let dir = startDir;
83
84
 
@@ -96,6 +97,7 @@ export function discoverExternalPackages(startDir = process.cwd()) {
96
97
 
97
98
  if (!nodeModulesDir) return externals;
98
99
 
100
+ /** @param {string} searchDir */
99
101
  const scanDir = (searchDir) => {
100
102
  if (!fs.existsSync(searchDir)) return;
101
103
  const entries = fs.readdirSync(searchDir, {withFileTypes: true});
@@ -141,6 +143,7 @@ export function discoverExternalPackages(startDir = process.cwd()) {
141
143
  /**
142
144
  * List available component directories in packages/core/src.
143
145
  * Returns directory names that contain Astryx*.tsx files.
146
+ * @param {string} coreDir
144
147
  */
145
148
  export function listComponents(coreDir) {
146
149
  const srcDir = path.join(coreDir, 'src');
@@ -14,12 +14,13 @@
14
14
  import * as fs from 'node:fs';
15
15
  import * as path from 'node:path';
16
16
  import {semverGt} from './semver.mjs';
17
+ import {getCliInvocation} from './package-manager.mjs';
17
18
 
18
19
  /**
19
20
  * Read the latest available version from local signals.
20
- * No network calls — purely filesystem and env var checks.
21
+ * No network calls — purely an env-var check ($ASTRYX_LATEST_VERSION),
22
+ * so it takes no arguments.
21
23
  *
22
- * @param {string} [cwd] - Project directory (default: process.cwd())
23
24
  * @returns {string|null} Latest version string, or null if unknown
24
25
  */
25
26
  export function getLatestVersion() {
@@ -63,7 +64,7 @@ export function getInstalledVersion(cwd = process.cwd()) {
63
64
  * @returns {string|null} FYI hint string, or null if up to date / unknown
64
65
  */
65
66
  export function checkForUpdate(cwd = process.cwd()) {
66
- const latest = getLatestVersion(cwd);
67
+ const latest = getLatestVersion();
67
68
  if (!latest) return null;
68
69
 
69
70
  // Persist for subsequent commands in this shell session
@@ -75,7 +76,7 @@ export function checkForUpdate(cwd = process.cwd()) {
75
76
  // Use semver-aware comparison so '0.0.20' is correctly treated as greater
76
77
  // than '0.0.5' (lexicographic compare gets that backwards).
77
78
  if (semverGt(latest, installed)) {
78
- return `FYI: A newer version of @astryxdesign/core (${latest}) is available. Install the new package version, then run: astryx upgrade --from <old-version> --apply`;
79
+ return `FYI: A newer version of @astryxdesign/core (${latest}) is available. Install the new package version, then run: ${getCliInvocation()} upgrade --from <old-version> --apply`;
79
80
  }
80
81
 
81
82
  return null;
@@ -33,12 +33,12 @@ afterEach(() => {
33
33
  describe('getLatestVersion', () => {
34
34
  it('reads from ASTRYX_LATEST_VERSION env var', () => {
35
35
  process.env.ASTRYX_LATEST_VERSION = '0.0.8';
36
- expect(getLatestVersion(tmpDir)).toBe('0.0.8');
36
+ expect(getLatestVersion()).toBe('0.0.8');
37
37
  });
38
38
 
39
39
  it('ignores invalid env var values', () => {
40
40
  process.env.ASTRYX_LATEST_VERSION = 'not-a-version';
41
- expect(getLatestVersion(tmpDir)).toBeNull();
41
+ expect(getLatestVersion()).toBeNull();
42
42
  });
43
43
 
44
44
  it('returns null when no signals exist', () => {
@@ -46,7 +46,7 @@ describe('getLatestVersion', () => {
46
46
  path.join(tmpDir, 'package.json'),
47
47
  JSON.stringify({name: 'test'}),
48
48
  );
49
- expect(getLatestVersion(tmpDir)).toBeNull();
49
+ expect(getLatestVersion()).toBeNull();
50
50
  });
51
51
  });
52
52
 
@@ -1,105 +0,0 @@
1
- # Authoring an Astryx Integration
2
-
3
- > **Status:** working notes. This should eventually move to the public wiki
4
- > alongside the rest of the integration-authoring guidance; it lives here for
5
- > now so it ships and is versioned with the CLI.
6
-
7
- An **Integration** is an npm package that contributes components, templates, and/or
8
- codemods to a consumer's design-system workflow. Consumers install the 3rd party
9
- package, add a line to their astryx.config file:
10
-
11
- ```js
12
- import {createConfig} from '@astryxdesign/cli/config';
13
-
14
- export default createConfig({
15
- integrations: ['@acme/astryx-widgets'],
16
- ...
17
- });
18
- ```
19
-
20
- Then the integration's components and templates will be surfaced alongside Astryx
21
- components in the Astryx CLI.
22
-
23
- ```sh
24
- astryx component AcmeCarousel --props
25
- astryx component --list --package @acme/astryx-widgets
26
- ```
27
-
28
- ## The Integration File
29
-
30
- In order to register your package as an Astryx Integration, create an
31
- `astryx.integration.{ts,mjs,js}` file as a sibling to your `package.json`. This file
32
- tells Astryx where to find your components, templates, codemods, etc.
33
-
34
- ```js
35
- // astryx.integration.{ts,mjs,js}
36
- import {createIntegration} from '@astryxdesign/cli/integration';
37
-
38
- export default createIntegration({
39
- components: './components',
40
- templates: './templates',
41
- codemods: './codemods',
42
- issuesUrl: 'https://github.com/acme/widgets/issues',
43
- });
44
- ```
45
-
46
- ## Components
47
-
48
- Your components themselves may be exported from your library as you see fit (consumers
49
- will still import them from your package) but Astryx CLI will look for a .doc.{ts,mjs,js}
50
- file with the same stem e.g. `AcmeCarousel.tsx` and `AcmeCarousel.doc.ts`.
51
-
52
- ```js
53
- // AcmeCarousel.doc.ts
54
- import {createComponentDoc} from '@astryxdesign/cli/doc';
55
-
56
- export default createComponentDoc({
57
- name: 'AcmeCarousel',
58
- description: '...',
59
- ...
60
- });
61
- ```
62
-
63
- ## Templates
64
-
65
- Templates are typically not exported from the package directly, but instead accessed
66
- via the Astryx CLI. Consumers can look through your templates and materialize them
67
- into their apps.
68
-
69
- You define a template with the `createPageTemplate` (for full pages) or `createBlockTemplate`
70
- (for smaller chunks). e.g. `AcmeLandingPage.tsx`, `AcmeLandingPage.template.ts`
71
-
72
- ```js
73
- // AcmeLandingPage.template.ts
74
- import {createPageTemplate} from '@astryxdesign/cli/template';
75
-
76
- export default createPageTemplate({
77
- ...
78
- });
79
- ```
80
-
81
- Note that, since the CLI needs access to the template source code, you need to make sure
82
- that it is included in your published package. This will also allow us to render previews
83
- of templates in the future by bundling your template into a doc site build.
84
-
85
- Typically, this is done via the package.json `exports` key.
86
-
87
- ```jsonc
88
- {
89
- "exports": {
90
- // ...
91
- "./templates/*.tsx": "./templates/*.tsx",
92
- },
93
- }
94
- ```
95
-
96
- In order to verify that it's working, you can test importing the template component like this:
97
-
98
- ```ts
99
- import('@acme/astryx-widgets/templates/AcmeLandingPage.tsx');
100
- ```
101
-
102
- Import **with the `.tsx` extension** — an extensionless specifier won't resolve
103
- under `moduleResolution: bundler`. The extensionful `"./templates/*.tsx"` export
104
- above is what lets that import type-check without consumers enabling
105
- `allowImportingTsExtensions`.