@astryxdesign/cli 0.6.3 → 0.6.4-canary.06c8fa3
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 +194 -0
- package/README.md +121 -85
- package/api/blog/blog.doc.mjs +1 -0
- package/api/build/_adapter.d.mts +50 -0
- package/api/build/_adapter.mjs +60 -0
- package/api/build/build.doc.mjs +16 -9
- package/api/build/build.test.mjs +197 -8
- package/api/build/build.type.d.mts +91 -2
- package/api/build/build.type.mjs +52 -8
- package/api/build/help/help.d.mts +12 -5
- package/api/build/help/help.mjs +69 -6
- package/api/build/kit/kit.d.mts +4 -1
- package/api/build/kit/kit.mjs +165 -49
- package/api/build/kit/rank.d.mts +44 -0
- package/api/build/kit/rank.mjs +432 -0
- package/api/build/kit/rank.test.mjs +196 -0
- package/api/component/_adapter.d.mts +31 -12
- package/api/component/_adapter.mjs +79 -15
- package/api/component/component.d.mts +6 -3
- package/api/component/component.doc.mjs +36 -13
- package/api/component/component.mjs +339 -22
- package/api/component/component.test.mjs +38 -0
- package/api/component/component.type.d.mts +47 -11
- package/api/component/component.type.mjs +76 -24
- package/api/component/detail/blocks/blocks.d.mts +2 -1
- package/api/component/detail/blocks/blocks.mjs +4 -3
- package/api/component/list/list.d.mts +0 -5
- package/api/component/list/list.mjs +40 -11
- package/api/discover/_adapter.d.mts +114 -6
- package/api/discover/_adapter.mjs +372 -17
- package/api/discover/_adapter.test.mjs +215 -0
- package/api/discover/_catalog-view.d.mts +115 -0
- package/api/discover/_catalog-view.mjs +203 -0
- package/api/discover/_catalog-view.test.mjs +128 -0
- package/api/discover/detail/detail.d.mts +18 -6
- package/api/discover/detail/detail.mjs +67 -13
- package/api/discover/detail/detail.test.mjs +85 -0
- package/api/discover/detail/item/item.d.mts +26 -0
- package/api/discover/detail/item/item.mjs +78 -0
- package/api/discover/detail/item/item.test.mjs +73 -0
- package/api/discover/discover.d.mts +3 -9
- package/api/discover/discover.doc.mjs +62 -18
- package/api/discover/discover.mjs +220 -36
- package/api/discover/discover.test.mjs +11 -2
- package/api/discover/discover.type.d.mts +150 -11
- package/api/discover/discover.type.mjs +107 -17
- package/api/discover/list/list.d.mts +20 -6
- package/api/discover/list/list.mjs +45 -12
- package/api/discover/list/list.test.mjs +46 -0
- package/api/discover/search/search.d.mts +18 -16
- package/api/discover/search/search.mjs +102 -56
- package/api/discover/search/search.test.mjs +144 -10
- package/api/docs/_adapter.d.mts +272 -41
- package/api/docs/_adapter.mjs +985 -108
- package/api/docs/compiled-topics.test.mjs +78 -0
- package/api/docs/detail/detail.mjs +22 -63
- package/api/docs/detail/section/section.d.mts +1 -1
- package/api/docs/detail/section/section.mjs +54 -19
- package/api/docs/detail/section/section.test.mjs +50 -0
- package/api/docs/docs.d.mts +10 -3
- package/api/docs/docs.doc.mjs +55 -16
- package/api/docs/docs.mjs +53 -10
- package/api/docs/docs.test.mjs +166 -4
- package/api/docs/docs.type.d.mts +221 -5
- package/api/docs/docs.type.mjs +153 -11
- package/api/docs/index/index.d.mts +18 -0
- package/api/docs/index/index.mjs +40 -0
- package/api/docs/index/index.test.mjs +62 -0
- package/api/docs/integration-tree.test.mjs +555 -0
- package/api/docs/integrationDocs.test.mjs +114 -8
- package/api/docs/list/list.mjs +28 -12
- package/api/docs/node/node.d.mts +43 -0
- package/api/docs/node/node.mjs +192 -0
- package/api/docs/reference-blocks.test.mjs +406 -0
- package/api/doctor/doctor.d.mts +104 -1
- package/api/doctor/doctor.doc.mjs +1 -0
- package/api/doctor/doctor.mjs +635 -7
- package/api/doctor/doctor.test.mjs +732 -11
- package/api/gap-report/gap-report.doc.mjs +8 -4
- package/api/hook/_adapter.mjs +19 -5
- package/api/hook/hook.doc.mjs +1 -0
- package/api/hook/hook.type.d.mts +3 -3
- package/api/hook/hook.type.mjs +11 -11
- package/api/hook/list/list.d.mts +2 -2
- package/api/hook/list/list.mjs +69 -17
- package/api/index.d.mts +2 -3
- package/api/index.mjs +5 -4
- package/api/init/init.doc.mjs +6 -1
- package/api/init/init.test.mjs +41 -1
- package/api/init/remove/remove.mjs +1 -1
- package/api/init/run/run.mjs +20 -10
- package/api/integration/add-contribution.component-names.test.mjs +120 -0
- package/api/integration/add-contribution.d.mts +2 -1
- package/api/integration/add-contribution.mjs +130 -15
- package/api/integration/add-contribution.test.mjs +258 -7
- package/api/integration/add-helpers.d.mts +5 -2
- package/api/integration/add-helpers.mjs +36 -9
- package/api/integration/add-theme.mjs +34 -64
- package/api/integration/add-theme.test.mjs +105 -21
- package/api/integration/authoring-checks.mjs +138 -28
- package/api/integration/authoring-checks.test.mjs +179 -7
- package/api/integration/authoring-checks.type.mjs +6 -1
- package/api/integration/integration-authoring.type.d.mts +3 -1
- package/api/integration/integration-authoring.type.mjs +2 -0
- package/api/integration/integration-block-exports.test.mjs +10 -6
- package/api/integration/integrationAdd.doc.mjs +14 -4
- package/api/integration/integrationAddAgentDoc.doc.mjs +1 -0
- package/api/integration/integrationAddCodemod.doc.mjs +1 -0
- package/api/integration/integrationAddComponent.doc.mjs +2 -1
- package/api/integration/integrationAddDoc.doc.mjs +8 -1
- package/api/integration/integrationAddTemplate.doc.mjs +1 -0
- package/api/integration/integrationAddTheme.doc.mjs +6 -5
- package/api/integration/integrationComponentConflicts.doc.mjs +1 -0
- package/api/integration/integrationDocConflicts.doc.mjs +2 -1
- package/api/integration/integrationPackCheck.doc.mjs +2 -1
- package/api/integration/integrationTemplateConflicts.doc.d.mts +3 -0
- package/api/integration/integrationTemplateConflicts.doc.mjs +4 -0
- package/api/integration/pack-check.lifecycle-output.test.mjs +105 -0
- package/api/integration/pack-check.mjs +111 -10
- package/api/integration/pack-check.test.mjs +387 -47
- package/api/integration/pack-check.type.d.mts +26 -2
- package/api/integration/pack-check.type.mjs +14 -1
- package/api/integration/summarizeIssues.doc.mjs +1 -0
- package/api/integration/template-conflict-compatibility.test.mjs +73 -0
- package/api/integration/validate-integration-fixes.test.mjs +1389 -0
- package/api/integration/validate-integration.mjs +52 -102
- package/api/integration/validate-integration.test.mjs +179 -26
- package/api/integration/validate-unread-theme-folders.test.mjs +110 -0
- package/api/integration/validateIntegration.doc.mjs +3 -2
- package/api/json/assertResponse.doc.mjs +1 -0
- package/api/json/envelope-types.test.mjs +76 -0
- package/api/json/index.ts +2 -1
- package/api/json/isError.doc.mjs +1 -0
- package/api/json/parseResponse.doc.mjs +3 -2
- package/api/search/search-return-type.test.mjs +54 -0
- package/api/search/search.d.mts +62 -11
- package/api/search/search.doc.mjs +8 -2
- package/api/search/search.mjs +471 -83
- package/api/search/search.test.mjs +142 -1
- package/api/search/search.type.d.mts +15 -3
- package/api/search/search.type.mjs +5 -2
- package/api/swizzle/copy/copy.mjs +28 -11
- package/api/swizzle/swizzle.doc.mjs +2 -1
- package/api/swizzle/swizzle.type.d.mts +2 -2
- package/api/swizzle/swizzle.type.mjs +2 -2
- package/api/template/copy/copy.mjs +17 -23
- package/api/template/copy/copy.test.mjs +17 -0
- package/api/template/list/list.mjs +1 -0
- package/api/template/table-floating-bulk-actions.test.mjs +66 -0
- package/api/template/template-integration.test.mjs +1008 -3
- package/api/template/template-suffix.test.mjs +41 -21
- package/api/template/template.d.mts +1 -1
- package/api/template/template.doc.mjs +30 -8
- package/api/template/template.mjs +46 -9
- package/api/template/template.type.d.mts +12 -14
- package/api/template/template.type.mjs +15 -14
- package/api/theme/_adapter.d.mts +2 -3
- package/api/theme/_adapter.mjs +4 -5
- package/api/theme/add/add.binary.test.mjs +84 -0
- package/api/theme/add/add.mjs +31 -22
- package/api/theme/add/add.rollback.test.mjs +158 -0
- package/api/theme/add/add.staging.test.mjs +83 -0
- package/api/theme/add/add.test.mjs +14 -1
- package/api/theme/build/build.family.test.mjs +7 -12
- package/api/theme/build/build.mjs +140 -59
- package/api/theme/build/build.public-component-vars.test.mjs +1 -1
- package/api/theme/build/build.receipt-doc.test.mjs +111 -0
- package/api/theme/build/build.rollback.test.mjs +148 -0
- package/api/theme/build/build.test.mjs +127 -0
- package/api/theme/build/font-warning.mjs +3 -3
- package/api/theme/build/font-warning.test.mjs +5 -2
- package/api/theme/generateTonalPalette.doc.mjs +1 -0
- package/api/theme/integration-themes.test.mjs +39 -28
- package/api/theme/list/list.test.mjs +19 -20
- package/api/theme/listThemes.doc.mjs +6 -5
- package/api/theme/palette/generate/generate.mjs +8 -3
- package/api/theme/palette/generate/generate.test.mjs +96 -0
- package/api/theme/palette/generate/generator.d.mts +10 -13
- package/api/theme/palette/generate/generator.mjs +15 -4
- package/api/theme/palette/generate/generator.test.mjs +10 -0
- package/api/theme/template/template.mjs +11 -2
- package/api/theme/template/template.test.mjs +20 -0
- package/api/theme/theme.type.d.mts +170 -11
- package/api/theme/theme.type.mjs +94 -27
- package/api/theme/themeAdd.doc.mjs +4 -3
- package/api/theme/themeBuild.doc.mjs +8 -4
- package/api/theme/themeList.doc.mjs +6 -3
- package/api/theme/themeListAvailable.doc.mjs +5 -3
- package/api/theme/themePaletteGenerate.doc.mjs +1 -0
- package/api/theme/themeTargets.doc.mjs +1 -0
- package/api/theme/themeTemplate.doc.mjs +6 -2
- package/api/upgrade/_adapter.d.mts +32 -5
- package/api/upgrade/_adapter.mjs +139 -22
- package/api/upgrade/list/list.mjs +2 -1
- package/api/upgrade/list/list.test.mjs +73 -0
- package/api/upgrade/project-context.test.mjs +272 -0
- package/api/upgrade/provider-agreement.test.mjs +152 -0
- package/api/upgrade/run/files-changed.test.mjs +111 -0
- package/api/upgrade/run/run.mjs +359 -60
- package/api/upgrade/status/status.mjs +2 -2
- package/api/upgrade/upgrade.doc.mjs +12 -5
- package/api/upgrade/upgrade.type.d.mts +43 -5
- package/api/upgrade/upgrade.type.mjs +29 -13
- package/assets/codemods/__tests__/registry.test.mjs +1 -0
- package/assets/codemods/__tests__/runner.test.mjs +332 -8
- package/assets/codemods/file-count.test.mjs +163 -0
- package/assets/codemods/integration-discovery.mjs +48 -4
- package/assets/codemods/integration-discovery.test.mjs +73 -0
- package/assets/codemods/integration-runner.mjs +59 -7
- package/assets/codemods/integration-runner.protection.test.mjs +153 -0
- package/assets/codemods/registry.mjs +1 -0
- package/assets/codemods/run-codemod.mjs +177 -34
- package/assets/codemods/runner.mjs +353 -104
- package/assets/codemods/term-log.mjs +32 -8
- package/assets/codemods/term-log.test.mjs +19 -1
- package/assets/codemods/transform-prop.mjs +109 -0
- package/assets/codemods/transform-prop.test.mjs +95 -0
- package/assets/codemods/transforms/v0.0.14/__tests__/rename-status-variants.test.mjs +86 -165
- package/assets/codemods/transforms/v0.0.14/rename-status-variants.mjs +72 -210
- package/assets/codemods/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +83 -115
- package/assets/codemods/transforms/v0.1.8/rename-avatar-size-scale.mjs +57 -186
- package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +27 -5
- package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +20 -5
- package/assets/codemods/transforms/v0.6.0/__tests__/next-codemods.test.mjs +47 -0
- package/assets/codemods/transforms/v0.6.0/rename-resizable-pixel-bounds.mjs +57 -10
- package/assets/codemods/transforms/v0.6.4/__tests__/migrate-native-picker-to-presentation.test.mjs +63 -0
- package/assets/codemods/transforms/v0.6.4/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +220 -0
- package/assets/codemods/transforms/v0.6.4/index.mjs +31 -0
- package/assets/codemods/transforms/v0.6.4/migrate-native-picker-to-presentation.mjs +148 -0
- package/assets/codemods/transforms/v0.6.4/migrate-theme-catalog-to-descriptors.mjs +141 -0
- package/assets/docs/README.md +9 -0
- package/assets/docs/authoring.doc.mjs +14 -0
- package/assets/docs/getting-started.doc.mjs +2 -2
- package/assets/docs/internationalization.doc.mjs +7 -5
- package/assets/docs/layout.doc.dense.mjs +2 -2
- package/assets/docs/layout.doc.mjs +1 -1
- package/assets/docs/principles.doc.mjs +6 -6
- package/assets/docs/styling-libraries.doc.mjs +4 -4
- package/assets/docs/styling.doc.mjs +4 -4
- package/assets/docs/theme.doc.mjs +5 -5
- package/assets/docs/tokens.doc.mjs +1 -1
- package/assets/docs/tree/api.doc.mjs +30 -0
- package/assets/docs/tree/cli.doc.mjs +23 -0
- package/assets/docs/tree/commands.doc.mjs +25 -0
- package/assets/docs/tree/component-lookups.doc.mjs +149 -0
- package/assets/docs/{cli-integrations.doc.mjs → tree/integrations.doc.mjs} +144 -26
- package/assets/docs/tree/integrations.test.mjs +62 -0
- package/assets/docs/tree/writing-docs.doc.mjs +286 -0
- package/assets/docs/working-with-ai.doc.mjs +4 -4
- package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.doc.mjs +1 -1
- package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.tsx +1 -3
- package/assets/templates/blocks/components/DateInput/DateInputDateRange.tsx +1 -1
- package/assets/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.tsx +1 -1
- package/assets/templates/blocks/components/Item/ItemDocumentTabs.doc.mjs +14 -0
- package/assets/templates/blocks/components/Item/ItemDocumentTabs.tsx +100 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.doc.mjs +14 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.tsx +61 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.doc.mjs +14 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.tsx +126 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.doc.mjs +15 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.tsx +86 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.doc.mjs +14 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.tsx +99 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.doc.mjs +14 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.tsx +122 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.doc.mjs +14 -0
- package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.tsx +95 -0
- package/assets/templates/blocks/components/Table/TableBulkActionsTable.doc.mjs +14 -0
- package/assets/templates/blocks/components/Table/TableBulkActionsTable.tsx +71 -0
- package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.doc.mjs +19 -0
- package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.tsx +139 -0
- package/assets/templates/blocks/components/TimeInput/TimeInputConstrained.tsx +1 -0
- package/assets/templates/blocks/components/Timer/TimerFormats.doc.mjs +14 -0
- package/assets/templates/blocks/components/Timer/TimerFormats.tsx +34 -0
- package/assets/templates/blocks/components/Timer/TimerInline.doc.mjs +14 -0
- package/assets/templates/blocks/components/Timer/TimerInline.tsx +14 -0
- package/assets/templates/blocks/components/Timer/TimerShowcase.doc.mjs +13 -0
- package/assets/templates/blocks/components/Timer/TimerShowcase.tsx +47 -0
- package/assets/templates/blocks/components/Timer/TimerTypography.doc.mjs +14 -0
- package/assets/templates/blocks/components/Timer/TimerTypography.tsx +31 -0
- package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.doc.mjs +19 -3
- package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +383 -65
- package/assets/templates/pages/table-tree/page.tsx +1704 -0
- package/assets/templates/pages/table-tree/template.doc.mjs +12 -0
- package/assets/templates/themes/butter/butterTheme.doc.mjs +11 -0
- package/assets/templates/themes/chocolate/chocolateTheme.doc.mjs +11 -0
- package/assets/templates/themes/gothic/gothicTheme.doc.mjs +11 -0
- package/assets/templates/themes/matcha/matchaTheme.doc.mjs +11 -0
- package/assets/templates/themes/neutral/neutralTheme.doc.mjs +11 -0
- package/assets/templates/themes/stone/stoneTheme.doc.mjs +11 -0
- package/assets/templates/themes/y2k/y2kTheme.doc.mjs +11 -0
- package/authoring/_shared/contract.ts +22 -0
- package/authoring/codemod/codemod.doc.mjs +7 -2
- package/authoring/codemod/parse.d.mts +8 -8
- package/authoring/codemod/parse.mjs +8 -6
- package/authoring/codemod/type.ts +12 -0
- package/authoring/config/config.doc.mjs +11 -3
- package/authoring/config/debug-composition.test.mjs +92 -0
- package/authoring/config/parse.d.mts +15 -13
- package/authoring/config/parse.mjs +27 -8
- package/authoring/config/parse.test.mjs +8 -0
- package/authoring/config/type.ts +31 -8
- package/authoring/debug/debug.doc.d.mts +11 -0
- package/authoring/debug/debug.doc.mjs +182 -0
- package/authoring/debug/parse.d.mts +8 -8
- package/authoring/debug/parse.mjs +3 -3
- package/authoring/discover/discover.doc.d.mts +13 -0
- package/authoring/discover/discover.doc.mjs +138 -0
- package/authoring/discover/parse.d.mts +24 -0
- package/authoring/discover/parse.mjs +128 -0
- package/authoring/discover/parse.test.mjs +124 -0
- package/authoring/discover/type.ts +87 -0
- package/authoring/doctypes/_schema.d.mts +790 -23
- package/authoring/doctypes/_schema.mjs +543 -39
- package/authoring/doctypes/base/graph-fields.doc.d.mts +9 -0
- package/authoring/doctypes/base/graph-fields.doc.mjs +64 -0
- package/authoring/doctypes/base/type.ts +41 -0
- package/authoring/doctypes/command/command.doc.mjs +5 -4
- package/authoring/doctypes/command/parse.d.mts +2 -2
- package/authoring/doctypes/command/parse.mjs +1 -1
- package/authoring/doctypes/command/type.ts +6 -5
- package/authoring/doctypes/component/component.doc.mjs +6 -3
- package/authoring/doctypes/component/parse.d.mts +2 -2
- package/authoring/doctypes/component/parse.mjs +1 -1
- package/authoring/doctypes/component/type.ts +6 -5
- package/authoring/doctypes/doctypes-new.test.mjs +48 -6
- package/authoring/doctypes/enum/enum.doc.mjs +1 -1
- package/authoring/doctypes/enum/parse.d.mts +2 -2
- package/authoring/doctypes/enum/parse.mjs +1 -1
- package/authoring/doctypes/enum/type.ts +4 -2
- package/authoring/doctypes/function/function.doc.mjs +7 -2
- package/authoring/doctypes/function/parse.d.mts +2 -2
- package/authoring/doctypes/function/parse.mjs +1 -1
- package/authoring/doctypes/function/type.ts +9 -4
- package/authoring/doctypes/hook/hook.doc.mjs +4 -0
- package/authoring/doctypes/hook/parse.d.mts +2 -2
- package/authoring/doctypes/hook/parse.mjs +1 -1
- package/authoring/doctypes/hook/type.ts +5 -4
- package/authoring/doctypes/legacy.d.mts +8 -6
- package/authoring/doctypes/legacy.mjs +5 -4
- package/authoring/doctypes/load-contract.test.mjs +233 -0
- package/authoring/doctypes/namespace/namespace.doc.d.mts +9 -0
- package/authoring/doctypes/namespace/namespace.doc.mjs +128 -0
- package/authoring/doctypes/namespace/parse.d.mts +12 -0
- package/authoring/doctypes/namespace/parse.mjs +25 -0
- package/authoring/doctypes/namespace/parse.test.mjs +163 -0
- package/authoring/doctypes/namespace/type.ts +74 -0
- package/authoring/doctypes/parse.d.mts +22 -18
- package/authoring/doctypes/parse.mjs +22 -11
- package/authoring/doctypes/parse.test.mjs +77 -3
- package/authoring/doctypes/reference/parse.d.mts +2 -2
- package/authoring/doctypes/reference/parse.mjs +8 -5
- package/authoring/doctypes/reference/reference.doc.mjs +48 -6
- package/authoring/doctypes/reference/type.ts +70 -7
- package/authoring/doctypes/schema/parse.d.mts +2 -2
- package/authoring/doctypes/schema/parse.mjs +1 -1
- package/authoring/doctypes/schema/schema.doc.mjs +1 -1
- package/authoring/doctypes/schema/type.ts +4 -4
- package/authoring/doctypes/template/parse.d.mts +94 -1
- package/authoring/doctypes/template/parse.mjs +40 -2
- package/authoring/doctypes/template/parse.test.mjs +26 -2
- package/authoring/doctypes/template/template.doc.mjs +13 -3
- package/authoring/doctypes/template/type.ts +13 -2
- package/authoring/doctypes/theme/parse.d.mts +35 -0
- package/authoring/doctypes/theme/parse.mjs +76 -0
- package/authoring/doctypes/theme/theme.doc.d.mts +9 -0
- package/authoring/doctypes/theme/theme.doc.mjs +79 -0
- package/authoring/doctypes/theme/type.ts +42 -0
- package/authoring/doctypes/types.ts +12 -10
- package/authoring/gap-report/gap-report.doc.d.mts +12 -0
- package/authoring/gap-report/gap-report.doc.mjs +183 -0
- package/authoring/gap-report/parse.d.mts +10 -10
- package/authoring/gap-report/parse.mjs +6 -6
- package/authoring/gap-report/type.ts +1 -1
- package/authoring/identity/identity.doc.d.mts +9 -0
- package/authoring/identity/identity.doc.mjs +61 -0
- package/authoring/identity/type.ts +132 -0
- package/authoring/index.d.mts +3 -0
- package/authoring/index.d.ts +62 -17
- package/authoring/index.mjs +4 -1
- package/authoring/integration/integration.doc.mjs +15 -8
- package/authoring/integration/parse.d.mts +2 -2
- package/authoring/integration/parse.mjs +1 -1
- package/authoring/integration/parse.test.mjs +10 -1
- package/authoring/integration/schema.d.mts +6 -4
- package/authoring/integration/schema.mjs +9 -3
- package/authoring/integration/type.ts +19 -8
- package/authoring/shadcn/receipt.d.mts +6 -6
- package/clients/cli/__tests__/cliManifest.test.ts +27 -29
- package/clients/cli/command-load-failure.test.mjs +83 -0
- package/clients/cli/command-result-coverage.test.mjs +7 -7
- package/clients/cli/commands/blog.doc.mjs +1 -1
- package/clients/cli/commands/blog.mjs +23 -8
- package/clients/cli/commands/blog.test.mjs +42 -1
- package/clients/cli/commands/build-theme.adaptations.test.mjs +100 -1
- package/clients/cli/commands/build-theme.ascii-output.test.mjs +161 -0
- package/clients/cli/commands/build-theme.flag-docs.test.mjs +110 -0
- package/clients/cli/commands/build-theme.mjs +16 -50
- package/clients/cli/commands/build-theme.path-safety.test.mjs +86 -1
- package/clients/cli/commands/build-theme.variants.test.mjs +76 -0
- package/clients/cli/commands/build.doc.mjs +16 -8
- package/clients/cli/commands/build.exit-codes-doc.test.mjs +50 -0
- package/clients/cli/commands/build.mjs +137 -114
- package/clients/cli/commands/build.playbook.test.mjs +75 -0
- package/clients/cli/commands/build.text-fields.test.mjs +81 -0
- package/clients/cli/commands/component/index.mjs +153 -61
- package/clients/cli/commands/component-batch.test.mjs +341 -0
- package/clients/cli/commands/component-ownership.test.mjs +92 -3
- package/clients/cli/commands/component-package.test.mjs +46 -0
- package/clients/cli/commands/component-resolution.test.mjs +21 -0
- package/clients/cli/commands/component.doc.mjs +24 -7
- package/clients/cli/commands/component.test.mjs +19 -0
- package/clients/cli/commands/debug-result-summary.test.mjs +2 -2
- package/clients/cli/commands/detail-levels.test.mjs +2 -2
- package/clients/cli/commands/discover.broken-integration.test.mjs +52 -5
- package/clients/cli/commands/discover.components-flag.test.mjs +97 -0
- package/clients/cli/commands/discover.doc.mjs +55 -9
- package/clients/cli/commands/discover.mjs +393 -118
- package/clients/cli/commands/discover.sources.test.mjs +267 -0
- package/clients/cli/commands/discover.text-projection.test.mjs +103 -0
- package/clients/cli/commands/docs.doc.mjs +28 -6
- package/clients/cli/commands/docs.mjs +240 -26
- package/clients/cli/commands/docs.test.mjs +222 -1
- package/clients/cli/commands/doctor-integration-components.doc.mjs +1 -1
- package/clients/cli/commands/doctor-integration-docs.doc.mjs +3 -3
- package/clients/cli/commands/doctor-integration-templates.doc.mjs +15 -8
- package/clients/cli/commands/doctor-integration-validate.doc.mjs +1 -1
- package/clients/cli/commands/doctor-integration.doc.mjs +1 -1
- package/clients/cli/commands/doctor-integration.package-json.test.mjs +53 -0
- package/clients/cli/commands/doctor-integration.test.mjs +90 -8
- package/clients/cli/commands/doctor.doc.mjs +1 -1
- package/clients/cli/commands/doctor.mjs +59 -32
- package/clients/cli/commands/doctor.test.mjs +42 -0
- package/clients/cli/commands/gap-report.doc.mjs +17 -6
- package/clients/cli/commands/gap-report.test.mjs +72 -0
- package/clients/cli/commands/hook/index.mjs +7 -17
- package/clients/cli/commands/hook.doc.mjs +1 -1
- package/clients/cli/commands/hook.text-projection.test.mjs +45 -0
- package/clients/cli/commands/init.doc.mjs +20 -9
- package/clients/cli/commands/init.flag-help.test.mjs +153 -0
- package/clients/cli/commands/integration-add.controls.test.mjs +132 -0
- package/clients/cli/commands/integration-add.doc.mjs +32 -6
- package/clients/cli/commands/integration-authoring.test.mjs +13 -9
- package/clients/cli/commands/integration-pack.doc.mjs +1 -1
- package/clients/cli/commands/integration-real-world.test.mjs +3 -9
- package/clients/cli/commands/integration.doc.mjs +1 -1
- package/clients/cli/commands/integration.mjs +1 -0
- package/clients/cli/commands/interactive-guard.test.mjs +101 -24
- package/clients/cli/commands/json-contract.test.mjs +33 -0
- package/clients/cli/commands/manifest.doc.mjs +1 -1
- package/clients/cli/commands/no-prompt-wording.test.mjs +94 -0
- package/clients/cli/commands/search.doc.mjs +7 -4
- package/clients/cli/commands/search.mjs +28 -9
- package/clients/cli/commands/search.test.mjs +75 -0
- package/clients/cli/commands/setup-nudge.test.mjs +6 -0
- package/clients/cli/commands/swizzle.doc.mjs +3 -2
- package/clients/cli/commands/swizzle.path-safety.test.mjs +42 -0
- package/clients/cli/commands/template.doc.mjs +52 -13
- package/clients/cli/commands/template.flag-help.test.mjs +117 -0
- package/clients/cli/commands/template.mjs +4 -91
- package/clients/cli/commands/template.path-help.test.mjs +40 -0
- package/clients/cli/commands/text-json-parity.test.mjs +702 -0
- package/clients/cli/commands/theme-add.doc.mjs +4 -3
- package/clients/cli/commands/theme-build.doc.mjs +8 -7
- package/clients/cli/commands/theme-list.doc.mjs +2 -2
- package/clients/cli/commands/theme-palette-generate.doc.mjs +9 -5
- package/clients/cli/commands/theme-palette-generate.test.mjs +19 -0
- package/clients/cli/commands/theme-palette.doc.mjs +1 -1
- package/clients/cli/commands/theme-targets.behavior.test.mjs +4 -3
- package/clients/cli/commands/theme-targets.doc.mjs +1 -1
- package/clients/cli/commands/theme-template.behavior.test.mjs +12 -0
- package/clients/cli/commands/theme-template.doc.mjs +2 -2
- package/clients/cli/commands/theme.doc.mjs +1 -1
- package/clients/cli/commands/upgrade.ascii-output.test.mjs +87 -0
- package/clients/cli/commands/upgrade.doc.mjs +22 -10
- package/clients/cli/commands/upgrade.file-protection.test.mjs +228 -0
- package/clients/cli/commands/upgrade.flag-help.test.mjs +188 -0
- package/clients/cli/commands/upgrade.hook-output.test.mjs +88 -0
- package/clients/cli/commands/upgrade.mjs +29 -7
- package/clients/cli/formatters/index.mjs +164 -1
- package/clients/cli/formatters/index.test.mjs +97 -0
- package/clients/cli/index.mjs +21 -34
- package/clients/cli/latest-version-env.test.mjs +50 -0
- package/clients/cli/lib/cli-error.test.mjs +7 -0
- package/clients/cli/lib/component-format.mjs +9 -9
- package/clients/cli/lib/component-format.test.mjs +1 -1
- package/clients/cli/lib/define-command.mjs +32 -6
- package/clients/cli/lib/doc-text-ascii.test.mjs +82 -0
- package/clients/cli/lib/exit-codes.test.mjs +90 -0
- package/clients/cli/lib/hook-format.mjs +19 -10
- package/clients/cli/lib/json-shim.mjs +62 -16
- package/clients/cli/lib/json-shim.test.mjs +69 -0
- package/clients/cli/lib/manifest.d.ts +2 -0
- package/clients/cli/lib/manifest.mjs +39 -10
- package/clients/cli/lib/manifest.test.mjs +22 -2
- package/clients/cli/lib/parse-error-format.test.mjs +81 -0
- package/foundation/agent-docs/agent-docs.d.mts +7 -2
- package/foundation/agent-docs/agent-docs.mjs +82 -12
- package/foundation/agent-docs/agent-docs.path-safety.test.mjs +266 -4
- package/foundation/agent-docs/agent-docs.test.mjs +19 -1
- package/foundation/config/integration-debug.test.mjs +28 -3
- package/foundation/config/project-themes.test.mjs +11 -19
- package/foundation/config/project.d.mts +20 -11
- package/foundation/config/project.mjs +263 -91
- package/foundation/config/project.test.mjs +270 -21
- package/foundation/discovery/authoring-self-docs.d.mts +87 -0
- package/foundation/discovery/authoring-self-docs.mjs +237 -0
- package/foundation/discovery/authoring-self-docs.test.mjs +170 -0
- package/foundation/discovery/authoring-surface.d.mts +74 -0
- package/foundation/discovery/authoring-surface.mjs +525 -0
- package/foundation/discovery/authoring-surface.test.mjs +392 -0
- package/foundation/discovery/cli-self-docs.d.mts +119 -0
- package/foundation/discovery/cli-self-docs.mjs +490 -0
- package/foundation/discovery/cli-self-docs.test.mjs +375 -0
- package/foundation/discovery/component-discovery.d.mts +39 -1
- package/foundation/discovery/component-discovery.mjs +50 -1
- package/foundation/discovery/component-loader.d.mts +35 -38
- package/foundation/discovery/component-loader.mjs +53 -222
- package/foundation/discovery/docs-discovery.d.mts +119 -11
- package/foundation/discovery/docs-discovery.mjs +423 -108
- package/foundation/discovery/docs-discovery.test.mjs +365 -20
- package/foundation/discovery/docs-output-budget.d.mts +28 -0
- package/foundation/discovery/docs-output-budget.mjs +50 -0
- package/foundation/discovery/docs-section-key.d.mts +116 -0
- package/foundation/discovery/docs-section-key.mjs +322 -0
- package/foundation/discovery/docs-section-key.test.mjs +246 -0
- package/foundation/discovery/template-adapter.d.mts +113 -11
- package/foundation/discovery/template-adapter.fixture-refs.test.mjs +248 -0
- package/foundation/discovery/template-adapter.integration-isolation.test.mjs +94 -0
- package/foundation/discovery/template-adapter.mjs +775 -84
- package/foundation/discovery/template-adapter.test.mjs +57 -0
- package/foundation/discovery/template-conflict-release.d.mts +13 -0
- package/foundation/discovery/template-conflict-release.mjs +40 -0
- package/foundation/discovery/template-conflict-release.test.mjs +40 -0
- package/foundation/discovery/theme-discovery.d.mts +67 -7
- package/foundation/discovery/theme-discovery.mjs +916 -186
- package/foundation/discovery/theme-discovery.test.mjs +613 -219
- package/foundation/discovery/theming-targets.test.mjs +4 -0
- package/foundation/doc-compiler/bundle.d.mts +47 -0
- package/foundation/doc-compiler/bundle.mjs +278 -0
- package/foundation/doc-compiler/bundle.test.mjs +266 -0
- package/foundation/doc-compiler/compile.d.mts +343 -0
- package/foundation/doc-compiler/compile.mjs +558 -0
- package/foundation/doc-compiler/diagnostics.d.mts +126 -0
- package/foundation/doc-compiler/diagnostics.mjs +305 -0
- package/foundation/doc-compiler/doc-compiler.test.mjs +714 -0
- package/foundation/doc-compiler/doc-loads.test.mjs +1630 -0
- package/foundation/doc-compiler/import.d.mts +24 -0
- package/foundation/doc-compiler/import.mjs +59 -0
- package/foundation/doc-compiler/inputs.d.mts +102 -0
- package/foundation/doc-compiler/inputs.mjs +291 -0
- package/foundation/doc-compiler/inputs.test.mjs +299 -0
- package/foundation/doc-compiler/ir.d.mts +22 -0
- package/foundation/doc-compiler/ir.mjs +471 -0
- package/foundation/doc-compiler/lenses.d.mts +36 -0
- package/foundation/doc-compiler/lenses.mjs +173 -0
- package/foundation/doc-compiler/links.d.mts +162 -0
- package/foundation/doc-compiler/links.mjs +294 -0
- package/foundation/doc-compiler/links.test.mjs +192 -0
- package/foundation/doc-compiler/lower-doc.test.mjs +495 -0
- package/foundation/doc-compiler/overlays.d.mts +37 -0
- package/foundation/doc-compiler/overlays.mjs +206 -0
- package/foundation/doc-compiler/parse-readable.d.mts +9 -0
- package/foundation/doc-compiler/parse-readable.mjs +29 -0
- package/foundation/doc-compiler/read.d.mts +127 -0
- package/foundation/doc-compiler/read.mjs +325 -0
- package/foundation/doc-compiler/read.test.mjs +313 -0
- package/foundation/doc-compiler/source.d.mts +33 -0
- package/foundation/doc-compiler/source.mjs +128 -0
- package/foundation/doc-compiler/tree.d.mts +288 -0
- package/foundation/doc-compiler/tree.mjs +876 -0
- package/foundation/doc-compiler/tree.test.mjs +606 -0
- package/foundation/fs/file-protection.d.mts +33 -0
- package/foundation/fs/file-protection.mjs +825 -0
- package/foundation/fs/file-protection.test.mjs +250 -0
- package/foundation/fs/module-loader.d.mts +1 -0
- package/foundation/fs/module-loader.mjs +50 -1
- package/foundation/fs/module-loader.stdout.test.mjs +332 -0
- package/foundation/fs/path-safety.d.mts +3 -2
- package/foundation/fs/path-safety.mjs +49 -19
- package/foundation/fs/path-safety.test.mjs +50 -0
- package/foundation/fs/publish-file-hardlink-unavailable.test.mjs +129 -94
- package/foundation/identity/provider-identity.d.mts +90 -0
- package/foundation/identity/provider-identity.mjs +320 -0
- package/foundation/identity/provider-identity.test.mjs +254 -0
- package/foundation/identity/providers.d.mts +7 -0
- package/foundation/identity/providers.mjs +16 -0
- package/foundation/integrations/autolink.d.mts +58 -1
- package/foundation/integrations/autolink.mjs +143 -45
- package/foundation/integrations/autolink.test.mjs +1 -1
- package/foundation/integrations/cli-requirement.d.mts +45 -0
- package/foundation/integrations/cli-requirement.mjs +154 -0
- package/foundation/integrations/cli-requirement.test.mjs +84 -0
- package/foundation/integrations/contribution-fixes.d.mts +145 -0
- package/foundation/integrations/contribution-fixes.mjs +1284 -0
- package/foundation/integrations/contribution-inventory.d.mts +3 -2
- package/foundation/integrations/contribution-inventory.mjs +27 -24
- package/foundation/integrations/contribution-inventory.test.mjs +86 -27
- package/foundation/integrations/integration-warnings.d.mts +9 -2
- package/foundation/integrations/integration-warnings.mjs +52 -21
- package/foundation/integrations/integration-warnings.test.mjs +74 -1
- package/foundation/integrations/integrations.d.mts +63 -3
- package/foundation/integrations/integrations.mjs +122 -9
- package/foundation/integrations/integrations.test.mjs +415 -1
- package/foundation/integrations/provider-conflicts.test.mjs +125 -0
- package/foundation/integrations/provider-ledger.test.mjs +275 -0
- package/foundation/integrations/provider-resolution.d.mts +152 -0
- package/foundation/integrations/provider-resolution.mjs +576 -0
- package/foundation/integrations/provider-resolution.test.mjs +369 -0
- package/foundation/integrations/theme-descriptor.d.mts +8 -0
- package/foundation/integrations/theme-descriptor.mjs +44 -0
- package/foundation/integrations/validate-contributions.d.mts +2 -0
- package/foundation/integrations/validate-contributions.mjs +131 -29
- package/foundation/response/base.d.ts +8 -4
- package/foundation/response/batch.type.d.mts +33 -0
- package/foundation/response/batch.type.mjs +34 -0
- package/foundation/response/error-codes.d.mts +3 -1
- package/foundation/response/error-codes.d.ts +2 -0
- package/foundation/response/error-codes.doc.mjs +13 -4
- package/foundation/response/error-codes.mjs +8 -2
- package/foundation/response/error-codes.test.mjs +137 -10
- package/foundation/response/json-contract.test.mjs +57 -17
- package/foundation/response/json.d.mts +4 -2
- package/foundation/response/json.mjs +8 -10
- package/foundation/response/response-types.doc.d.mts +5 -1
- package/foundation/response/response-types.doc.mjs +46 -38
- package/foundation/response/response-types.doc.test.mjs +181 -0
- package/foundation/response/response.doc.mjs +1 -1
- package/foundation/text/string-utils.d.mts +8 -0
- package/foundation/text/string-utils.mjs +40 -10
- package/foundation/xle/browser.d.mts +3 -3
- package/foundation/xle/browser.mjs +3 -3
- package/foundation/xle/expand.d.mts +2 -0
- package/foundation/xle/expand.mjs +6 -5
- package/foundation/xle/expand.test.mjs +54 -0
- package/foundation/xle/parse.mjs +1 -1
- package/foundation/xle/print.mjs +2 -2
- package/foundation/xle/splice.mjs +1 -1
- package/foundation/xle/xle.test.mjs +13 -0
- package/package.json +10 -11
- package/api/layout/_adapter.d.mts +0 -34
- package/api/layout/_adapter.mjs +0 -133
- package/api/layout/check/check.d.mts +0 -16
- package/api/layout/check/check.mjs +0 -40
- package/api/layout/expand/expand.d.mts +0 -22
- package/api/layout/expand/expand.mjs +0 -153
- package/api/layout/grammar/grammar.d.mts +0 -13
- package/api/layout/grammar/grammar.mjs +0 -86
- package/api/layout/layout.d.mts +0 -6
- package/api/layout/layout.mjs +0 -17
- package/api/layout/layout.test.mjs +0 -297
- package/api/layout/layout.type.d.mts +0 -89
- package/api/layout/layout.type.mjs +0 -103
- package/api/layout/layoutCheck.doc.d.mts +0 -11
- package/api/layout/layoutCheck.doc.mjs +0 -84
- package/api/layout/layoutExpand.doc.d.mts +0 -11
- package/api/layout/layoutExpand.doc.mjs +0 -106
- package/api/layout/layoutGrammar.doc.d.mts +0 -11
- package/api/layout/layoutGrammar.doc.mjs +0 -56
- package/assets/templates/themes/manifest.json +0 -95
- package/clients/cli/commands/layout-check.doc.mjs +0 -54
- package/clients/cli/commands/layout-expand.doc.mjs +0 -66
- package/clients/cli/commands/layout-grammar.doc.mjs +0 -30
- package/clients/cli/commands/layout.doc.mjs +0 -34
- package/clients/cli/commands/layout.error-codes.test.mjs +0 -66
- package/clients/cli/commands/layout.exit-parity.test.mjs +0 -41
- package/clients/cli/commands/layout.mjs +0 -263
- package/clients/cli/lib/update-check.mjs +0 -83
- package/clients/cli/lib/update-check.test.mjs +0 -137
- package/clients/cli/update-hint-commands.test.mjs +0 -54
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* @file Subprocess no-hang tests
|
|
4
|
+
* @file Subprocess no-hang tests: the CLI never waits on stdin (INV1).
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* Every run gets a stdin pipe that stays open and silent, the way an agent's
|
|
7
|
+
* harness holds it. A prompt or a stdin read for control flow then blocks until
|
|
8
|
+
* the deadline, and the run ends with signal SIGTERM and status null. With stdin
|
|
9
|
+
* ignored or closed, the same read would see EOF at once and pass.
|
|
10
|
+
*
|
|
11
|
+
* Every command and group in the manifest runs once, with a placeholder for
|
|
12
|
+
* each required argument so its action is reached, plus the bare `astryx`.
|
|
11
13
|
*/
|
|
12
14
|
|
|
13
15
|
import {describe, it, expect, beforeEach, afterEach} from 'vitest';
|
|
14
|
-
import {spawnSync} from 'node:child_process';
|
|
16
|
+
import {spawn, spawnSync} from 'node:child_process';
|
|
15
17
|
import * as fs from 'node:fs';
|
|
16
18
|
import * as path from 'node:path';
|
|
17
19
|
import * as os from 'node:os';
|
|
@@ -19,37 +21,112 @@ import {fileURLToPath} from 'node:url';
|
|
|
19
21
|
|
|
20
22
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
21
23
|
const CLI = path.resolve(__dirname, '..', 'bin', 'astryx.mjs');
|
|
24
|
+
const DEADLINE_MS = 20_000;
|
|
25
|
+
// Keeps every run offline: `blog` fetches its feed when run bare.
|
|
26
|
+
const OFFLINE = `data:text/javascript,${encodeURIComponent(
|
|
27
|
+
"globalThis.fetch = () => Promise.reject(new TypeError('fetch failed'));",
|
|
28
|
+
)}`;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Run `node <argv>` with a stdin pipe that is never written or ended.
|
|
32
|
+
* @param {string[]} argv
|
|
33
|
+
* @param {string} cwd
|
|
34
|
+
* @param {number} [deadline]
|
|
35
|
+
* @returns {Promise<{status: number | null, signal: NodeJS.Signals | null, output: string}>}
|
|
36
|
+
*/
|
|
37
|
+
function runHeld(argv, cwd, deadline = DEADLINE_MS) {
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
const child = spawn(process.execPath, argv, {
|
|
40
|
+
cwd,
|
|
41
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
42
|
+
env: {...process.env, FORCE_COLOR: '0', CI: ''},
|
|
43
|
+
});
|
|
44
|
+
// Never written or ended; a late EPIPE after exit is not a result.
|
|
45
|
+
child.stdin.on('error', () => {});
|
|
46
|
+
let output = '';
|
|
47
|
+
child.stdout.setEncoding('utf8').on('data', chunk => (output += chunk));
|
|
48
|
+
child.stderr.setEncoding('utf8').on('data', chunk => (output += chunk));
|
|
49
|
+
const timer = setTimeout(() => child.kill('SIGTERM'), deadline);
|
|
50
|
+
child.on('error', error => {
|
|
51
|
+
clearTimeout(timer);
|
|
52
|
+
reject(error);
|
|
53
|
+
});
|
|
54
|
+
child.on('close', (status, signal) => {
|
|
55
|
+
clearTimeout(timer);
|
|
56
|
+
resolve({status, signal, output});
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
22
60
|
|
|
23
|
-
|
|
61
|
+
/**
|
|
62
|
+
* @param {string[]} args
|
|
63
|
+
* @param {string} cwd
|
|
64
|
+
*/
|
|
65
|
+
function runCli(args, cwd) {
|
|
66
|
+
return runHeld(['--import', OFFLINE, CLI, ...args], cwd);
|
|
67
|
+
}
|
|
24
68
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
69
|
+
/** @returns {Array<[string, string[]]>} */
|
|
70
|
+
function manifestInvocations() {
|
|
71
|
+
const manifest = spawnSync(process.execPath, [CLI, 'manifest', '--json'], {
|
|
28
72
|
encoding: 'utf8',
|
|
29
|
-
timeout: 20_000,
|
|
30
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
31
|
-
env: {...process.env, FORCE_COLOR: '0', CI: ''},
|
|
32
73
|
});
|
|
74
|
+
/** @type {string[][]} */
|
|
75
|
+
const invocations = [[]];
|
|
76
|
+
/** @param {any[]} commands */
|
|
77
|
+
const walk = commands => {
|
|
78
|
+
for (const command of commands) {
|
|
79
|
+
invocations.push([
|
|
80
|
+
...command.name.split(' '),
|
|
81
|
+
...command.arguments.filter((/** @type {any} */ a) => a.required).map(() => 'x'),
|
|
82
|
+
]);
|
|
83
|
+
walk(command.subcommands ?? []);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
walk(JSON.parse(manifest.stdout).data.commands);
|
|
87
|
+
return invocations.map(args => [['astryx', ...args].join(' '), args]);
|
|
33
88
|
}
|
|
34
89
|
|
|
35
|
-
|
|
36
|
-
|
|
90
|
+
describe('the harness holds stdin open', () => {
|
|
91
|
+
it('so a stdin read is reported as a hang', async () => {
|
|
92
|
+
const r = await runHeld(['-e', 'process.stdin.resume()'], os.tmpdir(), 1_000);
|
|
93
|
+
expect(r.signal).toBe('SIGTERM');
|
|
94
|
+
expect(r.status).toBeNull();
|
|
95
|
+
});
|
|
37
96
|
});
|
|
38
97
|
|
|
39
|
-
|
|
40
|
-
|
|
98
|
+
describe('every command exits without waiting on stdin', () => {
|
|
99
|
+
it.concurrent.for(manifestInvocations())('%s', async ([label, args], {expect}) => {
|
|
100
|
+
const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-interactive-guard-'));
|
|
101
|
+
try {
|
|
102
|
+
const r = await runCli(args, cwd);
|
|
103
|
+
expect(r.signal, `${label} waited on stdin:\n${r.output.slice(-500)}`).toBeNull();
|
|
104
|
+
} finally {
|
|
105
|
+
fs.rmSync(cwd, {recursive: true, force: true});
|
|
106
|
+
}
|
|
107
|
+
});
|
|
41
108
|
});
|
|
42
109
|
|
|
43
110
|
describe('init is non-interactive by default (no TTY needed)', () => {
|
|
44
|
-
|
|
45
|
-
|
|
111
|
+
let tmpDir;
|
|
112
|
+
|
|
113
|
+
beforeEach(() => {
|
|
114
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-interactive-guard-'));
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
afterEach(() => {
|
|
118
|
+
fs.rmSync(tmpDir, {recursive: true, force: true});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('runs cleanly (exit 0, no hang) and writes agent docs', async () => {
|
|
122
|
+
const r = await runCli(['init'], tmpDir);
|
|
46
123
|
expect(r.signal).toBeNull(); // did not hang
|
|
47
124
|
expect(r.status).toBe(0); // succeeded without a TTY
|
|
48
125
|
expect(fs.readdirSync(tmpDir).length).toBeGreaterThan(0); // wrote the cheat sheet
|
|
49
126
|
});
|
|
50
127
|
|
|
51
|
-
it('writes an agent-doc file containing the ASTRYX cheat-sheet marker', () => {
|
|
52
|
-
runCli(['init']);
|
|
128
|
+
it('writes an agent-doc file containing the ASTRYX cheat-sheet marker', async () => {
|
|
129
|
+
await runCli(['init'], tmpDir);
|
|
53
130
|
// init injects into existing agent-doc files if present, else creates AGENTS.md
|
|
54
131
|
const candidates = ['AGENTS.md', 'CLAUDE.md', '.cursorrules', path.join('.claude', 'CLAUDE.md')];
|
|
55
132
|
const doc = candidates.find(f => fs.existsSync(path.join(tmpDir, f)));
|
|
@@ -57,8 +134,8 @@ describe('init is non-interactive by default (no TTY needed)', () => {
|
|
|
57
134
|
expect(fs.readFileSync(path.join(tmpDir, doc), 'utf8')).toMatch(/ASTRYX:START/);
|
|
58
135
|
});
|
|
59
136
|
|
|
60
|
-
it('still runs --features agents non-interactively', () => {
|
|
61
|
-
const r = runCli(['init', '--features', 'agents']);
|
|
137
|
+
it('still runs --features agents non-interactively', async () => {
|
|
138
|
+
const r = await runCli(['init', '--features', 'agents'], tmpDir);
|
|
62
139
|
expect(r.signal).toBeNull();
|
|
63
140
|
expect(r.status).toBe(0);
|
|
64
141
|
expect(fs.readdirSync(tmpDir).length).toBeGreaterThan(0);
|
|
@@ -172,3 +172,36 @@ describe('--json contract: supported commands emit valid envelopes', () => {
|
|
|
172
172
|
expect(parsed.data.summary.fail).toBeGreaterThan(0);
|
|
173
173
|
});
|
|
174
174
|
});
|
|
175
|
+
|
|
176
|
+
describe('--json contract: the flag describes the envelopes it emits', () => {
|
|
177
|
+
/** @param {string} shape e.g. ` apiVersion, error, code, suggestions? ` */
|
|
178
|
+
const fields = shape => shape.split(',').map(f => f.trim().replace(/\?$/, ''));
|
|
179
|
+
|
|
180
|
+
it('names every field of the success and error envelopes', async () => {
|
|
181
|
+
const manifest = parseJson((await runCli(['manifest', '--json'], {cwd: tmpDir})).stdout);
|
|
182
|
+
const {description} = manifest.data.globalOptions.find(o => o.flag === '--json');
|
|
183
|
+
const match = /Success envelope: \{([^}]*)\}.*Error envelope: \{([^}]*)\}/.exec(description);
|
|
184
|
+
expect(match, description).not.toBeNull();
|
|
185
|
+
const [, success, error] = /** @type {RegExpExecArray} */ (match);
|
|
186
|
+
|
|
187
|
+
for (const key of Object.keys(manifest)) expect(fields(success)).toContain(key);
|
|
188
|
+
expect(fields(success)).toContain('meta');
|
|
189
|
+
|
|
190
|
+
// An unknown command's envelope carries every error field, suggestions included.
|
|
191
|
+
const failure = parseJson((await runCli(['bogus-cmd', '--json'], {cwd: tmpDir})).stdout);
|
|
192
|
+
expect(Object.keys(failure)).toContain('suggestions');
|
|
193
|
+
for (const key of Object.keys(failure)) expect(fields(error)).toContain(key);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('the CLI README describes the same envelopes', () => {
|
|
197
|
+
const readme = fs.readFileSync(new URL('../../../README.md', import.meta.url), 'utf8');
|
|
198
|
+
const line = readme
|
|
199
|
+
.split('\n')
|
|
200
|
+
.find(l => l.startsWith('- `--json`: Output as typed JSON envelope:'));
|
|
201
|
+
expect(line, 'README global --json line').toBeDefined();
|
|
202
|
+
const [success, error] = [...String(line).matchAll(/`\{([^}]*)\}`/g)].map(m => fields(m[1]));
|
|
203
|
+
expect(success).toEqual(expect.arrayContaining(['apiVersion', 'type', 'data', 'meta']));
|
|
204
|
+
expect(error).toEqual(expect.arrayContaining(['apiVersion', 'error', 'code', 'suggestions']));
|
|
205
|
+
expect(readme).toContain('{"apiVersion": 1, "type": "component.detail"');
|
|
206
|
+
});
|
|
207
|
+
});
|
|
@@ -12,7 +12,7 @@ export const doc = {
|
|
|
12
12
|
type: 'command',
|
|
13
13
|
name: 'manifest',
|
|
14
14
|
displayName: 'astryx manifest',
|
|
15
|
-
namespace: 'cli',
|
|
15
|
+
namespace: 'cli/commands',
|
|
16
16
|
summary: 'Print the full CLI capability manifest (use with --json).',
|
|
17
17
|
description:
|
|
18
18
|
'Emits the complete CLI surface: every command with its arguments, options, ' +
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file The CLI never asks a question, so no help text, manifest entry or
|
|
5
|
+
* error-code description may say a flag skips a prompt. Each flag's text states
|
|
6
|
+
* what happens without it instead, and the CLI does that.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {describe, it, expect, beforeEach, afterEach} from 'vitest';
|
|
10
|
+
import * as fs from 'node:fs';
|
|
11
|
+
import * as os from 'node:os';
|
|
12
|
+
import * as path from 'node:path';
|
|
13
|
+
import {fileURLToPath} from 'node:url';
|
|
14
|
+
import {runCli} from '../../../test-utils/run-cli.mjs';
|
|
15
|
+
import {doc as errorCodesDoc} from '../../../foundation/response/error-codes.doc.mjs';
|
|
16
|
+
import {doc as upgradeFn} from '../../../api/upgrade/upgrade.doc.mjs';
|
|
17
|
+
|
|
18
|
+
const CLI_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..');
|
|
19
|
+
const SLOW = 30_000;
|
|
20
|
+
|
|
21
|
+
/** @type {string} */
|
|
22
|
+
let tmpDir;
|
|
23
|
+
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-no-prompt-'));
|
|
26
|
+
fs.writeFileSync(path.join(tmpDir, 'package.json'), JSON.stringify({name: 'consumer'}));
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
fs.rmSync(tmpDir, {recursive: true, force: true});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* One option's description from the manifest (subcommands are nested).
|
|
35
|
+
* @param {string} command @param {string} flag
|
|
36
|
+
*/
|
|
37
|
+
async function optionText(command, flag) {
|
|
38
|
+
const {stdout} = await runCli(['--json', 'manifest'], tmpDir);
|
|
39
|
+
/** @typedef {{name: string, options: Array<{flag: string, description: string}>, subcommands?: ManifestCommand[]}} ManifestCommand */
|
|
40
|
+
/** @param {ManifestCommand[]} list @returns {ManifestCommand | undefined} */
|
|
41
|
+
const find = list => {
|
|
42
|
+
for (const c of list) {
|
|
43
|
+
const hit = c.name === command ? c : find(c.subcommands ?? []);
|
|
44
|
+
if (hit) return hit;
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
47
|
+
};
|
|
48
|
+
const cmd = find(JSON.parse(stdout).data.commands);
|
|
49
|
+
return cmd?.options.find(o => o.flag.includes(flag))?.description ?? '';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
describe('no help text describes a prompt', () => {
|
|
53
|
+
it('theme add --overwrite states the refusal, and a refused run writes nothing', async () => {
|
|
54
|
+
const help = await optionText('theme add', '--overwrite');
|
|
55
|
+
expect(help).not.toMatch(/prompt/i);
|
|
56
|
+
expect(help).toContain('ERR_FILE_EXISTS');
|
|
57
|
+
expect(help).toMatch(/nothing is written/);
|
|
58
|
+
|
|
59
|
+
const first = await runCli(['--json', 'theme', 'add', 'matcha'], tmpDir);
|
|
60
|
+
expect(first.status).toBe(0);
|
|
61
|
+
const {outputDir, files} = JSON.parse(first.stdout).data;
|
|
62
|
+
expect(files.length).toBeGreaterThan(1);
|
|
63
|
+
const dir = path.join(tmpDir, outputDir);
|
|
64
|
+
fs.writeFileSync(path.join(dir, files[0]), '// edited\n');
|
|
65
|
+
fs.rmSync(path.join(dir, files[1]));
|
|
66
|
+
|
|
67
|
+
const refused = await runCli(['--json', 'theme', 'add', 'matcha'], tmpDir);
|
|
68
|
+
expect(refused.status).toBe(1);
|
|
69
|
+
expect(JSON.parse(refused.stdout).code).toBe('ERR_FILE_EXISTS');
|
|
70
|
+
expect(fs.readFileSync(path.join(dir, files[0]), 'utf8')).toBe('// edited\n');
|
|
71
|
+
expect(fs.existsSync(path.join(dir, files[1]))).toBe(false);
|
|
72
|
+
}, SLOW);
|
|
73
|
+
|
|
74
|
+
it('upgrade --install-deps names the failure without it, in help and in the API doc', async () => {
|
|
75
|
+
const help = await optionText('upgrade', '--install-deps');
|
|
76
|
+
const param = upgradeFn.params?.find(p => p.name === 'options.installDeps')?.description ?? '';
|
|
77
|
+
for (const text of [help, param]) {
|
|
78
|
+
expect(text).not.toMatch(/prompt/i);
|
|
79
|
+
expect(text).toContain('ERR_DEP_MISSING');
|
|
80
|
+
}
|
|
81
|
+
}, SLOW);
|
|
82
|
+
|
|
83
|
+
it('ERR_FILE_EXISTS is described without an interactive mode, in the code set, its doc and the README table', () => {
|
|
84
|
+
const member = errorCodesDoc.members.find(m => m.value === 'ERR_FILE_EXISTS');
|
|
85
|
+
expect(member?.description).toBe('Refused to overwrite an existing file.');
|
|
86
|
+
|
|
87
|
+
const source = fs.readFileSync(path.join(CLI_ROOT, 'foundation/response/error-codes.mjs'), 'utf8');
|
|
88
|
+
expect(source).toMatch(/\/\*\* Refused to overwrite an existing file\. \*\/\s*ERR_FILE_EXISTS:/);
|
|
89
|
+
|
|
90
|
+
const readme = fs.readFileSync(path.join(CLI_ROOT, 'README.md'), 'utf8');
|
|
91
|
+
const row = readme.split('\n').find(line => line.startsWith('| `ERR_FILE_EXISTS`'));
|
|
92
|
+
expect(row).toMatch(/\| Refused to overwrite an existing file\.\s+\|$/);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
@@ -12,7 +12,7 @@ export const doc = {
|
|
|
12
12
|
type: 'command',
|
|
13
13
|
name: 'search',
|
|
14
14
|
displayName: 'astryx search',
|
|
15
|
-
namespace: 'cli',
|
|
15
|
+
namespace: 'cli/commands',
|
|
16
16
|
summary: 'Search components, hooks, docs, and templates in one ranked list',
|
|
17
17
|
description:
|
|
18
18
|
'Terminal front-end to search(): prints one ranked, greppable list across ' +
|
|
@@ -29,11 +29,11 @@ export const doc = {
|
|
|
29
29
|
{
|
|
30
30
|
flag: '--limit <n>',
|
|
31
31
|
param: 'options.limit',
|
|
32
|
-
description: 'Max number of results (default 20)',
|
|
32
|
+
description: 'Max number of results, a positive integer (default 20)',
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
flag: '--verbose',
|
|
36
|
-
description:
|
|
36
|
+
description: "Also print each result's score and match reason",
|
|
37
37
|
},
|
|
38
38
|
],
|
|
39
39
|
examples: [
|
|
@@ -45,7 +45,10 @@ export const doc = {
|
|
|
45
45
|
],
|
|
46
46
|
exitCodes: [
|
|
47
47
|
{code: 0, when: 'success (including zero matches)'},
|
|
48
|
-
{
|
|
48
|
+
{
|
|
49
|
+
code: 1,
|
|
50
|
+
when: 'invalid --type, a --limit that is not a positive integer, or @astryxdesign/core cannot be found',
|
|
51
|
+
},
|
|
49
52
|
],
|
|
50
53
|
related: ['component', 'hook', 'docs', 'template', 'build'],
|
|
51
54
|
};
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* astryx search button Ranked results across all domains
|
|
17
17
|
* astryx search modal --type component Filter to a single domain
|
|
18
18
|
* astryx search forms --limit 5 Cap the result count
|
|
19
|
-
* astryx search button --verbose
|
|
19
|
+
* astryx search button --verbose Also print score / reason
|
|
20
20
|
* astryx search button --json Typed JSON envelope
|
|
21
21
|
*/
|
|
22
22
|
|
|
@@ -49,16 +49,15 @@ export function registerSearch(program) {
|
|
|
49
49
|
|
|
50
50
|
try {
|
|
51
51
|
const project = await Project.load(process.cwd());
|
|
52
|
-
await warnOnIntegrationIssues(project
|
|
52
|
+
await warnOnIntegrationIssues(project, {json});
|
|
53
53
|
} catch {
|
|
54
54
|
// Never let the nudge break the command.
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
const limit =
|
|
61
|
-
options.limit != null ? Number.parseInt(options.limit, 10) : 20;
|
|
57
|
+
// Number(), not parseInt(): parseInt truncates `1.5` and `5abc` into
|
|
58
|
+
// integers the API would reject. The API validates the value, so the
|
|
59
|
+
// flag and `search({limit})` accept and refuse the same inputs.
|
|
60
|
+
const limit = options.limit != null ? Number(options.limit) : 20;
|
|
62
61
|
|
|
63
62
|
/** @type {import('../../../api/search/search.type.mjs').SearchResponse} */
|
|
64
63
|
let result;
|
|
@@ -116,15 +115,32 @@ export function registerSearch(program) {
|
|
|
116
115
|
const fields = options.verbose
|
|
117
116
|
? [
|
|
118
117
|
'name',
|
|
118
|
+
'section',
|
|
119
119
|
'domain',
|
|
120
|
+
'package',
|
|
121
|
+
'title',
|
|
120
122
|
'displayName',
|
|
123
|
+
'kind',
|
|
121
124
|
'score',
|
|
122
125
|
'reason',
|
|
123
126
|
'import',
|
|
124
127
|
'description',
|
|
125
128
|
'command',
|
|
129
|
+
'parent',
|
|
126
130
|
]
|
|
127
|
-
: [
|
|
131
|
+
: [
|
|
132
|
+
'name',
|
|
133
|
+
'section',
|
|
134
|
+
'domain',
|
|
135
|
+
'package',
|
|
136
|
+
'title',
|
|
137
|
+
'displayName',
|
|
138
|
+
'kind',
|
|
139
|
+
'import',
|
|
140
|
+
'description',
|
|
141
|
+
'command',
|
|
142
|
+
'parent',
|
|
143
|
+
];
|
|
128
144
|
|
|
129
145
|
// The heading mirrors the JSON: `matchCount` is what matched, and the
|
|
130
146
|
// records below are the slice `--limit` allowed. Saying only "(20)" when
|
|
@@ -135,7 +151,10 @@ export function registerSearch(program) {
|
|
|
135
151
|
? `Results for "${q}" (${results.length} of ${matchCount})`
|
|
136
152
|
: `Results for "${q}" (${results.length})`,
|
|
137
153
|
),
|
|
138
|
-
records(results, {
|
|
154
|
+
records(results, {
|
|
155
|
+
fields,
|
|
156
|
+
format: {command: formatCliCommand, parent: formatCliCommand},
|
|
157
|
+
}),
|
|
139
158
|
);
|
|
140
159
|
return answered;
|
|
141
160
|
},
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import {describe, it, expect} from 'vitest';
|
|
14
|
+
import * as fs from 'node:fs';
|
|
15
|
+
import * as os from 'node:os';
|
|
14
16
|
import * as path from 'node:path';
|
|
15
17
|
import {fileURLToPath} from 'node:url';
|
|
16
18
|
import {search, scoreCandidate, SEARCH_DOMAINS} from '../../../api/search/search.mjs';
|
|
@@ -28,6 +30,33 @@ const OPTS = {cwd: REPO_ROOT};
|
|
|
28
30
|
// the vitest per-test timeout. Give both the same generous scan budget.
|
|
29
31
|
const SCAN_TIMEOUT = 30_000;
|
|
30
32
|
|
|
33
|
+
/**
|
|
34
|
+
* A JSON value as the formatters print it (they normalize typography to ASCII).
|
|
35
|
+
* @param {unknown} value
|
|
36
|
+
*/
|
|
37
|
+
function asText(value) {
|
|
38
|
+
return (Array.isArray(value) ? value.join(', ') : String(value))
|
|
39
|
+
.replace(/[\u2014\u2013]/g, '-')
|
|
40
|
+
.replace(/[\u2018\u2019]/g, "'")
|
|
41
|
+
.replace(/[\u201C\u201D]/g, '"')
|
|
42
|
+
.replace(/\u2026/g, '...')
|
|
43
|
+
.replace(/\u00a0/g, ' ')
|
|
44
|
+
.trimEnd();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Whether some text line prints `key:` with this value. The command field gains
|
|
49
|
+
* the caller's invocation prefix, so the value is matched as the line's end; a
|
|
50
|
+
* multi-line value is matched by its first line.
|
|
51
|
+
* @param {string[]} lines
|
|
52
|
+
* @param {string} key
|
|
53
|
+
* @param {unknown} value
|
|
54
|
+
*/
|
|
55
|
+
function printsField(lines, key, value) {
|
|
56
|
+
const shown = asText(value).split('\n')[0].trimEnd();
|
|
57
|
+
return lines.some(line => line.startsWith(`${key}:`) && line.trimEnd().endsWith(shown));
|
|
58
|
+
}
|
|
59
|
+
|
|
31
60
|
describe('search() API — ranking', () => {
|
|
32
61
|
it('ranks an exact component name match first', async () => {
|
|
33
62
|
const {data} = await search('button', OPTS);
|
|
@@ -172,6 +201,20 @@ describe('search CLI — exit codes + JSON contract', () => {
|
|
|
172
201
|
expect(r.status).toBe(1);
|
|
173
202
|
});
|
|
174
203
|
|
|
204
|
+
it.each(['1.5', '5abc'])(
|
|
205
|
+
'refuses --limit %s like search({limit}) does, in both modes',
|
|
206
|
+
async value => {
|
|
207
|
+
await expect(
|
|
208
|
+
search('x', {...OPTS, limit: Number(value)}),
|
|
209
|
+
).rejects.toMatchObject({code: 'ERR_INVALID_ARGUMENT'});
|
|
210
|
+
const json = await runCli(['--json', 'search', 'x', '--limit', value], REPO_ROOT);
|
|
211
|
+
expect(json.status).toBe(1);
|
|
212
|
+
expect(JSON.parse(json.stdout)).toMatchObject({code: 'ERR_INVALID_ARGUMENT'});
|
|
213
|
+
const text = await runCli(['search', 'x', '--limit', value], REPO_ROOT);
|
|
214
|
+
expect(text.status).toBe(1);
|
|
215
|
+
},
|
|
216
|
+
);
|
|
217
|
+
|
|
175
218
|
it('emits a valid --json envelope', async () => {
|
|
176
219
|
const r = await runCli(['--json', 'search', 'button'], REPO_ROOT);
|
|
177
220
|
expect(r.status).toBe(0);
|
|
@@ -223,6 +266,25 @@ describe('search CLI — exit codes + JSON contract', () => {
|
|
|
223
266
|
expect(r.stdout).toContain('description:');
|
|
224
267
|
});
|
|
225
268
|
|
|
269
|
+
it('prints every result field under its JSON key (score and reason with --verbose)', async () => {
|
|
270
|
+
// One query that reaches all four domains, so every per-domain field shows.
|
|
271
|
+
const args = ['search', 'theme', '--limit', '60'];
|
|
272
|
+
const env = JSON.parse((await runCli(['--json', ...args], REPO_ROOT)).stdout);
|
|
273
|
+
expect(new Set(env.data.results.map(r => r.domain))).toEqual(new Set(SEARCH_DOMAINS));
|
|
274
|
+
const plain = (await runCli(args, REPO_ROOT)).stdout.split('\n');
|
|
275
|
+
const verbose = (await runCli([...args, '--verbose'], REPO_ROOT)).stdout.split('\n');
|
|
276
|
+
for (const result of env.data.results) {
|
|
277
|
+
for (const [key, value] of Object.entries(result)) {
|
|
278
|
+
if (value == null || value === '') continue;
|
|
279
|
+
const label = `${result.domain} ${result.name}: ${key}`;
|
|
280
|
+
expect(printsField(verbose, key, value), label).toBe(true);
|
|
281
|
+
if (key !== 'score' && key !== 'reason') {
|
|
282
|
+
expect(printsField(plain, key, value), label).toBe(true);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}, 90_000);
|
|
287
|
+
|
|
226
288
|
it('--verbose exits 0 and prints import/match detail', async () => {
|
|
227
289
|
// Regression: the boolean verbose flag was named --detail, which collided
|
|
228
290
|
// with the value-taking global `--detail <level>` — a bare `search
|
|
@@ -236,4 +298,17 @@ describe('search CLI — exit codes + JSON contract', () => {
|
|
|
236
298
|
expect(r.stdout).toContain('score:');
|
|
237
299
|
expect(r.stdout).toContain('reason:');
|
|
238
300
|
});
|
|
301
|
+
|
|
302
|
+
it('exits 1 with ERR_CORE_NOT_FOUND when no @astryxdesign/core is reachable', async () => {
|
|
303
|
+
const empty = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-search-cli-no-core-'));
|
|
304
|
+
try {
|
|
305
|
+
const json = await runCli(['--json', 'search', 'button'], empty);
|
|
306
|
+
expect(json.status).toBe(1);
|
|
307
|
+
expect(JSON.parse(json.stdout)).toMatchObject({code: 'ERR_CORE_NOT_FOUND'});
|
|
308
|
+
const text = await runCli(['search', 'button'], empty);
|
|
309
|
+
expect(text.status).toBe(1);
|
|
310
|
+
} finally {
|
|
311
|
+
fs.rmSync(empty, {recursive: true, force: true});
|
|
312
|
+
}
|
|
313
|
+
});
|
|
239
314
|
}, SCAN_TIMEOUT);
|
|
@@ -89,6 +89,12 @@ describe('enforcement layer 3 — per-command setup nudge', () => {
|
|
|
89
89
|
expect((await runCli(['docs', 'tokens'], tmp)).stderr).not.toMatch(NUDGE);
|
|
90
90
|
});
|
|
91
91
|
|
|
92
|
+
it('is quiet in an integration package, which is not an app', async () => {
|
|
93
|
+
asProject();
|
|
94
|
+
write('astryx.integration.mjs', 'export default {};\n');
|
|
95
|
+
expect((await runCli(['docs', 'tokens'], tmp)).stderr).not.toMatch(NUDGE);
|
|
96
|
+
});
|
|
97
|
+
|
|
92
98
|
it('does not nudge for the installer command itself', async () => {
|
|
93
99
|
asProject();
|
|
94
100
|
expect((await runCli(['init'], tmp)).stderr).not.toMatch(NUDGE);
|
|
@@ -12,7 +12,7 @@ export const doc = {
|
|
|
12
12
|
type: 'command',
|
|
13
13
|
name: 'swizzle',
|
|
14
14
|
displayName: 'astryx swizzle',
|
|
15
|
-
namespace: 'cli',
|
|
15
|
+
namespace: 'cli/commands',
|
|
16
16
|
summary: 'Copy component source for customization',
|
|
17
17
|
description:
|
|
18
18
|
"Ejects a component's source from the resolved @astryxdesign/core (or its owning " +
|
|
@@ -40,7 +40,8 @@ export const doc = {
|
|
|
40
40
|
{
|
|
41
41
|
flag: '-f, --overwrite',
|
|
42
42
|
param: 'options.overwrite',
|
|
43
|
-
description:
|
|
43
|
+
description:
|
|
44
|
+
'Replace existing files. Without it, existing files fail the command with ERR_FILE_EXISTS and nothing is written',
|
|
44
45
|
},
|
|
45
46
|
],
|
|
46
47
|
examples: [
|
|
@@ -74,6 +74,37 @@ describe('swizzle path safety', () => {
|
|
|
74
74
|
expect(fs.existsSync(absTarget)).toBe(false);
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
+
it('rejects a component directory that is a symlink out of the project', async () => {
|
|
78
|
+
const {project, outside} = buildFakeRepo(tmpDir);
|
|
79
|
+
const base = path.join(project, 'components', 'astryx');
|
|
80
|
+
fs.mkdirSync(base, {recursive: true});
|
|
81
|
+
fs.symlinkSync(outside, path.join(base, 'Button'));
|
|
82
|
+
|
|
83
|
+
const result = await runCli(['--json', 'swizzle', 'Button'], project);
|
|
84
|
+
|
|
85
|
+
expect(result.code).not.toBe(0);
|
|
86
|
+
expect(JSON.parse(result.stdout).code).toBe('ERR_PATH_TRAVERSAL');
|
|
87
|
+
expect(fs.readdirSync(outside)).toEqual([]);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('rejects an existing file that is a symlink out of the project, even with --overwrite', async () => {
|
|
91
|
+
const {project, outside} = buildFakeRepo(tmpDir);
|
|
92
|
+
const outDir = path.join(project, 'components', 'astryx', 'Button');
|
|
93
|
+
fs.mkdirSync(outDir, {recursive: true});
|
|
94
|
+
const target = path.join(outside, 'kept.txt');
|
|
95
|
+
fs.writeFileSync(target, 'kept\n');
|
|
96
|
+
fs.symlinkSync(target, path.join(outDir, 'Button.tsx'));
|
|
97
|
+
|
|
98
|
+
const result = await runCli(
|
|
99
|
+
['--json', 'swizzle', 'Button', '--overwrite'],
|
|
100
|
+
project,
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
expect(result.code).not.toBe(0);
|
|
104
|
+
expect(JSON.parse(result.stdout).code).toBe('ERR_PATH_TRAVERSAL');
|
|
105
|
+
expect(fs.readFileSync(target, 'utf-8')).toBe('kept\n');
|
|
106
|
+
});
|
|
107
|
+
|
|
77
108
|
it('requires --overwrite in non-interactive mode when files already exist', async () => {
|
|
78
109
|
const {project} = buildFakeRepo(tmpDir);
|
|
79
110
|
const outDir = path.join(project, 'components', 'astryx', 'Button');
|
|
@@ -92,4 +123,15 @@ describe('swizzle path safety', () => {
|
|
|
92
123
|
// Existing file unchanged
|
|
93
124
|
expect(fs.readFileSync(existingPath, 'utf-8')).toBe('// my customizations\n');
|
|
94
125
|
});
|
|
126
|
+
|
|
127
|
+
// The CLI never prompts: without --overwrite it refuses with a code, and the
|
|
128
|
+
// manifest agents read must say so.
|
|
129
|
+
it('describes --overwrite by its refusal, not a prompt', async () => {
|
|
130
|
+
const {project} = buildFakeRepo(tmpDir);
|
|
131
|
+
const result = await runCli(['--json', 'manifest'], project);
|
|
132
|
+
const swizzle = JSON.parse(result.stdout).data.commands.find(c => c.name === 'swizzle');
|
|
133
|
+
const overwrite = swizzle.options.find(o => o.flag.includes('--overwrite'));
|
|
134
|
+
expect(overwrite.description).not.toMatch(/prompt/i);
|
|
135
|
+
expect(overwrite.description).toContain('ERR_FILE_EXISTS');
|
|
136
|
+
});
|
|
95
137
|
});
|