@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.
- package/CHANGELOG.md +40 -0
- package/README.md +115 -19
- package/{src/api → api/blog}/blog.mjs +42 -6
- package/{src/api → api/blog}/blog.test.mjs +2 -2
- package/api/build/build.mjs +92 -0
- package/api/build/build.test.mjs +92 -0
- package/{src/api → api/component}/component.mjs +49 -26
- package/{src/api → api/discover}/discover.mjs +55 -18
- package/{src/api → api/docs}/docs.mjs +47 -21
- package/{src/api → api/doctor}/doctor.mjs +13 -10
- package/{src/api → api}/error.mjs +2 -2
- package/{src/api → api/hook}/hook.mjs +11 -11
- package/{src/api → api}/index.mjs +16 -9
- package/{src/api → api/integration}/validate-integration.mjs +48 -15
- package/{src/api → api/integration}/validate-integration.test.mjs +1 -1
- package/{src/api → api/layout}/layout.mjs +66 -17
- package/{src/api → api/layout}/layout.test.mjs +1 -1
- package/{src/api → api/search}/search.mjs +71 -12
- package/api/swizzle/swizzle.mjs +283 -0
- package/{src/commands → api/swizzle}/swizzle.test.mjs +26 -1
- package/{src/api → api/template}/template-integration.test.mjs +2 -2
- package/{src/api → api/template}/template-suffix.test.mjs +3 -3
- package/{src/api → api/template}/template.mjs +96 -19
- package/{src/api → api/theme}/theme-add.mjs +35 -7
- package/{src → authoring}/codemod.mjs +6 -6
- package/{src → authoring}/config.test.mjs +1 -1
- package/{src → authoring}/doc.mjs +1 -1
- package/{src → authoring}/doc.test.mjs +1 -1
- package/{src → authoring}/template.mjs +1 -1
- package/bin/astryx.mjs +12 -10
- package/{src → cli}/commands/blog.mjs +48 -7
- package/{src → cli}/commands/build-theme.mjs +133 -115
- package/cli/commands/build.mjs +172 -0
- package/cli/commands/cli-postinstall.test.mjs +42 -0
- package/{src → cli}/commands/component/index.mjs +52 -25
- package/{src → cli}/commands/component-ownership.test.mjs +3 -3
- package/{src → cli}/commands/component-package.test.mjs +1 -1
- package/{src → cli}/commands/component-resolution.test.mjs +2 -2
- package/{src → cli}/commands/discover.mjs +23 -12
- package/{src → cli}/commands/docs.mjs +42 -10
- package/{src → cli}/commands/docs.test.mjs +1 -1
- package/{src → cli}/commands/doctor.mjs +3 -3
- package/{src → cli}/commands/doctor.test.mjs +2 -2
- package/{src → cli}/commands/ensure-core-built.mjs +3 -2
- package/{src → cli}/commands/external-showcase.test.mjs +1 -1
- package/{src → cli}/commands/hook/index.mjs +40 -17
- package/{src → cli}/commands/import-hint-correctness.test.mjs +1 -1
- package/cli/commands/init.mjs +195 -0
- package/{src → cli}/commands/init.next-steps.test.mjs +1 -1
- package/cli/commands/interactive-guard.test.mjs +66 -0
- package/{src → cli}/commands/json-contract.test.mjs +2 -2
- package/{src → cli}/commands/layout.mjs +59 -19
- package/{src → cli}/commands/search.mjs +22 -15
- package/{src → cli}/commands/search.test.mjs +1 -1
- package/cli/commands/setup-nudge.test.mjs +108 -0
- package/cli/commands/swizzle.mjs +103 -0
- package/{src → cli}/commands/template.mjs +84 -53
- package/{src → cli}/commands/template.path-safety.test.mjs +2 -2
- package/{src → cli}/commands/upgrade.integration-policy.test.mjs +1 -1
- package/{src → cli}/commands/upgrade.mjs +291 -77
- package/cli/commands/upgrade.test.mjs +314 -0
- package/{src → cli}/commands/validate-integration.mjs +17 -37
- package/{src → cli}/index.mjs +55 -19
- package/{src/codemods → codemods}/__tests__/registry.test.mjs +1 -0
- package/{src/codemods → codemods}/ensure-jscodeshift.mjs +12 -28
- package/{src/codemods → codemods}/integration-discovery.mjs +6 -3
- package/{src/codemods → codemods}/integration-discovery.test.mjs +1 -1
- package/{src/codemods → codemods}/integration-runner.mjs +8 -3
- package/{src/codemods → codemods}/registry.mjs +4 -1
- package/{src/codemods → codemods}/run-codemod.mjs +18 -11
- package/{src/codemods → codemods}/runner.mjs +24 -14
- package/{src/codemods → codemods}/transforms/v0.0.10/remove-size-props.mjs +9 -4
- package/{src/codemods → codemods}/transforms/v0.0.12/add-is-icon-only.mjs +27 -22
- package/{src/codemods → codemods}/transforms/v0.0.13/icon-name-deprecations.mjs +12 -5
- package/{src/codemods → codemods}/transforms/v0.0.13/rename-attachments-to-drawer.mjs +15 -8
- package/{src/codemods → codemods}/transforms/v0.0.13/toolbar-density-to-size.mjs +10 -4
- package/{src/codemods → codemods}/transforms/v0.0.14/rename-action-props.mjs +11 -5
- package/{src/codemods → codemods}/transforms/v0.0.14/rename-section-wash-to-muted.mjs +11 -6
- package/{src/codemods → codemods}/transforms/v0.0.14/rename-status-variants.mjs +15 -10
- package/{src/codemods → codemods}/transforms/v0.0.15/migrate-item-children-to-endcontent.mjs +13 -8
- package/{src/codemods → codemods}/transforms/v0.0.15/migrate-selector-children-to-render-option.mjs +18 -13
- package/{src/codemods → codemods}/transforms/v0.0.15/migrate-theme-selectors-to-data-attrs.mjs +8 -4
- package/{src/codemods → codemods}/transforms/v0.0.15/rename-date-picker-to-input.mjs +11 -6
- package/{src/codemods → codemods}/transforms/v0.0.15/rename-imperative-ref-to-handleRef.mjs +6 -1
- package/{src/codemods → codemods}/transforms/v0.0.15/rename-isStreaming-to-isStopShown.mjs +6 -1
- package/{src/codemods → codemods}/transforms/v0.0.15/rename-stack-element-to-as.mjs +8 -3
- package/{src/codemods → codemods}/transforms/v0.0.2/migrate-badge-dot-to-statusdot.mjs +17 -10
- package/{src/codemods → codemods}/transforms/v0.0.2/migrate-gap-to-numeric.mjs +7 -1
- package/{src/codemods → codemods}/transforms/v0.0.2/migrate-isFullBleed-to-padding.mjs +9 -4
- package/{src/codemods → codemods}/transforms/v0.0.2/migrate-useXDSIcon-to-getIcon.mjs +12 -7
- package/{src/codemods → codemods}/transforms/v0.0.2/rename-banner-endButton-to-endContent.mjs +7 -2
- package/{src/codemods → codemods}/transforms/v0.0.2/rename-form-tooltip-startIcon.mjs +8 -2
- package/{src/codemods → codemods}/transforms/v0.0.2/rename-isShown-to-isOpen.mjs +7 -2
- package/{src/codemods → codemods}/transforms/v0.0.2/rename-selector-items-to-options.mjs +7 -2
- package/{src/codemods → codemods}/transforms/v0.0.2/rename-sidenav-header-to-heading.mjs +11 -4
- package/{src/codemods → codemods}/transforms/v0.0.2/rename-topnav-title-to-heading.mjs +10 -4
- package/{src/codemods → codemods}/transforms/v0.0.2/unify-uncontrolled-to-defaultX.mjs +7 -2
- package/{src/codemods → codemods}/transforms/v0.0.2/unify-visibility-to-onOpenChange.mjs +10 -5
- package/{src/codemods → codemods}/transforms/v0.0.6/migrate-badge-children-to-label.mjs +7 -2
- package/{src/codemods → codemods}/transforms/v0.0.6/migrate-collapse-to-collapsible.mjs +9 -3
- package/{src/codemods → codemods}/transforms/v0.0.6/migrate-radius-tokens.mjs +11 -5
- package/{src/codemods → codemods}/transforms/v0.0.6/migrate-shadow-tokens.mjs +13 -6
- package/{src/codemods → codemods}/transforms/v0.0.6/migrate-skeleton-radius.mjs +7 -1
- package/{src/codemods → codemods}/transforms/v0.0.6/migrate-token-names.mjs +11 -5
- package/{src/codemods → codemods}/transforms/v0.0.7/rename-banner-variant-to-container.mjs +8 -3
- package/{src/codemods → codemods}/transforms/v0.0.8/migrate-token-renames.mjs +15 -8
- package/{src/codemods → codemods}/transforms/v0.0.8/rename-endslot-to-endcontent.mjs +7 -2
- package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/drop-xds-prefix-imports.test.mjs +42 -7
- package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/migrate-xds-module-specifiers.test.mjs +43 -0
- package/{src/codemods → codemods}/transforms/v0.1.0/drop-xds-prefix-imports.mjs +117 -13
- package/{src/codemods → codemods}/transforms/v0.1.0/migrate-xds-css-surfaces.mjs +21 -17
- package/{src/codemods → codemods}/transforms/v0.1.0/migrate-xds-declare-module.mjs +7 -2
- package/{src/codemods → codemods}/transforms/v0.1.0/migrate-xds-module-specifiers.mjs +86 -15
- package/{src/codemods → codemods}/transforms/v0.1.2/rename-text-color-active-to-accent.mjs +15 -9
- package/{src/codemods → codemods}/transforms/v0.1.3/migrate-layout-components-to-experimental.mjs +17 -12
- package/{src/codemods → codemods}/transforms/v0.1.5/rename-switch-label-spacing-default-to-hug.mjs +15 -9
- package/{src/codemods → codemods}/transforms/v0.1.7/migrate-table-tableprops-to-direct-props.mjs +17 -10
- package/{src/codemods → codemods}/transforms/v0.1.7/rename-table-renderprops-styles-to-xstyle.mjs +18 -13
- package/codemods/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +161 -0
- package/codemods/transforms/v0.1.8/index.mjs +19 -0
- package/codemods/transforms/v0.1.8/rename-avatar-size-scale.mjs +239 -0
- package/docs/cli-integrations.doc.mjs +150 -0
- package/docs/elevation.doc.mjs +79 -1
- package/docs/getting-started.doc.mjs +9 -9
- package/docs/internationalization.doc.mjs +92 -46
- package/docs/migration.doc.mjs +18 -18
- package/docs/principles.doc.dense.mjs +1 -1
- package/docs/principles.doc.mjs +6 -6
- package/docs/principles.doc.zh.mjs +1 -1
- package/docs/styling-libraries.doc.mjs +3 -3
- package/docs/styling.doc.mjs +4 -4
- package/docs/theme.doc.dense.mjs +2 -2
- package/docs/theme.doc.mjs +7 -7
- package/docs/theme.doc.zh.mjs +1 -1
- package/docs/tokens.doc.mjs +1 -1
- package/docs/working-with-ai.doc.mjs +19 -19
- package/{src/commands → lib/agent-docs}/agent-docs.mjs +164 -29
- package/{src/commands → lib/agent-docs}/agent-docs.path-safety.test.mjs +1 -1
- package/{src/commands → lib/agent-docs}/agent-docs.test.mjs +123 -10
- package/{src/lib → lib}/cli-error.mjs +2 -2
- package/{src/lib → lib}/component-discovery.mjs +44 -2
- package/{src/lib → lib}/component-format.mjs +67 -25
- package/{src/lib → lib}/component-loader.mjs +27 -13
- package/{src/lib → lib}/componentDocOverlay.test.mjs +0 -1
- package/{src/lib → lib}/error-codes.test.mjs +1 -1
- package/{src/lib → lib}/hook-discovery.mjs +14 -1
- package/{src/lib → lib}/hook-format.mjs +29 -5
- package/{src/lib → lib}/integration-warnings.mjs +2 -2
- package/{src/lib → lib}/integrations.mjs +20 -0
- package/{src/lib → lib}/integrations.test.mjs +1 -1
- package/{src/lib → lib}/json-contract.test.mjs +1 -1
- package/{src/lib → lib}/json-shim.mjs +11 -6
- package/{src/lib → lib}/json-shim.test.mjs +1 -1
- package/{src/lib → lib}/json.mjs +3 -3
- package/{src/lib → lib}/levenshtein.mjs +6 -0
- package/{src/lib → lib}/manifest.mjs +7 -5
- package/{src/lib → lib}/manifest.test.mjs +2 -2
- package/{src/lib → lib}/module-loader.mjs +1 -0
- package/{src/lib → lib}/package-scanner.mjs +47 -0
- package/{src/lib → lib}/project.mjs +48 -18
- package/{src/lib → lib}/project.test.mjs +1 -1
- package/{src/lib → lib}/resolve-theme.mjs +5 -0
- package/{src/lib → lib}/string-utils.mjs +15 -0
- package/lib/term-log.mjs +57 -0
- package/{src/lib → lib}/xle/browser.mjs +18 -8
- package/{src/lib → lib}/xle/expand.mjs +155 -22
- package/{src/lib → lib}/xle/parse.mjs +119 -13
- package/{src/lib → lib}/xle/print.mjs +54 -14
- package/{src/lib → lib}/xle/registry-core.mjs +28 -3
- package/{src/lib → lib}/xle/registry.mjs +9 -4
- package/{src/lib → lib}/xle/splice.mjs +13 -2
- package/{src/lib → lib}/xle/validate.mjs +95 -14
- package/lib/xle/xle-ast.d.ts +214 -0
- package/package.json +37 -28
- package/scripts/postinstall.mjs +74 -0
- package/templates/blocks/components/Avatar/AvatarFallbackChain.tsx +4 -4
- package/templates/blocks/components/Avatar/AvatarGroup.tsx +2 -2
- package/templates/blocks/components/Avatar/AvatarInitialsFallback.tsx +1 -1
- package/templates/blocks/components/Avatar/AvatarShowcase.tsx +5 -5
- package/templates/blocks/components/Avatar/AvatarUserCard.tsx +1 -1
- package/templates/blocks/components/Avatar/AvatarWithImage.tsx +4 -4
- package/templates/blocks/components/Avatar/AvatarWithStatus.tsx +3 -3
- package/templates/blocks/components/AvatarGroup/AvatarGroupShowcase.tsx +2 -2
- package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowCustomText.tsx +1 -1
- package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowDefault.tsx +1 -1
- package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowShowcase.tsx +2 -2
- package/templates/blocks/components/AvatarStatusDot/AvatarStatusDotShowcase.tsx +3 -3
- package/templates/blocks/components/AvatarStatusDot/AvatarStatusDotVariants.tsx +3 -3
- package/templates/blocks/components/Banner/BannerFloating.doc.mjs +14 -0
- package/templates/blocks/components/Banner/BannerFloating.tsx +16 -0
- package/templates/blocks/components/Button/ButtonFloating.doc.mjs +14 -0
- package/templates/blocks/components/Button/ButtonFloating.tsx +37 -0
- package/templates/blocks/components/ButtonGroup/ButtonGroupFloating.doc.mjs +14 -0
- package/templates/blocks/components/ButtonGroup/ButtonGroupFloating.tsx +23 -0
- package/templates/blocks/components/Card/CardElevations.doc.mjs +14 -0
- package/templates/blocks/components/Card/CardElevations.tsx +32 -0
- package/templates/blocks/components/Card/ClickableCardElevated.doc.mjs +14 -0
- package/templates/blocks/components/Card/ClickableCardElevated.tsx +21 -0
- package/templates/blocks/components/Card/SelectableCardElevated.doc.mjs +14 -0
- package/templates/blocks/components/Card/SelectableCardElevated.tsx +37 -0
- package/templates/blocks/components/Carousel/CarouselSnap.tsx +1 -1
- package/templates/blocks/components/ChatComposer/ChatComposerFlat.doc.mjs +14 -0
- package/templates/blocks/components/ChatComposer/ChatComposerFlat.tsx +75 -0
- package/templates/blocks/components/ChatMessage/ChatMessageAvatarName.tsx +2 -2
- package/templates/blocks/components/ChatMessage/ChatMessageMultiBubble.tsx +1 -1
- package/templates/blocks/components/ChatMessageBubble/ChatMessageBubbleGrouping.tsx +1 -1
- package/templates/blocks/components/ChatMessageBubble/ChatMessageBubbleMetadata.tsx +1 -1
- package/templates/blocks/components/ChatMessageList/ChatMessageListDensity.tsx +5 -9
- package/templates/blocks/components/ChatMessageList/ChatMessageListFullFeatured.tsx +1 -1
- package/templates/blocks/components/CodeBlock/CodeBlockTerminal.tsx +1 -1
- package/templates/blocks/components/HoverCard/HoverCardShowcase.tsx +1 -1
- package/templates/blocks/components/IconButton/IconButtonFloating.doc.mjs +14 -0
- package/templates/blocks/components/IconButton/IconButtonFloating.tsx +37 -0
- package/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.doc.mjs +19 -0
- package/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.tsx +46 -0
- package/templates/blocks/components/InternationalizationProvider/InternationalizationProvider02Overrides.doc.mjs +14 -0
- package/templates/blocks/components/InternationalizationProvider/InternationalizationProvider02Overrides.tsx +33 -0
- package/templates/blocks/components/Item/ItemWithMedia.tsx +2 -2
- package/templates/blocks/components/ListItem/ListItemWithMedia.tsx +2 -2
- package/templates/blocks/components/OverflowList/OverflowListCappedToolbar.doc.mjs +14 -0
- package/templates/blocks/components/OverflowList/OverflowListCappedToolbar.tsx +39 -0
- package/templates/blocks/components/OverflowList/OverflowListMultiRowTags.doc.mjs +14 -0
- package/templates/blocks/components/OverflowList/OverflowListMultiRowTags.tsx +44 -0
- package/templates/blocks/components/Pagination/PaginationDotsCarousel.tsx +2 -6
- package/templates/blocks/components/Stack/StackFillItem.tsx +2 -6
- package/templates/blocks/components/TabList/TabListTabsWithActions.doc.mjs +1 -1
- package/templates/blocks/components/TabList/TabListTabsWithActions.tsx +2 -7
- package/templates/blocks/components/Table/TableRowStatusTable.doc.mjs +14 -0
- package/templates/blocks/components/Table/TableRowStatusTable.tsx +59 -0
- package/templates/blocks/components/Thumbnail/ThumbnailDisabled.tsx +6 -1
- package/templates/blocks/components/Thumbnail/ThumbnailGallery.tsx +1 -0
- package/templates/blocks/components/Thumbnail/ThumbnailRemovable.tsx +1 -0
- package/templates/blocks/components/TypeaheadItem/TypeaheadItemShowcase.tsx +1 -1
- package/templates/pages/ai-chat/page.tsx +4 -4
- package/templates/pages/dashboard-portfolio/page.tsx +3 -11
- package/templates/pages/detail-page/page.tsx +5 -12
- package/templates/pages/documentation-design/page.tsx +1 -1
- package/templates/pages/messaging-shell/page.tsx +6 -8
- package/templates/pages/table-grouped/page.tsx +9 -14
- package/templates/pages/table-page/page.tsx +7 -9
- package/templates/pages/table-page-heatmap-status/page.tsx +5 -13
- package/{src/types → types}/api.contract.assert.ts +17 -8
- package/{src/types → types}/api.d.ts +110 -9
- package/{src/types → types}/base.d.ts +40 -4
- package/types/build.d.ts +53 -0
- package/types/codemod.d.ts +166 -0
- package/{src/types → types}/component.d.ts +1 -1
- package/{src/types → types}/discover.d.ts +1 -1
- package/{src/types → types}/docs.d.ts +1 -4
- package/{src/types → types}/hook.d.ts +1 -1
- package/{src/types → types}/index.d.ts +1 -0
- package/types/jscodeshift.d.ts +19 -0
- package/types/layout.d.ts +74 -0
- package/{src/types → types}/swizzle.d.ts +4 -0
- package/{src/types → types}/template-api.d.ts +4 -1
- package/types/theme.d.ts +53 -0
- package/types/upgrade.d.ts +108 -0
- package/utils/package-manager.mjs +178 -0
- package/utils/package-manager.test.mjs +220 -0
- package/{src/utils → utils}/path-safety.mjs +0 -18
- package/{src/utils → utils}/paths.mjs +4 -1
- package/{src/utils → utils}/update-check.mjs +5 -4
- package/{src/utils → utils}/update-check.test.mjs +3 -3
- package/docs/integration-authoring.md +0 -105
- package/src/commands/build.mjs +0 -196
- package/src/commands/init.mjs +0 -288
- package/src/commands/interactive-guard.test.mjs +0 -69
- package/src/commands/swizzle.mjs +0 -440
- package/src/commands/upgrade.test.mjs +0 -160
- package/src/types/codemod.d.ts +0 -81
- package/src/types/theme.d.ts +0 -23
- package/src/types/upgrade.d.ts +0 -64
- package/src/utils/interactive.mjs +0 -76
- package/src/utils/interactive.test.mjs +0 -70
- package/src/utils/package-manager.mjs +0 -74
- package/src/utils/package-manager.test.mjs +0 -113
- /package/{src/api → api/docs}/docOverlays.test.mjs +0 -0
- /package/{src/api → api/integration}/integration-block-exports.test.mjs +0 -0
- /package/{src/api → api/template}/template.test.mjs +0 -0
- /package/{src → authoring}/codemod.test.mjs +0 -0
- /package/{src → authoring}/config.mjs +0 -0
- /package/{src → authoring}/integration.mjs +0 -0
- /package/{src → authoring}/template.test.mjs +0 -0
- /package/{src → cli}/cli-exit-codes.test.mjs +0 -0
- /package/{src → cli}/commands/build-theme.color-scheme.test.mjs +0 -0
- /package/{src → cli}/commands/build-theme.import-path.test.mjs +0 -0
- /package/{src → cli}/commands/build-theme.path-safety.test.mjs +0 -0
- /package/{src → cli}/commands/build-theme.prose.test.mjs +0 -0
- /package/{src → cli}/commands/build-theme.variants.test.mjs +0 -0
- /package/{src → cli}/commands/build-theme.watch.test.mjs +0 -0
- /package/{src → cli}/commands/component.test.mjs +0 -0
- /package/{src → cli}/commands/detail-levels.test.mjs +0 -0
- /package/{src → cli}/commands/swizzle.path-safety.test.mjs +0 -0
- /package/{src → cli}/commands/swizzle.routing.test.mjs +0 -0
- /package/{src → cli}/commands/template.test.mjs +0 -0
- /package/{src → cli}/commands/upgrade.config-ordering.test.mjs +0 -0
- /package/{src → cli}/commands/validate-integration.test.mjs +0 -0
- /package/{src → cli}/update-hint-commands.test.mjs +0 -0
- /package/{src/codemods → codemods}/__tests__/rename-imperative-ref-to-handleRef.test.mjs +0 -0
- /package/{src/codemods → codemods}/__tests__/rename-isStreaming-to-isStopShown.test.mjs +0 -0
- /package/{src/codemods → codemods}/__tests__/rename-section-wash-to-muted.test.mjs +0 -0
- /package/{src/codemods → codemods}/__tests__/runner.test.mjs +0 -0
- /package/{src/codemods → codemods}/__tests__/toolbar-density-to-size.test.mjs +0 -0
- /package/{src/codemods → codemods}/__tests__/validation.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.10/__tests__/remove-size-props.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.10/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.12/__tests__/add-is-icon-only.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.12/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.13/__tests__/icon-name-deprecations.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.13/__tests__/rename-attachments-to-drawer.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.13/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.14/__tests__/rename-action-props.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.14/__tests__/rename-status-variants.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.14/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.15/__tests__/migrate-item-children-to-endcontent.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.15/__tests__/migrate-selector-children-to-render-option.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.15/__tests__/migrate-theme-selectors-to-data-attrs.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.15/__tests__/rename-date-picker-to-input.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.15/__tests__/rename-stack-element-to-as.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.15/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/migrate-badge-dot-to-statusdot.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/migrate-gap-to-numeric.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/migrate-isFullBleed-to-padding.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/migrate-useXDSIcon-to-getIcon.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-banner-endButton-to-endContent.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-form-tooltip-startIcon.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-isShown-to-isOpen.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-selector-items-to-options.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-sidenav-header-to-heading.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-topnav-title-to-heading.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/unify-uncontrolled-to-defaultX.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/unify-visibility-to-onOpenChange.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.2/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.6/__tests__/migrate-collapse-to-collapsible.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.6/__tests__/migrate-radius-tokens.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.6/__tests__/migrate-shadow-tokens.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.6/__tests__/migrate-skeleton-radius.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.6/__tests__/migrate-token-names.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.6/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.7/__tests__/rename-banner-variant-to-container.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.7/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.8/__tests__/migrate-token-renames.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.8/__tests__/rename-endslot-to-endcontent.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.0.8/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/migrate-xds-css-surfaces.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/migrate-xds-declare-module.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/v0.1.0-ordering.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.0/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.2/__tests__/rename-text-color-active-to-accent.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.2/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.3/__tests__/migrate-layout-components-to-experimental.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.3/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.5/__tests__/rename-switch-label-spacing-default-to-hug.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.5/index.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.7/__tests__/migrate-table-tableprops-to-direct-props.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.7/__tests__/rename-table-renderprops-styles-to-xstyle.test.mjs +0 -0
- /package/{src/codemods → codemods}/transforms/v0.1.7/index.mjs +0 -0
- /package/{src/lib → lib}/cli-error.test.mjs +0 -0
- /package/{src/lib → lib}/component-discovery.importpath.test.mjs +0 -0
- /package/{src/lib → lib}/component-format.test.mjs +0 -0
- /package/{src/lib → lib}/component-loader.test.mjs +0 -0
- /package/{src/lib → lib}/config-cache.mjs +0 -0
- /package/{src/lib → lib}/config-cache.test.mjs +0 -0
- /package/{src/lib → lib}/config-schema.mjs +0 -0
- /package/{src/lib → lib}/error-codes.mjs +0 -0
- /package/{src/lib → lib}/integration-warnings.test.mjs +0 -0
- /package/{src/lib → lib}/module-loader.test.mjs +0 -0
- /package/{src/lib → lib}/node-version.mjs +0 -0
- /package/{src/lib → lib}/node-version.test.mjs +0 -0
- /package/{src/lib → lib}/parse.mjs +0 -0
- /package/{src/lib → lib}/site.mjs +0 -0
- /package/{src/lib → lib}/xle/browser.d.ts +0 -0
- /package/{src/lib → lib}/xle/xle.test.mjs +0 -0
- /package/{src/schemas → schemas}/doc-schema.mjs +0 -0
- /package/{src/schemas → schemas}/template-schema.mjs +0 -0
- /package/{src/types → types}/config.d.ts +0 -0
- /package/{src/types → types}/doc.d.ts +0 -0
- /package/{src/types → types}/doctor.d.ts +0 -0
- /package/{src/types → types}/error-codes.d.ts +0 -0
- /package/{src/types → types}/integration.d.ts +0 -0
- /package/{src/types → types}/manifest.d.ts +0 -0
- /package/{src/types → types}/search.d.ts +0 -0
- /package/{src/types → types}/template.d.ts +0 -0
- /package/{src/types → types}/validate-integration.d.ts +0 -0
- /package/{src/utils → utils}/github.mjs +0 -0
- /package/{src/utils → utils}/path-safety.test.mjs +0 -0
- /package/{src/utils → utils}/paths.test.mjs +0 -0
- /package/{src/utils → utils}/semver.mjs +0 -0
- /package/{src/utils → utils}/semver.test.mjs +0 -0
|
@@ -19,8 +19,8 @@ import {
|
|
|
19
19
|
checkAgentDocs,
|
|
20
20
|
checkPeerDeps,
|
|
21
21
|
checkPackageManager,
|
|
22
|
-
} from '
|
|
23
|
-
import {MIN_NODE_VERSION} from '
|
|
22
|
+
} from '../../api/doctor/doctor.mjs';
|
|
23
|
+
import {MIN_NODE_VERSION} from '../../lib/node-version.mjs';
|
|
24
24
|
|
|
25
25
|
let tmpDir;
|
|
26
26
|
let logCalls;
|
|
@@ -40,6 +40,7 @@ const BUILD_TIMEOUT_MS = 180_000;
|
|
|
40
40
|
const STALE_LOCK_MS = BUILD_TIMEOUT_MS + 20_000;
|
|
41
41
|
const POLL_MS = 250;
|
|
42
42
|
|
|
43
|
+
/** @param {number} ms */
|
|
43
44
|
function sleepSync(ms) {
|
|
44
45
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
45
46
|
}
|
|
@@ -67,7 +68,7 @@ function tryAcquire() {
|
|
|
67
68
|
fs.mkdirSync(LOCK_DIR);
|
|
68
69
|
return true;
|
|
69
70
|
} catch (err) {
|
|
70
|
-
if (err.code !== 'EEXIST') {
|
|
71
|
+
if (/** @type {NodeJS.ErrnoException} */ (err).code !== 'EEXIST') {
|
|
71
72
|
throw err;
|
|
72
73
|
}
|
|
73
74
|
if (lockIsStale()) {
|
|
@@ -76,7 +77,7 @@ function tryAcquire() {
|
|
|
76
77
|
fs.mkdirSync(LOCK_DIR);
|
|
77
78
|
return true;
|
|
78
79
|
} catch (retryErr) {
|
|
79
|
-
if (retryErr.code !== 'EEXIST') {
|
|
80
|
+
if (/** @type {NodeJS.ErrnoException} */ (retryErr).code !== 'EEXIST') {
|
|
80
81
|
throw retryErr;
|
|
81
82
|
}
|
|
82
83
|
}
|
|
@@ -4,7 +4,7 @@ import {describe, it, expect, beforeEach, afterEach} from 'vitest';
|
|
|
4
4
|
import * as fs from 'node:fs';
|
|
5
5
|
import * as path from 'node:path';
|
|
6
6
|
import * as os from 'node:os';
|
|
7
|
-
import {findShowcase, findRelatedBlocks} from '
|
|
7
|
+
import {findShowcase, findRelatedBlocks} from '../../api/template/template.mjs';
|
|
8
8
|
|
|
9
9
|
// These tests verify that findShowcase and findRelatedBlocks can discover
|
|
10
10
|
// blocks from external packages that declare xds.blocks in package.json.
|
|
@@ -11,14 +11,29 @@ import {
|
|
|
11
11
|
formatHookCompact,
|
|
12
12
|
formatHookBrief,
|
|
13
13
|
formatHookParams,
|
|
14
|
-
} from '
|
|
15
|
-
import {
|
|
16
|
-
import {jsonOut, humanLog} from '
|
|
17
|
-
import {cliError} from '
|
|
18
|
-
import {ERROR_CODES} from '
|
|
19
|
-
import {hook as hookApi} from '
|
|
20
|
-
import {findRelatedBlocks} from '
|
|
14
|
+
} from '../../../lib/hook-format.mjs';
|
|
15
|
+
import {getCliInvocation} from '../../../utils/package-manager.mjs';
|
|
16
|
+
import {jsonOut, humanLog} from '../../../lib/json.mjs';
|
|
17
|
+
import {cliError} from '../../../lib/cli-error.mjs';
|
|
18
|
+
import {ERROR_CODES} from '../../../lib/error-codes.mjs';
|
|
19
|
+
import {hook as hookApi} from '../../../api/hook/hook.mjs';
|
|
20
|
+
import {findRelatedBlocks} from '../../../api/template/template.mjs';
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* The api layer's hook() widens its return to `{type: string, data: unknown}`,
|
|
24
|
+
* so annotate the command-local result with the precise discriminated union from
|
|
25
|
+
* src/types/hook to get narrowing + typed data.
|
|
26
|
+
*
|
|
27
|
+
* @typedef {(
|
|
28
|
+
* | import('../../../types/hook').HookListResponse
|
|
29
|
+
* | import('../../../types/hook').HookBriefResponse
|
|
30
|
+
* | import('../../../types/hook').HookFullResponse
|
|
31
|
+
* | import('../../../types/hook').HookDetailResponse
|
|
32
|
+
* | import('../../../types/hook').HookDetailParamsResponse
|
|
33
|
+
* )} HookResult
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/** @param {import('commander').Command} program */
|
|
22
37
|
export function registerHook(program) {
|
|
23
38
|
program
|
|
24
39
|
.command('hook [name]')
|
|
@@ -26,8 +41,13 @@ export function registerHook(program) {
|
|
|
26
41
|
.option('--list', 'List all hooks grouped by category')
|
|
27
42
|
.option('--category <category>', 'List hooks in a specific category')
|
|
28
43
|
.option('--params', 'Print only the parameters table')
|
|
29
|
-
.action(
|
|
30
|
-
|
|
44
|
+
.action(
|
|
45
|
+
/**
|
|
46
|
+
* @param {string|undefined} name
|
|
47
|
+
* @param {{list?: boolean, category?: string, params?: boolean}} options
|
|
48
|
+
*/
|
|
49
|
+
async (name, options) => {
|
|
50
|
+
const run = getCliInvocation();
|
|
31
51
|
const zh = program.opts().zh || false;
|
|
32
52
|
const lang = program.opts().lang || null;
|
|
33
53
|
const detailSource = program.getOptionValueSource('detail');
|
|
@@ -43,18 +63,20 @@ export function registerHook(program) {
|
|
|
43
63
|
return;
|
|
44
64
|
}
|
|
45
65
|
|
|
66
|
+
/** @type {HookResult} */
|
|
46
67
|
let result;
|
|
47
68
|
try {
|
|
48
|
-
result = await hookApi(name, {
|
|
69
|
+
result = /** @type {HookResult} */ (await hookApi(name, {
|
|
49
70
|
cwd: process.cwd(),
|
|
50
71
|
list: options.list,
|
|
51
72
|
category: options.category,
|
|
52
73
|
params: options.params,
|
|
53
74
|
detail,
|
|
54
75
|
lang, zh,
|
|
55
|
-
});
|
|
76
|
+
}));
|
|
56
77
|
} catch (e) {
|
|
57
|
-
|
|
78
|
+
const err = /** @type {import('../../../api/error.mjs').AstryxError} */ (e);
|
|
79
|
+
cliError(err.message, {suggestions: err.suggestions, code: err.code});
|
|
58
80
|
return;
|
|
59
81
|
}
|
|
60
82
|
|
|
@@ -76,7 +98,7 @@ export function registerHook(program) {
|
|
|
76
98
|
for (const h of hookNames) humanLog(` ${h}`);
|
|
77
99
|
}
|
|
78
100
|
humanLog('');
|
|
79
|
-
humanLog(`Usage: ${run}
|
|
101
|
+
humanLog(`Usage: ${run} hook <name>`);
|
|
80
102
|
humanLog('');
|
|
81
103
|
}
|
|
82
104
|
break;
|
|
@@ -93,7 +115,7 @@ export function registerHook(program) {
|
|
|
93
115
|
}
|
|
94
116
|
humanLog('');
|
|
95
117
|
}
|
|
96
|
-
humanLog(`Usage: ${run}
|
|
118
|
+
humanLog(`Usage: ${run} hook <name>`);
|
|
97
119
|
humanLog('');
|
|
98
120
|
break;
|
|
99
121
|
}
|
|
@@ -123,6 +145,7 @@ export function registerHook(program) {
|
|
|
123
145
|
}
|
|
124
146
|
// Show related block templates from relatedComponents
|
|
125
147
|
const relatedComps = result.data.relatedComponents || [];
|
|
148
|
+
/** @type {import('../../../api/template/template.mjs').DiscoveredTemplate[]} */
|
|
126
149
|
const allBlocks = [];
|
|
127
150
|
for (const comp of relatedComps) {
|
|
128
151
|
const blocks = await findRelatedBlocks(comp);
|
|
@@ -152,12 +175,12 @@ export function registerHook(program) {
|
|
|
152
175
|
}
|
|
153
176
|
|
|
154
177
|
// Re-export lib functions for external consumers
|
|
155
|
-
export {discoverHooks, findHookDoc, getAllHookNames} from '
|
|
156
|
-
export {loadDocs} from '
|
|
178
|
+
export {discoverHooks, findHookDoc, getAllHookNames} from '../../../lib/hook-discovery.mjs';
|
|
179
|
+
export {loadDocs} from '../../../lib/component-loader.mjs';
|
|
157
180
|
export {
|
|
158
181
|
formatHookFull,
|
|
159
182
|
formatHookCompact,
|
|
160
183
|
formatHookBrief,
|
|
161
184
|
formatHookBriefAll,
|
|
162
185
|
formatHookParams,
|
|
163
|
-
} from '
|
|
186
|
+
} from '../../../lib/hook-format.mjs';
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
discoverComponents,
|
|
24
24
|
findComponentSource,
|
|
25
25
|
} from './component/index.mjs';
|
|
26
|
-
import {findCoreDir} from '
|
|
26
|
+
import {findCoreDir} from '../../utils/paths.mjs';
|
|
27
27
|
|
|
28
28
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
29
29
|
const CLI_BIN = path.resolve(__dirname, '../../bin/astryx.mjs');
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file init command — non-interactive setup + feature installer
|
|
5
|
+
*
|
|
6
|
+
* `astryx init` is non-interactive by default: it installs the AGENTS.md/
|
|
7
|
+
* CLAUDE.md cheat sheet with NO prompts, so it behaves identically for humans,
|
|
8
|
+
* AI agents, CI, and piped I/O — it never hangs or errors on a missing TTY.
|
|
9
|
+
* Non-interactive feature install: `astryx init --features agents,theme,template`
|
|
10
|
+
* Re-runnable: safe to run multiple times, idempotent
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
13
|
+
* agents — Install AGENTS.md/CLAUDE.md cheat sheet for AI coding agents
|
|
14
|
+
* theme — Point to the theme workflow (`astryx theme`)
|
|
15
|
+
* template — Copy a starter page template
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import * as path from 'node:path';
|
|
19
|
+
import * as fs from 'node:fs';
|
|
20
|
+
import {CLI_ROOT} from '../../utils/paths.mjs';
|
|
21
|
+
import {PathSafetyError} from '../../utils/path-safety.mjs';
|
|
22
|
+
import {getCliInvocation} from '../../utils/package-manager.mjs';
|
|
23
|
+
import {installAgentDocs, removeAgentDocs} from '../../lib/agent-docs/agent-docs.mjs';
|
|
24
|
+
import {listTemplates} from './template.mjs';
|
|
25
|
+
import {humanLog} from '../../lib/json.mjs';
|
|
26
|
+
import {cliError} from '../../lib/cli-error.mjs';
|
|
27
|
+
import {ERROR_CODES} from '../../lib/error-codes.mjs';
|
|
28
|
+
|
|
29
|
+
const VALID_FEATURES = ['agents', 'theme', 'template'];
|
|
30
|
+
const run = getCliInvocation();
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Build the "Next steps" lines printed at the end of `astryx init`.
|
|
34
|
+
*
|
|
35
|
+
* Theme guidance must match the runtime recommendation emitted by core's
|
|
36
|
+
* <Theme> component (packages/core/src/theme/Theme.tsx): the pre-built theme
|
|
37
|
+
* path (`/built` import + `theme.css`) plus the base CSS import, so users
|
|
38
|
+
* don't end up with an unstyled app or the slower runtime style-injection
|
|
39
|
+
* path. See https://github.com/facebook/astryx/issues/3080.
|
|
40
|
+
*
|
|
41
|
+
* Exported for testing.
|
|
42
|
+
*
|
|
43
|
+
* @param {string} invocation install-aware CLI invocation stem (e.g. `npx astryx`, `pnpm exec astryx`, or `npx @astryxdesign/cli` for one-off runs)
|
|
44
|
+
* @returns {string[]} ordered list of human-facing lines
|
|
45
|
+
*/
|
|
46
|
+
export function getNextSteps(invocation) {
|
|
47
|
+
return [
|
|
48
|
+
'',
|
|
49
|
+
' Next steps:',
|
|
50
|
+
" 1. Import base styles: import '@astryxdesign/core/reset.css'",
|
|
51
|
+
" and import '@astryxdesign/core/astryx.css'",
|
|
52
|
+
" 2. Import components: import { Button } from '@astryxdesign/core'",
|
|
53
|
+
' 3. Optionally add a theme (use the pre-built path for performance):',
|
|
54
|
+
" import { neutralTheme } from '@astryxdesign/theme-neutral/built'",
|
|
55
|
+
" import '@astryxdesign/theme-neutral/theme.css'",
|
|
56
|
+
' <Theme theme={neutralTheme}>...</Theme>',
|
|
57
|
+
` For custom themes, run \`${invocation} theme build <file>\` to generate the built artifacts.`,
|
|
58
|
+
` 4. ${invocation} --help for all commands`,
|
|
59
|
+
'',
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ─── Feature: agents ─────────────────────────────────────────────────────────
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @param {string} targetDir
|
|
67
|
+
* @param {{agent?: string, agentDocsPath?: string | string[]}} [opts]
|
|
68
|
+
*/
|
|
69
|
+
function runAgents(targetDir, {agent, agentDocsPath} = {}) {
|
|
70
|
+
try {
|
|
71
|
+
const paths = agentDocsPath
|
|
72
|
+
? Array.isArray(agentDocsPath)
|
|
73
|
+
? agentDocsPath
|
|
74
|
+
: [agentDocsPath]
|
|
75
|
+
: undefined;
|
|
76
|
+
const written = installAgentDocs(targetDir, {agent, paths});
|
|
77
|
+
const summary = written.join(', ');
|
|
78
|
+
humanLog(`✓ AI agent docs installed → ${summary}`);
|
|
79
|
+
} catch (err) {
|
|
80
|
+
// PathSafetyError carries a precise, user-actionable message —
|
|
81
|
+
// surface it instead of the generic "could not install" warning so
|
|
82
|
+
// misconfigured --agent-docs-path values aren't silently swallowed.
|
|
83
|
+
if (err instanceof PathSafetyError) {
|
|
84
|
+
console.error(`Error: ${err.message}`);
|
|
85
|
+
process.exitCode = 1;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
console.error(`Could not install agent docs. Try again with \`${run} init --features agents\`.`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ─── Feature: theme ──────────────────────────────────────────────────────────
|
|
93
|
+
|
|
94
|
+
function runTheme() {
|
|
95
|
+
humanLog(`✓ For a custom theme, run \`${run} theme\` (browse) or \`${run} theme add <slug>\` (scaffold).`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ─── Feature: template ───────────────────────────────────────────────────────
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @param {string} targetDir
|
|
102
|
+
* @param {{templateName?: string}} [opts]
|
|
103
|
+
*/
|
|
104
|
+
function runTemplate(targetDir, {templateName} = {}) {
|
|
105
|
+
const templates = listTemplates();
|
|
106
|
+
if (templates.length === 0) return;
|
|
107
|
+
|
|
108
|
+
if (!templateName) {
|
|
109
|
+
// Point agents at the build workflow rather than dumping page-template
|
|
110
|
+
// names — `build` surfaces pages AND blocks AND components for an idea,
|
|
111
|
+
// and `build` with no args is the full how-to-build playbook.
|
|
112
|
+
humanLog('✓ To build UI, use these commands:');
|
|
113
|
+
humanLog('');
|
|
114
|
+
humanLog(` ${run} build "<what you're building>" build a page — kit: closest template + blocks + components`);
|
|
115
|
+
humanLog(` ${run} build the how-to-build workflow (read this first)`);
|
|
116
|
+
humanLog(` ${run} search <query> find anything — components, docs, templates, blocks`);
|
|
117
|
+
humanLog('');
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (!templates.includes(templateName)) {
|
|
122
|
+
cliError(`Unknown template "${templateName}". Available: ${templates.join(', ')}`, {code: ERROR_CODES.ERR_UNKNOWN_TEMPLATE});
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const outputDir = path.resolve(targetDir, `./src/pages/${templateName}`);
|
|
127
|
+
const srcPath = path.join(CLI_ROOT, 'templates', 'pages', templateName, 'page.tsx');
|
|
128
|
+
fs.mkdirSync(outputDir, {recursive: true});
|
|
129
|
+
fs.copyFileSync(srcPath, path.join(outputDir, 'page.tsx'));
|
|
130
|
+
humanLog(`✓ Template created at ${path.relative(targetDir, outputDir)}/page.tsx`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ─── Command ─────────────────────────────────────────────────────────────────
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @param {import('commander').Command} program
|
|
137
|
+
*/
|
|
138
|
+
export function registerInit(program) {
|
|
139
|
+
program
|
|
140
|
+
.command('init')
|
|
141
|
+
.description('Initialize the design system in your project')
|
|
142
|
+
.option('--features <list>', 'Comma-separated features to install (agents, theme, template)')
|
|
143
|
+
.option('--all', 'Install all features, no prompts')
|
|
144
|
+
.option('--remove-agents', 'Remove AI agent docs from all agent doc files')
|
|
145
|
+
.option('--agent <tool>', 'Target AI tool for agent docs: claude, cursor, codex, hermes, all')
|
|
146
|
+
.option('--agent-docs-path <path...>', 'Explicit file path(s) for agent docs')
|
|
147
|
+
.action((/** @type {{features?: string, all?: boolean, removeAgents?: boolean, agent?: string, agentDocsPath?: string | string[]}} */ options) => {
|
|
148
|
+
const targetDir = process.cwd();
|
|
149
|
+
|
|
150
|
+
// Remove mode
|
|
151
|
+
if (options.removeAgents) {
|
|
152
|
+
removeAgentDocs(targetDir);
|
|
153
|
+
humanLog('✓ AI agent docs removed.');
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Non-interactive: --features or --all
|
|
158
|
+
if (options.features || options.all) {
|
|
159
|
+
const features = options.all
|
|
160
|
+
? VALID_FEATURES
|
|
161
|
+
: /** @type {string} */ (options.features).split(',').map(f => f.trim().toLowerCase());
|
|
162
|
+
|
|
163
|
+
const invalid = features.filter(f => !VALID_FEATURES.includes(f));
|
|
164
|
+
if (invalid.length > 0) {
|
|
165
|
+
cliError(`Unknown features: ${invalid.join(', ')}. Valid features: ${VALID_FEATURES.join(', ')}`, {code: ERROR_CODES.ERR_UNKNOWN_FEATURE});
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
for (const feature of features) {
|
|
170
|
+
if (feature === 'agents') runAgents(targetDir, {
|
|
171
|
+
agent: options.agent,
|
|
172
|
+
agentDocsPath: options.agentDocsPath,
|
|
173
|
+
});
|
|
174
|
+
if (feature === 'theme') runTheme();
|
|
175
|
+
if (feature === 'template') runTemplate(targetDir, {});
|
|
176
|
+
}
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// No flags: TTY-free default. `astryx init` installs the AI agent cheat
|
|
181
|
+
// sheet with NO prompts, so it behaves identically for humans, agents, CI,
|
|
182
|
+
// and piped I/O — it never hangs or errors on a missing TTY. (A guided
|
|
183
|
+
// `--interactive` setup may return later as an explicit opt-in.)
|
|
184
|
+
runAgents(targetDir, {
|
|
185
|
+
agent: options.agent,
|
|
186
|
+
agentDocsPath: options.agentDocsPath,
|
|
187
|
+
});
|
|
188
|
+
humanLog('');
|
|
189
|
+
humanLog(` Tip: \`${run} init --all\` also points you to the theme and page-building workflows.`);
|
|
190
|
+
|
|
191
|
+
for (const line of getNextSteps(run)) {
|
|
192
|
+
humanLog(line);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
}
|
|
@@ -23,7 +23,7 @@ import {describe, it, expect} from 'vitest';
|
|
|
23
23
|
import {getNextSteps} from './init.mjs';
|
|
24
24
|
|
|
25
25
|
describe('init Next steps theme guidance', () => {
|
|
26
|
-
const text = getNextSteps('npx').join('\n');
|
|
26
|
+
const text = getNextSteps('npx astryx').join('\n');
|
|
27
27
|
|
|
28
28
|
it('mentions the base CSS imports so the app is not left unstyled', () => {
|
|
29
29
|
expect(text).toContain("'@astryxdesign/core/reset.css'");
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Subprocess no-hang tests for `astryx init`.
|
|
5
|
+
*
|
|
6
|
+
* TTY was removed from the CLI: `init` is non-interactive by default and must
|
|
7
|
+
* run cleanly (exit 0, writing the agent cheat sheet) instead of hanging on a
|
|
8
|
+
* prompt. These tests spawn the CLI with stdin/stdout NOT a TTY (the CI / piped
|
|
9
|
+
* / agent condition). A hang would show as signal SIGTERM + status null; we
|
|
10
|
+
* assert `signal === null && status === 0` to prove it exits cleanly and works.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {describe, it, expect, beforeEach, afterEach} from 'vitest';
|
|
14
|
+
import {spawnSync} from 'node:child_process';
|
|
15
|
+
import * as fs from 'node:fs';
|
|
16
|
+
import * as path from 'node:path';
|
|
17
|
+
import * as os from 'node:os';
|
|
18
|
+
import {fileURLToPath} from 'node:url';
|
|
19
|
+
|
|
20
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
21
|
+
const CLI = path.resolve(__dirname, '..', '..', 'bin', 'astryx.mjs');
|
|
22
|
+
|
|
23
|
+
let tmpDir;
|
|
24
|
+
|
|
25
|
+
function runCli(args) {
|
|
26
|
+
return spawnSync(process.execPath, [CLI, ...args], {
|
|
27
|
+
cwd: tmpDir,
|
|
28
|
+
encoding: 'utf8',
|
|
29
|
+
timeout: 20_000,
|
|
30
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
31
|
+
env: {...process.env, FORCE_COLOR: '0', CI: ''},
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-interactive-guard-'));
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
afterEach(() => {
|
|
40
|
+
fs.rmSync(tmpDir, {recursive: true, force: true});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('init is non-interactive by default (no TTY needed)', () => {
|
|
44
|
+
it('runs cleanly (exit 0, no hang) and writes agent docs', () => {
|
|
45
|
+
const r = runCli(['init']);
|
|
46
|
+
expect(r.signal).toBeNull(); // did not hang
|
|
47
|
+
expect(r.status).toBe(0); // succeeded without a TTY
|
|
48
|
+
expect(fs.readdirSync(tmpDir).length).toBeGreaterThan(0); // wrote the cheat sheet
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('writes an agent-doc file containing the ASTRYX cheat-sheet marker', () => {
|
|
52
|
+
runCli(['init']);
|
|
53
|
+
// init injects into existing agent-doc files if present, else creates AGENTS.md
|
|
54
|
+
const candidates = ['AGENTS.md', 'CLAUDE.md', '.cursorrules', path.join('.claude', 'CLAUDE.md')];
|
|
55
|
+
const doc = candidates.find(f => fs.existsSync(path.join(tmpDir, f)));
|
|
56
|
+
expect(doc).toBeTruthy();
|
|
57
|
+
expect(fs.readFileSync(path.join(tmpDir, doc), 'utf8')).toMatch(/ASTRYX:START/);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('still runs --features agents non-interactively', () => {
|
|
61
|
+
const r = runCli(['init', '--features', 'agents']);
|
|
62
|
+
expect(r.signal).toBeNull();
|
|
63
|
+
expect(r.status).toBe(0);
|
|
64
|
+
expect(fs.readdirSync(tmpDir).length).toBeGreaterThan(0);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -45,7 +45,7 @@ function runCli(args, {cwd} = {}) {
|
|
|
45
45
|
|
|
46
46
|
function parseJson(stdout) {
|
|
47
47
|
// CLI emits a single JSON document. If anything else snuck onto stdout
|
|
48
|
-
// (
|
|
48
|
+
// (log output, console.log strings, etc.) JSON.parse will throw —
|
|
49
49
|
// which is exactly the failure mode we want to catch in tests.
|
|
50
50
|
return JSON.parse(stdout);
|
|
51
51
|
}
|
|
@@ -61,7 +61,7 @@ afterEach(() => {
|
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
describe('--json contract: rejects before side effects', () => {
|
|
64
|
-
it('astryx init --json --features agents does not write
|
|
64
|
+
it('astryx init --json --features agents does not write agent docs', () => {
|
|
65
65
|
const before = fs.readdirSync(tmpDir);
|
|
66
66
|
expect(before).toEqual([]);
|
|
67
67
|
|
|
@@ -13,21 +13,55 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import * as fs from 'node:fs';
|
|
16
|
-
import {jsonOut, humanLog} from '
|
|
17
|
-
import {cliError} from '
|
|
18
|
-
import {layoutExpand, layoutCheck, layoutGrammar} from '
|
|
16
|
+
import {jsonOut, humanLog} from '../../lib/json.mjs';
|
|
17
|
+
import {cliError} from '../../lib/cli-error.mjs';
|
|
18
|
+
import {layoutExpand, layoutCheck, layoutGrammar} from '../../api/layout/layout.mjs';
|
|
19
19
|
|
|
20
|
-
/**
|
|
21
|
-
|
|
20
|
+
/**
|
|
21
|
+
* The api layer's @returns for these functions widen the `type` discriminator
|
|
22
|
+
* to `string`, so annotate the command-local result with the precise response
|
|
23
|
+
* shapes from src/types/layout so narrowing + jsonOut typecheck.
|
|
24
|
+
*
|
|
25
|
+
* @typedef {import('../../types/layout').LayoutExpandResponse} LayoutExpandResponse
|
|
26
|
+
* @typedef {import('../../types/layout').LayoutCheckResponse} LayoutCheckResponse
|
|
27
|
+
* @typedef {import('../../types/layout').LayoutGrammarResponse} LayoutGrammarResponse
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @typedef {object} LayoutExpandOptions
|
|
32
|
+
* @property {string} [file]
|
|
33
|
+
* @property {'compact'|'outline'|'auto'} [form]
|
|
34
|
+
* @property {string} [name]
|
|
35
|
+
* @property {boolean} [loose]
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @typedef {object} LayoutCheckOptions
|
|
40
|
+
* @property {string} [file]
|
|
41
|
+
* @property {'compact'|'outline'|'auto'} [form]
|
|
42
|
+
* @property {boolean} [loose]
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Resolve the expression from arg, --file, or stdin ('-').
|
|
47
|
+
* @param {string} [expr]
|
|
48
|
+
* @param {{file?: string}} [options]
|
|
49
|
+
* @returns {Promise<string>}
|
|
50
|
+
*/
|
|
51
|
+
async function readExpression(expr, options = {}) {
|
|
22
52
|
if (options.file) return fs.readFileSync(options.file, 'utf-8');
|
|
23
|
-
if (expr === '-'
|
|
53
|
+
if (expr === '-') {
|
|
54
|
+
/** @type {Buffer[]} */
|
|
24
55
|
const chunks = [];
|
|
25
|
-
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
56
|
+
for await (const chunk of process.stdin) chunks.push(/** @type {Buffer} */ (chunk));
|
|
26
57
|
return Buffer.concat(chunks).toString('utf-8');
|
|
27
58
|
}
|
|
28
|
-
return expr;
|
|
59
|
+
return expr ?? '';
|
|
29
60
|
}
|
|
30
61
|
|
|
62
|
+
/**
|
|
63
|
+
* @param {import('commander').Command} program
|
|
64
|
+
*/
|
|
31
65
|
export function registerLayout(program) {
|
|
32
66
|
const layoutCmd = program
|
|
33
67
|
.command('layout')
|
|
@@ -40,24 +74,26 @@ export function registerLayout(program) {
|
|
|
40
74
|
.option('--form <form>', 'Input surface: compact, outline, or auto', 'auto')
|
|
41
75
|
.option('--name <name>', 'Generated component name (PascalCase)', 'GeneratedLayout')
|
|
42
76
|
.option('--loose', 'Downgrade unknown {block} hints to TODO placeholders')
|
|
43
|
-
.action(async (expression, targetPath, options) => {
|
|
77
|
+
.action(async (/** @type {string} */ expression, /** @type {string} */ targetPath, /** @type {LayoutExpandOptions} */ options) => {
|
|
44
78
|
const json = program.opts().json || false;
|
|
45
79
|
const source = await readExpression(expression, options);
|
|
46
80
|
if (!source || source.trim() === '') {
|
|
47
81
|
cliError('No layout expression given — pass it as an argument, via --file, or on stdin');
|
|
48
82
|
return;
|
|
49
83
|
}
|
|
84
|
+
/** @type {LayoutExpandResponse} */
|
|
50
85
|
let result;
|
|
51
86
|
try {
|
|
52
|
-
result = await layoutExpand(source, {
|
|
87
|
+
result = /** @type {LayoutExpandResponse} */ (await layoutExpand(source, {
|
|
53
88
|
targetPath,
|
|
54
89
|
form: options.form,
|
|
55
90
|
loose: options.loose || false,
|
|
56
91
|
name: options.name,
|
|
57
92
|
cwd: process.cwd(),
|
|
58
|
-
});
|
|
93
|
+
}));
|
|
59
94
|
} catch (e) {
|
|
60
|
-
|
|
95
|
+
const err = /** @type {import('../../api/error.mjs').AstryxError} */ (e);
|
|
96
|
+
cliError(err.message, {suggestions: err.suggestions || [], code: err.code});
|
|
61
97
|
return;
|
|
62
98
|
}
|
|
63
99
|
if (json) return jsonOut(result.type, result.data);
|
|
@@ -81,22 +117,24 @@ export function registerLayout(program) {
|
|
|
81
117
|
.option('--file <file>', 'Read the expression from a file')
|
|
82
118
|
.option('--form <form>', 'Input surface: compact, outline, or auto', 'auto')
|
|
83
119
|
.option('--loose', 'Downgrade unknown {block} hints to TODO placeholders')
|
|
84
|
-
.action(async (expression, options) => {
|
|
120
|
+
.action(async (/** @type {string} */ expression, /** @type {LayoutCheckOptions} */ options) => {
|
|
85
121
|
const json = program.opts().json || false;
|
|
86
122
|
const source = await readExpression(expression, options);
|
|
87
123
|
if (!source || source.trim() === '') {
|
|
88
124
|
cliError('No layout expression given — pass it as an argument, via --file, or on stdin');
|
|
89
125
|
return;
|
|
90
126
|
}
|
|
127
|
+
/** @type {LayoutCheckResponse} */
|
|
91
128
|
let result;
|
|
92
129
|
try {
|
|
93
|
-
result = await layoutCheck(source, {
|
|
130
|
+
result = /** @type {LayoutCheckResponse} */ (await layoutCheck(source, {
|
|
94
131
|
form: options.form,
|
|
95
132
|
loose: options.loose || false,
|
|
96
133
|
cwd: process.cwd(),
|
|
97
|
-
});
|
|
134
|
+
}));
|
|
98
135
|
} catch (e) {
|
|
99
|
-
|
|
136
|
+
const err = /** @type {import('../../api/error.mjs').AstryxError} */ (e);
|
|
137
|
+
cliError(err.message, {suggestions: err.suggestions || [], code: err.code});
|
|
100
138
|
return;
|
|
101
139
|
}
|
|
102
140
|
if (json) return jsonOut(result.type, result.data);
|
|
@@ -106,7 +144,7 @@ export function registerLayout(program) {
|
|
|
106
144
|
humanLog(`\n✗ Invalid (${errors.length} error${errors.length === 1 ? '' : 's'}):`);
|
|
107
145
|
for (const e of errors) {
|
|
108
146
|
humanLog(` - ${e.formatted}`);
|
|
109
|
-
if (e.suggestions
|
|
147
|
+
if (e.suggestions && e.suggestions.length > 0) humanLog(` did you mean: ${e.suggestions.join(', ')}?`);
|
|
110
148
|
}
|
|
111
149
|
humanLog('');
|
|
112
150
|
process.exitCode = 1;
|
|
@@ -126,11 +164,13 @@ export function registerLayout(program) {
|
|
|
126
164
|
.description('Print the XLE/XLO cheatsheet (alias table generated from this branch)')
|
|
127
165
|
.action(async () => {
|
|
128
166
|
const json = program.opts().json || false;
|
|
167
|
+
/** @type {LayoutGrammarResponse} */
|
|
129
168
|
let result;
|
|
130
169
|
try {
|
|
131
|
-
result = await layoutGrammar({cwd: process.cwd()});
|
|
170
|
+
result = /** @type {LayoutGrammarResponse} */ (await layoutGrammar({cwd: process.cwd()}));
|
|
132
171
|
} catch (e) {
|
|
133
|
-
|
|
172
|
+
const err = /** @type {import('../../api/error.mjs').AstryxError} */ (e);
|
|
173
|
+
cliError(err.message, {suggestions: err.suggestions || [], code: err.code});
|
|
134
174
|
return;
|
|
135
175
|
}
|
|
136
176
|
if (json) return jsonOut(result.type, result.data);
|