@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
|
@@ -0,0 +1,677 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Which release answers a run (spec AST-081 FR2, FR3, FR6, FR9).
|
|
5
|
+
*
|
|
6
|
+
* As released, the project decides who answers (DEC-10):
|
|
7
|
+
*
|
|
8
|
+
* - **In a project that installs its own CLI**, that CLI answers, whatever its
|
|
9
|
+
* version: every other copy hands the run to it, `astryx upgrade` included.
|
|
10
|
+
* - **In a project with no CLI of its own** (only Core, or nothing installed
|
|
11
|
+
* yet), the copy that started the run answers, as it always has; a hint,
|
|
12
|
+
* once a day, names the command that adds the CLI at Core's version
|
|
13
|
+
* (notices.mjs).
|
|
14
|
+
* - **When the project's own CLI cannot start**, the release equal to the
|
|
15
|
+
* project's Core answers (the matched release): the copy that started the
|
|
16
|
+
* run when it is that release, else the release in the per-user cache,
|
|
17
|
+
* installed first. When it cannot be obtained, the copy that started the
|
|
18
|
+
* run answers, announced (handoff.mjs).
|
|
19
|
+
* - **Outside a project**, every copy answers itself, the global copy
|
|
20
|
+
* included; a newer release is announced, never installed (notices.mjs).
|
|
21
|
+
*
|
|
22
|
+
* Core deciding over the project's own CLI, and the matched release for a
|
|
23
|
+
* project with only Core, are the next minor release's change.
|
|
24
|
+
*
|
|
25
|
+
* A copy never hands a run to itself, so a run is handed off at most once:
|
|
26
|
+
* the copy it reaches makes the same choice and finds itself.
|
|
27
|
+
*
|
|
28
|
+
* @input the folder, the running copy
|
|
29
|
+
* @output a {@link ReleaseChoice}
|
|
30
|
+
* @position foundation/release — called once per run by handoff.mjs.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import * as fs from 'node:fs';
|
|
34
|
+
import * as os from 'node:os';
|
|
35
|
+
import * as path from 'node:path';
|
|
36
|
+
import {
|
|
37
|
+
readReleaseFacts,
|
|
38
|
+
readJson,
|
|
39
|
+
CORE_PACKAGE_NAME,
|
|
40
|
+
CLI_PACKAGE_NAME,
|
|
41
|
+
} from './project.mjs';
|
|
42
|
+
import {
|
|
43
|
+
cliBinOf,
|
|
44
|
+
isInReleaseCache,
|
|
45
|
+
isReleaseVersion,
|
|
46
|
+
resolvePublishedVersion,
|
|
47
|
+
userCacheDir,
|
|
48
|
+
} from './cache.mjs';
|
|
49
|
+
import {relativeWithin, samePath} from '../fs/path-compare.mjs';
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The copy that is running.
|
|
53
|
+
* @typedef {object} RunningCopy
|
|
54
|
+
* @property {string} version its package version
|
|
55
|
+
* @property {string} root its package folder
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Who answers the run.
|
|
60
|
+
* @typedef {object} ReleaseChoice
|
|
61
|
+
* @property {'project' | 'starting' | 'matched' | 'carried' | 'fallback'} copy
|
|
62
|
+
* the kind of copy that answers (`meta.answeredBy.copy`): `project`, the
|
|
63
|
+
* project's own CLI; `starting`, the copy that started the run, in a project
|
|
64
|
+
* with no CLI of its own; `matched`, the release equal to the project's
|
|
65
|
+
* Core, when the project's own CLI cannot start; `carried`, outside a
|
|
66
|
+
* project; `fallback`, the copy that started the run when the matched
|
|
67
|
+
* release could not be obtained (spec AST-081 FR2, FR5)
|
|
68
|
+
* @property {'self' | 'project-cli' | 'release'} answer `self`: this copy;
|
|
69
|
+
* `project-cli`: hand off to the project's CLI; `release`: hand off to the
|
|
70
|
+
* cached release `version`
|
|
71
|
+
* @property {string} version the release that answers
|
|
72
|
+
* @property {string | null} bin the entry file to hand off to (`project-cli`
|
|
73
|
+
* and a cached `release` that is already installed)
|
|
74
|
+
* @property {string | null} coreVersion the Core the answering release pairs
|
|
75
|
+
* with, when known now
|
|
76
|
+
* @property {boolean} inProject
|
|
77
|
+
* @property {string | null} unavailable why the release cannot answer, when it
|
|
78
|
+
* cannot
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @param {string} p
|
|
83
|
+
* @returns {string}
|
|
84
|
+
*/
|
|
85
|
+
function real(p) {
|
|
86
|
+
try {
|
|
87
|
+
return fs.realpathSync(p);
|
|
88
|
+
} catch {
|
|
89
|
+
return path.resolve(p);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Folder-name patterns of package-manager global installs that hold a package.json. */
|
|
94
|
+
const GLOBAL_OWNER_PATTERNS = [
|
|
95
|
+
// pnpm: `<pnpm home>/global/5` before pnpm 10, `<pnpm home>/global/v11/<id>` since.
|
|
96
|
+
/[\\/]global[\\/]v?\d+(?:[\\/][^\\/]+)?$/,
|
|
97
|
+
// Yarn 1: `~/.config/yarn/global`, or `%LOCALAPPDATA%\Yarn\Data\global` on Windows.
|
|
98
|
+
/[\\/]yarn[\\/](?:data[\\/])?global$/i,
|
|
99
|
+
// Bun: `<BUN_INSTALL>/install/global`, `~/.bun/install/global` by default.
|
|
100
|
+
/[\\/]install[\\/]global$/i,
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Where a global install's settings come from: the home folder, the
|
|
105
|
+
* environment, and the platform. Defaults to this process's.
|
|
106
|
+
* @typedef {{home?: string, env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform}} GlobalWhere
|
|
107
|
+
*/
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The value a line `<key> <value>` or `<key>=<value>` sets in a package
|
|
111
|
+
* manager's settings file (`.yarnrc`, `.npmrc`, `bunfig.toml`), unquoted, or
|
|
112
|
+
* null.
|
|
113
|
+
* @param {string} file
|
|
114
|
+
* @param {string} key
|
|
115
|
+
* @returns {string | null}
|
|
116
|
+
*/
|
|
117
|
+
function settingIn(file, key) {
|
|
118
|
+
let text;
|
|
119
|
+
try {
|
|
120
|
+
text = fs.readFileSync(file, 'utf8');
|
|
121
|
+
} catch {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
const escaped = key.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
125
|
+
const match = new RegExp(
|
|
126
|
+
`^\\s*${escaped}\\s*(?:=|\\s)\\s*(.+?)\\s*$`,
|
|
127
|
+
'mu',
|
|
128
|
+
).exec(text);
|
|
129
|
+
if (!match) return null;
|
|
130
|
+
return match[1].replace(/^(["'])(.*)\1$/u, '$2');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* An absolute folder from a setting, with `~` for the home folder; null for a
|
|
135
|
+
* relative or empty one.
|
|
136
|
+
* @param {string | null | undefined} value
|
|
137
|
+
* @param {string} home
|
|
138
|
+
* @param {NodeJS.Platform} platform
|
|
139
|
+
* @returns {string | null}
|
|
140
|
+
*/
|
|
141
|
+
function absoluteFolder(value, home, platform) {
|
|
142
|
+
if (!value) return null;
|
|
143
|
+
const paths = platform === 'win32' ? path.win32 : path.posix;
|
|
144
|
+
const expanded = value.startsWith('~')
|
|
145
|
+
? paths.join(home, value.slice(1))
|
|
146
|
+
: value;
|
|
147
|
+
return paths.isAbsolute(expanded) ? paths.normalize(expanded) : null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* The global folders the package managers' own settings name on this
|
|
152
|
+
* computer, read the way each package manager reads them, never guessed from
|
|
153
|
+
* a folder's layout:
|
|
154
|
+
* - Bun: `$BUN_INSTALL/install/global`, else `~/.bun/install/global`, and a
|
|
155
|
+
* `globalDir` in `~/.bunfig.toml` or `$XDG_CONFIG_HOME/.bunfig.toml`.
|
|
156
|
+
* - Yarn 1: the `global-folder` setting (`YARN_GLOBAL_FOLDER`,
|
|
157
|
+
* `npm_config_global_folder`, or `global-folder` in `~/.yarnrc`), else
|
|
158
|
+
* `<data folder>/global`: `%LOCALAPPDATA%\Yarn\Data` on Windows,
|
|
159
|
+
* `$XDG_DATA_HOME/yarn`, else `~/.config/yarn`.
|
|
160
|
+
* - pnpm: `<PNPM_HOME>/global`, else `<data folder>/global` (`$XDG_DATA_HOME/pnpm`,
|
|
161
|
+
* else `%LOCALAPPDATA%\pnpm`, `~/Library/pnpm`, or `~/.local/share/pnpm`), and a
|
|
162
|
+
* `global-dir` in `~/.npmrc` or pnpm's `rc` file; a global install is a
|
|
163
|
+
* numbered folder below it.
|
|
164
|
+
* @param {GlobalWhere} [where]
|
|
165
|
+
* @returns {Array<{manager: 'bun' | 'yarn' | 'pnpm', folder: string}>}
|
|
166
|
+
*/
|
|
167
|
+
export function configuredGlobalFolders(where = {}) {
|
|
168
|
+
const {
|
|
169
|
+
home = os.homedir(),
|
|
170
|
+
env = process.env,
|
|
171
|
+
platform = process.platform,
|
|
172
|
+
} = where;
|
|
173
|
+
const paths = platform === 'win32' ? path.win32 : path.posix;
|
|
174
|
+
const abs = (/** @type {string | null | undefined} */ value) =>
|
|
175
|
+
absoluteFolder(value, home, platform);
|
|
176
|
+
const xdgConfig = abs(env.XDG_CONFIG_HOME) ?? paths.join(home, '.config');
|
|
177
|
+
const xdgData = abs(env.XDG_DATA_HOME);
|
|
178
|
+
const localAppData =
|
|
179
|
+
abs(env.LOCALAPPDATA) ?? paths.join(home, 'AppData', 'Local');
|
|
180
|
+
/** @type {Array<{manager: 'bun' | 'yarn' | 'pnpm', folder: string}>} */
|
|
181
|
+
const out = [];
|
|
182
|
+
// Bun
|
|
183
|
+
out.push({
|
|
184
|
+
manager: 'bun',
|
|
185
|
+
folder: paths.join(
|
|
186
|
+
abs(env.BUN_INSTALL) ?? paths.join(home, '.bun'),
|
|
187
|
+
'install',
|
|
188
|
+
'global',
|
|
189
|
+
),
|
|
190
|
+
});
|
|
191
|
+
for (const file of [
|
|
192
|
+
paths.join(home, '.bunfig.toml'),
|
|
193
|
+
paths.join(xdgConfig, '.bunfig.toml'),
|
|
194
|
+
]) {
|
|
195
|
+
const dir = abs(settingIn(file, 'globalDir'));
|
|
196
|
+
if (dir) out.push({manager: 'bun', folder: dir});
|
|
197
|
+
}
|
|
198
|
+
// Yarn 1
|
|
199
|
+
const yarnSetting =
|
|
200
|
+
abs(env.YARN_GLOBAL_FOLDER) ??
|
|
201
|
+
abs(env.npm_config_global_folder) ??
|
|
202
|
+
abs(settingIn(paths.join(home, '.yarnrc'), 'global-folder'));
|
|
203
|
+
const yarnData =
|
|
204
|
+
platform === 'win32'
|
|
205
|
+
? paths.join(localAppData, 'Yarn', 'Data')
|
|
206
|
+
: xdgData
|
|
207
|
+
? paths.join(xdgData, 'yarn')
|
|
208
|
+
: paths.join(home, '.config', 'yarn');
|
|
209
|
+
out.push({
|
|
210
|
+
manager: 'yarn',
|
|
211
|
+
folder: yarnSetting ?? paths.join(yarnData, 'global'),
|
|
212
|
+
});
|
|
213
|
+
// pnpm
|
|
214
|
+
// pnpm's data folder: PNPM_HOME, else $XDG_DATA_HOME/pnpm on any platform,
|
|
215
|
+
// else the platform's own.
|
|
216
|
+
const pnpmHome =
|
|
217
|
+
abs(env.PNPM_HOME) ??
|
|
218
|
+
(xdgData
|
|
219
|
+
? paths.join(xdgData, 'pnpm')
|
|
220
|
+
: platform === 'win32'
|
|
221
|
+
? paths.join(localAppData, 'pnpm')
|
|
222
|
+
: platform === 'darwin'
|
|
223
|
+
? paths.join(home, 'Library', 'pnpm')
|
|
224
|
+
: paths.join(home, '.local', 'share', 'pnpm'));
|
|
225
|
+
out.push({manager: 'pnpm', folder: paths.join(pnpmHome, 'global')});
|
|
226
|
+
for (const file of [
|
|
227
|
+
paths.join(home, '.npmrc'),
|
|
228
|
+
paths.join(xdgConfig, 'pnpm', 'rc'),
|
|
229
|
+
]) {
|
|
230
|
+
const dir = abs(settingIn(file, 'global-dir'));
|
|
231
|
+
if (dir) out.push({manager: 'pnpm', folder: dir});
|
|
232
|
+
}
|
|
233
|
+
return out;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* The package manager's global folder that holds the CLI at `root`, when the
|
|
238
|
+
* package manager's own settings name that folder (configuredGlobalFolders);
|
|
239
|
+
* null otherwise. A folder that only looks like one, such as an app made with
|
|
240
|
+
* `yarn add` alone or one under a folder named `install/global`, is not.
|
|
241
|
+
* @param {string} root the CLI package's real folder
|
|
242
|
+
* @param {GlobalWhere} [where]
|
|
243
|
+
* @returns {{manager: 'bun' | 'pnpm' | 'yarn', folder: string} | null}
|
|
244
|
+
*/
|
|
245
|
+
export function globalFolderOf(root, where = {}) {
|
|
246
|
+
const place = installPlaceOf(root);
|
|
247
|
+
if (place.runner || !place.owner) return null;
|
|
248
|
+
const owner = place.owner;
|
|
249
|
+
const platform = where.platform ?? process.platform;
|
|
250
|
+
for (const known of configuredGlobalFolders(where)) {
|
|
251
|
+
// Compared as real folders, so a linked home folder reads the same.
|
|
252
|
+
const folder = real(known.folder);
|
|
253
|
+
if (known.manager === 'pnpm') {
|
|
254
|
+
// `<global-dir>/<n>` before pnpm 11, `<global-dir>/v<n>/<id>` since.
|
|
255
|
+
const rel = relativeWithin(folder, owner, platform);
|
|
256
|
+
if (rel !== null && /^v?\d+(?:[\\/][^\\/]+)?$/u.test(rel)) {
|
|
257
|
+
return {manager: 'pnpm', folder: owner};
|
|
258
|
+
}
|
|
259
|
+
} else if (samePath(folder, owner, platform)) {
|
|
260
|
+
return {manager: known.manager, folder: owner};
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** Path markers of package runners' temporary installs. */
|
|
267
|
+
const RUNNER_CACHE =
|
|
268
|
+
/[\\/]_npx[\\/]|[\\/]dlx[-\\/]|[\\/]\.bun[\\/]install[\\/]cache[\\/]|[\\/]bunx-|[\\/]xfs-/i;
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Where an installed CLI package lives: its owner, the folder that holds the
|
|
272
|
+
* `node_modules` it is in (above pnpm's `.pnpm` store), and whether that owner
|
|
273
|
+
* is named like a package manager's default global folder (`knownGlobal`, a
|
|
274
|
+
* hint only: isGlobalCopy decides from the package managers' settings). Pure:
|
|
275
|
+
* reads no file, and
|
|
276
|
+
* accepts either separator, so Windows paths read the same on every platform.
|
|
277
|
+
* @param {string} root the package's real folder
|
|
278
|
+
* @returns {{runner: boolean, owner: string | null, knownGlobal: boolean}}
|
|
279
|
+
*/
|
|
280
|
+
export function installPlaceOf(root) {
|
|
281
|
+
if (RUNNER_CACHE.test(root)) {
|
|
282
|
+
return {runner: true, owner: null, knownGlobal: false};
|
|
283
|
+
}
|
|
284
|
+
const sep = /^[A-Za-z]:\\|^\\\\/.test(root) ? '\\' : path.sep;
|
|
285
|
+
const parts = root.split(/[\\/]/);
|
|
286
|
+
const at = parts.lastIndexOf('node_modules');
|
|
287
|
+
if (at < 1) return {runner: false, owner: null, knownGlobal: false};
|
|
288
|
+
let owner = parts.slice(0, at).join(sep) || sep;
|
|
289
|
+
// pnpm keeps the real folder in `<owner>/node_modules/.pnpm/<id>/node_modules`,
|
|
290
|
+
// or, for its global folder before pnpm 11, in `<owner>/.pnpm/<id>/node_modules`.
|
|
291
|
+
const pnpmAt = parts.lastIndexOf('.pnpm');
|
|
292
|
+
if (pnpmAt > 0 && pnpmAt < at) {
|
|
293
|
+
owner =
|
|
294
|
+
parts
|
|
295
|
+
.slice(0, parts[pnpmAt - 1] === 'node_modules' ? pnpmAt - 1 : pnpmAt)
|
|
296
|
+
.join(sep) || sep;
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
runner: false,
|
|
300
|
+
owner,
|
|
301
|
+
knownGlobal: GLOBAL_OWNER_PATTERNS.some(re => re.test(owner)),
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Whether `root` is inside a pnpm store's `links` folder (`<store>/v<N>/links`),
|
|
307
|
+
* where the global virtual store keeps its packages.
|
|
308
|
+
* @param {string} root
|
|
309
|
+
* @returns {boolean}
|
|
310
|
+
*/
|
|
311
|
+
function inPnpmStoreLinks(root) {
|
|
312
|
+
const parts = root.split(/[\\/]/);
|
|
313
|
+
const at = parts.lastIndexOf('links');
|
|
314
|
+
return at >= 2 && /^v\d+$/u.test(parts[at - 1]);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Whether a global folder of pnpm's, as its settings name it, installs the
|
|
319
|
+
* CLI package at `root`: `<global-dir>/v<N>/<id>/node_modules/@astryxdesign/cli`
|
|
320
|
+
* (or `<global-dir>/<N>/node_modules/…` before pnpm 11) resolves to it.
|
|
321
|
+
* @param {string} root the CLI package's real folder
|
|
322
|
+
* @param {GlobalWhere} where
|
|
323
|
+
* @returns {boolean}
|
|
324
|
+
*/
|
|
325
|
+
function linkedFromPnpmGlobal(root, where) {
|
|
326
|
+
const platform = where.platform ?? process.platform;
|
|
327
|
+
const cliIn = (/** @type {string} */ dir) =>
|
|
328
|
+
path.join(dir, 'node_modules', '@astryxdesign', 'cli');
|
|
329
|
+
for (const known of configuredGlobalFolders(where)) {
|
|
330
|
+
if (known.manager !== 'pnpm') continue;
|
|
331
|
+
/** @type {string[]} */
|
|
332
|
+
let versions;
|
|
333
|
+
try {
|
|
334
|
+
versions = fs.readdirSync(known.folder);
|
|
335
|
+
} catch {
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
for (const version of versions.filter(v => /^v?\d+$/u.test(v))) {
|
|
339
|
+
const dir = path.join(known.folder, version);
|
|
340
|
+
/** @type {string[]} */
|
|
341
|
+
let ids = [];
|
|
342
|
+
try {
|
|
343
|
+
ids = fs.readdirSync(dir);
|
|
344
|
+
} catch {
|
|
345
|
+
// Not a folder.
|
|
346
|
+
}
|
|
347
|
+
for (const candidate of [dir, ...ids.map(id => path.join(dir, id))]) {
|
|
348
|
+
if (samePath(real(cliIn(candidate)), root, platform)) return true;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return false;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Is the running copy the CLI package installed for the computer
|
|
357
|
+
* (`npm i -g`, `pnpm add -g`, `yarn global add`, `bun add -g`, Volta)?
|
|
358
|
+
*
|
|
359
|
+
* Read from where the package lives: in a `node_modules` folder whose owner
|
|
360
|
+
* holds no package.json (npm's global folder), or whose owner is a global
|
|
361
|
+
* folder a package manager's own settings name (globalFolderOf). A copy in a
|
|
362
|
+
* project, in a package runner's temporary install, or in the release cache
|
|
363
|
+
* is not, and when unsure the answer is no: a copy that is not global runs no
|
|
364
|
+
* update check and writes no agent skill.
|
|
365
|
+
*
|
|
366
|
+
* @param {string} cliRoot
|
|
367
|
+
* @param {string} [cacheDir]
|
|
368
|
+
* @param {GlobalWhere} [where]
|
|
369
|
+
* @returns {boolean}
|
|
370
|
+
*/
|
|
371
|
+
export function isGlobalCopy(cliRoot, cacheDir = userCacheDir(), where = {}) {
|
|
372
|
+
const root = real(cliRoot);
|
|
373
|
+
const place = installPlaceOf(root);
|
|
374
|
+
if (place.runner || !place.owner || isInReleaseCache(root, cacheDir)) {
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
377
|
+
if (globalFolderOf(root, where)) return true;
|
|
378
|
+
// pnpm's global virtual store keeps every package, a project's own CLI
|
|
379
|
+
// included, in `<store>/v<N>/links/…`, whose folders hold no package.json:
|
|
380
|
+
// global only when a pnpm global folder the settings name links to it.
|
|
381
|
+
if (inPnpmStoreLinks(root)) return linkedFromPnpmGlobal(root, where);
|
|
382
|
+
// npm's global folder holds no package.json; a project always has one.
|
|
383
|
+
return !fs.existsSync(path.join(place.owner, 'package.json'));
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* The Core release a project records, without asking the registry: the Core
|
|
388
|
+
* the folder reads, else the version its lockfile records, else an exact
|
|
389
|
+
* declared version; null for a range.
|
|
390
|
+
* @param {import('./project.mjs').ReleaseFacts} facts
|
|
391
|
+
* @returns {string | null}
|
|
392
|
+
*/
|
|
393
|
+
export function coreVersionOf(facts) {
|
|
394
|
+
if (facts.core) return facts.core.version;
|
|
395
|
+
if (isReleaseVersion(facts.lockedCoreVersion)) {
|
|
396
|
+
return /** @type {string} */ (facts.lockedCoreVersion);
|
|
397
|
+
}
|
|
398
|
+
if (facts.declaredCoreRange) {
|
|
399
|
+
return exactOrRange(CORE_PACKAGE_NAME, facts.declaredCoreRange).version;
|
|
400
|
+
}
|
|
401
|
+
return null;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* The release that matches a project's facts, before any registry question.
|
|
406
|
+
* @param {import('./project.mjs').ReleaseFacts} facts
|
|
407
|
+
* @returns {{version: string | null, range: {name: string, spec: string} | null}}
|
|
408
|
+
*/
|
|
409
|
+
export function matchedVersionOf(facts) {
|
|
410
|
+
if (facts.core) return {version: facts.core.version, range: null};
|
|
411
|
+
if (isReleaseVersion(facts.lockedCoreVersion)) {
|
|
412
|
+
return {version: facts.lockedCoreVersion, range: null};
|
|
413
|
+
}
|
|
414
|
+
if (facts.declaredCoreRange) {
|
|
415
|
+
return exactOrRange(CORE_PACKAGE_NAME, facts.declaredCoreRange);
|
|
416
|
+
}
|
|
417
|
+
if (facts.cli) return {version: facts.cli.version, range: null};
|
|
418
|
+
if (isReleaseVersion(facts.lockedCliVersion)) {
|
|
419
|
+
return {version: facts.lockedCliVersion, range: null};
|
|
420
|
+
}
|
|
421
|
+
if (facts.declaredCliRange) {
|
|
422
|
+
return exactOrRange(CLI_PACKAGE_NAME, facts.declaredCliRange);
|
|
423
|
+
}
|
|
424
|
+
return {version: null, range: null};
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* @param {string} name
|
|
429
|
+
* @param {string} spec
|
|
430
|
+
* @returns {{version: string | null, range: {name: string, spec: string} | null}}
|
|
431
|
+
*/
|
|
432
|
+
function exactOrRange(name, spec) {
|
|
433
|
+
const trimmed = spec.trim().replace(/^=/, '').replace(/^v/, '');
|
|
434
|
+
if (isReleaseVersion(trimmed)) return {version: trimmed, range: null};
|
|
435
|
+
return {version: null, range: {name, spec}};
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Choose who answers a run started by `self` in `cwd`.
|
|
440
|
+
*
|
|
441
|
+
* A command that acts on the computer rather than the folder is chosen as
|
|
442
|
+
* outside a project wherever it runs (`computer`), so a project's older CLI
|
|
443
|
+
* never answers it.
|
|
444
|
+
*
|
|
445
|
+
* @param {{cwd: string, self: RunningCopy, cacheDir?: string, resolve?: typeof resolvePublishedVersion, computer?: boolean}} input
|
|
446
|
+
* @returns {ReleaseChoice}
|
|
447
|
+
*/
|
|
448
|
+
export function chooseRelease({
|
|
449
|
+
cwd,
|
|
450
|
+
self,
|
|
451
|
+
resolve = resolvePublishedVersion,
|
|
452
|
+
computer = false,
|
|
453
|
+
}) {
|
|
454
|
+
const facts = computer ? OUTSIDE : readReleaseFacts(cwd);
|
|
455
|
+
const selfReal = real(self.root);
|
|
456
|
+
|
|
457
|
+
if (!facts.inProject) {
|
|
458
|
+
return {
|
|
459
|
+
copy: 'carried',
|
|
460
|
+
answer: 'self',
|
|
461
|
+
version: self.version,
|
|
462
|
+
bin: null,
|
|
463
|
+
coreVersion: null,
|
|
464
|
+
inProject: false,
|
|
465
|
+
unavailable: null,
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// A project that installs its own CLI is answered by that CLI, whatever its
|
|
470
|
+
// version, and a project with none by the copy that started the run, as
|
|
471
|
+
// released (FR2, DEC-10; `spec:AST-017` FR12). Only a project whose own CLI
|
|
472
|
+
// cannot start gets the Core-matched release.
|
|
473
|
+
if (!facts.cli) {
|
|
474
|
+
// A copy that lives inside the project itself, such as a workspace's own
|
|
475
|
+
// CLI package beside its Core package, is the project's own CLI.
|
|
476
|
+
const inside = isInside(selfReal, projectRootOf(facts));
|
|
477
|
+
return {
|
|
478
|
+
copy: inside ? 'project' : 'starting',
|
|
479
|
+
answer: 'self',
|
|
480
|
+
version: self.version,
|
|
481
|
+
bin: null,
|
|
482
|
+
coreVersion: coreVersionOf(facts),
|
|
483
|
+
inProject: true,
|
|
484
|
+
unavailable: null,
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
{
|
|
488
|
+
if (samePath(real(facts.cli.dir), selfReal)) {
|
|
489
|
+
return {
|
|
490
|
+
copy: 'project',
|
|
491
|
+
answer: 'self',
|
|
492
|
+
version: facts.cli.version,
|
|
493
|
+
bin: null,
|
|
494
|
+
coreVersion: facts.core?.version ?? null,
|
|
495
|
+
inProject: true,
|
|
496
|
+
unavailable: null,
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
const bin = cliBinOf(facts.cli.dir);
|
|
500
|
+
if (bin) {
|
|
501
|
+
return {
|
|
502
|
+
copy: 'project',
|
|
503
|
+
answer: 'project-cli',
|
|
504
|
+
version: facts.cli.version,
|
|
505
|
+
bin,
|
|
506
|
+
coreVersion: facts.core?.version ?? null,
|
|
507
|
+
inProject: true,
|
|
508
|
+
unavailable: null,
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
let {version, range} = matchedVersionOf(facts);
|
|
513
|
+
if (!version && range) {
|
|
514
|
+
version = resolve(range.name, range.spec);
|
|
515
|
+
if (!version) {
|
|
516
|
+
return {
|
|
517
|
+
copy: 'matched',
|
|
518
|
+
answer: 'release',
|
|
519
|
+
version: `${range.name}@${range.spec}`,
|
|
520
|
+
bin: null,
|
|
521
|
+
coreVersion: null,
|
|
522
|
+
inProject: true,
|
|
523
|
+
unavailable: `no published release of ${range.name} matching "${range.spec}" could be found`,
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
const coreVersion = facts.core?.version ?? version;
|
|
529
|
+
if (!version || version === self.version) {
|
|
530
|
+
// A copy that lives inside the project itself, such as a workspace's own
|
|
531
|
+
// CLI package beside its Core package, is the project's own CLI.
|
|
532
|
+
if (isInside(selfReal, projectRootOf(facts))) {
|
|
533
|
+
return {
|
|
534
|
+
copy: 'project',
|
|
535
|
+
answer: 'self',
|
|
536
|
+
version: self.version,
|
|
537
|
+
bin: null,
|
|
538
|
+
coreVersion: facts.core?.version ?? null,
|
|
539
|
+
inProject: true,
|
|
540
|
+
unavailable: null,
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
return {
|
|
544
|
+
copy: 'matched',
|
|
545
|
+
answer: 'self',
|
|
546
|
+
version: self.version,
|
|
547
|
+
bin: null,
|
|
548
|
+
coreVersion,
|
|
549
|
+
inProject: true,
|
|
550
|
+
unavailable: null,
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
return {
|
|
554
|
+
copy: 'matched',
|
|
555
|
+
answer: 'release',
|
|
556
|
+
version,
|
|
557
|
+
bin: null,
|
|
558
|
+
coreVersion,
|
|
559
|
+
inProject: true,
|
|
560
|
+
unavailable: null,
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* The folder a project's facts point at: the declaring package.json's folder,
|
|
566
|
+
* else the folder that holds the Core (the one above its node_modules, or the
|
|
567
|
+
* workspace root above `packages/core`).
|
|
568
|
+
* @param {import('./project.mjs').ReleaseFacts} facts
|
|
569
|
+
* @returns {string | null}
|
|
570
|
+
*/
|
|
571
|
+
export function projectRootOf(facts) {
|
|
572
|
+
if (facts.declaringDir) return facts.declaringDir;
|
|
573
|
+
const dir = facts.core?.dir ?? facts.cli?.dir;
|
|
574
|
+
if (!dir) return null;
|
|
575
|
+
const parts = path.resolve(dir).split(path.sep);
|
|
576
|
+
const at = parts.indexOf('node_modules');
|
|
577
|
+
if (at > 0) return parts.slice(0, at).join(path.sep) || path.sep;
|
|
578
|
+
return path.dirname(path.dirname(dir));
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Is `child` inside `parent` (both real paths), outside any node_modules
|
|
583
|
+
* folder in between? A package installed into a project's node_modules is
|
|
584
|
+
* found as the project's CLI already; this covers a copy that is part of the
|
|
585
|
+
* project's own source, such as a workspace package.
|
|
586
|
+
* @param {string} child
|
|
587
|
+
* @param {string | null} parent
|
|
588
|
+
* @returns {boolean}
|
|
589
|
+
*/
|
|
590
|
+
function isInside(child, parent) {
|
|
591
|
+
if (!parent) return false;
|
|
592
|
+
const rel = relativeWithin(real(parent), child);
|
|
593
|
+
if (rel === null) return false;
|
|
594
|
+
return !rel.split(/[\\/]/).includes('node_modules');
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/** The facts of a folder outside any project. */
|
|
598
|
+
const OUTSIDE = Object.freeze({
|
|
599
|
+
inProject: false,
|
|
600
|
+
core: null,
|
|
601
|
+
cli: null,
|
|
602
|
+
declaringDir: null,
|
|
603
|
+
declaredCoreRange: null,
|
|
604
|
+
declaredCliRange: null,
|
|
605
|
+
lockedCoreVersion: null,
|
|
606
|
+
lockedCliVersion: null,
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
/** Options that take a value, so their value is not the command or topic. */
|
|
610
|
+
const VALUE_OPTIONS = new Set(['--lang', '--detail', '--depth']);
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Is this run a command that acts on the computer rather than the folder it
|
|
614
|
+
* runs in? `astryx init --user`, which writes the computer-level agent text,
|
|
615
|
+
* and `astryx docs global[/…]`, the docs of global mode itself, which the copy
|
|
616
|
+
* that started the run answers, so they are readable inside a project whose
|
|
617
|
+
* release predates them (spec AST-081 FR8, FR9).
|
|
618
|
+
* @param {string[]} argv arguments after `astryx`
|
|
619
|
+
* @returns {boolean}
|
|
620
|
+
*/
|
|
621
|
+
export function isComputerLevel(argv) {
|
|
622
|
+
const words = [];
|
|
623
|
+
for (let i = 0; i < argv.length && words.length < 2; i++) {
|
|
624
|
+
const arg = argv[i];
|
|
625
|
+
if (VALUE_OPTIONS.has(arg)) {
|
|
626
|
+
i += 1;
|
|
627
|
+
continue;
|
|
628
|
+
}
|
|
629
|
+
if (!arg.startsWith('-')) words.push(arg);
|
|
630
|
+
}
|
|
631
|
+
const [command, topic] = words;
|
|
632
|
+
if (command === 'init') return argv.includes('--user');
|
|
633
|
+
return (
|
|
634
|
+
command === 'docs' &&
|
|
635
|
+
typeof topic === 'string' &&
|
|
636
|
+
(topic === 'global' || topic.startsWith('global/'))
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* The running copy, from its package folder.
|
|
642
|
+
* @param {string} root
|
|
643
|
+
* @returns {RunningCopy}
|
|
644
|
+
*/
|
|
645
|
+
export function runningCopy(root) {
|
|
646
|
+
const pkg = readJson(path.join(root, 'package.json'));
|
|
647
|
+
return {version: String(pkg?.version ?? '0.0.0'), root};
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Does the package at `cliDir` print its own who-answered line? Releases that
|
|
652
|
+
* carry this module do; older ones answer silently, so the copy that hands a
|
|
653
|
+
* run to them prints the line for them.
|
|
654
|
+
* @param {string} cliDir
|
|
655
|
+
* @returns {boolean}
|
|
656
|
+
*/
|
|
657
|
+
export function namesWhoAnswered(cliDir) {
|
|
658
|
+
return fs.existsSync(
|
|
659
|
+
path.join(cliDir, 'foundation', 'release', 'choose.mjs'),
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* The CLI package folder an entry file belongs to.
|
|
665
|
+
* @param {string} bin
|
|
666
|
+
* @returns {string}
|
|
667
|
+
*/
|
|
668
|
+
export function packageRootOf(bin) {
|
|
669
|
+
let dir = path.dirname(real(bin));
|
|
670
|
+
for (;;) {
|
|
671
|
+
if (readJson(path.join(dir, 'package.json'))?.name === CLI_PACKAGE_NAME)
|
|
672
|
+
return dir;
|
|
673
|
+
const parent = path.dirname(dir);
|
|
674
|
+
if (parent === dir) return path.dirname(real(bin));
|
|
675
|
+
dir = parent;
|
|
676
|
+
}
|
|
677
|
+
}
|