@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
|
@@ -1,11 +1,67 @@
|
|
|
1
1
|
// @generated by scripts/sync-api-types.mjs from the JSDoc in foundation/**/*.mjs.
|
|
2
2
|
// DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* The Core a command answers from: the project's (see
|
|
6
|
+
* {@link findProjectCoreDir}), else, when a copy other than the project's own
|
|
7
|
+
* CLI answers, the Core that copy carries (spec AST-081 FR3): the
|
|
8
|
+
* `@astryxdesign/core` of its own release, beside it or in the per-user
|
|
9
|
+
* release cache. Never fetches; {@link requireCoreDir} does.
|
|
10
|
+
*
|
|
11
|
+
* Commands that judge or change a project (`doctor`, `swizzle`, `upgrade`)
|
|
12
|
+
* read {@link findProjectCoreDir} instead, so a carried Core never passes a
|
|
13
|
+
* project check or lands in a folder that installed none.
|
|
14
|
+
*
|
|
15
|
+
* @param {string} [startDir]
|
|
16
|
+
* @returns {string | null}
|
|
17
|
+
*/
|
|
18
|
+
export function findCoreDir(startDir?: string): string | null;
|
|
19
|
+
/**
|
|
20
|
+
* Why a command that reads Core cannot run, when the answering release's own
|
|
21
|
+
* Core is needed and cannot be installed: outside a project, or in a project
|
|
22
|
+
* with nothing installed (spec AST-081 FR3).
|
|
23
|
+
* @param {{unavailable: string | null, version?: string, reason?: string}} found
|
|
24
|
+
* @param {boolean} inProject
|
|
25
|
+
* @returns {string}
|
|
26
|
+
*/
|
|
27
|
+
export function unavailableCoreMessage(found: {
|
|
28
|
+
unavailable: string | null;
|
|
29
|
+
version?: string;
|
|
30
|
+
reason?: string;
|
|
31
|
+
}, inProject: boolean): string;
|
|
32
|
+
/**
|
|
33
|
+
* Like {@link findCoreDir}, but a copy that carries no Core installs its
|
|
34
|
+
* release's Core into the per-user cache first. Throws ERR_CORE_NOT_FOUND
|
|
35
|
+
* when there is no Core to answer from, and ERR_VERSIONS_UNAVAILABLE when the
|
|
36
|
+
* carried Core is needed and cannot be installed.
|
|
37
|
+
*
|
|
38
|
+
* @param {string} [startDir]
|
|
39
|
+
* @returns {string}
|
|
40
|
+
*/
|
|
41
|
+
export function requireCoreDir(startDir?: string): string;
|
|
42
|
+
/**
|
|
43
|
+
* The carried Core alone, for a caller that already looked for the project's
|
|
44
|
+
* Core its own way: the folder, or null when the copy answering in `startDir`
|
|
45
|
+
* is the project's own CLI or carries none.
|
|
46
|
+
* @param {string} startDir
|
|
47
|
+
* @param {{fetch?: boolean}} [options]
|
|
48
|
+
* @returns {string | null}
|
|
49
|
+
*/
|
|
50
|
+
export function findCarriedCoreDir(startDir: string, { fetch }?: {
|
|
51
|
+
fetch?: boolean;
|
|
52
|
+
}): string | null;
|
|
4
53
|
/**
|
|
5
54
|
* Find packages/core directory by walking up from startDir.
|
|
6
55
|
* Also checks node_modules/@astryxdesign/core for installed usage.
|
|
56
|
+
*
|
|
57
|
+
* The project's Core only: in the folder or four above it, the reach every
|
|
58
|
+
* released version used, else from the folder of the package.json that makes
|
|
59
|
+
* the folder part of a project, however deep the folder is.
|
|
60
|
+
*
|
|
61
|
+
* @param {string} [startDir]
|
|
62
|
+
* @returns {string | null}
|
|
7
63
|
*/
|
|
8
|
-
export function
|
|
64
|
+
export function findProjectCoreDir(startDir?: string): string | null;
|
|
9
65
|
/**
|
|
10
66
|
* Locate a package the project at `startDir` actually installed.
|
|
11
67
|
*
|
package/foundation/fs/paths.mjs
CHANGED
|
@@ -11,17 +11,144 @@ import {createRequire} from 'node:module';
|
|
|
11
11
|
import * as path from 'node:path';
|
|
12
12
|
import {fileURLToPath} from 'node:url';
|
|
13
13
|
import {listDir, pathExists} from './listing-cache.mjs';
|
|
14
|
+
import {ERROR_CODES} from '../response/error-codes.mjs';
|
|
15
|
+
import {carriedCore, runChoice} from '../release/run-context.mjs';
|
|
16
|
+
import {findDeclaringPackage} from '../release/project.mjs';
|
|
14
17
|
|
|
15
18
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
16
19
|
|
|
17
20
|
/** Root of the @astryxdesign/cli package */
|
|
18
21
|
export const CLI_ROOT = path.resolve(__dirname, '..', '..');
|
|
19
22
|
|
|
23
|
+
/**
|
|
24
|
+
* The Core a command answers from: the project's (see
|
|
25
|
+
* {@link findProjectCoreDir}), else, when a copy other than the project's own
|
|
26
|
+
* CLI answers, the Core that copy carries (spec AST-081 FR3): the
|
|
27
|
+
* `@astryxdesign/core` of its own release, beside it or in the per-user
|
|
28
|
+
* release cache. Never fetches; {@link requireCoreDir} does.
|
|
29
|
+
*
|
|
30
|
+
* Commands that judge or change a project (`doctor`, `swizzle`, `upgrade`)
|
|
31
|
+
* read {@link findProjectCoreDir} instead, so a carried Core never passes a
|
|
32
|
+
* project check or lands in a folder that installed none.
|
|
33
|
+
*
|
|
34
|
+
* @param {string} [startDir]
|
|
35
|
+
* @returns {string | null}
|
|
36
|
+
*/
|
|
37
|
+
export function findCoreDir(startDir = process.cwd()) {
|
|
38
|
+
return findProjectCoreDir(startDir) ?? carriedCoreFor(startDir).dir;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Why a command that reads Core cannot run, when the answering release's own
|
|
43
|
+
* Core is needed and cannot be installed: outside a project, or in a project
|
|
44
|
+
* with nothing installed (spec AST-081 FR3).
|
|
45
|
+
* @param {{unavailable: string | null, version?: string, reason?: string}} found
|
|
46
|
+
* @param {boolean} inProject
|
|
47
|
+
* @returns {string}
|
|
48
|
+
*/
|
|
49
|
+
export function unavailableCoreMessage(found, inProject) {
|
|
50
|
+
const unwritable = /cannot be written/.test(found.unavailable ?? '');
|
|
51
|
+
if (inProject) {
|
|
52
|
+
const core = found.version ? `Core ${found.version}` : 'its Core';
|
|
53
|
+
const why = found.reason ? ` (${found.reason})` : '';
|
|
54
|
+
return `This project has no Core installed, and ${core} could not be downloaded${why}. Install the project's dependencies${unwritable ? ', or make that folder writable' : ''}, then run again.`;
|
|
55
|
+
}
|
|
56
|
+
return `${found.unavailable}. Outside a project, commands that read Core use the Core of the release that answers; ${unwritable ? 'make that folder writable and run again' : 'run again when the package registry can be reached'}.`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Like {@link findCoreDir}, but a copy that carries no Core installs its
|
|
61
|
+
* release's Core into the per-user cache first. Throws ERR_CORE_NOT_FOUND
|
|
62
|
+
* when there is no Core to answer from, and ERR_VERSIONS_UNAVAILABLE when the
|
|
63
|
+
* carried Core is needed and cannot be installed.
|
|
64
|
+
*
|
|
65
|
+
* @param {string} [startDir]
|
|
66
|
+
* @returns {string}
|
|
67
|
+
*/
|
|
68
|
+
export function requireCoreDir(startDir = process.cwd()) {
|
|
69
|
+
const found = findProjectCoreDir(startDir) ?? carriedCoreFor(startDir, true);
|
|
70
|
+
if (typeof found === 'string') return found;
|
|
71
|
+
if (found.unavailable) {
|
|
72
|
+
throw codedError(
|
|
73
|
+
unavailableCoreMessage(found, runChoice(startDir).inProject),
|
|
74
|
+
ERROR_CODES.ERR_VERSIONS_UNAVAILABLE,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
if (found.dir) return found.dir;
|
|
78
|
+
throw codedError(
|
|
79
|
+
'Could not find @astryxdesign/core package',
|
|
80
|
+
ERROR_CODES.ERR_CORE_NOT_FOUND,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* An Error carrying a stable error code, which the JSON envelope and every
|
|
86
|
+
* command's error output read the way they read an API error's.
|
|
87
|
+
* @param {string} message
|
|
88
|
+
* @param {string} code
|
|
89
|
+
* @returns {Error & {code: string}}
|
|
90
|
+
*/
|
|
91
|
+
function codedError(message, code) {
|
|
92
|
+
return Object.assign(new Error(message), {code});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The carried Core alone, for a caller that already looked for the project's
|
|
97
|
+
* Core its own way: the folder, or null when the copy answering in `startDir`
|
|
98
|
+
* is the project's own CLI or carries none.
|
|
99
|
+
* @param {string} startDir
|
|
100
|
+
* @param {{fetch?: boolean}} [options]
|
|
101
|
+
* @returns {string | null}
|
|
102
|
+
*/
|
|
103
|
+
export function findCarriedCoreDir(startDir, {fetch = false} = {}) {
|
|
104
|
+
return carriedCoreFor(startDir, fetch).dir;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* The carried Core for a run in `startDir`, when the copy answering there is
|
|
109
|
+
* not the project's own CLI.
|
|
110
|
+
* @param {string} startDir
|
|
111
|
+
* @param {boolean} [fetch]
|
|
112
|
+
* @returns {{dir: string | null, unavailable: string | null, version?: string, reason?: string}}
|
|
113
|
+
*/
|
|
114
|
+
function carriedCoreFor(startDir, fetch = false) {
|
|
115
|
+
const carried = carriedCore({fetch: false});
|
|
116
|
+
if (!carried.dir && !fetch) return carried;
|
|
117
|
+
if (runChoice(startDir).copy === 'project') {
|
|
118
|
+
return {dir: null, unavailable: null};
|
|
119
|
+
}
|
|
120
|
+
return carried.dir ? carried : carriedCore({fetch: true});
|
|
121
|
+
}
|
|
122
|
+
|
|
20
123
|
/**
|
|
21
124
|
* Find packages/core directory by walking up from startDir.
|
|
22
125
|
* Also checks node_modules/@astryxdesign/core for installed usage.
|
|
126
|
+
*
|
|
127
|
+
* The project's Core only: in the folder or four above it, the reach every
|
|
128
|
+
* released version used, else from the folder of the package.json that makes
|
|
129
|
+
* the folder part of a project, however deep the folder is.
|
|
130
|
+
*
|
|
131
|
+
* @param {string} [startDir]
|
|
132
|
+
* @returns {string | null}
|
|
23
133
|
*/
|
|
24
|
-
export function
|
|
134
|
+
export function findProjectCoreDir(startDir = process.cwd()) {
|
|
135
|
+
const near = findNearbyCoreDir(startDir);
|
|
136
|
+
if (near) return near;
|
|
137
|
+
// A folder deeper than that reach still belongs to the project the walk to
|
|
138
|
+
// its package.json finds, so its Core is looked up from there too (spec
|
|
139
|
+
// AST-081, a folder's project): never the carried Core in its place.
|
|
140
|
+
const declaring = findDeclaringPackage(startDir);
|
|
141
|
+
return declaring && declaring.dir !== path.resolve(startDir)
|
|
142
|
+
? findNearbyCoreDir(declaring.dir)
|
|
143
|
+
: null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* The Core installed in `startDir` or one of the four folders above it.
|
|
148
|
+
* @param {string} startDir
|
|
149
|
+
* @returns {string | null}
|
|
150
|
+
*/
|
|
151
|
+
function findNearbyCoreDir(startDir) {
|
|
25
152
|
let dir = startDir;
|
|
26
153
|
|
|
27
154
|
for (let i = 0; i < 5; i++) {
|
|
@@ -153,7 +280,7 @@ export function discoverExternalPackages(startDir = process.cwd()) {
|
|
|
153
280
|
if (!nodeModulesDir) return externals;
|
|
154
281
|
|
|
155
282
|
/** @param {string} searchDir */
|
|
156
|
-
const scanDir =
|
|
283
|
+
const scanDir = searchDir => {
|
|
157
284
|
if (!fs.existsSync(searchDir)) return;
|
|
158
285
|
const entries = fs.readdirSync(searchDir, {withFileTypes: true});
|
|
159
286
|
|
|
@@ -236,7 +363,8 @@ export function existsCaseExact(targetPath, rootDir) {
|
|
|
236
363
|
|
|
237
364
|
const rel = path.relative(rootDir, targetPath);
|
|
238
365
|
if (rel === '') return true;
|
|
239
|
-
if (path.isAbsolute(rel) || rel === '..' || rel.startsWith(`..${path.sep}`))
|
|
366
|
+
if (path.isAbsolute(rel) || rel === '..' || rel.startsWith(`..${path.sep}`))
|
|
367
|
+
return false;
|
|
240
368
|
|
|
241
369
|
let dir = rootDir;
|
|
242
370
|
for (const segment of rel.split(path.sep)) {
|
|
@@ -4,7 +4,9 @@ import {describe, it, expect, beforeEach, afterEach} from 'vitest';
|
|
|
4
4
|
import * as fs from 'node:fs';
|
|
5
5
|
import * as path from 'node:path';
|
|
6
6
|
import * as os from 'node:os';
|
|
7
|
-
import {findCoreDir, findProjectRoot, listComponents, discoverExternalPackages, existsCaseExact, findInstalledPackage} from './paths.mjs';
|
|
7
|
+
import {findCoreDir, findProjectCoreDir, findProjectRoot, listComponents, discoverExternalPackages, existsCaseExact, findInstalledPackage} from './paths.mjs';
|
|
8
|
+
import {CLI_ROOT} from './paths.mjs';
|
|
9
|
+
import {linkThisCliAsProjectCli} from '../../test-utils/release-fixtures.mjs';
|
|
8
10
|
|
|
9
11
|
let tmpDir;
|
|
10
12
|
|
|
@@ -39,6 +41,13 @@ describe('findCoreDir', () => {
|
|
|
39
41
|
});
|
|
40
42
|
|
|
41
43
|
it('returns null when nothing found', () => {
|
|
44
|
+
expect(findProjectCoreDir(tmpDir)).toBeNull();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('falls back to the carried Core outside a project, and only there', () => {
|
|
48
|
+
// This copy's carried Core is the workspace Core beside it.
|
|
49
|
+
expect(findCoreDir(tmpDir)).toBe(path.resolve(CLI_ROOT, '..', 'core'));
|
|
50
|
+
linkThisCliAsProjectCli(tmpDir);
|
|
42
51
|
expect(findCoreDir(tmpDir)).toBeNull();
|
|
43
52
|
});
|
|
44
53
|
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// @generated by scripts/sync-api-types.mjs from the JSDoc in foundation/**/*.mjs.
|
|
2
|
+
// DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The install root of the CLI package at `cliRoot`, or null when it has none
|
|
6
|
+
* that counts: it is not installed in a `node_modules` folder, or it lives in
|
|
7
|
+
* a package runner's temporary install or the per-user release cache.
|
|
8
|
+
* @param {string} cliRoot
|
|
9
|
+
* @param {{cacheDir?: string}} [options]
|
|
10
|
+
* @returns {string | null}
|
|
11
|
+
*/
|
|
12
|
+
export function computerInstallRoot(cliRoot: string, options?: {
|
|
13
|
+
cacheDir?: string;
|
|
14
|
+
}): string | null;
|
|
15
|
+
/**
|
|
16
|
+
* Every install root that holds packages installed with the CLI at
|
|
17
|
+
* `cliRoot`. Usually one: its install root. pnpm 11 and later install each
|
|
18
|
+
* global package in a folder of its own, `<pnpm home>/global/v<N>/<id>`, with
|
|
19
|
+
* its files in `<pnpm home>/store/v<N>/links` or inside that folder, so every
|
|
20
|
+
* such global folder counts, provided one of them installs this CLI.
|
|
21
|
+
* @param {string} cliRoot
|
|
22
|
+
* @param {{cacheDir?: string}} [options]
|
|
23
|
+
* @returns {string[]}
|
|
24
|
+
*/
|
|
25
|
+
export function computerInstallRoots(cliRoot: string, options?: {
|
|
26
|
+
cacheDir?: string;
|
|
27
|
+
}): string[];
|
|
28
|
+
/**
|
|
29
|
+
* Why `pkg`'s peer ranges exclude `release`, or null when they admit it.
|
|
30
|
+
* @param {Record<string, any>} pkg
|
|
31
|
+
* @param {string} release the answering release's version
|
|
32
|
+
* @returns {string | null}
|
|
33
|
+
*/
|
|
34
|
+
export function peerProblem(pkg: Record<string, any>, release: string): string | null;
|
|
35
|
+
/**
|
|
36
|
+
* The computer-level integrations installed beside the CLI at `cliRoot`, in
|
|
37
|
+
* name order (declaration order when the root declares them). Reads
|
|
38
|
+
* package.json files only.
|
|
39
|
+
* @param {{cliRoot: string, release: string, cacheDir?: string}} options
|
|
40
|
+
* @returns {ComputerIntegrationCandidate[]}
|
|
41
|
+
*/
|
|
42
|
+
export function scanComputerIntegrations({ cliRoot, release, cacheDir }: {
|
|
43
|
+
cliRoot: string;
|
|
44
|
+
release: string;
|
|
45
|
+
cacheDir?: string;
|
|
46
|
+
}): ComputerIntegrationCandidate[];
|
|
47
|
+
/**
|
|
48
|
+
* Load the compatible computer-level integrations as provider candidates,
|
|
49
|
+
* each in isolation, under the autolinked policy (a broken one is recorded
|
|
50
|
+
* and contributes nothing; the same package reached twice loads once). Each
|
|
51
|
+
* loaded record is marked `__computer`. An incompatible one is not loaded.
|
|
52
|
+
* @param {ComputerIntegrationCandidate[]} candidates
|
|
53
|
+
* @param {{fresh?: boolean, exclude?: Iterable<string>}} [options] `exclude`
|
|
54
|
+
* names packages the folder already loads, which keep their own copy
|
|
55
|
+
* @returns {Promise<import('./provider-resolution.mjs').ProviderCandidate[]>}
|
|
56
|
+
*/
|
|
57
|
+
export function loadComputerIntegrations(candidates: ComputerIntegrationCandidate[], options?: {
|
|
58
|
+
fresh?: boolean;
|
|
59
|
+
exclude?: Iterable<string>;
|
|
60
|
+
}): Promise<import("./provider-resolution.mjs").ProviderCandidate[]>;
|
|
61
|
+
export type ComputerIntegrationCandidate = {
|
|
62
|
+
/**
|
|
63
|
+
* the package name
|
|
64
|
+
*/
|
|
65
|
+
name: string;
|
|
66
|
+
version: string | undefined;
|
|
67
|
+
description: string | undefined;
|
|
68
|
+
packageDir: string;
|
|
69
|
+
/**
|
|
70
|
+
* the folder whose node_modules holds it
|
|
71
|
+
*/
|
|
72
|
+
hostDir: string;
|
|
73
|
+
/**
|
|
74
|
+
* why its peer ranges exclude the
|
|
75
|
+
* answering release, or null
|
|
76
|
+
*/
|
|
77
|
+
incompatible: string | null;
|
|
78
|
+
};
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Computer-level integrations (spec AST-081 FR12): the integration
|
|
5
|
+
* packages installed in the same install root as the running copy of the CLI,
|
|
6
|
+
* such as a package manager's global folder beside a global copy, or the
|
|
7
|
+
* package set a door installs together.
|
|
8
|
+
*
|
|
9
|
+
* - The install root is the folder whose `node_modules` holds the running
|
|
10
|
+
* CLI package (above pnpm's `.pnpm` store). pnpm 11 and later give each
|
|
11
|
+
* global package a folder of its own, and every one of them counts. A
|
|
12
|
+
* package runner's temporary install and the per-user release cache are not
|
|
13
|
+
* install roots: they hold what one run asked for.
|
|
14
|
+
* - When the root has a package.json, its declared dependencies are read, as
|
|
15
|
+
* autolink reads a project's; otherwise (npm's global folder) every package
|
|
16
|
+
* directly in its `node_modules`, scoped ones included. Either way, only a
|
|
17
|
+
* package with exactly one root `astryx.integration.*` manifest counts, and
|
|
18
|
+
* the CLI and Core packages never do.
|
|
19
|
+
* - Outside a project they load as a project's integrations do (Project.load).
|
|
20
|
+
* One whose declared `@astryxdesign/core` or `@astryxdesign/cli` peer range
|
|
21
|
+
* excludes the answering release is skipped, and doctor says why.
|
|
22
|
+
* - Inside a project none load; discover lists the ones the project does not
|
|
23
|
+
* install as available, and doctor names them.
|
|
24
|
+
*
|
|
25
|
+
* Listing reads package.json files only; nothing is imported until a load.
|
|
26
|
+
*
|
|
27
|
+
* @input the running CLI package's folder
|
|
28
|
+
* @output the computer-level integration candidates, and their loaded records
|
|
29
|
+
* @position foundation/integrations — read by config/project, discover, and
|
|
30
|
+
* doctor.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import * as fs from 'node:fs';
|
|
34
|
+
import * as path from 'node:path';
|
|
35
|
+
import {findManifestPaths, loadIntegrations} from './integrations.mjs';
|
|
36
|
+
import {
|
|
37
|
+
readDeclaredDependencies,
|
|
38
|
+
resolveInstalledPackageDir,
|
|
39
|
+
} from './autolink.mjs';
|
|
40
|
+
import {installPlaceOf} from '../release/choose.mjs';
|
|
41
|
+
import {isInReleaseCache} from '../release/cache.mjs';
|
|
42
|
+
import {satisfiesRange} from '../env/semver.mjs';
|
|
43
|
+
|
|
44
|
+
/** Packages that are the CLI itself, never an integration of it. */
|
|
45
|
+
const NOT_INTEGRATIONS = new Set(['@astryxdesign/cli', '@astryxdesign/core']);
|
|
46
|
+
|
|
47
|
+
/** Peers whose ranges must admit the answering release. */
|
|
48
|
+
const RELEASE_PEERS = ['@astryxdesign/core', '@astryxdesign/cli'];
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @typedef {object} ComputerIntegrationCandidate
|
|
52
|
+
* @property {string} name the package name
|
|
53
|
+
* @property {string | undefined} version
|
|
54
|
+
* @property {string | undefined} description
|
|
55
|
+
* @property {string} packageDir
|
|
56
|
+
* @property {string} hostDir the folder whose node_modules holds it
|
|
57
|
+
* @property {string | null} incompatible why its peer ranges exclude the
|
|
58
|
+
* answering release, or null
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @param {string} p
|
|
63
|
+
* @returns {string}
|
|
64
|
+
*/
|
|
65
|
+
function real(p) {
|
|
66
|
+
try {
|
|
67
|
+
return fs.realpathSync(p);
|
|
68
|
+
} catch {
|
|
69
|
+
return path.resolve(p);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @param {string} dir
|
|
75
|
+
* @returns {Record<string, any> | null}
|
|
76
|
+
*/
|
|
77
|
+
function readPackage(dir) {
|
|
78
|
+
try {
|
|
79
|
+
const pkg = JSON.parse(
|
|
80
|
+
fs.readFileSync(path.join(dir, 'package.json'), 'utf8'),
|
|
81
|
+
);
|
|
82
|
+
return pkg && typeof pkg === 'object' ? pkg : null;
|
|
83
|
+
} catch {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The install root of the CLI package at `cliRoot`, or null when it has none
|
|
90
|
+
* that counts: it is not installed in a `node_modules` folder, or it lives in
|
|
91
|
+
* a package runner's temporary install or the per-user release cache.
|
|
92
|
+
* @param {string} cliRoot
|
|
93
|
+
* @param {{cacheDir?: string}} [options]
|
|
94
|
+
* @returns {string | null}
|
|
95
|
+
*/
|
|
96
|
+
export function computerInstallRoot(cliRoot, options = {}) {
|
|
97
|
+
const root = real(cliRoot);
|
|
98
|
+
const place = installPlaceOf(root);
|
|
99
|
+
if (place.runner || !place.owner) return null;
|
|
100
|
+
if (isInReleaseCache(root, options.cacheDir)) return null;
|
|
101
|
+
return place.owner;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Every install root that holds packages installed with the CLI at
|
|
106
|
+
* `cliRoot`. Usually one: its install root. pnpm 11 and later install each
|
|
107
|
+
* global package in a folder of its own, `<pnpm home>/global/v<N>/<id>`, with
|
|
108
|
+
* its files in `<pnpm home>/store/v<N>/links` or inside that folder, so every
|
|
109
|
+
* such global folder counts, provided one of them installs this CLI.
|
|
110
|
+
* @param {string} cliRoot
|
|
111
|
+
* @param {{cacheDir?: string}} [options]
|
|
112
|
+
* @returns {string[]}
|
|
113
|
+
*/
|
|
114
|
+
export function computerInstallRoots(cliRoot, options = {}) {
|
|
115
|
+
const fromPnpm = pnpmGlobalFolders(real(cliRoot));
|
|
116
|
+
if (fromPnpm.length > 0) return fromPnpm;
|
|
117
|
+
const root = computerInstallRoot(cliRoot, options);
|
|
118
|
+
return root ? [root] : [];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* pnpm's global folders for a CLI installed globally by pnpm 11 or later, or
|
|
123
|
+
* none. Its files are either in pnpm's store (`<home>/store/v<N>/links/...`,
|
|
124
|
+
* with the global virtual store) or inside its own global folder
|
|
125
|
+
* (`<home>/global/v<N>/<id>/node_modules/...`, without it).
|
|
126
|
+
* @param {string} cli the CLI package's real path
|
|
127
|
+
* @returns {string[]}
|
|
128
|
+
*/
|
|
129
|
+
function pnpmGlobalFolders(cli) {
|
|
130
|
+
const parts = cli.split(/[\\/]/);
|
|
131
|
+
/** @type {string | null} */
|
|
132
|
+
let globalDir = null;
|
|
133
|
+
const storeAt = parts.lastIndexOf('store');
|
|
134
|
+
if (
|
|
135
|
+
storeAt > 0 &&
|
|
136
|
+
/^v\d+$/.test(parts[storeAt + 1] ?? '') &&
|
|
137
|
+
parts[storeAt + 2] === 'links'
|
|
138
|
+
) {
|
|
139
|
+
const home = parts.slice(0, storeAt).join(path.sep) || path.sep;
|
|
140
|
+
globalDir = path.join(home, 'global', parts[storeAt + 1]);
|
|
141
|
+
} else {
|
|
142
|
+
const at = parts.findIndex(
|
|
143
|
+
(part, k) =>
|
|
144
|
+
part === 'global' &&
|
|
145
|
+
/^v\d+$/.test(parts[k + 1] ?? '') &&
|
|
146
|
+
parts[k + 3] === 'node_modules',
|
|
147
|
+
);
|
|
148
|
+
if (at > 0) globalDir = parts.slice(0, at + 2).join(path.sep) || path.sep;
|
|
149
|
+
}
|
|
150
|
+
if (globalDir == null) return [];
|
|
151
|
+
/** @type {string[]} */
|
|
152
|
+
let names;
|
|
153
|
+
try {
|
|
154
|
+
names = fs.readdirSync(globalDir).sort();
|
|
155
|
+
} catch {
|
|
156
|
+
return [];
|
|
157
|
+
}
|
|
158
|
+
const folders = names
|
|
159
|
+
.map(name => path.join(globalDir, name))
|
|
160
|
+
.filter(dir => fs.existsSync(path.join(dir, 'package.json')));
|
|
161
|
+
const installsThisCli = folders.some(
|
|
162
|
+
dir => real(path.join(dir, 'node_modules', '@astryxdesign', 'cli')) === cli,
|
|
163
|
+
);
|
|
164
|
+
return installsThisCli ? folders : [];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Every package name directly in `<root>/node_modules`, scoped ones included.
|
|
169
|
+
* @param {string} root
|
|
170
|
+
* @returns {string[]}
|
|
171
|
+
*/
|
|
172
|
+
function installedNames(root) {
|
|
173
|
+
const modules = path.join(root, 'node_modules');
|
|
174
|
+
/** @type {string[]} */
|
|
175
|
+
const names = [];
|
|
176
|
+
/** @type {fs.Dirent[]} */
|
|
177
|
+
let entries;
|
|
178
|
+
try {
|
|
179
|
+
entries = fs.readdirSync(modules, {withFileTypes: true});
|
|
180
|
+
} catch {
|
|
181
|
+
return names;
|
|
182
|
+
}
|
|
183
|
+
for (const entry of entries) {
|
|
184
|
+
if (entry.name.startsWith('.')) continue;
|
|
185
|
+
if (entry.name.startsWith('@')) {
|
|
186
|
+
try {
|
|
187
|
+
for (const scoped of fs.readdirSync(path.join(modules, entry.name))) {
|
|
188
|
+
if (!scoped.startsWith('.')) names.push(`${entry.name}/${scoped}`);
|
|
189
|
+
}
|
|
190
|
+
} catch {
|
|
191
|
+
// An unreadable scope folder holds nothing to read.
|
|
192
|
+
}
|
|
193
|
+
} else {
|
|
194
|
+
names.push(entry.name);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return names.sort();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Why `pkg`'s peer ranges exclude `release`, or null when they admit it.
|
|
202
|
+
* @param {Record<string, any>} pkg
|
|
203
|
+
* @param {string} release the answering release's version
|
|
204
|
+
* @returns {string | null}
|
|
205
|
+
*/
|
|
206
|
+
export function peerProblem(pkg, release) {
|
|
207
|
+
const peers = pkg.peerDependencies;
|
|
208
|
+
if (!peers || typeof peers !== 'object') return null;
|
|
209
|
+
for (const peer of RELEASE_PEERS) {
|
|
210
|
+
const range = peers[peer];
|
|
211
|
+
if (typeof range !== 'string') continue;
|
|
212
|
+
let admits;
|
|
213
|
+
try {
|
|
214
|
+
admits = satisfiesRange(release, range);
|
|
215
|
+
} catch {
|
|
216
|
+
// A range this CLI cannot read never keeps the integration out.
|
|
217
|
+
admits = true;
|
|
218
|
+
}
|
|
219
|
+
if (!admits) {
|
|
220
|
+
return `it needs ${peer} ${range}, and this computer's CLI is ${release}`;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* The computer-level integrations installed beside the CLI at `cliRoot`, in
|
|
228
|
+
* name order (declaration order when the root declares them). Reads
|
|
229
|
+
* package.json files only.
|
|
230
|
+
* @param {{cliRoot: string, release: string, cacheDir?: string}} options
|
|
231
|
+
* @returns {ComputerIntegrationCandidate[]}
|
|
232
|
+
*/
|
|
233
|
+
export function scanComputerIntegrations({cliRoot, release, cacheDir}) {
|
|
234
|
+
const self = real(cliRoot);
|
|
235
|
+
/** @type {ComputerIntegrationCandidate[]} */
|
|
236
|
+
const found = [];
|
|
237
|
+
const seen = new Set();
|
|
238
|
+
for (const root of computerInstallRoots(cliRoot, {cacheDir})) {
|
|
239
|
+
scanRoot(root, {self, release, found, seen});
|
|
240
|
+
}
|
|
241
|
+
return found;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Add the integrations installed in one install root.
|
|
246
|
+
* @param {string} root
|
|
247
|
+
* @param {{self: string, release: string, found: ComputerIntegrationCandidate[], seen: Set<string>}} into
|
|
248
|
+
*/
|
|
249
|
+
function scanRoot(root, {self, release, found, seen}) {
|
|
250
|
+
const declared = readPackage(root)
|
|
251
|
+
? readDeclaredDependencies(root).map(d => d.name)
|
|
252
|
+
: installedNames(root);
|
|
253
|
+
for (const name of declared) {
|
|
254
|
+
if (NOT_INTEGRATIONS.has(name)) continue;
|
|
255
|
+
const resolved = resolveInstalledPackageDir(name, root);
|
|
256
|
+
if (!resolved) continue;
|
|
257
|
+
const identity = real(resolved.packageDir);
|
|
258
|
+
if (identity === self || seen.has(identity)) continue;
|
|
259
|
+
if (findManifestPaths(resolved.packageDir).length !== 1) continue;
|
|
260
|
+
const pkg = readPackage(resolved.packageDir);
|
|
261
|
+
if (!pkg || typeof pkg.name !== 'string') continue;
|
|
262
|
+
if (NOT_INTEGRATIONS.has(pkg.name)) continue;
|
|
263
|
+
seen.add(identity);
|
|
264
|
+
found.push({
|
|
265
|
+
name: pkg.name,
|
|
266
|
+
version: typeof pkg.version === 'string' ? pkg.version : undefined,
|
|
267
|
+
description:
|
|
268
|
+
typeof pkg.description === 'string' ? pkg.description : undefined,
|
|
269
|
+
packageDir: resolved.packageDir,
|
|
270
|
+
hostDir: resolved.hostDir,
|
|
271
|
+
incompatible: peerProblem(pkg, release),
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Load the compatible computer-level integrations as provider candidates,
|
|
278
|
+
* each in isolation, under the autolinked policy (a broken one is recorded
|
|
279
|
+
* and contributes nothing; the same package reached twice loads once). Each
|
|
280
|
+
* loaded record is marked `__computer`. An incompatible one is not loaded.
|
|
281
|
+
* @param {ComputerIntegrationCandidate[]} candidates
|
|
282
|
+
* @param {{fresh?: boolean, exclude?: Iterable<string>}} [options] `exclude`
|
|
283
|
+
* names packages the folder already loads, which keep their own copy
|
|
284
|
+
* @returns {Promise<import('./provider-resolution.mjs').ProviderCandidate[]>}
|
|
285
|
+
*/
|
|
286
|
+
export async function loadComputerIntegrations(candidates, options = {}) {
|
|
287
|
+
const {fresh = false, exclude = []} = options;
|
|
288
|
+
const taken = new Set(exclude);
|
|
289
|
+
/** @type {import('./provider-resolution.mjs').ProviderCandidate[]} */
|
|
290
|
+
const loaded = [];
|
|
291
|
+
for (const candidate of candidates) {
|
|
292
|
+
if (candidate.incompatible || taken.has(candidate.name)) continue;
|
|
293
|
+
try {
|
|
294
|
+
const [integration] = await loadIntegrations([candidate.name], {
|
|
295
|
+
cwd: candidate.hostDir,
|
|
296
|
+
fresh,
|
|
297
|
+
});
|
|
298
|
+
loaded.push({
|
|
299
|
+
source: 'autolinked',
|
|
300
|
+
spec: candidate.name,
|
|
301
|
+
packageDir: candidate.packageDir,
|
|
302
|
+
...(integration == null
|
|
303
|
+
? {}
|
|
304
|
+
: {integration: {...integration, __computer: true}}),
|
|
305
|
+
});
|
|
306
|
+
} catch (error) {
|
|
307
|
+
loaded.push({
|
|
308
|
+
source: 'autolinked',
|
|
309
|
+
spec: candidate.name,
|
|
310
|
+
packageDir: candidate.packageDir,
|
|
311
|
+
error: error instanceof Error ? error.message : String(error),
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return loaded;
|
|
316
|
+
}
|