@astryxdesign/cli 0.6.3-canary.98a2e4e → 0.6.3-canary.9c4d44d
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/README.md +117 -79
- 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 +6 -12
- package/api/component/_adapter.mjs +20 -10
- package/api/component/component.doc.mjs +13 -3
- package/api/component/component.mjs +91 -14
- package/api/component/component.test.mjs +38 -0
- package/api/component/component.type.d.mts +22 -11
- package/api/component/component.type.mjs +32 -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 +268 -47
- package/api/docs/_adapter.mjs +970 -149
- package/api/docs/compiled-topics.test.mjs +78 -0
- package/api/docs/detail/detail.d.mts +0 -15
- package/api/docs/detail/detail.mjs +22 -78
- package/api/docs/detail/section/section.mjs +39 -24
- package/api/docs/detail/section/section.test.mjs +19 -9
- package/api/docs/docs.d.mts +5 -3
- package/api/docs/docs.doc.mjs +39 -17
- package/api/docs/docs.mjs +44 -8
- package/api/docs/docs.test.mjs +158 -4
- package/api/docs/docs.type.d.mts +185 -6
- package/api/docs/docs.type.mjs +127 -13
- package/api/docs/index/index.mjs +15 -6
- package/api/docs/index/index.test.mjs +1 -1
- package/api/docs/integration-tree.test.mjs +555 -0
- package/api/docs/integrationDocs.test.mjs +14 -14
- 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 +54 -4
- package/api/doctor/doctor.doc.mjs +1 -0
- package/api/doctor/doctor.mjs +332 -21
- package/api/doctor/doctor.test.mjs +420 -7
- 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 +1 -1
- package/api/hook/list/list.mjs +69 -17
- package/api/index.d.mts +1 -1
- package/api/index.mjs +1 -0
- 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 +2 -0
- 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.mjs +83 -7
- 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 -0
- package/api/json/isError.doc.mjs +1 -0
- package/api/json/parseResponse.doc.mjs +3 -2
- package/api/layout/_adapter.mjs +20 -5
- package/api/layout/expand/expand.mjs +7 -5
- package/api/layout/expand/expand.path-safety.test.mjs +53 -0
- package/api/layout/grammar/grammar.mjs +2 -1
- package/api/layout/layoutCheck.doc.mjs +1 -0
- package/api/layout/layoutExpand.doc.mjs +2 -1
- package/api/layout/layoutGrammar.doc.mjs +1 -0
- package/api/search/search-return-type.test.mjs +54 -0
- package/api/search/search.d.mts +61 -10
- package/api/search/search.doc.mjs +8 -2
- package/api/search/search.mjs +471 -83
- package/api/search/search.test.mjs +124 -1
- package/api/search/search.type.d.mts +14 -2
- 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 +1072 -3
- package/api/template/template-suffix.test.mjs +41 -21
- package/api/template/template.doc.mjs +30 -8
- package/api/template/template.mjs +45 -8
- package/api/template/template.type.d.mts +11 -13
- 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 +124 -73
- package/api/upgrade/list/list.mjs +2 -1
- package/api/upgrade/list/list.test.mjs +73 -0
- package/api/upgrade/provider-agreement.test.mjs +152 -0
- package/api/upgrade/run/run.mjs +356 -59
- package/api/upgrade/status/status.mjs +2 -2
- package/api/upgrade/upgrade.doc.mjs +8 -2
- package/api/upgrade/upgrade.type.d.mts +42 -4
- package/api/upgrade/upgrade.type.mjs +26 -10
- package/assets/codemods/__tests__/runner.test.mjs +330 -8
- package/assets/codemods/integration-discovery.mjs +48 -4
- package/assets/codemods/integration-discovery.test.mjs +73 -0
- package/assets/codemods/integration-runner.mjs +56 -4
- package/assets/codemods/integration-runner.protection.test.mjs +153 -0
- package/assets/codemods/run-codemod.mjs +177 -34
- package/assets/codemods/runner.mjs +350 -102
- 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/next/__tests__/migrate-native-picker-to-presentation.test.mjs +63 -0
- package/assets/codemods/transforms/next/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +220 -0
- package/assets/codemods/transforms/next/index.mjs +19 -1
- package/assets/codemods/transforms/next/migrate-native-picker-to-presentation.mjs +148 -0
- package/assets/codemods/transforms/next/migrate-theme-catalog-to-descriptors.mjs +141 -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/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/{cli-integrations.doc.mjs → tree/integrations.doc.mjs} +95 -39
- 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/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 +10 -2
- 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 +29 -6
- package/authoring/debug/debug.doc.d.mts +11 -0
- package/authoring/debug/debug.doc.mjs +182 -0
- package/authoring/debug/parse.d.mts +7 -7
- 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 +240 -128
- package/authoring/doctypes/_schema.mjs +198 -16
- package/authoring/doctypes/base/graph-fields.doc.mjs +15 -6
- package/authoring/doctypes/base/type.ts +9 -4
- package/authoring/doctypes/command/command.doc.mjs +4 -3
- package/authoring/doctypes/command/parse.d.mts +2 -2
- package/authoring/doctypes/command/parse.mjs +1 -1
- package/authoring/doctypes/command/type.ts +4 -4
- package/authoring/doctypes/component/component.doc.mjs +5 -2
- package/authoring/doctypes/component/parse.d.mts +2 -2
- package/authoring/doctypes/component/parse.mjs +1 -1
- package/authoring/doctypes/component/type.ts +3 -3
- 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 +2 -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 +4 -3
- 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 +3 -3
- package/authoring/doctypes/legacy.d.mts +6 -6
- package/authoring/doctypes/legacy.mjs +3 -3
- package/authoring/doctypes/load-contract.test.mjs +233 -0
- package/authoring/doctypes/namespace/namespace.doc.mjs +9 -9
- package/authoring/doctypes/namespace/parse.d.mts +2 -2
- package/authoring/doctypes/namespace/parse.mjs +1 -1
- package/authoring/doctypes/namespace/parse.test.mjs +23 -25
- package/authoring/doctypes/namespace/type.ts +6 -3
- package/authoring/doctypes/parse.d.mts +22 -20
- package/authoring/doctypes/parse.mjs +19 -14
- package/authoring/doctypes/reference/parse.d.mts +2 -2
- package/authoring/doctypes/reference/parse.mjs +1 -1
- package/authoring/doctypes/reference/reference.doc.mjs +39 -6
- package/authoring/doctypes/reference/type.ts +31 -14
- 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 +3 -4
- package/authoring/doctypes/template/parse.d.mts +94 -1
- package/authoring/doctypes/template/parse.mjs +37 -1
- package/authoring/doctypes/template/parse.test.mjs +18 -0
- package/authoring/doctypes/template/template.doc.mjs +13 -3
- package/authoring/doctypes/template/type.ts +12 -1
- 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 -11
- 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 +9 -9
- package/authoring/gap-report/parse.mjs +6 -6
- package/authoring/gap-report/type.ts +1 -1
- package/authoring/identity/identity.doc.mjs +3 -2
- package/authoring/identity/type.ts +10 -10
- package/authoring/index.d.mts +2 -0
- package/authoring/index.d.ts +32 -19
- package/authoring/index.mjs +3 -1
- package/authoring/integration/integration.doc.mjs +2 -2
- package/authoring/integration/parse.d.mts +2 -2
- package/authoring/integration/parse.mjs +1 -1
- package/authoring/integration/schema.d.mts +4 -4
- package/authoring/integration/schema.mjs +3 -3
- package/authoring/integration/type.ts +5 -11
- package/clients/cli/__tests__/cliManifest.test.ts +27 -29
- package/clients/cli/command-load-failure.test.mjs +83 -0
- 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 +3 -8
- package/clients/cli/commands/component-ownership.test.mjs +3 -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 +1 -1
- package/clients/cli/commands/component.test.mjs +19 -0
- 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 +21 -9
- package/clients/cli/commands/docs.mjs +184 -70
- package/clients/cli/commands/docs.test.mjs +120 -16
- 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/layout-check.doc.mjs +15 -4
- package/clients/cli/commands/layout-expand.doc.mjs +22 -5
- package/clients/cli/commands/layout-grammar.doc.mjs +1 -1
- package/clients/cli/commands/layout.doc.mjs +3 -3
- package/clients/cli/commands/layout.mjs +21 -9
- package/clients/cli/commands/layout.path-help.test.mjs +33 -0
- package/clients/cli/commands/layout.stdin-cap.test.mjs +47 -0
- package/clients/cli/commands/layout.text-fields.test.mjs +39 -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 +719 -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 +3 -3
- 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 +20 -8
- 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 +2 -0
- package/clients/cli/formatters/index.test.mjs +6 -0
- package/clients/cli/index.mjs +21 -30
- 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 +97 -0
- package/clients/cli/lib/hook-format.mjs +19 -10
- package/clients/cli/lib/json-shim.mjs +38 -2
- package/clients/cli/lib/json-shim.test.mjs +83 -0
- package/clients/cli/lib/manifest.d.ts +2 -0
- package/clients/cli/lib/manifest.mjs +32 -2
- package/clients/cli/lib/manifest.test.mjs +17 -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 +246 -89
- package/foundation/config/project.test.mjs +270 -21
- package/foundation/discovery/authoring-self-docs.d.mts +18 -0
- package/foundation/discovery/authoring-self-docs.mjs +38 -15
- package/foundation/discovery/authoring-self-docs.test.mjs +87 -12
- 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 +38 -0
- package/foundation/discovery/component-discovery.mjs +48 -0
- package/foundation/discovery/component-loader.d.mts +35 -38
- package/foundation/discovery/component-loader.mjs +53 -222
- package/foundation/discovery/docs-discovery.d.mts +114 -9
- package/foundation/discovery/docs-discovery.mjs +239 -30
- package/foundation/discovery/docs-discovery.test.mjs +150 -35
- package/foundation/discovery/docs-output-budget.d.mts +2 -2
- package/foundation/discovery/docs-output-budget.mjs +1 -1
- package/foundation/discovery/docs-section-key.d.mts +28 -10
- package/foundation/discovery/docs-section-key.mjs +134 -33
- package/foundation/discovery/docs-section-key.test.mjs +41 -19
- 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 +772 -82
- 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 +1642 -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 +598 -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/integrations/autolink.d.mts +58 -1
- package/foundation/integrations/autolink.mjs +143 -52
- 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 +51 -26
- package/foundation/integrations/integration-warnings.test.mjs +74 -1
- package/foundation/integrations/integrations.d.mts +17 -1
- package/foundation/integrations/integrations.mjs +52 -98
- package/foundation/integrations/integrations.test.mjs +31 -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.mjs +121 -29
- package/foundation/response/base.d.ts +8 -4
- 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 +11 -0
- 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 +37 -22
- package/foundation/response/response-types.doc.test.mjs +158 -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/expand.d.mts +2 -0
- package/foundation/xle/expand.mjs +4 -3
- package/foundation/xle/expand.test.mjs +54 -0
- package/foundation/xle/xle.test.mjs +13 -0
- package/package.json +10 -11
- package/assets/templates/themes/manifest.json +0 -95
- 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
|
@@ -22,11 +22,12 @@
|
|
|
22
22
|
import * as fs from 'node:fs';
|
|
23
23
|
import * as path from 'node:path';
|
|
24
24
|
import {findCoreDir, CLI_ROOT} from '../fs/paths.mjs';
|
|
25
|
-
import {assertWithin} from '../fs/path-safety.mjs';
|
|
25
|
+
import {assertWithin, PathSafetyError} from '../fs/path-safety.mjs';
|
|
26
26
|
import {getCliInvocation} from '../env/package-manager.mjs';
|
|
27
27
|
import {discoverComponents} from '../discovery/component-discovery.mjs';
|
|
28
28
|
import {Project} from '../config/project.mjs';
|
|
29
29
|
import {humanLog} from '../response/json.mjs';
|
|
30
|
+
import {ERROR_CODES} from '../response/error-codes.mjs';
|
|
30
31
|
import {
|
|
31
32
|
AGENTS_MD,
|
|
32
33
|
CLAUDE_MD,
|
|
@@ -353,8 +354,9 @@ export function detectStylingSystem(targetDir) {
|
|
|
353
354
|
* Generate the agent cheat sheet from live CLI metadata.
|
|
354
355
|
*
|
|
355
356
|
* Structured as: workflow (behavioral) → rules (error prevention) → CLI reference.
|
|
356
|
-
* Templates
|
|
357
|
-
*
|
|
357
|
+
* Templates lead the workflow: every page starts from a scaffolded template,
|
|
358
|
+
* because the template already carries the frame and spacing that an agent
|
|
359
|
+
* composing from components would have to re-derive, and usually gets wrong.
|
|
358
360
|
*
|
|
359
361
|
* `stylingSystem` tailors the custom-styling guidance to what the project has
|
|
360
362
|
* configured (see {@link detectStylingSystem}) so the agent never reaches for a
|
|
@@ -427,17 +429,19 @@ export function generateCompressedIndex(
|
|
|
427
429
|
lines.push(' import "@astryxdesign/core/astryx.css";');
|
|
428
430
|
lines.push('');
|
|
429
431
|
|
|
430
|
-
// Workflow — `build` is the front door
|
|
431
|
-
|
|
432
|
-
lines.push('
|
|
433
|
-
lines.push('
|
|
434
|
-
lines.push('
|
|
432
|
+
// Workflow — `build` is the front door, and every page starts from the
|
|
433
|
+
// template it names.
|
|
434
|
+
lines.push('WORKFLOW — start every page from a template. Never lay out a page from scratch:');
|
|
435
|
+
lines.push('1. `astryx build "<idea>"` — START HERE: names the [page] template to start from (always one: the closest match, or the app shell), two other templates, and the [block]s + [component]s for parts it lacks. No args = full playbook.');
|
|
436
|
+
lines.push('2. `astryx template <name> <path>` — scaffold that template into your project. Keep its frame, gap and padding; replace its data, copy and sections; delete sections you do not need.');
|
|
437
|
+
lines.push('3. `astryx template <Block>` for a part the template lacks; `astryx component <Name>` for props + examples before you use or change a component.');
|
|
438
|
+
lines.push('Changing a page you already have? Keep it: skip step 2 and add blocks and components inside its sections.');
|
|
435
439
|
lines.push('');
|
|
436
440
|
|
|
437
441
|
// Rules — the top error-preventers.
|
|
438
442
|
lines.push('RULES:');
|
|
439
443
|
lines.push('- No <div> — components do all layout/spacing, page frame included.');
|
|
440
|
-
lines.push('- Frame first:
|
|
444
|
+
lines.push('- Frame first: the template you scaffold sets the page frame. Read `astryx docs layout` before you change it — region widths, breakpoint behavior.');
|
|
441
445
|
lines.push('- Dense data = rows (Table, List/Item), never Card-wrapped list items; Card is for standalone widgets. Status = StatusDot/Token; Badge = counts only.');
|
|
442
446
|
// Styling guidance tailored to the project's configured system — never
|
|
443
447
|
// recommend a path that isn't compiled here (xstyle needs the StyleX compiler;
|
|
@@ -462,7 +466,7 @@ export function generateCompressedIndex(
|
|
|
462
466
|
css: 'replace any raw <div>/<span> layout, imported .css/@apply, or hardcoded value (#hex, 16px) with the component or a token (var(--color-*|--spacing-*|…))',
|
|
463
467
|
};
|
|
464
468
|
lines.push(
|
|
465
|
-
`- SELF-CHECK before you finish: re-read the file and ${selfCheckFix[stylingSystem] ?? selfCheckFix.css}. If unsure a component/prop exists, run \`astryx component <Name>\` / \`astryx search "<thing>"\`; don't hand-roll CSS.`,
|
|
469
|
+
`- SELF-CHECK before you finish: re-read the file and ${selfCheckFix[stylingSystem] ?? selfCheckFix.css}. Confirm the page kept its template's frame, gap and padding. If unsure a component/prop exists, run \`astryx component <Name>\` / \`astryx search "<thing>"\`; don't hand-roll CSS.`,
|
|
466
470
|
);
|
|
467
471
|
lines.push('');
|
|
468
472
|
|
|
@@ -485,6 +489,7 @@ export function generateCompressedIndex(
|
|
|
485
489
|
if (resolvedTopics.length > 0) {
|
|
486
490
|
lines.push(` docs <topic> ${resolvedTopics.join(', ')}`);
|
|
487
491
|
}
|
|
492
|
+
lines.push(' docs cli commands, API reference, integration authoring (one level at a time)');
|
|
488
493
|
lines.push(' swizzle <Name> eject component source for deep customization');
|
|
489
494
|
lines.push(' upgrade --apply run after any Astryx or integration dependency bump');
|
|
490
495
|
const appendCount = agentDocs.reduce(
|
|
@@ -705,12 +710,65 @@ export function removeXdsBlock(filePath, {deleteIfEmpty = false} = {}) {
|
|
|
705
710
|
return true;
|
|
706
711
|
}
|
|
707
712
|
|
|
713
|
+
/**
|
|
714
|
+
* Whether an agent-doc file already carries a managed-block marker.
|
|
715
|
+
* @param {string} filePath
|
|
716
|
+
* @returns {boolean}
|
|
717
|
+
*/
|
|
718
|
+
function hasManagedMarker(filePath) {
|
|
719
|
+
try {
|
|
720
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
721
|
+
return content.includes(MARKER_START) || content.includes(LEGACY_MARKER_START);
|
|
722
|
+
} catch {
|
|
723
|
+
return false;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Whether `removeXdsBlock` would change `filePath`: it holds one well-formed
|
|
729
|
+
* managed block.
|
|
730
|
+
* @param {string} filePath
|
|
731
|
+
* @returns {boolean}
|
|
732
|
+
*/
|
|
733
|
+
function hasRemovableBlock(filePath) {
|
|
734
|
+
try {
|
|
735
|
+
return findManagedBlock(fs.readFileSync(filePath, 'utf-8')) != null;
|
|
736
|
+
} catch {
|
|
737
|
+
return false;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* Every file a run writes must resolve inside `targetDir`, symlinks
|
|
743
|
+
* included. Checked for the whole write set before the first write, so an
|
|
744
|
+
* escape writes nothing.
|
|
745
|
+
* @param {string} targetDir
|
|
746
|
+
* @param {Iterable<string>} relPaths
|
|
747
|
+
*/
|
|
748
|
+
function assertTargetsWithin(targetDir, relPaths) {
|
|
749
|
+
for (const p of relPaths) {
|
|
750
|
+
assertWithin(p, targetDir, {label: 'agent docs path'});
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
708
754
|
/**
|
|
709
755
|
* Remove Astryx section from all known agent doc files.
|
|
710
756
|
* @param {string} targetDir
|
|
757
|
+
* @throws {PathSafetyError} `ERR_PATH_TRAVERSAL` when a file it would change
|
|
758
|
+
* resolves outside `targetDir`; nothing is changed.
|
|
711
759
|
*/
|
|
712
760
|
export function removeAgentDocs(targetDir) {
|
|
713
761
|
const allPaths = discoverAgentDocs(targetDir);
|
|
762
|
+
try {
|
|
763
|
+
assertTargetsWithin(
|
|
764
|
+
targetDir,
|
|
765
|
+
allPaths.filter(p => hasRemovableBlock(path.join(targetDir, p))),
|
|
766
|
+
);
|
|
767
|
+
} catch (err) {
|
|
768
|
+
// The code reaches the error envelope as is, so it must be registered.
|
|
769
|
+
if (!(err instanceof PathSafetyError)) throw err;
|
|
770
|
+
throw new PathSafetyError(err.message, ERROR_CODES.ERR_PATH_TRAVERSAL);
|
|
771
|
+
}
|
|
714
772
|
|
|
715
773
|
for (const p of allPaths) {
|
|
716
774
|
const filePath = path.join(targetDir, p);
|
|
@@ -718,9 +776,9 @@ export function removeAgentDocs(targetDir) {
|
|
|
718
776
|
const deleteIfEmpty = p === AGENTS_MD || p === CLAUDE_DIR_MD;
|
|
719
777
|
if (removeXdsBlock(filePath, {deleteIfEmpty})) {
|
|
720
778
|
if (!fs.existsSync(filePath)) {
|
|
721
|
-
humanLog(
|
|
779
|
+
humanLog(`[ok] Removed empty ${p}`);
|
|
722
780
|
} else {
|
|
723
|
-
humanLog(
|
|
781
|
+
humanLog(`[ok] Removed design system section from ${p}`);
|
|
724
782
|
}
|
|
725
783
|
}
|
|
726
784
|
}
|
|
@@ -750,6 +808,8 @@ export function removeAgentDocs(targetDir) {
|
|
|
750
808
|
* @param {string} [options.renderedBlock] - Fully rendered expected block. Init
|
|
751
809
|
* and upgrade pass one shared block to every target.
|
|
752
810
|
* @returns {string[]} List of files written
|
|
811
|
+
* @throws {import('../fs/path-safety.mjs').PathSafetyError} when a file it would
|
|
812
|
+
* write resolves outside `targetDir`; nothing is written.
|
|
753
813
|
*/
|
|
754
814
|
export function installAgentDocs(
|
|
755
815
|
targetDir,
|
|
@@ -806,6 +866,7 @@ export function installAgentDocs(
|
|
|
806
866
|
// Agent preset
|
|
807
867
|
if (agent) {
|
|
808
868
|
const {inject, create} = resolveAgentPaths(targetDir, agent);
|
|
869
|
+
assertTargetsWithin(targetDir, [...inject, ...create]);
|
|
809
870
|
for (const p of inject) {
|
|
810
871
|
injectXdsBlock(path.join(targetDir, p), compressedIndex);
|
|
811
872
|
written.push(p);
|
|
@@ -833,6 +894,14 @@ export function installAgentDocs(
|
|
|
833
894
|
if (existing.length > 0) {
|
|
834
895
|
const wrappers = discoverAgentDocWrappers(targetDir, existing);
|
|
835
896
|
const targets = existing.filter(p => !wrappers.has(p));
|
|
897
|
+
// A refresh skips unmarked files and a wrapper is only written when it
|
|
898
|
+
// carries a block, so only the files this run writes are checked.
|
|
899
|
+
/** @param {string} p */
|
|
900
|
+
const marked = p => hasManagedMarker(path.join(targetDir, p));
|
|
901
|
+
assertTargetsWithin(targetDir, [
|
|
902
|
+
...targets.filter(p => !onlyReplace || marked(p)),
|
|
903
|
+
...[...wrappers].filter(marked),
|
|
904
|
+
]);
|
|
836
905
|
|
|
837
906
|
for (const p of targets) {
|
|
838
907
|
const didWrite = injectXdsBlock(path.join(targetDir, p), compressedIndex, {onlyReplace});
|
|
@@ -860,6 +929,7 @@ export function installAgentDocs(
|
|
|
860
929
|
if (onlyReplace) return written;
|
|
861
930
|
|
|
862
931
|
const defaultPath = AGENTS_MD;
|
|
932
|
+
assertTargetsWithin(targetDir, [defaultPath]);
|
|
863
933
|
injectXdsBlock(path.join(targetDir, defaultPath), compressedIndex, {
|
|
864
934
|
createIfMissing: true,
|
|
865
935
|
header: `# AGENTS.md\n\nProject-specific guidance for AI coding agents.`,
|
|
@@ -1,22 +1,31 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* @file Path-safety regression tests for
|
|
4
|
+
* @file Path-safety regression tests for agent-doc writes.
|
|
5
5
|
*
|
|
6
6
|
* `installAgentDocs(targetDir, {paths})` previously joined each path
|
|
7
7
|
* onto `targetDir` with no validation, so:
|
|
8
8
|
* - `../OUT.md` wrote outside `targetDir`
|
|
9
9
|
* - `/tmp/x.md` was silently re-rooted under `targetDir`
|
|
10
10
|
*
|
|
11
|
-
*
|
|
11
|
+
* Auto-detected and preset files were never checked at all, so a `CLAUDE.md`
|
|
12
|
+
* or `.claude/` symlinked out of the project had the block written through
|
|
13
|
+
* it. Every case now throws PathSafetyError before any file is touched.
|
|
14
|
+
*
|
|
15
|
+
* `removeAgentDocs` (`init --remove-agents`) stripped or deleted a block
|
|
16
|
+
* through the same kind of link and reported success. It now refuses with
|
|
17
|
+
* `ERR_PATH_TRAVERSAL` before any file is touched.
|
|
12
18
|
*/
|
|
13
19
|
|
|
14
|
-
import {describe, it, expect, beforeEach, afterEach} from 'vitest';
|
|
20
|
+
import {describe, it, expect, beforeEach, afterEach, vi} from 'vitest';
|
|
15
21
|
import * as fs from 'node:fs';
|
|
16
22
|
import * as path from 'node:path';
|
|
17
23
|
import * as os from 'node:os';
|
|
18
|
-
import {installAgentDocs} from './agent-docs.mjs';
|
|
24
|
+
import {installAgentDocs, removeAgentDocs} from './agent-docs.mjs';
|
|
19
25
|
import {PathSafetyError} from '../fs/path-safety.mjs';
|
|
26
|
+
import {runCli} from '../../test-utils/run-cli.mjs';
|
|
27
|
+
|
|
28
|
+
const BLOCK = '<!-- ASTRYX:START -->\nmanaged\n<!-- ASTRYX:END -->';
|
|
20
29
|
|
|
21
30
|
let tmpDir;
|
|
22
31
|
beforeEach(() => {
|
|
@@ -26,6 +35,28 @@ afterEach(() => {
|
|
|
26
35
|
fs.rmSync(tmpDir, {recursive: true, force: true});
|
|
27
36
|
});
|
|
28
37
|
|
|
38
|
+
/** A project dir plus a sibling dir outside it. */
|
|
39
|
+
function layout() {
|
|
40
|
+
const project = path.join(tmpDir, 'project');
|
|
41
|
+
const outside = path.join(tmpDir, 'outside');
|
|
42
|
+
fs.mkdirSync(project, {recursive: true});
|
|
43
|
+
fs.mkdirSync(outside, {recursive: true});
|
|
44
|
+
return {project, outside};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @param {() => unknown} fn
|
|
49
|
+
* @returns {unknown} what `fn` threw
|
|
50
|
+
*/
|
|
51
|
+
function thrownBy(fn) {
|
|
52
|
+
try {
|
|
53
|
+
fn();
|
|
54
|
+
} catch (err) {
|
|
55
|
+
return err;
|
|
56
|
+
}
|
|
57
|
+
throw new Error('expected a throw');
|
|
58
|
+
}
|
|
59
|
+
|
|
29
60
|
describe('installAgentDocs path safety', () => {
|
|
30
61
|
it('rejects --agent-docs-path that escapes the target directory', () => {
|
|
31
62
|
const target = path.join(tmpDir, 'project');
|
|
@@ -64,3 +95,234 @@ describe('installAgentDocs path safety', () => {
|
|
|
64
95
|
expect(fs.existsSync(path.join(tmpDir, 'escaped.md'))).toBe(false);
|
|
65
96
|
});
|
|
66
97
|
});
|
|
98
|
+
|
|
99
|
+
describe('installAgentDocs never writes through a symlink out of the project', () => {
|
|
100
|
+
it('refuses an auto-detected file that links outside', () => {
|
|
101
|
+
const {project, outside} = layout();
|
|
102
|
+
const shared = path.join(outside, 'CLAUDE.md');
|
|
103
|
+
fs.writeFileSync(shared, '# Shared\n');
|
|
104
|
+
fs.symlinkSync(shared, path.join(project, 'CLAUDE.md'));
|
|
105
|
+
|
|
106
|
+
expect(() => installAgentDocs(project, {renderedBlock: BLOCK})).toThrow(
|
|
107
|
+
/outside the project root/,
|
|
108
|
+
);
|
|
109
|
+
expect(fs.readFileSync(shared, 'utf-8')).toBe('# Shared\n');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('refuses a preset file reached through a symlinked directory', () => {
|
|
113
|
+
const {project, outside} = layout();
|
|
114
|
+
fs.symlinkSync(outside, path.join(project, '.claude'));
|
|
115
|
+
|
|
116
|
+
expect(() =>
|
|
117
|
+
installAgentDocs(project, {agent: 'claude', renderedBlock: BLOCK}),
|
|
118
|
+
).toThrow(PathSafetyError);
|
|
119
|
+
expect(fs.readdirSync(outside)).toEqual([]);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('refuses an existing preset file that links outside', () => {
|
|
123
|
+
const {project, outside} = layout();
|
|
124
|
+
const shared = path.join(outside, 'rules');
|
|
125
|
+
fs.writeFileSync(shared, 'rules\n');
|
|
126
|
+
fs.symlinkSync(shared, path.join(project, '.cursorrules'));
|
|
127
|
+
|
|
128
|
+
expect(() =>
|
|
129
|
+
installAgentDocs(project, {agent: 'cursor', renderedBlock: BLOCK}),
|
|
130
|
+
).toThrow(PathSafetyError);
|
|
131
|
+
expect(fs.readFileSync(shared, 'utf-8')).toBe('rules\n');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('writes nothing when any file of the set escapes', () => {
|
|
135
|
+
const {project, outside} = layout();
|
|
136
|
+
fs.writeFileSync(path.join(project, 'AGENTS.md'), '# Agents\n');
|
|
137
|
+
const shared = path.join(outside, 'CLAUDE.md');
|
|
138
|
+
fs.writeFileSync(shared, '# Shared\n');
|
|
139
|
+
fs.symlinkSync(shared, path.join(project, 'CLAUDE.md'));
|
|
140
|
+
|
|
141
|
+
expect(() => installAgentDocs(project, {renderedBlock: BLOCK})).toThrow(
|
|
142
|
+
PathSafetyError,
|
|
143
|
+
);
|
|
144
|
+
expect(fs.readFileSync(path.join(project, 'AGENTS.md'), 'utf-8')).toBe(
|
|
145
|
+
'# Agents\n',
|
|
146
|
+
);
|
|
147
|
+
expect(fs.readFileSync(shared, 'utf-8')).toBe('# Shared\n');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('refuses to refresh a managed block that lives outside', () => {
|
|
151
|
+
const {project, outside} = layout();
|
|
152
|
+
const shared = path.join(outside, 'CLAUDE.md');
|
|
153
|
+
fs.writeFileSync(shared, `# Shared\n\n${BLOCK.replace('managed', 'old')}\n`);
|
|
154
|
+
const before = fs.readFileSync(shared, 'utf-8');
|
|
155
|
+
fs.symlinkSync(shared, path.join(project, 'CLAUDE.md'));
|
|
156
|
+
|
|
157
|
+
expect(() =>
|
|
158
|
+
installAgentDocs(project, {onlyReplace: true, renderedBlock: BLOCK}),
|
|
159
|
+
).toThrow(PathSafetyError);
|
|
160
|
+
expect(fs.readFileSync(shared, 'utf-8')).toBe(before);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('refuses to strip a duplicate block from a wrapper that links outside', () => {
|
|
164
|
+
const {project, outside} = layout();
|
|
165
|
+
fs.writeFileSync(path.join(project, 'AGENTS.md'), `# Agents\n\n${BLOCK}\n`);
|
|
166
|
+
const shared = path.join(outside, 'CLAUDE.md');
|
|
167
|
+
fs.writeFileSync(shared, `@AGENTS.md\n\n${BLOCK}\n`);
|
|
168
|
+
fs.symlinkSync(shared, path.join(project, 'CLAUDE.md'));
|
|
169
|
+
|
|
170
|
+
expect(() => installAgentDocs(project, {renderedBlock: BLOCK})).toThrow(
|
|
171
|
+
PathSafetyError,
|
|
172
|
+
);
|
|
173
|
+
expect(fs.readFileSync(shared, 'utf-8')).toBe(`@AGENTS.md\n\n${BLOCK}\n`);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('still refreshes in-project blocks beside an unmarked outside link it skips', () => {
|
|
177
|
+
const {project, outside} = layout();
|
|
178
|
+
fs.writeFileSync(
|
|
179
|
+
path.join(project, 'AGENTS.md'),
|
|
180
|
+
`# Agents\n\n${BLOCK.replace('managed', 'old')}\n`,
|
|
181
|
+
);
|
|
182
|
+
const shared = path.join(outside, 'rules');
|
|
183
|
+
fs.writeFileSync(shared, 'rules\n');
|
|
184
|
+
fs.symlinkSync(shared, path.join(project, '.cursorrules'));
|
|
185
|
+
|
|
186
|
+
expect(
|
|
187
|
+
installAgentDocs(project, {onlyReplace: true, renderedBlock: BLOCK}),
|
|
188
|
+
).toEqual(['AGENTS.md']);
|
|
189
|
+
expect(fs.readFileSync(path.join(project, 'AGENTS.md'), 'utf-8')).toContain(
|
|
190
|
+
'managed',
|
|
191
|
+
);
|
|
192
|
+
expect(fs.readFileSync(shared, 'utf-8')).toBe('rules\n');
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('writes through a symlink that stays inside the project', () => {
|
|
196
|
+
const {project} = layout();
|
|
197
|
+
fs.writeFileSync(path.join(project, 'AGENTS.md'), '# Agents\n');
|
|
198
|
+
fs.symlinkSync('AGENTS.md', path.join(project, 'CLAUDE.md'));
|
|
199
|
+
|
|
200
|
+
expect(installAgentDocs(project, {renderedBlock: BLOCK})).toEqual([
|
|
201
|
+
'AGENTS.md',
|
|
202
|
+
'CLAUDE.md',
|
|
203
|
+
]);
|
|
204
|
+
const content = fs.readFileSync(path.join(project, 'AGENTS.md'), 'utf-8');
|
|
205
|
+
expect(content.split('<!-- ASTRYX:START -->')).toHaveLength(2);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
describe('init --features agents with an agent doc linked outside the project', () => {
|
|
210
|
+
it('writes nothing outside, reports path-safety, and exits 1 in both modes', async () => {
|
|
211
|
+
const project = path.join(tmpDir, 'project');
|
|
212
|
+
const outside = path.join(tmpDir, 'outside');
|
|
213
|
+
fs.mkdirSync(project, {recursive: true});
|
|
214
|
+
fs.mkdirSync(outside, {recursive: true});
|
|
215
|
+
fs.writeFileSync(path.join(project, 'package.json'), '{"name":"app"}\n');
|
|
216
|
+
const shared = path.join(outside, 'CLAUDE.md');
|
|
217
|
+
fs.writeFileSync(shared, '# Shared\n');
|
|
218
|
+
fs.symlinkSync(shared, path.join(project, 'CLAUDE.md'));
|
|
219
|
+
|
|
220
|
+
const json = await runCli(['init', '--features', 'agents', '--json'], project);
|
|
221
|
+
expect(json.status).toBe(1);
|
|
222
|
+
const env = JSON.parse(json.stdout);
|
|
223
|
+
expect(env.type).toBe('init.run');
|
|
224
|
+
expect(env.data.docsError).toMatchObject({kind: 'path-safety'});
|
|
225
|
+
|
|
226
|
+
const text = await runCli(['init', '--features', 'agents'], project);
|
|
227
|
+
expect(text.status).toBe(1);
|
|
228
|
+
|
|
229
|
+
expect(fs.readFileSync(shared, 'utf-8')).toBe('# Shared\n');
|
|
230
|
+
}, 30_000);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
describe('removeAgentDocs never changes a file out of the project', () => {
|
|
234
|
+
beforeEach(() => {
|
|
235
|
+
vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
236
|
+
});
|
|
237
|
+
afterEach(() => {
|
|
238
|
+
vi.restoreAllMocks();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('refuses to strip a block from a file that links outside', () => {
|
|
242
|
+
const {project, outside} = layout();
|
|
243
|
+
const shared = path.join(outside, 'CLAUDE.md');
|
|
244
|
+
fs.writeFileSync(shared, `# Shared\n\n${BLOCK}\n`);
|
|
245
|
+
fs.symlinkSync(shared, path.join(project, 'CLAUDE.md'));
|
|
246
|
+
|
|
247
|
+
const err = thrownBy(() => removeAgentDocs(project));
|
|
248
|
+
expect(err).toBeInstanceOf(PathSafetyError);
|
|
249
|
+
expect(err).toMatchObject({code: 'ERR_PATH_TRAVERSAL'});
|
|
250
|
+
expect(fs.readFileSync(shared, 'utf-8')).toBe(`# Shared\n\n${BLOCK}\n`);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it('refuses to delete a file reached through a symlinked directory', () => {
|
|
254
|
+
const {project, outside} = layout();
|
|
255
|
+
const shared = path.join(outside, 'CLAUDE.md');
|
|
256
|
+
const content = `# CLAUDE\n\nProject-specific guidance for AI coding agents.\n\n${BLOCK}\n`;
|
|
257
|
+
fs.writeFileSync(shared, content);
|
|
258
|
+
fs.symlinkSync(outside, path.join(project, '.claude'));
|
|
259
|
+
|
|
260
|
+
expect(thrownBy(() => removeAgentDocs(project))).toMatchObject({
|
|
261
|
+
code: 'ERR_PATH_TRAVERSAL',
|
|
262
|
+
});
|
|
263
|
+
expect(fs.readFileSync(shared, 'utf-8')).toBe(content);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it('changes nothing when any file of the set escapes', () => {
|
|
267
|
+
const {project, outside} = layout();
|
|
268
|
+
const agents = `# Agents\n\nkeep\n\n${BLOCK}\n`;
|
|
269
|
+
fs.writeFileSync(path.join(project, 'AGENTS.md'), agents);
|
|
270
|
+
const shared = path.join(outside, 'CLAUDE.md');
|
|
271
|
+
fs.writeFileSync(shared, `# Shared\n\n${BLOCK}\n`);
|
|
272
|
+
fs.symlinkSync(shared, path.join(project, 'CLAUDE.md'));
|
|
273
|
+
|
|
274
|
+
expect(thrownBy(() => removeAgentDocs(project))).toBeInstanceOf(PathSafetyError);
|
|
275
|
+
expect(fs.readFileSync(path.join(project, 'AGENTS.md'), 'utf-8')).toBe(agents);
|
|
276
|
+
expect(fs.readFileSync(shared, 'utf-8')).toBe(`# Shared\n\n${BLOCK}\n`);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('still strips in-project blocks beside an unmarked outside link it skips', () => {
|
|
280
|
+
const {project, outside} = layout();
|
|
281
|
+
fs.writeFileSync(path.join(project, 'AGENTS.md'), `# Agents\n\nkeep\n\n${BLOCK}\n`);
|
|
282
|
+
const shared = path.join(outside, 'rules');
|
|
283
|
+
fs.writeFileSync(shared, 'rules\n');
|
|
284
|
+
fs.symlinkSync(shared, path.join(project, '.cursorrules'));
|
|
285
|
+
|
|
286
|
+
removeAgentDocs(project);
|
|
287
|
+
expect(fs.readFileSync(path.join(project, 'AGENTS.md'), 'utf-8')).toBe(
|
|
288
|
+
'# Agents\n\nkeep\n',
|
|
289
|
+
);
|
|
290
|
+
expect(fs.readFileSync(shared, 'utf-8')).toBe('rules\n');
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it('strips through a symlink that stays inside the project', () => {
|
|
294
|
+
const {project} = layout();
|
|
295
|
+
fs.writeFileSync(path.join(project, 'AGENTS.md'), `# Agents\n\nkeep\n\n${BLOCK}\n`);
|
|
296
|
+
fs.symlinkSync('AGENTS.md', path.join(project, 'CLAUDE.md'));
|
|
297
|
+
|
|
298
|
+
removeAgentDocs(project);
|
|
299
|
+
expect(fs.readFileSync(path.join(project, 'AGENTS.md'), 'utf-8')).toBe(
|
|
300
|
+
'# Agents\n\nkeep\n',
|
|
301
|
+
);
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
describe('init --remove-agents with an agent doc linked outside the project', () => {
|
|
306
|
+
it('changes nothing outside, fails with ERR_PATH_TRAVERSAL, and exits 1 in both modes', async () => {
|
|
307
|
+
const {project, outside} = layout();
|
|
308
|
+
fs.writeFileSync(path.join(project, 'package.json'), '{"name":"app"}\n');
|
|
309
|
+
const shared = path.join(outside, 'CLAUDE.md');
|
|
310
|
+
const content = `# Shared\n\n${BLOCK}\n`;
|
|
311
|
+
fs.writeFileSync(shared, content);
|
|
312
|
+
fs.symlinkSync(shared, path.join(project, 'CLAUDE.md'));
|
|
313
|
+
|
|
314
|
+
const json = await runCli(['init', '--remove-agents', '--json'], project);
|
|
315
|
+
expect(json.status).toBe(1);
|
|
316
|
+
const env = JSON.parse(json.stdout);
|
|
317
|
+
expect(env).toMatchObject({apiVersion: 1, code: 'ERR_PATH_TRAVERSAL'});
|
|
318
|
+
expect(env.error).toMatch(/"CLAUDE\.md": resolves outside the project root/);
|
|
319
|
+
expect(env).not.toHaveProperty('data');
|
|
320
|
+
|
|
321
|
+
const text = await runCli(['init', '--remove-agents'], project);
|
|
322
|
+
expect(text.status).toBe(1);
|
|
323
|
+
expect(text.stderr).toMatch(/^Error: .*"CLAUDE\.md": resolves outside the project root/m);
|
|
324
|
+
expect(text.stdout).not.toMatch(/removed/i);
|
|
325
|
+
|
|
326
|
+
expect(fs.readFileSync(shared, 'utf-8')).toBe(content);
|
|
327
|
+
}, 30_000);
|
|
328
|
+
});
|
|
@@ -55,6 +55,15 @@ describe('generateCompressedIndex', () => {
|
|
|
55
55
|
expect(frameRule).not.toMatch(/https?:/);
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
+
it('starts every page from a template before any component', () => {
|
|
59
|
+
const lines = generateCompressedIndex('1.0.0').split('\n');
|
|
60
|
+
const workflow = lines.findIndex(l => l.startsWith('WORKFLOW'));
|
|
61
|
+
expect(lines[workflow]).toMatch(/start every page from a template/);
|
|
62
|
+
expect(lines[workflow + 1]).toMatch(/^1\. `astryx build /);
|
|
63
|
+
expect(lines[workflow + 2]).toMatch(/^2\. `astryx template <name> <path>`/);
|
|
64
|
+
expect(lines.join('\n')).not.toMatch(/reference code/);
|
|
65
|
+
});
|
|
66
|
+
|
|
58
67
|
it('includes the post-generation self-check rule', () => {
|
|
59
68
|
const result = generateCompressedIndex('1.0.0');
|
|
60
69
|
expect(result).toContain('SELF-CHECK before you finish');
|
|
@@ -134,7 +143,6 @@ describe('generateCompressedIndex', () => {
|
|
|
134
143
|
const line = topicLine(generateCompressedIndex('1.0.0'));
|
|
135
144
|
for (const topic of [
|
|
136
145
|
'getting-started',
|
|
137
|
-
'cli-integrations',
|
|
138
146
|
'browser-support',
|
|
139
147
|
'styling-libraries',
|
|
140
148
|
'working-with-ai',
|
|
@@ -143,6 +151,16 @@ describe('generateCompressedIndex', () => {
|
|
|
143
151
|
}
|
|
144
152
|
});
|
|
145
153
|
|
|
154
|
+
it('points to the CLI docs tree on a line of its own', () => {
|
|
155
|
+
// The integration guide lives in the docs tree now (cli/integrations), so
|
|
156
|
+
// the topic line no longer names it; the tree's entry point does.
|
|
157
|
+
const block = generateCompressedIndex('1.0.0');
|
|
158
|
+
expect(block).toContain(
|
|
159
|
+
' docs cli commands, API reference, integration authoring (one level at a time)',
|
|
160
|
+
);
|
|
161
|
+
expect(topicLine(block)).not.toContain('cli-integrations');
|
|
162
|
+
});
|
|
163
|
+
|
|
146
164
|
it('lists the topics it is given, so an integration’s reach the agent', () => {
|
|
147
165
|
const line = topicLine(
|
|
148
166
|
generateCompressedIndex('1.0.0', {topics: ['tokens', 'deploying']}),
|
|
@@ -63,11 +63,18 @@ function config(integrations, ownHandler = false) {
|
|
|
63
63
|
);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
/**
|
|
67
|
-
|
|
66
|
+
/**
|
|
67
|
+
* @param {Record<string, unknown>} [astryx]
|
|
68
|
+
* @param {Record<string, string>} [dependencies]
|
|
69
|
+
*/
|
|
70
|
+
function packageJson(astryx, dependencies) {
|
|
68
71
|
fs.writeFileSync(
|
|
69
72
|
path.join(tmpDir, 'package.json'),
|
|
70
|
-
JSON.stringify({
|
|
73
|
+
JSON.stringify({
|
|
74
|
+
name: 'consumer',
|
|
75
|
+
...(dependencies ? {dependencies} : {}),
|
|
76
|
+
...(astryx ? {astryx} : {}),
|
|
77
|
+
}),
|
|
71
78
|
);
|
|
72
79
|
}
|
|
73
80
|
|
|
@@ -172,6 +179,24 @@ describe('an app can refuse an inherited handler', () => {
|
|
|
172
179
|
|
|
173
180
|
expect(fired()).toEqual(['reporting-integration']);
|
|
174
181
|
});
|
|
182
|
+
|
|
183
|
+
it('keeps an autolinked handler in a project with no astryx.config', async () => {
|
|
184
|
+
packageJson(undefined, {'reporting-integration': '1.0.0'});
|
|
185
|
+
integration('reporting-integration');
|
|
186
|
+
|
|
187
|
+
await runOneCommand();
|
|
188
|
+
|
|
189
|
+
expect(fired()).toEqual(['reporting-integration']);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('drops an autolinked handler under astryx.inheritDebug false with no astryx.config', async () => {
|
|
193
|
+
packageJson({inheritDebug: false}, {'reporting-integration': '1.0.0'});
|
|
194
|
+
integration('reporting-integration');
|
|
195
|
+
|
|
196
|
+
await runOneCommand();
|
|
197
|
+
|
|
198
|
+
expect(fired()).toEqual([]);
|
|
199
|
+
});
|
|
175
200
|
});
|
|
176
201
|
|
|
177
202
|
describe('loading the project twice delivers once', () => {
|
|
@@ -15,6 +15,7 @@ function installThemeIntegration(packageName, slug) {
|
|
|
15
15
|
...packageName.split('/'),
|
|
16
16
|
);
|
|
17
17
|
const themeDir = path.join(packageDir, 'themes', slug);
|
|
18
|
+
const stem = `${slug.replace(/-([a-z0-9])/gu, (_, character) => character.toUpperCase())}Theme`;
|
|
18
19
|
fs.mkdirSync(themeDir, {recursive: true});
|
|
19
20
|
fs.writeFileSync(
|
|
20
21
|
path.join(packageDir, 'package.json'),
|
|
@@ -22,28 +23,19 @@ function installThemeIntegration(packageName, slug) {
|
|
|
22
23
|
);
|
|
23
24
|
fs.writeFileSync(
|
|
24
25
|
path.join(packageDir, 'astryx.integration.mjs'),
|
|
25
|
-
`export default {themes: './themes'}
|
|
26
|
+
`export default {themes: './themes'};
|
|
27
|
+
`,
|
|
26
28
|
);
|
|
27
29
|
fs.writeFileSync(
|
|
28
|
-
path.join(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
{
|
|
33
|
-
slug,
|
|
34
|
-
displayName: 'Ocean',
|
|
35
|
-
description: 'Blue and calm.',
|
|
36
|
-
maintained: true,
|
|
37
|
-
entry: 'oceanTheme.ts',
|
|
38
|
-
exportName: 'oceanTheme',
|
|
39
|
-
files: ['oceanTheme.ts'],
|
|
40
|
-
},
|
|
41
|
-
],
|
|
42
|
-
}),
|
|
30
|
+
path.join(themeDir, `${stem}.doc.mjs`),
|
|
31
|
+
`/** @type {import('@astryxdesign/cli/authoring').ThemeDoc} */
|
|
32
|
+
export default {type: 'theme', name: '${slug}', displayName: 'Ocean', description: 'Blue and calm.', maintained: true};
|
|
33
|
+
`,
|
|
43
34
|
);
|
|
44
35
|
fs.writeFileSync(
|
|
45
|
-
path.join(themeDir,
|
|
46
|
-
`export const
|
|
36
|
+
path.join(themeDir, `${stem}.ts`),
|
|
37
|
+
`export const ${stem} = {};
|
|
38
|
+
`,
|
|
47
39
|
);
|
|
48
40
|
}
|
|
49
41
|
|
|
@@ -99,7 +91,7 @@ describe('Project themes', () => {
|
|
|
99
91
|
]);
|
|
100
92
|
});
|
|
101
93
|
|
|
102
|
-
it('records an invalid integration theme
|
|
94
|
+
it('records an invalid integration theme descriptor as an issue', async () => {
|
|
103
95
|
installThemeIntegration('@acme/themes', 'ocean');
|
|
104
96
|
fs.rmSync(
|
|
105
97
|
path.join(
|