@astryxdesign/cli 0.7.2-canary.fdd384f → 0.7.2
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 +119 -0
- package/README.md +169 -149
- package/api/build/_adapter.d.mts +8 -0
- package/api/build/_adapter.mjs +12 -1
- package/api/build/build.doc.mjs +4 -0
- package/api/build/kit/kit.mjs +3 -11
- package/api/component/_adapter.d.mts +31 -0
- package/api/component/_adapter.mjs +119 -11
- package/api/component/component.doc.mjs +6 -1
- package/api/component/component.mjs +60 -10
- package/api/component/doc-links.test.mjs +386 -0
- package/api/discover/_adapter.d.mts +132 -12
- package/api/discover/_adapter.mjs +488 -27
- package/api/discover/_adapter.test.mjs +599 -17
- package/api/discover/_catalog-view.d.mts +16 -5
- package/api/discover/_catalog-view.mjs +32 -8
- package/api/discover/detail/doc/doc.mjs +9 -1
- package/api/discover/discover.d.mts +11 -0
- package/api/discover/discover.doc.mjs +9 -7
- package/api/discover/discover.mjs +121 -19
- package/api/discover/discover.type.d.mts +20 -7
- package/api/discover/discover.type.mjs +17 -7
- package/api/discover/list/list.d.mts +4 -3
- package/api/discover/list/list.mjs +17 -10
- package/api/docs/_adapter.d.mts +63 -0
- package/api/docs/_adapter.mjs +312 -18
- package/api/docs/docs.doc.mjs +2 -1
- package/api/docs/docs.mjs +2 -1
- package/api/docs/docs.test.mjs +5 -2
- package/api/docs/integration-tree.test.mjs +22 -0
- package/api/docs/list/list.mjs +12 -2
- package/api/docs/reference-blocks.test.mjs +1 -3
- package/api/doctor/_adapter.d.mts +108 -0
- package/api/doctor/_adapter.mjs +223 -4
- package/api/doctor/doctor.d.mts +199 -0
- package/api/doctor/doctor.doc.mjs +3 -2
- package/api/doctor/doctor.mjs +530 -34
- package/api/doctor/doctor.test.mjs +180 -14
- package/api/doctor/release-checks.test.mjs +156 -0
- package/api/doctor/theme-checks.mjs +16 -3
- package/api/doctor/theme-checks.test.mjs +223 -7
- package/api/error.d.mts +10 -0
- package/api/error.mjs +25 -0
- package/api/gap-report/gap-report.d.mts +3 -0
- package/api/gap-report/gap-report.doc.mjs +11 -3
- package/api/gap-report/gap-report.mjs +152 -48
- package/api/gap-report/gap-report.test.mjs +233 -0
- package/api/gap-report/gap-report.type.d.mts +41 -0
- package/api/gap-report/gap-report.type.mjs +18 -0
- package/api/hook/_adapter.mjs +3 -11
- package/api/hook/hook.doc.mjs +4 -0
- package/api/hook/list/list.d.mts +1 -1
- package/api/init/_adapter.d.mts +22 -0
- package/api/init/_adapter.mjs +59 -0
- package/api/init/init.d.mts +7 -5
- package/api/init/init.doc.mjs +28 -7
- package/api/init/init.mjs +28 -4
- package/api/init/init.type.d.mts +48 -3
- package/api/init/init.type.mjs +37 -3
- package/api/init/run/run.d.mts +1 -1
- package/api/init/run/run.mjs +15 -4
- package/api/init/user/user.d.mts +14 -0
- package/api/init/user/user.mjs +87 -0
- package/api/init/user/user.test.mjs +232 -0
- package/api/integration/_adapter.d.mts +33 -0
- package/api/integration/_adapter.mjs +58 -0
- package/api/integration/authoring-checks.mjs +100 -5
- package/api/integration/authoring-checks.test.mjs +769 -0
- package/api/integration/authoring-checks.type.d.mts +134 -0
- package/api/integration/authoring-checks.type.mjs +60 -1
- package/api/integration/integrationCheck.doc.mjs +1 -1
- package/api/integration/integrationComponentConflicts.doc.mjs +11 -3
- package/api/integration/integrationDocConflicts.doc.mjs +22 -5
- package/api/integration/pack-check.mjs +303 -13
- package/api/integration/pack-check.test.mjs +371 -10
- package/api/integration/validate-integration-fixes.test.mjs +67 -0
- package/api/integration/validate-integration.d.mts +8 -0
- package/api/integration/validate-integration.mjs +55 -9
- package/api/integration/validate-integration.test.mjs +77 -8
- package/api/integration/validate-integration.type.d.mts +8 -0
- package/api/integration/validate-integration.type.mjs +3 -1
- package/api/integration/validate-unread-theme-folders.test.mjs +3 -2
- package/api/integration/validateIntegration.doc.mjs +4 -2
- package/api/search/_adapter.d.mts +11 -0
- package/api/search/_adapter.mjs +25 -0
- package/api/search/search.d.mts +73 -13
- package/api/search/search.doc.mjs +8 -3
- package/api/search/search.domain-priority.test.mjs +108 -18
- package/api/search/search.mjs +541 -52
- package/api/search/search.test.mjs +143 -1
- package/api/search/search.type.d.mts +14 -1
- package/api/search/search.type.mjs +6 -1
- package/api/swizzle/_adapter.mjs +2 -2
- package/api/swizzle/copy/copy.mjs +1 -1
- package/api/template/template-integration.test.mjs +1 -1
- package/api/theme/_adapter.d.mts +16 -0
- package/api/theme/_adapter.mjs +32 -5
- package/api/theme/build/build.d.mts +2 -1
- package/api/theme/build/build.mjs +70 -14
- package/api/theme/build/build.packed-old-core.test.mjs +20 -3
- package/api/theme/build/font-warning.mjs +5 -3
- package/api/theme/build/font-warning.test.mjs +2 -1
- package/api/theme/remove/remove.test.mjs +2 -2
- package/api/theme/targets/targets.mjs +3 -10
- package/api/theme/themeTargets.doc.mjs +4 -0
- package/api/theme/use/use.test.mjs +1 -1
- package/api/upgrade/_adapter.d.mts +40 -2
- package/api/upgrade/_adapter.mjs +118 -5
- package/api/upgrade/run/cli-behind-core.test.mjs +438 -0
- package/api/upgrade/run/run.mjs +35 -2
- package/api/upgrade/status/status.d.mts +21 -5
- package/api/upgrade/status/status.mjs +45 -8
- package/api/upgrade/upgrade.doc.mjs +6 -3
- package/api/upgrade/upgrade.mjs +5 -1
- package/api/upgrade/upgrade.type.d.mts +23 -0
- package/api/upgrade/upgrade.type.mjs +16 -1
- package/assets/codemods/__tests__/registry.test.mjs +1 -0
- package/assets/codemods/registry.mjs +1 -0
- package/assets/codemods/runner.mjs +7 -1
- package/assets/codemods/transforms/next/index.mjs +1 -11
- package/assets/codemods/transforms/v0.7.2/index.mjs +20 -0
- package/assets/discover/official-packages.json +367 -0
- package/assets/docs/author-a-theme.doc.mjs +2 -2
- package/assets/docs/browser-support.doc.mjs +1 -1
- package/assets/docs/getting-started.doc.mjs +23 -3
- package/assets/docs/styling-overview.doc.mjs +1 -1
- package/assets/docs/theme.doc.mjs +1 -1
- package/assets/docs/tree/add-a-component.doc.mjs +12 -2
- package/assets/docs/tree/add-a-theme.doc.mjs +13 -3
- package/assets/docs/tree/add-a-topic.doc.mjs +54 -9
- package/assets/docs/tree/agent-guidance.doc.mjs +19 -5
- package/assets/docs/tree/block-template.doc.mjs +6 -18
- package/assets/docs/tree/build-the-template.doc.mjs +1 -1
- package/assets/docs/tree/building-blocks.doc.mjs +4 -0
- package/assets/docs/tree/check-the-props.doc.mjs +8 -3
- package/assets/docs/tree/check-your-docs.doc.mjs +30 -13
- package/assets/docs/tree/checks.doc.mjs +17 -17
- package/assets/docs/tree/ci-and-containers.doc.mjs +88 -0
- package/assets/docs/tree/cli-command.doc.mjs +142 -0
- package/assets/docs/tree/cli.doc.mjs +6 -0
- package/assets/docs/tree/codemods.doc.mjs +17 -7
- package/assets/docs/tree/commands.doc.mjs +7 -1
- package/assets/docs/tree/component-family.doc.mjs +3 -5
- package/assets/docs/tree/component-imports.doc.mjs +13 -3
- package/assets/docs/tree/components.doc.mjs +7 -1
- package/assets/docs/tree/computer-agent-guide.doc.mjs +160 -0
- package/assets/docs/tree/computer-integrations.doc.mjs +93 -0
- package/assets/docs/tree/configuration.doc.mjs +7 -3
- package/assets/docs/tree/debug-and-gap-reports.doc.mjs +41 -22
- package/assets/docs/tree/define-the-theme.doc.mjs +6 -5
- package/assets/docs/tree/describe-the-component.doc.mjs +2 -2
- package/assets/docs/tree/docs.doc.mjs +9 -3
- package/assets/docs/tree/document-the-template.doc.mjs +1 -1
- package/assets/docs/tree/document-the-theme.doc.mjs +3 -3
- package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
- package/assets/docs/tree/extend-or-replace.doc.mjs +19 -9
- package/assets/docs/tree/fonts-and-assets.doc.mjs +2 -2
- package/assets/docs/tree/generate-a-palette.doc.mjs +7 -5
- package/assets/docs/tree/global-integrations.doc.mjs +124 -0
- package/assets/docs/tree/global.doc.mjs +131 -0
- package/assets/docs/tree/grade-template-with-agent.doc.mjs +5 -5
- package/assets/docs/tree/install-once.doc.mjs +105 -0
- package/assets/docs/tree/integrations.doc.mjs +13 -1
- package/assets/docs/tree/layout-spacing.doc.mjs +2 -3
- package/assets/docs/tree/layout.doc.mjs +6 -6
- package/assets/docs/tree/links.doc.mjs +6 -5
- package/assets/docs/tree/migration-setup.doc.mjs +3 -2
- package/assets/docs/tree/migration-verification.doc.mjs +0 -1
- package/assets/docs/tree/migration.doc.mjs +0 -1
- package/assets/docs/tree/monorepos.doc.mjs +84 -0
- package/assets/docs/tree/package-and-test.doc.mjs +1 -1
- package/assets/docs/tree/page-template.doc.mjs +3 -7
- package/assets/docs/tree/problems.doc.mjs +205 -0
- package/assets/docs/tree/project-global-or-both.doc.mjs +131 -0
- package/assets/docs/tree/publishing.doc.mjs +6 -6
- package/assets/docs/tree/quick-start.doc.mjs +52 -26
- package/assets/docs/tree/reference.doc.mjs +192 -0
- package/assets/docs/tree/replace-a-core-component.doc.mjs +15 -7
- package/assets/docs/tree/replace-a-core-template.doc.mjs +9 -11
- package/assets/docs/tree/scaffold.doc.mjs +1 -1
- package/assets/docs/tree/sections-and-placement.doc.mjs +9 -11
- package/assets/docs/tree/see-it-in-an-app.doc.mjs +17 -5
- package/assets/docs/tree/short-and-findable.doc.mjs +9 -8
- package/assets/docs/tree/single-component.doc.mjs +14 -6
- package/assets/docs/tree/start-a-template.doc.mjs +18 -8
- package/assets/docs/tree/subcomponent.doc.mjs +6 -6
- package/assets/docs/tree/template-assets.doc.mjs +2 -2
- package/assets/docs/tree/template-doc-overview.doc.mjs +6 -17
- package/assets/docs/tree/template-fonts.doc.mjs +1 -1
- package/assets/docs/tree/template-icons.doc.mjs +1 -1
- package/assets/docs/tree/template-images-media.doc.mjs +1 -1
- package/assets/docs/tree/template-styles.doc.mjs +2 -2
- package/assets/docs/tree/templates.doc.mjs +7 -1
- package/assets/docs/tree/test-in-an-app.doc.mjs +7 -7
- package/assets/docs/tree/test-template-in-app.doc.mjs +5 -5
- package/assets/docs/tree/themes.doc.mjs +4 -0
- package/assets/docs/tree/tokens-and-setup.doc.mjs +19 -15
- package/assets/docs/tree/troubleshooting.doc.mjs +22 -14
- package/assets/docs/tree/uninstall.doc.mjs +109 -0
- package/assets/docs/tree/updates.doc.mjs +92 -0
- package/assets/docs/tree/upgrading.doc.mjs +6 -6
- package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +14 -2
- package/assets/docs/tree/verify-packed-template.doc.mjs +3 -3
- package/assets/docs/tree/versioning.doc.mjs +9 -9
- package/assets/docs/tree/who-answers.doc.mjs +119 -0
- package/assets/docs/tree/write-the-template-file.doc.mjs +5 -5
- package/assets/docs/working-with-ai.doc.mjs +23 -9
- package/authoring/codemod/codemod.doc.mjs +7 -3
- package/authoring/config/config.doc.mjs +9 -6
- package/authoring/config/type.ts +4 -2
- package/authoring/debug/parse.d.mts +5 -5
- package/authoring/discover/discover.doc.mjs +7 -1
- package/authoring/doctypes/_schema.d.mts +8 -3
- package/authoring/doctypes/_schema.mjs +1 -0
- package/authoring/doctypes/base/graph-fields.doc.mjs +6 -4
- package/authoring/doctypes/command/command.doc.mjs +20 -12
- package/authoring/doctypes/command/type.ts +14 -0
- package/authoring/doctypes/component/component.doc.mjs +29 -26
- package/authoring/doctypes/component/type.ts +15 -5
- package/authoring/doctypes/enum/enum.doc.mjs +7 -4
- package/authoring/doctypes/function/function.doc.mjs +9 -8
- package/authoring/doctypes/hook/hook.doc.mjs +5 -4
- package/authoring/doctypes/hook/type.ts +4 -0
- package/authoring/doctypes/namespace/namespace.doc.mjs +7 -6
- package/authoring/doctypes/reference/reference.doc.mjs +12 -11
- package/authoring/doctypes/schema/schema.doc.mjs +9 -9
- package/authoring/doctypes/template/template.doc.mjs +2 -2
- package/authoring/doctypes/theme/theme.doc.mjs +2 -2
- package/authoring/gap-report/gap-report.doc.mjs +2 -2
- package/authoring/identity/identity.doc.mjs +3 -3
- package/authoring/index.d.ts +1 -0
- package/authoring/integration/integration.doc.mjs +22 -5
- package/authoring/integration/parse.test.mjs +11 -0
- package/authoring/integration/schema.d.mts +14 -3
- package/authoring/integration/schema.mjs +33 -2
- package/authoring/integration/type.ts +8 -0
- package/clients/cli/bin/astryx.mjs +20 -3
- package/clients/cli/cli-command.test.mjs +166 -0
- package/clients/cli/commands/blog.doc.mjs +1 -0
- package/clients/cli/commands/build-theme.batch-report.test.mjs +14 -2
- package/clients/cli/commands/build-theme.font-warning.test.mjs +3 -3
- package/clients/cli/commands/build-theme.mjs +25 -12
- package/clients/cli/commands/build.doc.mjs +1 -0
- package/clients/cli/commands/build.exit-codes-doc.test.mjs +4 -0
- package/clients/cli/commands/cli-postinstall.test.mjs +49 -1
- package/clients/cli/commands/component.doc.mjs +1 -0
- package/clients/cli/commands/discover.broken-integration.test.mjs +11 -7
- package/clients/cli/commands/discover.doc.mjs +9 -1
- package/clients/cli/commands/discover.mjs +144 -93
- package/clients/cli/commands/discover.no-source.test.mjs +448 -33
- package/clients/cli/commands/discover.sources.test.mjs +20 -1
- package/clients/cli/commands/docs.doc.mjs +1 -0
- package/clients/cli/commands/docs.mjs +49 -19
- package/clients/cli/commands/docs.test.mjs +2 -2
- package/clients/cli/commands/doctor-integration-components.doc.mjs +7 -3
- package/clients/cli/commands/doctor-integration-docs.doc.mjs +20 -5
- package/clients/cli/commands/doctor-integration-templates.doc.mjs +1 -0
- package/clients/cli/commands/doctor-integration-validate.doc.mjs +13 -2
- package/clients/cli/commands/doctor-integration.test.mjs +52 -4
- package/clients/cli/commands/doctor.doc.mjs +12 -2
- package/clients/cli/commands/doctor.mjs +102 -7
- package/clients/cli/commands/doctor.test.mjs +10 -4
- package/clients/cli/commands/gap-report.doc.mjs +15 -2
- package/clients/cli/commands/gap-report.mjs +24 -2
- package/clients/cli/commands/gap-report.test.mjs +79 -0
- package/clients/cli/commands/hook.doc.mjs +1 -0
- package/clients/cli/commands/init.behavior.test.mjs +5 -0
- package/clients/cli/commands/init.doc.mjs +29 -3
- package/clients/cli/commands/integration-add.doc.mjs +7 -0
- package/clients/cli/commands/integration-authoring.test.mjs +49 -3
- package/clients/cli/commands/integration-check.doc.mjs +10 -2
- package/clients/cli/commands/integration-check.test.mjs +175 -1
- package/clients/cli/commands/integration-pack.doc.mjs +8 -1
- package/clients/cli/commands/integration-verify.doc.mjs +8 -1
- package/clients/cli/commands/integration.mjs +15 -9
- package/clients/cli/commands/json-contract.test.mjs +11 -2
- package/clients/cli/commands/manifest.doc.mjs +1 -0
- package/clients/cli/commands/outside-project.test.mjs +774 -0
- package/clients/cli/commands/search.doc.mjs +1 -0
- package/clients/cli/commands/search.mjs +16 -11
- package/clients/cli/commands/search.test.mjs +429 -296
- package/clients/cli/commands/setup-nudge.test.mjs +102 -2
- package/clients/cli/commands/swizzle.doc.mjs +7 -0
- package/clients/cli/commands/swizzle.mjs +5 -3
- package/clients/cli/commands/swizzle.routing.test.mjs +19 -2
- package/clients/cli/commands/template.doc.mjs +1 -0
- package/clients/cli/commands/theme-add-lifecycle.test.mjs +3 -3
- package/clients/cli/commands/theme-add.doc.mjs +8 -1
- package/clients/cli/commands/theme-build.doc.mjs +1 -0
- package/clients/cli/commands/theme-eject.doc.mjs +1 -0
- package/clients/cli/commands/theme-list.behavior.test.mjs +6 -0
- package/clients/cli/commands/theme-list.doc.mjs +1 -0
- package/clients/cli/commands/theme-palette-generate.doc.mjs +1 -0
- package/clients/cli/commands/theme-remove.doc.mjs +7 -0
- package/clients/cli/commands/theme-targets.doc.mjs +1 -0
- package/clients/cli/commands/theme-template.doc.mjs +1 -0
- package/clients/cli/commands/theme-use.doc.mjs +7 -0
- package/clients/cli/commands/upgrade.config-ordering.test.mjs +2 -1
- package/clients/cli/commands/upgrade.doc.mjs +22 -1
- package/clients/cli/commands/upgrade.file-protection.test.mjs +3 -2
- package/clients/cli/commands/upgrade.hook-output.test.mjs +2 -1
- package/clients/cli/commands/upgrade.older-cli.test.mjs +160 -0
- package/clients/cli/index.mjs +111 -16
- package/clients/cli/lib/cli-error.mjs +4 -1
- package/clients/cli/lib/component-format.test.mjs +1 -1
- package/clients/cli/lib/define-command.mjs +2 -2
- package/clients/cli/lib/json-shim.mjs +3 -1
- package/clients/cli/lib/manifest.d.ts +9 -0
- package/clients/cli/lib/manifest.mjs +17 -1
- package/clients/cli/lib/manifest.test.mjs +25 -0
- package/foundation/agent-docs/agent-doc-state.d.mts +35 -6
- package/foundation/agent-docs/agent-doc-state.mjs +66 -6
- package/foundation/agent-docs/agent-docs.d.mts +4 -3
- package/foundation/agent-docs/agent-docs.mjs +11 -9
- package/foundation/agent-docs/computer-agent-text.d.mts +133 -0
- package/foundation/agent-docs/computer-agent-text.mjs +623 -0
- package/foundation/agent-docs/computer-agent-text.test.mjs +602 -0
- package/foundation/config/project.d.mts +35 -3
- package/foundation/config/project.mjs +145 -8
- package/foundation/config/project.test.mjs +66 -0
- package/foundation/config/theme-state.mjs +5 -4
- package/foundation/discovery/authoring-self-docs.mjs +1 -1
- package/foundation/discovery/cli-self-docs.mjs +20 -3
- package/foundation/discovery/cli-self-docs.test.mjs +3 -2
- package/foundation/discovery/component-replacement.mjs +2 -1
- package/foundation/discovery/copied-passages.d.mts +216 -0
- package/foundation/discovery/copied-passages.mjs +720 -0
- package/foundation/discovery/copied-passages.test.mjs +124 -0
- package/foundation/discovery/doc-consistency.d.mts +34 -0
- package/foundation/discovery/doc-consistency.mjs +513 -0
- package/foundation/discovery/doc-consistency.test.mjs +347 -0
- package/foundation/discovery/doc-fluff.d.mts +112 -0
- package/foundation/discovery/doc-fluff.mjs +328 -0
- package/foundation/discovery/doc-fluff.test.mjs +142 -0
- package/foundation/discovery/doc-types.d.mts +1 -1
- package/foundation/discovery/doc-types.mjs +15 -8
- package/foundation/discovery/doc-types.test.mjs +94 -2
- package/foundation/discovery/docs-discovery.d.mts +7 -0
- package/foundation/discovery/docs-discovery.mjs +26 -2
- package/foundation/discovery/project-typescript.d.mts +11 -2
- package/foundation/discovery/project-typescript.mjs +32 -4
- package/foundation/discovery/prop-drift.d.mts +26 -7
- package/foundation/discovery/prop-drift.mjs +173 -8
- package/foundation/discovery/prop-drift.test.mjs +120 -2
- package/foundation/discovery/runner-allowlist.d.mts +40 -0
- package/foundation/discovery/runner-allowlist.mjs +53 -0
- package/foundation/discovery/stray-pointers.d.mts +52 -0
- package/foundation/discovery/stray-pointers.mjs +293 -0
- package/foundation/discovery/stray-pointers.test.mjs +86 -0
- package/foundation/discovery/template-needs.mjs +5 -2
- package/foundation/discovery/theme-imports.mjs +8 -4
- package/foundation/discovery/theme-imports.test.mjs +1 -1
- package/foundation/discovery/type-text.mjs +1 -1
- package/foundation/discovery/type-text.test.mjs +1 -1
- package/foundation/doc-compiler/doc-loads.test.mjs +42 -2
- package/foundation/doc-compiler/inputs.mjs +4 -1
- package/foundation/doc-compiler/links.d.mts +32 -0
- package/foundation/doc-compiler/links.mjs +163 -26
- package/foundation/doc-compiler/links.test.mjs +97 -4
- package/foundation/doc-compiler/read.d.mts +1 -1
- package/foundation/doc-compiler/tree.mjs +30 -1
- package/foundation/doc-compiler/tree.test.mjs +8 -1
- package/foundation/env/cli-command.d.mts +83 -0
- package/foundation/env/cli-command.mjs +152 -0
- package/foundation/env/cli-command.test.mjs +129 -0
- package/foundation/env/node-version.test.mjs +15 -3
- package/foundation/env/package-manager.d.mts +93 -9
- package/foundation/env/package-manager.global.test.mjs +66 -0
- package/foundation/env/package-manager.mjs +184 -13
- package/foundation/env/package-manager.test.mjs +341 -15
- package/foundation/env/project-scope.d.mts +9 -0
- package/foundation/env/project-scope.mjs +33 -0
- package/foundation/env/search-path.d.mts +42 -0
- package/foundation/env/search-path.mjs +205 -0
- package/foundation/env/search-path.test.mjs +122 -0
- package/foundation/env/user-dirs.d.mts +39 -0
- package/foundation/env/user-dirs.mjs +93 -0
- package/foundation/env/user-dirs.test.mjs +72 -0
- package/foundation/env/user-settings.d.mts +46 -0
- package/foundation/env/user-settings.mjs +106 -0
- package/foundation/env/user-settings.test.mjs +64 -0
- package/foundation/fs/file-protection.mjs +15 -1
- package/foundation/fs/module-loader.d.mts +2 -1
- package/foundation/fs/module-loader.mjs +60 -4
- package/foundation/fs/module-loader.stdout.test.mjs +3 -2
- package/foundation/fs/module-loader.test.mjs +194 -0
- package/foundation/fs/path-compare.d.mts +33 -0
- package/foundation/fs/path-compare.mjs +73 -0
- package/foundation/fs/paths.d.mts +57 -1
- package/foundation/fs/paths.mjs +131 -3
- package/foundation/fs/paths.test.mjs +10 -1
- package/foundation/integrations/computer-integrations.d.mts +78 -0
- package/foundation/integrations/computer-integrations.mjs +316 -0
- package/foundation/integrations/computer-integrations.test.mjs +292 -0
- package/foundation/integrations/contribution-inventory.d.mts +11 -0
- package/foundation/integrations/contribution-inventory.mjs +50 -2
- package/foundation/integrations/integration-warnings.mjs +3 -2
- package/foundation/integrations/integration-warnings.test.mjs +8 -9
- package/foundation/integrations/integrations.d.mts +25 -1
- package/foundation/integrations/integrations.mjs +46 -3
- package/foundation/integrations/issue.ts +6 -0
- package/foundation/integrations/validate-contributions.d.mts +2 -0
- package/foundation/integrations/validate-contributions.mjs +41 -1
- package/foundation/release/agent-text-worker.d.mts +4 -0
- package/foundation/release/agent-text-worker.mjs +52 -0
- package/foundation/release/cache.d.mts +310 -0
- package/foundation/release/cache.mjs +1216 -0
- package/foundation/release/cache.test.mjs +920 -0
- package/foundation/release/choose.d.mts +207 -0
- package/foundation/release/choose.mjs +677 -0
- package/foundation/release/choose.test.mjs +427 -0
- package/foundation/release/core-worker.d.mts +4 -0
- package/foundation/release/core-worker.mjs +38 -0
- package/foundation/release/global-state.d.mts +259 -0
- package/foundation/release/global-state.mjs +472 -0
- package/foundation/release/global-state.test.mjs +381 -0
- package/foundation/release/handoff.d.mts +60 -0
- package/foundation/release/handoff.e2e.test.mjs +278 -0
- package/foundation/release/handoff.mjs +357 -0
- package/foundation/release/lock-lease.d.mts +23 -0
- package/foundation/release/lock-lease.mjs +80 -0
- package/foundation/release/notices.d.mts +253 -0
- package/foundation/release/notices.mjs +596 -0
- package/foundation/release/notices.test.mjs +565 -0
- package/foundation/release/npm-guard.d.mts +4 -0
- package/foundation/release/npm-guard.mjs +126 -0
- package/foundation/release/project.d.mts +141 -0
- package/foundation/release/project.mjs +466 -0
- package/foundation/release/project.test.mjs +288 -0
- package/foundation/release/refresh-worker.d.mts +4 -0
- package/foundation/release/refresh-worker.mjs +27 -0
- package/foundation/release/run-context.d.mts +47 -0
- package/foundation/release/run-context.mjs +149 -0
- package/foundation/release/update-notice-env.d.mts +28 -0
- package/foundation/release/update-notice-env.mjs +39 -0
- package/foundation/response/base.d.ts +26 -3
- package/foundation/response/error-codes.d.mts +3 -1
- package/foundation/response/error-codes.doc.mjs +12 -0
- package/foundation/response/error-codes.mjs +17 -0
- package/foundation/response/error-codes.test.mjs +2 -0
- package/foundation/response/json-contract.test.mjs +7 -2
- package/foundation/response/json.mjs +4 -1
- package/foundation/response/response-types.doc.mjs +17 -11
- package/foundation/response/response-types.doc.test.mjs +46 -0
- package/foundation/response/response.doc.mjs +3 -3
- package/foundation/xle/browser-imports.test.mjs +74 -0
- package/package.json +11 -11
- package/scripts/postinstall.mjs +24 -5
- /package/assets/codemods/transforms/{next → v0.7.2}/__tests__/migrate-list-edge-compensation-to-edge.test.mjs +0 -0
- /package/assets/codemods/transforms/{next → v0.7.2}/migrate-list-edge-compensation-to-edge.mjs +0 -0
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import {afterEach, describe, expect, it} from 'vitest';
|
|
6
6
|
import * as fs from 'node:fs';
|
|
7
|
+
import * as os from 'node:os';
|
|
7
8
|
import * as path from 'node:path';
|
|
8
9
|
import {spawnSync} from 'node:child_process';
|
|
9
10
|
import {checkAppThemes, checkThemes} from './theme-checks.mjs';
|
|
@@ -12,6 +13,8 @@ import {themeAdd} from '../theme/add/add.mjs';
|
|
|
12
13
|
import {themeEject} from '../theme/eject/eject.mjs';
|
|
13
14
|
import {themeBuild} from '../theme/build/build.mjs';
|
|
14
15
|
import {parseThemeModuleRecord} from '../../foundation/config/theme-state.mjs';
|
|
16
|
+
import {CLI_VERSION} from '../../test-utils/release-fixtures.mjs';
|
|
17
|
+
import {globalCli} from '../../test-utils/global-local-fixtures.mjs';
|
|
15
18
|
|
|
16
19
|
/** @type {string[]} */
|
|
17
20
|
const dirs = [];
|
|
@@ -25,11 +28,12 @@ function write(file, content) {
|
|
|
25
28
|
|
|
26
29
|
/**
|
|
27
30
|
* @param {Array<{slug: string, css?: string, fontFamily?: string, fontCss?: string}>} themeSpecs
|
|
28
|
-
* @param {{peerRange?: string, importModule?: boolean}} [options]
|
|
31
|
+
* @param {{peerRange?: string, importModule?: boolean, root?: string}} [options]
|
|
32
|
+
* `root`: the folder the fixture is made in (default: this package)
|
|
29
33
|
*/
|
|
30
34
|
async function fixture(themeSpecs = [{slug: 'ocean'}], options = {}) {
|
|
31
35
|
const dir = fs.mkdtempSync(
|
|
32
|
-
path.join(process.cwd(), '.astryx-doctor-themes-'),
|
|
36
|
+
path.join(options.root ?? process.cwd(), '.astryx-doctor-themes-'),
|
|
33
37
|
);
|
|
34
38
|
dirs.push(dir);
|
|
35
39
|
fs.mkdirSync(path.join(dir, 'src'), {recursive: true});
|
|
@@ -47,7 +51,7 @@ async function fixture(themeSpecs = [{slug: 'ocean'}], options = {}) {
|
|
|
47
51
|
);
|
|
48
52
|
write(
|
|
49
53
|
path.join(dir, 'node_modules/@astryxdesign/core/package.json'),
|
|
50
|
-
JSON.stringify({name: '@astryxdesign/core', version:
|
|
54
|
+
JSON.stringify({name: '@astryxdesign/core', version: CLI_VERSION}),
|
|
51
55
|
);
|
|
52
56
|
|
|
53
57
|
const packageDir = path.join(dir, 'node_modules/@acme/themes');
|
|
@@ -67,7 +71,7 @@ async function fixture(themeSpecs = [{slug: 'ocean'}], options = {}) {
|
|
|
67
71
|
version: '1.0.0',
|
|
68
72
|
type: 'module',
|
|
69
73
|
peerDependencies: {
|
|
70
|
-
'@astryxdesign/core': options.peerRange ??
|
|
74
|
+
'@astryxdesign/core': options.peerRange ?? `^${CLI_VERSION}`,
|
|
71
75
|
},
|
|
72
76
|
exports: exportsMap,
|
|
73
77
|
}),
|
|
@@ -340,6 +344,142 @@ describe('app-theme doctor checks', () => {
|
|
|
340
344
|
expect(result.message).not.toMatch(/\n\s+at /u);
|
|
341
345
|
});
|
|
342
346
|
|
|
347
|
+
it('passes theme-owners when a built module imports its stylesheet', async () => {
|
|
348
|
+
const {dir, packageDir} = await fixture();
|
|
349
|
+
write(
|
|
350
|
+
path.join(packageDir, 'dist/ocean.js'),
|
|
351
|
+
"import './ocean.css';\nimport '@acme/themes/themes/ocean.css';\nexport const oceanTheme = {name: 'ocean', tokens: {}};\n",
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
const checks = await checkAppThemes(dir);
|
|
355
|
+
|
|
356
|
+
expect(checks.map(item => item.status)).toEqual(Array(10).fill('pass'));
|
|
357
|
+
expect(check(checks, 'theme-owners').message).toContain(
|
|
358
|
+
'every built module loads',
|
|
359
|
+
);
|
|
360
|
+
const cli = runDoctor(dir);
|
|
361
|
+
expect(cli.status).toBe(0);
|
|
362
|
+
expect(cli.stdout).not.toContain('could not load its built module');
|
|
363
|
+
}, 30_000);
|
|
364
|
+
|
|
365
|
+
it('passes every check for an entry that loads its fonts and stylesheet and re-exports the built module', async () => {
|
|
366
|
+
const {dir, packageDir} = await fixture([
|
|
367
|
+
{
|
|
368
|
+
slug: 'ocean',
|
|
369
|
+
fontFamily: 'Ocean Sans',
|
|
370
|
+
fontCss:
|
|
371
|
+
"@font-face { font-family: 'Ocean Sans'; src: local('Ocean Sans'); }\n",
|
|
372
|
+
},
|
|
373
|
+
]);
|
|
374
|
+
write(
|
|
375
|
+
path.join(packageDir, 'dist/ocean.built.js'),
|
|
376
|
+
"export const oceanTheme = {name: 'ocean', tokens: {}, fontFamily: 'Ocean Sans'};\n",
|
|
377
|
+
);
|
|
378
|
+
write(
|
|
379
|
+
path.join(packageDir, 'dist/ocean.js'),
|
|
380
|
+
"import './ocean.fonts.css';\nimport '@acme/themes/themes/ocean.css';\nexport {oceanTheme} from './ocean.built.js';\n",
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
const checks = await checkAppThemes(dir);
|
|
384
|
+
|
|
385
|
+
expect(checks.map(item => [item.id, item.status])).toEqual(
|
|
386
|
+
checks.map(item => [item.id, 'pass']),
|
|
387
|
+
);
|
|
388
|
+
expect(checks).toHaveLength(10);
|
|
389
|
+
const cli = runDoctor(dir);
|
|
390
|
+
expect(cli.status).toBe(0);
|
|
391
|
+
expect(cli.stdout).not.toContain('could not load its built module');
|
|
392
|
+
}, 30_000);
|
|
393
|
+
|
|
394
|
+
it('passes every check for an entry that re-exports a theme whose own name differs from its slug', async () => {
|
|
395
|
+
const {dir, packageDir} = await fixture([
|
|
396
|
+
{
|
|
397
|
+
slug: 'ocean',
|
|
398
|
+
css: '[data-astryx-theme="deep-sea"] { --color-text: black; }\n',
|
|
399
|
+
fontFamily: 'Ocean Sans',
|
|
400
|
+
fontCss:
|
|
401
|
+
"@font-face { font-family: 'Ocean Sans'; src: local('Ocean Sans'); }\n",
|
|
402
|
+
},
|
|
403
|
+
]);
|
|
404
|
+
write(
|
|
405
|
+
path.join(packageDir, 'dist/deep-sea.js'),
|
|
406
|
+
"export const deepSeaTheme = {name: 'deep-sea', tokens: {}, fontFamily: 'Ocean Sans'};\n",
|
|
407
|
+
);
|
|
408
|
+
write(
|
|
409
|
+
path.join(packageDir, 'dist/ocean.js'),
|
|
410
|
+
"import './ocean.fonts.css';\nimport './ocean.css';\nexport {deepSeaTheme as oceanTheme} from './deep-sea.js';\n",
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
const checks = await checkAppThemes(dir);
|
|
414
|
+
|
|
415
|
+
expect(checks.map(item => [item.id, item.status])).toEqual(
|
|
416
|
+
checks.map(item => [item.id, 'pass']),
|
|
417
|
+
);
|
|
418
|
+
expect(checks).toHaveLength(10);
|
|
419
|
+
}, 30_000);
|
|
420
|
+
|
|
421
|
+
it.each([
|
|
422
|
+
[
|
|
423
|
+
'a missing dependency',
|
|
424
|
+
"import '@acme/definitely-missing-dep';\nexport const oceanTheme = {name: 'ocean', tokens: {}};\n",
|
|
425
|
+
'@acme/definitely-missing-dep',
|
|
426
|
+
],
|
|
427
|
+
[
|
|
428
|
+
'a throwing module',
|
|
429
|
+
"throw new Error('broken theme module');\nexport const oceanTheme = {name: 'ocean', tokens: {}};\n",
|
|
430
|
+
'broken theme module',
|
|
431
|
+
],
|
|
432
|
+
])(
|
|
433
|
+
'still fails theme-owners when a built module imports its stylesheet and has %s',
|
|
434
|
+
async (_label, rest, detail) => {
|
|
435
|
+
const {dir, packageDir} = await fixture();
|
|
436
|
+
write(
|
|
437
|
+
path.join(packageDir, 'dist/ocean.js'),
|
|
438
|
+
`import './ocean.css';\n${rest}`,
|
|
439
|
+
);
|
|
440
|
+
|
|
441
|
+
const result = check(await checkAppThemes(dir), 'theme-owners');
|
|
442
|
+
|
|
443
|
+
expect(result).toMatchObject({id: 'theme-owners', status: 'fail'});
|
|
444
|
+
expect(result.message).toContain(
|
|
445
|
+
'Theme "ocean" from @acme/themes could not load its built module',
|
|
446
|
+
);
|
|
447
|
+
expect(result.message).toContain(detail);
|
|
448
|
+
},
|
|
449
|
+
);
|
|
450
|
+
|
|
451
|
+
it("still fails theme-owners when the theme's stylesheet export is missing", async () => {
|
|
452
|
+
const {dir, packageDir} = await fixture();
|
|
453
|
+
write(
|
|
454
|
+
path.join(packageDir, 'dist/ocean.js'),
|
|
455
|
+
"import './ocean.css';\nexport const oceanTheme = {name: 'ocean', tokens: {}};\n",
|
|
456
|
+
);
|
|
457
|
+
fs.rmSync(path.join(packageDir, 'dist/ocean.css'));
|
|
458
|
+
|
|
459
|
+
const result = check(await checkAppThemes(dir), 'theme-owners');
|
|
460
|
+
|
|
461
|
+
expect(result).toMatchObject({id: 'theme-owners', status: 'fail'});
|
|
462
|
+
expect(result.message).toContain(
|
|
463
|
+
'Missing stylesheet export @acme/themes/themes/ocean.css',
|
|
464
|
+
);
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
it('still fails theme-owners when another stylesheet the built module imports is missing', async () => {
|
|
468
|
+
const {dir, packageDir} = await fixture();
|
|
469
|
+
write(
|
|
470
|
+
path.join(packageDir, 'dist/ocean.js'),
|
|
471
|
+
"import './ocean.css';\nimport './fonts.css';\nexport const oceanTheme = {name: 'ocean', tokens: {}};\n",
|
|
472
|
+
);
|
|
473
|
+
|
|
474
|
+
const result = check(await checkAppThemes(dir), 'theme-owners');
|
|
475
|
+
|
|
476
|
+
expect(result).toMatchObject({id: 'theme-owners', status: 'fail'});
|
|
477
|
+
expect(result.message).toContain(
|
|
478
|
+
'Theme "ocean" from @acme/themes could not load its built module',
|
|
479
|
+
);
|
|
480
|
+
expect(result.message).toContain('fonts.css');
|
|
481
|
+
});
|
|
482
|
+
|
|
343
483
|
it('fails theme-owners for an ambiguous multi-theme record', async () => {
|
|
344
484
|
const {dir, packageDir} = await fixture([{slug: 'ocean'}, {slug: 'reef'}]);
|
|
345
485
|
const packageFile = path.join(packageDir, 'package.json');
|
|
@@ -456,6 +596,82 @@ describe('app-theme doctor checks', () => {
|
|
|
456
596
|
});
|
|
457
597
|
});
|
|
458
598
|
|
|
599
|
+
it("check 5 is info, and builds nothing, when the project's Core is not installed (spec AST-081 FR3)", async () => {
|
|
600
|
+
// Outside this repository, whose own installed Core would be found above.
|
|
601
|
+
const {dir} = await fixture(undefined, {root: os.tmpdir()});
|
|
602
|
+
await themeEject('ocean', {cwd: dir, package: '@acme/themes'});
|
|
603
|
+
const sourceFile = path.join(dir, 'src/themes/ocean/oceanTheme.ts');
|
|
604
|
+
fs.writeFileSync(
|
|
605
|
+
sourceFile,
|
|
606
|
+
"const oceanTheme = {name: 'ocean', tokens: {'--color-bg': '#000'}};\nexport {oceanTheme};\nexport default oceanTheme;\n",
|
|
607
|
+
);
|
|
608
|
+
await themeBuild(sourceFile, {}, {cwd: dir});
|
|
609
|
+
await themeAdd('ocean', {cwd: dir, import: true});
|
|
610
|
+
// A fresh clone: the project declares Core but has not installed it.
|
|
611
|
+
fs.rmSync(path.join(dir, 'node_modules/@astryxdesign/core'), {
|
|
612
|
+
recursive: true,
|
|
613
|
+
force: true,
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
expect(check(await checkAppThemes(dir), 'theme-local-builds')).toEqual({
|
|
617
|
+
id: 'theme-local-builds',
|
|
618
|
+
label: 'Local theme build freshness',
|
|
619
|
+
status: 'info',
|
|
620
|
+
message:
|
|
621
|
+
"The project's Core isn't installed, so local theme builds were not checked. Install the project's dependencies, then run doctor again.",
|
|
622
|
+
});
|
|
623
|
+
// A build that may read only the project's Core refuses instead of
|
|
624
|
+
// reading another one.
|
|
625
|
+
await expect(
|
|
626
|
+
themeBuild(sourceFile, {check: true}, {cwd: dir, projectCore: true}),
|
|
627
|
+
).rejects.toMatchObject({code: 'ERR_CORE_NOT_FOUND'});
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
it.skipIf(process.platform === 'win32')(
|
|
631
|
+
'check 5 through a CLI installed for the computer, in a fresh clone: info, and no carried Core is read or fetched',
|
|
632
|
+
async () => {
|
|
633
|
+
const home = fs.mkdtempSync(
|
|
634
|
+
path.join(os.tmpdir(), 'astryx-doctor-home-'),
|
|
635
|
+
);
|
|
636
|
+
dirs.push(home);
|
|
637
|
+
const g = globalCli('npm', CLI_VERSION, {root: home});
|
|
638
|
+
const {dir} = await fixture(undefined, {root: os.tmpdir()});
|
|
639
|
+
await themeEject('ocean', {cwd: dir, package: '@acme/themes'});
|
|
640
|
+
const sourceFile = path.join(dir, 'src/themes/ocean/oceanTheme.ts');
|
|
641
|
+
await themeBuild(sourceFile, {}, {cwd: dir});
|
|
642
|
+
await themeAdd('ocean', {cwd: dir, import: true});
|
|
643
|
+
fs.rmSync(path.join(dir, 'node_modules/@astryxdesign/core'), {
|
|
644
|
+
recursive: true,
|
|
645
|
+
force: true,
|
|
646
|
+
});
|
|
647
|
+
const cache = path.join(home, '.cache');
|
|
648
|
+
const result = spawnSync(process.execPath, [g.bin, 'doctor', '--json'], {
|
|
649
|
+
cwd: dir,
|
|
650
|
+
encoding: 'utf8',
|
|
651
|
+
timeout: 120_000,
|
|
652
|
+
env: {
|
|
653
|
+
PATH: path.dirname(process.execPath),
|
|
654
|
+
HOME: home,
|
|
655
|
+
USERPROFILE: home,
|
|
656
|
+
XDG_CACHE_HOME: cache,
|
|
657
|
+
XDG_CONFIG_HOME: path.join(home, '.config'),
|
|
658
|
+
// Nothing can be fetched: a fetch of the carried Core would fail.
|
|
659
|
+
npm_config_registry: 'http://127.0.0.1:9/',
|
|
660
|
+
npm_config_update_notifier: 'false',
|
|
661
|
+
NO_COLOR: '1',
|
|
662
|
+
},
|
|
663
|
+
});
|
|
664
|
+
const checks = JSON.parse(result.stdout).data.checks;
|
|
665
|
+
expect(checks.find(c => c.id === 'theme-local-builds')).toMatchObject({
|
|
666
|
+
status: 'info',
|
|
667
|
+
});
|
|
668
|
+
expect(
|
|
669
|
+
fs.existsSync(path.join(cache, 'astryx', 'releases', CLI_VERSION)),
|
|
670
|
+
).toBe(false);
|
|
671
|
+
},
|
|
672
|
+
180_000,
|
|
673
|
+
);
|
|
674
|
+
|
|
459
675
|
it('check 6 ignores private variables generated from guaranteed component properties', async () => {
|
|
460
676
|
const {dir, packageDir} = await fixture([
|
|
461
677
|
{
|
|
@@ -610,7 +826,7 @@ describe('app-theme doctor checks', () => {
|
|
|
610
826
|
for (const name of ['@astryxdesign/core', '@astryxdesign/theme-neutral']) {
|
|
611
827
|
write(
|
|
612
828
|
path.join(root, 'node_modules', name, 'package.json'),
|
|
613
|
-
JSON.stringify({name, version:
|
|
829
|
+
JSON.stringify({name, version: CLI_VERSION}),
|
|
614
830
|
);
|
|
615
831
|
}
|
|
616
832
|
const app = path.join(root, 'packages/app');
|
|
@@ -620,8 +836,8 @@ describe('app-theme doctor checks', () => {
|
|
|
620
836
|
name: 'app',
|
|
621
837
|
private: true,
|
|
622
838
|
dependencies: {
|
|
623
|
-
'@astryxdesign/core':
|
|
624
|
-
'@astryxdesign/theme-neutral':
|
|
839
|
+
'@astryxdesign/core': CLI_VERSION,
|
|
840
|
+
'@astryxdesign/theme-neutral': CLI_VERSION,
|
|
625
841
|
},
|
|
626
842
|
astryx: {theme: '@astryxdesign/theme-neutral'},
|
|
627
843
|
}),
|
package/api/error.d.mts
CHANGED
|
@@ -23,6 +23,16 @@
|
|
|
23
23
|
* @returns {AstryxError}
|
|
24
24
|
*/
|
|
25
25
|
export function writeFailed(target: string, cwd: string, cause: unknown, unrestored?: string[]): AstryxError;
|
|
26
|
+
/**
|
|
27
|
+
* Locate the Core a command answers from (`requireCoreDir` in
|
|
28
|
+
* foundation/fs/paths.mjs), raising its coded failure as an AstryxError:
|
|
29
|
+
* ERR_CORE_NOT_FOUND with no Core to answer from, ERR_VERSIONS_UNAVAILABLE
|
|
30
|
+
* when the carried Core is needed and cannot be installed.
|
|
31
|
+
* @param {(cwd: string) => string} lookup the foundation lookup
|
|
32
|
+
* @param {string} cwd
|
|
33
|
+
* @returns {string}
|
|
34
|
+
*/
|
|
35
|
+
export function coreDirOrThrow(lookup: (cwd: string) => string, cwd: string): string;
|
|
26
36
|
export class AstryxError extends Error {
|
|
27
37
|
/**
|
|
28
38
|
* @param {string} message
|
package/api/error.mjs
CHANGED
|
@@ -78,3 +78,28 @@ export function writeFailed(target, cwd, cause, unrestored = []) {
|
|
|
78
78
|
ERROR_CODES.ERR_WRITE_FAILED,
|
|
79
79
|
);
|
|
80
80
|
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Locate the Core a command answers from (`requireCoreDir` in
|
|
84
|
+
* foundation/fs/paths.mjs), raising its coded failure as an AstryxError:
|
|
85
|
+
* ERR_CORE_NOT_FOUND with no Core to answer from, ERR_VERSIONS_UNAVAILABLE
|
|
86
|
+
* when the carried Core is needed and cannot be installed.
|
|
87
|
+
* @param {(cwd: string) => string} lookup the foundation lookup
|
|
88
|
+
* @param {string} cwd
|
|
89
|
+
* @returns {string}
|
|
90
|
+
*/
|
|
91
|
+
export function coreDirOrThrow(lookup, cwd) {
|
|
92
|
+
try {
|
|
93
|
+
return lookup(cwd);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
const code = /** @type {any} */ (error)?.code;
|
|
96
|
+
if (typeof code === 'string' && code.startsWith('ERR_')) {
|
|
97
|
+
throw new AstryxError(
|
|
98
|
+
error instanceof Error ? error.message : String(error),
|
|
99
|
+
undefined,
|
|
100
|
+
code,
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -60,6 +60,9 @@ export const GAP_REPORT_CATEGORIES: readonly (Readonly<{
|
|
|
60
60
|
label: "Other";
|
|
61
61
|
}>)[];
|
|
62
62
|
export const PUBLIC_CONFIRMATION_MESSAGE: "Rerun with --confirm-public to file this report.";
|
|
63
|
+
/** What an agent does when more than one destination exists. */
|
|
64
|
+
export const ASK_DESTINATION_MESSAGE: "Ask the person where to file this report, then pass their choice with --to <package>. Never pick a package destination yourself; leave --to out to use the default.";
|
|
65
|
+
export type GapReportDestination = import("./gap-report.type.mjs").GapReportDestination;
|
|
63
66
|
export type ReportTarget = {
|
|
64
67
|
package: string;
|
|
65
68
|
version: string | null;
|
|
@@ -19,6 +19,8 @@ export const doc = {
|
|
|
19
19
|
'Sends a gap report to every configured handler: the project config handler first, then each integration handler in config order. ' +
|
|
20
20
|
'Each handler has 30 s to finish, and its output goes to stderr. Public handlers run only with confirmPublic; internal handlers always run. ' +
|
|
21
21
|
"With no handler, it files a GitHub issue for the owning package only with confirmPublic (without it nothing is sent), or returns the package's issues URL when that is not on GitHub. " +
|
|
22
|
+
"With options.to, the report goes only to that integration's issues URL instead, under the same confirmPublic rule. " +
|
|
23
|
+
'When loaded integrations name their own issues URLs, the response lists every destination with a line telling an agent to ask the person where to file; pass their choice as options.to, never a package the agent picked itself. ' +
|
|
22
24
|
'The report records whether an agent or a person ran it, and the response lists each handler outcome in order.',
|
|
23
25
|
importPath: '@astryxdesign/cli/api',
|
|
24
26
|
signature:
|
|
@@ -67,14 +69,20 @@ export const doc = {
|
|
|
67
69
|
name: 'options.confirmPublic',
|
|
68
70
|
type: 'boolean',
|
|
69
71
|
description:
|
|
70
|
-
'Allow public delivery: public handlers run, and
|
|
72
|
+
'Allow public delivery: public handlers run, and a GitHub issues URL gets an issue filed through the gh CLI.',
|
|
71
73
|
default: 'false',
|
|
72
74
|
},
|
|
75
|
+
{
|
|
76
|
+
name: 'options.to',
|
|
77
|
+
type: 'string',
|
|
78
|
+
description:
|
|
79
|
+
'A destination the person chose: a loaded integration whose manifest names an issues URL. The report goes only to that issues URL; handlers do not run.',
|
|
80
|
+
},
|
|
73
81
|
{
|
|
74
82
|
name: 'options.listCategories',
|
|
75
83
|
type: 'boolean',
|
|
76
84
|
description:
|
|
77
|
-
'Return categories without resolving a route or writing; the component and every other option are refused with ERR_INVALID_ARGUMENT.',
|
|
85
|
+
'Return categories, and the destinations in meta when there is more than one, without resolving a route or writing; the component and every other option are refused with ERR_INVALID_ARGUMENT.',
|
|
78
86
|
default: 'false',
|
|
79
87
|
},
|
|
80
88
|
{
|
|
@@ -115,7 +123,7 @@ export const doc = {
|
|
|
115
123
|
},
|
|
116
124
|
{
|
|
117
125
|
code: 'ERR_UNKNOWN_PACKAGE',
|
|
118
|
-
when: 'the explicitly selected package is not loaded',
|
|
126
|
+
when: 'the explicitly selected package is not loaded, or options.to names no destination (the error lists the destinations)',
|
|
119
127
|
},
|
|
120
128
|
{
|
|
121
129
|
code: 'ERR_NOT_FOUND',
|
|
@@ -55,6 +55,14 @@ export const GAP_REPORT_CATEGORIES = Object.freeze([
|
|
|
55
55
|
export const PUBLIC_CONFIRMATION_MESSAGE =
|
|
56
56
|
'Rerun with --confirm-public to file this report.';
|
|
57
57
|
|
|
58
|
+
/** What an agent does when more than one destination exists. */
|
|
59
|
+
export const ASK_DESTINATION_MESSAGE =
|
|
60
|
+
'Ask the person where to file this report, then pass their choice with --to <package>. Never pick a package destination yourself; leave --to out to use the default.';
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @typedef {import('./gap-report.type.mjs').GapReportDestination} GapReportDestination
|
|
64
|
+
*/
|
|
65
|
+
|
|
58
66
|
/**
|
|
59
67
|
* @typedef {object} ReportTarget
|
|
60
68
|
* @property {string} package
|
|
@@ -537,15 +545,14 @@ function githubRoute(issuesUrl) {
|
|
|
537
545
|
}
|
|
538
546
|
|
|
539
547
|
/**
|
|
540
|
-
*
|
|
541
|
-
* Requires confirmPublic.
|
|
548
|
+
* File a report on GitHub with `gh` — for the zero-handler fallback and for a
|
|
549
|
+
* destination the caller names. Requires confirmPublic.
|
|
542
550
|
*
|
|
543
|
-
* @param {ReportTarget} target
|
|
544
551
|
* @param {{component: string, categoryLabel: string, intention: string, detail?: string, source: string, timestamp: string}} report
|
|
545
552
|
* @param {{repo: string}} github
|
|
546
553
|
* @returns {Promise<Pick<import('./gap-report.type.mjs').GapReportDelivery, 'status'|'url'|'message'>>}
|
|
547
554
|
*/
|
|
548
|
-
async function runGithubFallback(
|
|
555
|
+
async function runGithubFallback(report, github) {
|
|
549
556
|
const {execFile} = await import('node:child_process');
|
|
550
557
|
const title = `[gap] ${report.component}: ${report.intention.slice(0, 70)}`;
|
|
551
558
|
const body = [
|
|
@@ -607,6 +614,87 @@ async function runGithubFallback(target, report, github) {
|
|
|
607
614
|
}
|
|
608
615
|
}
|
|
609
616
|
|
|
617
|
+
/**
|
|
618
|
+
* Send a report to an issues URL: a GitHub issues URL is filed with `gh` only
|
|
619
|
+
* with consent; any other URL comes back as routed_only. Serves the
|
|
620
|
+
* zero-handler fallback (spec:AST-031/FR8) and a destination named with `to`
|
|
621
|
+
* (architecture:cli-surface INV36).
|
|
622
|
+
*
|
|
623
|
+
* @param {string} issuesUrl
|
|
624
|
+
* @param {{component: string, categoryLabel: string, intention: string, detail?: string, source: string, timestamp: string}} report
|
|
625
|
+
* @param {boolean} confirmPublic
|
|
626
|
+
* @returns {Promise<import('./gap-report.type.mjs').GapReportDelivery>}
|
|
627
|
+
*/
|
|
628
|
+
async function deliverToIssuesUrl(issuesUrl, report, confirmPublic) {
|
|
629
|
+
const github = githubRoute(issuesUrl);
|
|
630
|
+
if (github != null && !confirmPublic) {
|
|
631
|
+
return {
|
|
632
|
+
handlerType: 'fallback',
|
|
633
|
+
handler: 'github',
|
|
634
|
+
audience: 'public',
|
|
635
|
+
status: 'consent_required',
|
|
636
|
+
url: null,
|
|
637
|
+
message: PUBLIC_CONFIRMATION_MESSAGE,
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
if (github) {
|
|
641
|
+
return {
|
|
642
|
+
handlerType: 'fallback',
|
|
643
|
+
handler: 'github',
|
|
644
|
+
audience: 'public',
|
|
645
|
+
...(await runGithubFallback(report, github)),
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
return {
|
|
649
|
+
handlerType: 'fallback',
|
|
650
|
+
handler: 'issuesUrl',
|
|
651
|
+
audience: null,
|
|
652
|
+
status: 'routed_only',
|
|
653
|
+
url: issuesUrl,
|
|
654
|
+
message:
|
|
655
|
+
'No automatic handler is available; open the routed URL to file this report.',
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Where a report can go: the default (the handlers, or with none the owning
|
|
661
|
+
* package's issues URL), then each loaded integration that names its own
|
|
662
|
+
* issues URL (architecture:cli-surface INV36).
|
|
663
|
+
*
|
|
664
|
+
* @param {Project} project
|
|
665
|
+
* @returns {GapReportDestination[]}
|
|
666
|
+
*/
|
|
667
|
+
function listDestinations(project) {
|
|
668
|
+
/** @type {GapReportDestination[]} */
|
|
669
|
+
const destinations = [{to: null, default: true, issuesUrl: null}];
|
|
670
|
+
for (const integration of project.loadedIntegrations) {
|
|
671
|
+
if (integration.__loadError || !integration.issuesUrl) continue;
|
|
672
|
+
if (destinations.some(destination => destination.to === integration.name))
|
|
673
|
+
continue;
|
|
674
|
+
destinations.push({
|
|
675
|
+
to: integration.name,
|
|
676
|
+
default: false,
|
|
677
|
+
issuesUrl: integration.issuesUrl,
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
return destinations;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* The destinations of the project at `cwd`, or only the default when no
|
|
685
|
+
* project loads there.
|
|
686
|
+
* @param {string|undefined} cwd
|
|
687
|
+
* @returns {Promise<GapReportDestination[]>}
|
|
688
|
+
*/
|
|
689
|
+
async function destinationsAt(cwd) {
|
|
690
|
+
try {
|
|
691
|
+
const {resolve} = await import('node:path');
|
|
692
|
+
return listDestinations(await Project.load(resolve(cwd ?? process.cwd())));
|
|
693
|
+
} catch {
|
|
694
|
+
return [{to: null, default: true, issuesUrl: null}];
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
610
698
|
/**
|
|
611
699
|
* Compute the aggregate status from the deliveries.
|
|
612
700
|
* @param {import('./gap-report.type.mjs').GapReportDelivery[]} deliveries
|
|
@@ -665,6 +753,7 @@ export async function gapReport(component, options = {}) {
|
|
|
665
753
|
options.detail ? '--additional-context' : null,
|
|
666
754
|
options.package ? '--package' : null,
|
|
667
755
|
options.confirmPublic ? '--confirm-public' : null,
|
|
756
|
+
options.to != null ? '--to' : null,
|
|
668
757
|
].filter(Boolean);
|
|
669
758
|
if (ignored.length > 0) {
|
|
670
759
|
throw new AstryxError(
|
|
@@ -673,9 +762,13 @@ export async function gapReport(component, options = {}) {
|
|
|
673
762
|
ERROR_CODES.ERR_INVALID_ARGUMENT,
|
|
674
763
|
);
|
|
675
764
|
}
|
|
765
|
+
const destinations = await destinationsAt(options.cwd);
|
|
676
766
|
return {
|
|
677
767
|
type: 'gap-report.categories',
|
|
678
768
|
data: GAP_REPORT_CATEGORIES.map(category => ({...category})),
|
|
769
|
+
...(destinations.length > 1
|
|
770
|
+
? {meta: {destinations, ask: ASK_DESTINATION_MESSAGE}}
|
|
771
|
+
: {}),
|
|
679
772
|
};
|
|
680
773
|
}
|
|
681
774
|
|
|
@@ -704,7 +797,33 @@ export async function gapReport(component, options = {}) {
|
|
|
704
797
|
options.package,
|
|
705
798
|
);
|
|
706
799
|
|
|
707
|
-
const
|
|
800
|
+
const destinations = listDestinations(project);
|
|
801
|
+
/** @type {GapReportDestination | undefined} */
|
|
802
|
+
let chosen;
|
|
803
|
+
// `to: null` is absent, like `package: null`; any other value is matched
|
|
804
|
+
// against the destinations as given, so an empty or unknown one lists them.
|
|
805
|
+
if (options.to != null) {
|
|
806
|
+
const to = options.to;
|
|
807
|
+
chosen = destinations.find(
|
|
808
|
+
destination => !destination.default && destination.to === to,
|
|
809
|
+
);
|
|
810
|
+
if (!chosen) {
|
|
811
|
+
const choices = destinations.filter(destination => !destination.default);
|
|
812
|
+
const named = JSON.stringify(String(to).slice(0, 214));
|
|
813
|
+
throw new AstryxError(
|
|
814
|
+
choices.length > 0
|
|
815
|
+
? `No gap-report destination ${named}. Choose one of: ${choices.map(destination => destination.to).join(', ')}; or leave out --to for the default.`
|
|
816
|
+
: `No gap-report destination ${named}: no loaded integration names an issues URL. Leave out --to for the default.`,
|
|
817
|
+
choices.map(destination => ({
|
|
818
|
+
name: /** @type {string} */ (destination.to),
|
|
819
|
+
reason: /** @type {string} */ (destination.issuesUrl),
|
|
820
|
+
})),
|
|
821
|
+
ERROR_CODES.ERR_UNKNOWN_PACKAGE,
|
|
822
|
+
);
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
const entries = chosen ? [] : collectGapReportHandlers(project);
|
|
708
827
|
|
|
709
828
|
const timestamp = new Date().toISOString();
|
|
710
829
|
const source = captureEnv().invocationSource;
|
|
@@ -731,8 +850,24 @@ export async function gapReport(component, options = {}) {
|
|
|
731
850
|
|
|
732
851
|
/** @type {import('./gap-report.type.mjs').GapReportDelivery[]} */
|
|
733
852
|
const deliveries = [];
|
|
853
|
+
const routeReport = {
|
|
854
|
+
component: resolvedComponent,
|
|
855
|
+
categoryLabel: categoryEntry.label,
|
|
856
|
+
intention,
|
|
857
|
+
detail,
|
|
858
|
+
source,
|
|
859
|
+
timestamp,
|
|
860
|
+
};
|
|
734
861
|
|
|
735
|
-
if (
|
|
862
|
+
if (chosen) {
|
|
863
|
+
deliveries.push(
|
|
864
|
+
await deliverToIssuesUrl(
|
|
865
|
+
/** @type {string} */ (chosen.issuesUrl),
|
|
866
|
+
routeReport,
|
|
867
|
+
options.confirmPublic === true,
|
|
868
|
+
),
|
|
869
|
+
);
|
|
870
|
+
} else if (entries.length > 0) {
|
|
736
871
|
deliveries.push(
|
|
737
872
|
...(await deliverGapReportHandlers(entries, report, {
|
|
738
873
|
confirmPublic: options.confirmPublic === true,
|
|
@@ -746,47 +881,13 @@ export async function gapReport(component, options = {}) {
|
|
|
746
881
|
ERROR_CODES.ERR_NOT_FOUND,
|
|
747
882
|
);
|
|
748
883
|
}
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
status: 'consent_required',
|
|
757
|
-
url: null,
|
|
758
|
-
message: PUBLIC_CONFIRMATION_MESSAGE,
|
|
759
|
-
});
|
|
760
|
-
} else if (github) {
|
|
761
|
-
const outcome = await runGithubFallback(
|
|
762
|
-
target,
|
|
763
|
-
{
|
|
764
|
-
component: resolvedComponent,
|
|
765
|
-
categoryLabel: categoryEntry.label,
|
|
766
|
-
intention,
|
|
767
|
-
detail,
|
|
768
|
-
source,
|
|
769
|
-
timestamp,
|
|
770
|
-
},
|
|
771
|
-
github,
|
|
772
|
-
);
|
|
773
|
-
deliveries.push({
|
|
774
|
-
handlerType: 'fallback',
|
|
775
|
-
handler: 'github',
|
|
776
|
-
audience: 'public',
|
|
777
|
-
...outcome,
|
|
778
|
-
});
|
|
779
|
-
} else {
|
|
780
|
-
deliveries.push({
|
|
781
|
-
handlerType: 'fallback',
|
|
782
|
-
handler: 'issuesUrl',
|
|
783
|
-
audience: null,
|
|
784
|
-
status: 'routed_only',
|
|
785
|
-
url: target.issuesUrl,
|
|
786
|
-
message:
|
|
787
|
-
'No automatic handler is available; open the routed URL to file this report.',
|
|
788
|
-
});
|
|
789
|
-
}
|
|
884
|
+
deliveries.push(
|
|
885
|
+
await deliverToIssuesUrl(
|
|
886
|
+
target.issuesUrl,
|
|
887
|
+
routeReport,
|
|
888
|
+
options.confirmPublic === true,
|
|
889
|
+
),
|
|
890
|
+
);
|
|
790
891
|
}
|
|
791
892
|
|
|
792
893
|
const filedCount = deliveries.filter(d => d.status === 'filed').length;
|
|
@@ -800,10 +901,13 @@ export async function gapReport(component, options = {}) {
|
|
|
800
901
|
data: {
|
|
801
902
|
status,
|
|
802
903
|
package: target.package,
|
|
803
|
-
issuesUrl: target.issuesUrl,
|
|
904
|
+
issuesUrl: chosen ? chosen.issuesUrl : target.issuesUrl,
|
|
804
905
|
deliveries,
|
|
805
906
|
filedCount,
|
|
806
907
|
routedOnlyCount,
|
|
908
|
+
...(!chosen && destinations.length > 1
|
|
909
|
+
? {destinations, ask: ASK_DESTINATION_MESSAGE}
|
|
910
|
+
: {}),
|
|
807
911
|
},
|
|
808
912
|
};
|
|
809
913
|
}
|