@astryxdesign/cli 0.7.2-canary.fe2c655 → 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 +175 -154
- 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/help/help.mjs +1 -1
- package/api/build/kit/kit.mjs +3 -11
- package/api/component/_adapter.d.mts +72 -1
- package/api/component/_adapter.mjs +212 -18
- package/api/component/component.doc.mjs +6 -1
- package/api/component/component.mjs +82 -15
- package/api/component/component.test.mjs +80 -0
- package/api/component/doc-links.test.mjs +386 -0
- package/api/component/integration-export-name.test.mjs +644 -0
- package/api/component/list/list.mjs +42 -4
- 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 +74 -0
- package/api/docs/_adapter.mjs +553 -16
- 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/integrationDocs.test.mjs +124 -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 +17 -4
- 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 +219 -52
- 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/index.d.mts +2 -0
- package/api/index.mjs +2 -0
- 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 +17 -6
- 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 +45 -0
- package/api/integration/_adapter.mjs +112 -0
- package/api/integration/add-contribution.component-names.test.mjs +66 -0
- package/api/integration/add-contribution.mjs +8 -4
- package/api/integration/add-contribution.test.mjs +4 -2
- package/api/integration/authoring-checks.mjs +110 -6
- package/api/integration/authoring-checks.test.mjs +808 -0
- package/api/integration/authoring-checks.type.d.mts +143 -0
- package/api/integration/authoring-checks.type.mjs +74 -2
- package/api/integration/check/check.d.mts +96 -0
- package/api/integration/check/check.mjs +357 -0
- package/api/integration/check/check.test.mjs +489 -0
- package/api/integration/integration-check.type.d.mts +118 -0
- package/api/integration/integration-check.type.mjs +84 -0
- package/api/integration/integrationCheck.doc.d.mts +10 -0
- package/api/integration/integrationCheck.doc.mjs +73 -0
- package/api/integration/integrationComponentConflicts.doc.mjs +45 -6
- package/api/integration/integrationDocConflicts.doc.mjs +22 -5
- package/api/integration/pack-check.mjs +364 -120
- package/api/integration/pack-check.test.mjs +730 -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 +63 -9
- package/api/integration/validate-integration.test.mjs +88 -8
- package/api/integration/validate-integration.type.d.mts +16 -0
- package/api/integration/validate-integration.type.mjs +14 -1
- package/api/integration/validate-unread-theme-folders.test.mjs +3 -2
- package/api/integration/validateIntegration.doc.mjs +19 -3
- package/api/search/_adapter.d.mts +11 -0
- package/api/search/_adapter.mjs +25 -0
- package/api/search/search.d.mts +82 -13
- package/api/search/search.doc.mjs +8 -3
- package/api/search/search.domain-priority.test.mjs +108 -18
- package/api/search/search.integration-check.test.mjs +24 -0
- package/api/search/search.mjs +645 -64
- package/api/search/search.test.mjs +179 -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 +29 -15
- package/api/template/template-integration.test.mjs +1 -1
- package/api/template/template.test.mjs +120 -3
- 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.family.test.mjs +64 -0
- package/api/theme/build/build.mjs +250 -38
- 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/themeBuild.doc.mjs +4 -4
- 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/v0.7.2/__tests__/migrate-list-edge-compensation-to-edge.test.mjs +120 -0
- package/assets/codemods/transforms/v0.7.2/index.mjs +20 -0
- package/assets/codemods/transforms/v0.7.2/migrate-list-edge-compensation-to-edge.mjs +198 -0
- package/assets/discover/official-packages.json +367 -0
- package/assets/docs/README.md +10 -0
- package/assets/docs/author-a-theme.doc.mjs +3 -3
- package/assets/docs/browser-support.doc.mjs +1 -1
- package/assets/docs/getting-started.doc.mjs +26 -6
- package/assets/docs/styling-overview.doc.mjs +1 -1
- package/assets/docs/theme.doc.dense.mjs +1 -1
- package/assets/docs/theme.doc.mjs +2 -2
- package/assets/docs/theme.doc.zh.mjs +1 -1
- package/assets/docs/tree/add-a-component.doc.mjs +22 -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 +8 -20
- 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 +201 -0
- package/assets/docs/tree/check-your-docs.doc.mjs +69 -11
- package/assets/docs/tree/checks.doc.mjs +32 -24
- 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 +8 -6
- package/assets/docs/tree/component-imports.doc.mjs +21 -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 +3 -3
- 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 +7 -6
- 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 +4 -8
- 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 +53 -27
- 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 +10 -12
- 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 +15 -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 +29 -13
- package/assets/docs/tree/type-scale.doc.mjs +3 -3
- 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 +10 -9
- package/assets/docs/tree/who-answers.doc.mjs +119 -0
- package/assets/docs/tree/write-the-template-file.doc.mjs +7 -6
- package/assets/docs/use-a-theme.doc.mjs +2 -2
- package/assets/docs/working-with-ai.doc.mjs +66 -13
- package/assets/theme.template.ts +1 -1
- 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 +30 -27
- package/authoring/doctypes/component/type.ts +21 -8
- 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/integration-template.doc.d.mts +11 -0
- package/authoring/doctypes/template/integration-template.doc.mjs +49 -0
- package/authoring/doctypes/template/parse.d.mts +6 -2
- package/authoring/doctypes/template/parse.mjs +3 -1
- package/authoring/doctypes/template/template.doc.mjs +3 -3
- package/authoring/doctypes/template/type.ts +22 -0
- 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 +2 -0
- package/authoring/integration/integration.doc.mjs +30 -6
- package/authoring/integration/parse.test.mjs +21 -0
- package/authoring/integration/schema.d.mts +16 -3
- package/authoring/integration/schema.mjs +34 -2
- package/authoring/integration/type.ts +12 -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 +17 -3
- package/clients/cli/commands/build-theme.font-warning.test.mjs +3 -3
- package/clients/cli/commands/build-theme.mjs +26 -13
- package/clients/cli/commands/build-theme.path-safety.test.mjs +224 -6
- package/clients/cli/commands/build-theme.registry.test.mjs +5 -2
- 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 +19 -4
- 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 +22 -2
- package/clients/cli/commands/doctor-integration.test.mjs +888 -3
- package/clients/cli/commands/doctor.doc.mjs +12 -2
- package/clients/cli/commands/doctor.mjs +292 -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 +93 -0
- package/clients/cli/commands/integration-check.test.mjs +441 -0
- 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.doc.mjs +6 -2
- package/clients/cli/commands/integration.mjs +119 -7
- 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/text-json-parity.test.mjs +5 -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 +3 -2
- 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 +112 -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 +226 -7
- package/foundation/config/project.test.mjs +66 -0
- package/foundation/config/theme-state.mjs +5 -4
- package/foundation/discovery/authoring-self-docs.mjs +2 -1
- package/foundation/discovery/cli-self-docs.mjs +20 -3
- package/foundation/discovery/cli-self-docs.test.mjs +3 -2
- package/foundation/discovery/component-discovery.d.mts +190 -10
- package/foundation/discovery/component-discovery.export-names.test.mjs +760 -0
- package/foundation/discovery/component-discovery.mjs +864 -56
- package/foundation/discovery/component-discovery.test.mjs +96 -0
- package/foundation/discovery/component-replacement.mjs +20 -1
- package/foundation/discovery/component-replacement.test.mjs +40 -0
- 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 +157 -0
- package/foundation/discovery/doc-types.mjs +1231 -0
- package/foundation/discovery/doc-types.test.mjs +744 -0
- package/foundation/discovery/docs-discovery.d.mts +88 -0
- package/foundation/discovery/docs-discovery.mjs +83 -2
- package/foundation/discovery/integration-doc-files.d.mts +22 -0
- package/foundation/discovery/integration-doc-files.mjs +231 -0
- package/foundation/discovery/integration-doc-files.test.mjs +246 -0
- package/foundation/discovery/module-exports.d.mts +27 -0
- package/foundation/discovery/module-exports.mjs +356 -31
- package/foundation/discovery/module-exports.test.mjs +172 -0
- package/foundation/discovery/package-tsconfig.d.mts +14 -0
- package/foundation/discovery/package-tsconfig.mjs +228 -0
- package/foundation/discovery/package-tsconfig.test.mjs +210 -0
- package/foundation/discovery/project-typescript.d.mts +32 -0
- package/foundation/discovery/project-typescript.mjs +89 -0
- package/foundation/discovery/prop-drift.d.mts +297 -0
- package/foundation/discovery/prop-drift.mjs +2428 -0
- package/foundation/discovery/prop-drift.test.mjs +2337 -0
- 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-adapter.mjs +74 -5
- 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-match.d.mts +53 -0
- package/foundation/discovery/type-match.mjs +660 -0
- package/foundation/discovery/type-match.test.mjs +169 -0
- package/foundation/discovery/type-text.d.mts +68 -0
- package/foundation/discovery/type-text.mjs +658 -0
- package/foundation/discovery/type-text.test.mjs +196 -0
- package/foundation/discovery/unresolved-references.d.mts +62 -0
- package/foundation/discovery/unresolved-references.mjs +790 -0
- package/foundation/discovery/unresolved-references.test.mjs +567 -0
- package/foundation/doc-compiler/doc-loads.test.mjs +51 -1
- package/foundation/doc-compiler/inputs.mjs +27 -1
- package/foundation/doc-compiler/inputs.test.mjs +0 -1
- package/foundation/doc-compiler/links.d.mts +41 -5
- package/foundation/doc-compiler/links.mjs +167 -28
- 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 +56 -3
- 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 +22 -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/foundation/xle/registry.mjs +4 -0
- package/foundation/xle/registry.test.mjs +28 -0
- package/package.json +11 -11
- package/scripts/postinstall.mjs +24 -5
package/api/doctor/doctor.mjs
CHANGED
|
@@ -4,7 +4,11 @@
|
|
|
4
4
|
* @file Health-check engine for `astryx doctor`.
|
|
5
5
|
*
|
|
6
6
|
* Runs a series of diagnostic checks against the user's project and
|
|
7
|
-
* environment, returning a structured report.
|
|
7
|
+
* environment, returning a structured report. Outside a project it checks the
|
|
8
|
+
* computer instead (spec AST-081 FR4): the Node version, the release that
|
|
9
|
+
* answered, the newest release the computer knows of, and whether the
|
|
10
|
+
* computer-level agent text is present and current; no check fails because
|
|
11
|
+
* the folder has no project. Each check is a small,
|
|
8
12
|
* self-contained function that returns a {@link DoctorCheck} record, so
|
|
9
13
|
* adding a new diagnostic is just appending a function to {@link SYNC_CHECKS}.
|
|
10
14
|
*
|
|
@@ -25,8 +29,9 @@ import * as path from 'node:path';
|
|
|
25
29
|
|
|
26
30
|
import {MIN_NODE_VERSION, isNodeVersionSupported} from '../../foundation/env/node-version.mjs';
|
|
27
31
|
import {AGENT_DOC_PATHS} from '../../foundation/agent-docs/agent-doc-state.mjs';
|
|
28
|
-
import {CLI_ROOT,
|
|
29
|
-
import {explainPackageManager, getCliInvocation} from '../../foundation/env/package-manager.mjs';
|
|
32
|
+
import {CLI_ROOT, findProjectCoreDir, findInstalledPackage} from '../../foundation/fs/paths.mjs';
|
|
33
|
+
import {explainPackageManager, formatCliCommand, getCliInvocation, guessCliInvocation} from '../../foundation/env/package-manager.mjs';
|
|
34
|
+
import {chooseDeclaredCliCommand, declaredCliCommandsOf} from '../../foundation/env/cli-command.mjs';
|
|
30
35
|
import {
|
|
31
36
|
findConfigPath,
|
|
32
37
|
Project,
|
|
@@ -52,6 +57,8 @@ import {typedEdges} from '../docs/node/node.mjs';
|
|
|
52
57
|
import {detailView, indexView} from '../../foundation/doc-compiler/lenses.mjs';
|
|
53
58
|
import {semverCompare, isValidSemver, satisfiesRange} from '../../foundation/env/semver.mjs';
|
|
54
59
|
import {checkAppThemes, checkThemes} from './theme-checks.mjs';
|
|
60
|
+
import {availableLine, upgradeLine} from '../../foundation/release/notices.mjs';
|
|
61
|
+
import {alignCommand, addCliCommandFor, computerAgentTextState, installCommandFor, projectCoreVersion, projectHasOwnCli, computerIntegrationsOutside, computerIntegrationsToAdd, displayHomePath, outsideProject, releaseFacts} from './_adapter.mjs';
|
|
55
62
|
|
|
56
63
|
/**
|
|
57
64
|
* @typedef {'pass'|'warn'|'fail'|'info'} DoctorStatus
|
|
@@ -71,6 +78,10 @@ import {checkAppThemes, checkThemes} from './theme-checks.mjs';
|
|
|
71
78
|
* @property {string} cwd - Directory to diagnose.
|
|
72
79
|
* @property {string} nodeVersion - Running Node version.
|
|
73
80
|
* @property {string|null} coreDir - Resolved core package directory, or null.
|
|
81
|
+
* @property {boolean} [ownCli] - Whether the project installs its own CLI;
|
|
82
|
+
* false means the copy that started the run answered it (spec AST-081 FR2).
|
|
83
|
+
* @property {string|null} [projectCore] - The Core release the project names
|
|
84
|
+
* (installed, else locked, else declared), as the daily hint reads it.
|
|
74
85
|
* @property {string|null} configPath - Resolved astryx.config.mjs path, or null.
|
|
75
86
|
* @property {import('../../foundation/integrations/integrations.mjs').LoadedIntegration[]|null} [integrations]
|
|
76
87
|
* Every integration the project loaded, or null when the project could not be
|
|
@@ -229,7 +240,12 @@ export function checkCoreInstalled(ctx) {
|
|
|
229
240
|
* @returns {DoctorCheck}
|
|
230
241
|
*/
|
|
231
242
|
export function checkVersionAlignment(ctx) {
|
|
232
|
-
|
|
243
|
+
// A project with no CLI of its own and no Core installed yet (a fresh
|
|
244
|
+
// clone) is compared by the Core it locks or declares, as the daily hint
|
|
245
|
+
// compares it (spec AST-081 FR2).
|
|
246
|
+
const coreVersion =
|
|
247
|
+
pkgVersion(ctx.coreDir) ??
|
|
248
|
+
(ctx.ownCli === false ? (ctx.projectCore ?? null) : null);
|
|
233
249
|
const cliPkg = readPkg(path.join(CLI_ROOT, 'package.json'));
|
|
234
250
|
const cliVersion = cliPkg?.version ?? null;
|
|
235
251
|
|
|
@@ -258,25 +274,33 @@ export function checkVersionAlignment(ctx) {
|
|
|
258
274
|
};
|
|
259
275
|
}
|
|
260
276
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
277
|
+
// A project with no CLI of its own is answered by the copy that started
|
|
278
|
+
// the run (spec AST-081 FR2): say so, and how to add the CLI at Core's
|
|
279
|
+
// version.
|
|
280
|
+
if (ctx.ownCli === false) {
|
|
281
|
+
return {
|
|
282
|
+
id: 'version-alignment',
|
|
283
|
+
label: '@astryxdesign/core <-> @astryxdesign/cli alignment',
|
|
284
|
+
status: coreVersion === cliVersion ? 'info' : 'warn',
|
|
285
|
+
message:
|
|
286
|
+
coreVersion === cliVersion
|
|
287
|
+
? `This project has no Astryx CLI installed; CLI ${cliVersion}, the one you started, answered and matches its Core.`
|
|
288
|
+
: `This project has no Astryx CLI installed; CLI ${cliVersion}, the one you started, answered while its Core is ${coreVersion}.`,
|
|
289
|
+
fix: `${coreVersion === cliVersion ? 'To pin it for the team and CI' : 'To match'}, run: ${addCliCommandFor(ctx.cwd, coreVersion)}.`,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
// The project's own CLI answers this project whatever its version
|
|
293
|
+
// (spec AST-081 FR2), so any difference means templates, docs, and agent
|
|
294
|
+
// text come from one release and components from another.
|
|
295
|
+
const drift = coreVersion !== cliVersion;
|
|
265
296
|
return {
|
|
266
297
|
id: 'version-alignment',
|
|
267
298
|
label: '@astryxdesign/core <-> @astryxdesign/cli alignment',
|
|
268
299
|
status: drift ? 'warn' : 'pass',
|
|
269
300
|
message: drift
|
|
270
|
-
?
|
|
301
|
+
? `This project's CLI ${cliVersion} answers it, but its Core is ${coreVersion}: templates, docs, and agent text come from CLI ${cliVersion}, components from Core ${coreVersion}.`
|
|
271
302
|
: `@astryxdesign/core v${coreVersion} is in step with @astryxdesign/cli v${cliVersion}.`,
|
|
272
|
-
...(drift
|
|
273
|
-
? {
|
|
274
|
-
fix:
|
|
275
|
-
semverCompare(cliVersion, coreVersion) > 0
|
|
276
|
-
? `Update @astryxdesign/core to ${cliMajor}.${cliMinor}.x to match the CLI.`
|
|
277
|
-
: `Update @astryxdesign/cli to ${coreMajor}.${coreMinor}.x to match @astryxdesign/core.`,
|
|
278
|
-
}
|
|
279
|
-
: {}),
|
|
303
|
+
...(drift ? {fix: `To align them, run: ${alignCommand(ctx.cwd, cliVersion, coreVersion)}.`} : {}),
|
|
280
304
|
};
|
|
281
305
|
}
|
|
282
306
|
|
|
@@ -331,7 +355,7 @@ export async function checkConfig(ctx) {
|
|
|
331
355
|
label: 'astryx.config.mjs',
|
|
332
356
|
status: 'fail',
|
|
333
357
|
message: `astryx.config.mjs loads, but the CLI could not load the project from it: ${firstLine(ctx.projectError)}`,
|
|
334
|
-
fix:
|
|
358
|
+
fix: `Fix what the message names. \`${formatCliCommand('docs authoring config', ctx.cwd)}\` lists every field astryx.config accepts.`,
|
|
335
359
|
};
|
|
336
360
|
}
|
|
337
361
|
return {
|
|
@@ -351,6 +375,26 @@ export async function checkConfig(ctx) {
|
|
|
351
375
|
}
|
|
352
376
|
}
|
|
353
377
|
|
|
378
|
+
/**
|
|
379
|
+
* Why no integration is implicitly linked, from what actually loaded. A
|
|
380
|
+
* configured integration is named in astryx.config; the package's own manifest
|
|
381
|
+
* loads as itself (`__local`). Only the first may be described as named in
|
|
382
|
+
* astryx.config: a package with no config that loads its own manifest has no
|
|
383
|
+
* config file to name it.
|
|
384
|
+
*
|
|
385
|
+
* @param {Array<{name?: string, __local?: boolean}>} integrations loaded, none
|
|
386
|
+
* autolinked and none that failed to load
|
|
387
|
+
* @returns {string}
|
|
388
|
+
*/
|
|
389
|
+
function describeNoImplicit(integrations) {
|
|
390
|
+
const own = integrations.filter(integration => integration.__local);
|
|
391
|
+
const configured = integrations.length - own.length;
|
|
392
|
+
const ownNames = own.map(integration => integration.name ?? 'this package').join(', ');
|
|
393
|
+
if (own.length === 0) return 'None — every loaded integration is named in astryx.config.';
|
|
394
|
+
if (configured === 0) return `None — the only loaded integration is this package's own manifest (${ownNames}).`;
|
|
395
|
+
return `None — every loaded integration is named in astryx.config or is this package's own manifest (${ownNames}).`;
|
|
396
|
+
}
|
|
397
|
+
|
|
354
398
|
/**
|
|
355
399
|
* Check 6 — integrations that are loaded without an astryx.config entry.
|
|
356
400
|
*
|
|
@@ -395,14 +439,18 @@ export function checkImplicitIntegrations(ctx) {
|
|
|
395
439
|
const unreadable = describeUnreadableManifests(ctx.autolinkFailures ?? []);
|
|
396
440
|
|
|
397
441
|
if (implicit.length === 0) {
|
|
442
|
+
// A record that carries `__loadError` (the package's own manifest, or a
|
|
443
|
+
// configured one, that failed to load) loaded nothing, so it is not named
|
|
444
|
+
// as loaded beside the line reporting that it could not be loaded.
|
|
445
|
+
const loaded = ctx.integrations.filter(integration => !integration.__loadError);
|
|
398
446
|
return {
|
|
399
447
|
id,
|
|
400
448
|
label,
|
|
401
449
|
status: 'info',
|
|
402
450
|
message:
|
|
403
|
-
(
|
|
404
|
-
?
|
|
405
|
-
: unreadable
|
|
451
|
+
(loaded.length > 0
|
|
452
|
+
? describeNoImplicit(loaded)
|
|
453
|
+
: ctx.integrations.length > 0 || unreadable
|
|
406
454
|
? 'None loaded.'
|
|
407
455
|
: 'None — no installed dependency ships an astryx.integration.* manifest.') +
|
|
408
456
|
unreadable,
|
|
@@ -476,7 +524,7 @@ function describeUnreadableManifests(failures) {
|
|
|
476
524
|
return (
|
|
477
525
|
` ${failures.length} installed ${one ? 'dependency ships' : 'dependencies ship'} ` +
|
|
478
526
|
`an astryx.integration.* manifest that could not be loaded, so ${one ? 'it contributes' : 'they contribute'} ` +
|
|
479
|
-
`nothing: ${listed}. Run
|
|
527
|
+
`nothing: ${listed}. Run \`${formatCliCommand('doctor integration validate <package>')}\` for details.`
|
|
480
528
|
);
|
|
481
529
|
}
|
|
482
530
|
|
|
@@ -550,7 +598,7 @@ export function checkConfiguredIntegrations(ctx) {
|
|
|
550
598
|
`${withdrawn.length} of ${configured.length} integration${plural} named in astryx.config could not be loaded, ` +
|
|
551
599
|
`so ${withdrawn.length === 1 ? 'it contributes' : 'they contribute'} nothing: ${listed}.`,
|
|
552
600
|
fix:
|
|
553
|
-
|
|
601
|
+
`Install each one, fix its astryx.integration.* manifest (\`${formatCliCommand('doctor integration validate <package>', ctx.cwd)}\` says what is wrong), ` +
|
|
554
602
|
'or remove it from `integrations` in astryx.config.',
|
|
555
603
|
};
|
|
556
604
|
}
|
|
@@ -748,7 +796,7 @@ export function checkIntegrationIssues(ctx) {
|
|
|
748
796
|
label: 'Integration contributions',
|
|
749
797
|
status: 'warn',
|
|
750
798
|
message: `${issues.length} integration issue(s)${errors > 0 ? `, ${errors} of them errors` : ''}: ${details}`,
|
|
751
|
-
fix:
|
|
799
|
+
fix: `Run \`${formatCliCommand('doctor integration', ctx.cwd)}\` for package-specific diagnostics and resolve cross-package precedence in astryx.config.`,
|
|
752
800
|
};
|
|
753
801
|
}
|
|
754
802
|
|
|
@@ -954,7 +1002,7 @@ function surfaceProblems(surface) {
|
|
|
954
1002
|
const problems = [];
|
|
955
1003
|
if (surface.types === 0 && surface.untraced.length === 0) {
|
|
956
1004
|
problems.push(
|
|
957
|
-
|
|
1005
|
+
`@astryxdesign/cli/authoring exports no types, so nothing was compared with \`${formatCliCommand('docs authoring')}\``,
|
|
958
1006
|
);
|
|
959
1007
|
}
|
|
960
1008
|
for (const {module, names, reason, source, key} of surface.unreadable) {
|
|
@@ -967,7 +1015,7 @@ function surfaceProblems(surface) {
|
|
|
967
1015
|
? `${source} does not load`
|
|
968
1016
|
: `${source} renders section "${key}", which the topic's index does not list`;
|
|
969
1017
|
problems.push(
|
|
970
|
-
`${nameTypes(names)} from ${module} ${names.length === 1 ? 'has' : 'have'} no doc in
|
|
1018
|
+
`${nameTypes(names)} from ${module} ${names.length === 1 ? 'has' : 'have'} no doc in \`${formatCliCommand('docs authoring')}\`: ${why}`,
|
|
971
1019
|
);
|
|
972
1020
|
}
|
|
973
1021
|
for (const {name, reason} of surface.untraced) {
|
|
@@ -1008,7 +1056,7 @@ export async function checkAuthoringDocs(_ctx, options = {}) {
|
|
|
1008
1056
|
const audit = await auditAuthoringSelfDocs({root, sources});
|
|
1009
1057
|
const problems = [
|
|
1010
1058
|
...audit.unreachable.map(
|
|
1011
|
-
source => `${source} is not in
|
|
1059
|
+
source => `${source} is not in \`${formatCliCommand('docs authoring')}\``,
|
|
1012
1060
|
),
|
|
1013
1061
|
...audit.failed.map(
|
|
1014
1062
|
({source, error}) => `${source} failed to load: ${error}`,
|
|
@@ -1024,7 +1072,7 @@ export async function checkAuthoringDocs(_ctx, options = {}) {
|
|
|
1024
1072
|
: {keys: options.topicKeys};
|
|
1025
1073
|
const surface = [
|
|
1026
1074
|
...('error' in topic
|
|
1027
|
-
? [
|
|
1075
|
+
? [`\`${formatCliCommand('docs authoring')}\` could not be read: ${topic.error}`]
|
|
1028
1076
|
: []),
|
|
1029
1077
|
...surfaceProblems(
|
|
1030
1078
|
await auditAuthoringSurface({root, sources, topicKeys: topic.keys}),
|
|
@@ -1048,7 +1096,7 @@ export async function checkAuthoringDocs(_ctx, options = {}) {
|
|
|
1048
1096
|
id,
|
|
1049
1097
|
label,
|
|
1050
1098
|
status: 'pass',
|
|
1051
|
-
message: `All ${audit.sections} authoring schemas are readable in
|
|
1099
|
+
message: `All ${audit.sections} authoring schemas are readable in \`${formatCliCommand('docs authoring')}\`.`,
|
|
1052
1100
|
};
|
|
1053
1101
|
} catch (err) {
|
|
1054
1102
|
return {
|
|
@@ -1088,11 +1136,11 @@ export async function checkCliDocs(_ctx, options = {}) {
|
|
|
1088
1136
|
const problems = [
|
|
1089
1137
|
...audit.missing.map(
|
|
1090
1138
|
source =>
|
|
1091
|
-
`${source} has no namespace, so no
|
|
1139
|
+
`${source} has no namespace, so no \`${formatCliCommand('docs')}\` topic reads it`,
|
|
1092
1140
|
),
|
|
1093
1141
|
...audit.unknown.map(
|
|
1094
1142
|
({source, namespace}) =>
|
|
1095
|
-
`${source} has namespace "${namespace}", which no
|
|
1143
|
+
`${source} has namespace "${namespace}", which no \`${formatCliCommand('docs')}\` topic reads`,
|
|
1096
1144
|
),
|
|
1097
1145
|
...audit.misfiled.map(({message}) => message),
|
|
1098
1146
|
...audit.failed.map(
|
|
@@ -1116,7 +1164,7 @@ export async function checkCliDocs(_ctx, options = {}) {
|
|
|
1116
1164
|
id,
|
|
1117
1165
|
label,
|
|
1118
1166
|
status: 'pass',
|
|
1119
|
-
message: `All ${audit.docs} CLI docs are readable: ${audit.tree} in the
|
|
1167
|
+
message: `All ${audit.docs} CLI docs are readable: ${audit.tree} in the \`${formatCliCommand('docs cli')}\` tree and ${audit.authoring} in \`${formatCliCommand('docs authoring')}\`.`,
|
|
1120
1168
|
};
|
|
1121
1169
|
} catch (err) {
|
|
1122
1170
|
return {
|
|
@@ -1278,6 +1326,423 @@ export async function checkDocsProgressiveDisclosure(ctx) {
|
|
|
1278
1326
|
};
|
|
1279
1327
|
}
|
|
1280
1328
|
|
|
1329
|
+
/**
|
|
1330
|
+
* Check 11 — the command every printed command starts with, and a warning when
|
|
1331
|
+
* loaded integrations declare different ones (their `cliCommand`). Then the
|
|
1332
|
+
* picker uses neither, so commands fall back to the package-manager guess.
|
|
1333
|
+
*
|
|
1334
|
+
* @param {DoctorContext} ctx
|
|
1335
|
+
* @returns {DoctorCheck}
|
|
1336
|
+
*/
|
|
1337
|
+
export function checkCliCommand(ctx) {
|
|
1338
|
+
const id = 'cli-command';
|
|
1339
|
+
const label = 'CLI command';
|
|
1340
|
+
const {command, conflict, declared} = chooseDeclaredCliCommand(
|
|
1341
|
+
declaredCliCommandsOf(ctx.integrations ?? []),
|
|
1342
|
+
);
|
|
1343
|
+
if (conflict) {
|
|
1344
|
+
const claims = declared
|
|
1345
|
+
.map(entry => `${entry.package} (\`${entry.command}\`)`)
|
|
1346
|
+
.join(', ');
|
|
1347
|
+
return {
|
|
1348
|
+
id,
|
|
1349
|
+
label,
|
|
1350
|
+
status: 'warn',
|
|
1351
|
+
message: `Loaded integrations declare different CLI commands: ${claims}. Neither is used, so printed commands start with \`${guessCliInvocation(ctx.cwd)}\`.`,
|
|
1352
|
+
fix: 'Remove the integration that does not belong here, or have every package declare the same `cliCommand` in its astryx.integration manifest.',
|
|
1353
|
+
};
|
|
1354
|
+
}
|
|
1355
|
+
if (command) {
|
|
1356
|
+
const packages = declared.map(entry => entry.package).join(', ');
|
|
1357
|
+
return {
|
|
1358
|
+
id,
|
|
1359
|
+
label,
|
|
1360
|
+
status: 'pass',
|
|
1361
|
+
message: `Printed commands start with \`${command}\`, the cliCommand of ${packages}.`,
|
|
1362
|
+
};
|
|
1363
|
+
}
|
|
1364
|
+
return {
|
|
1365
|
+
id,
|
|
1366
|
+
label,
|
|
1367
|
+
status: 'info',
|
|
1368
|
+
message: `No loaded integration declares a cliCommand, so printed commands start with \`${getCliInvocation(ctx.cwd)}\`.`,
|
|
1369
|
+
};
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
/* ── outside a project: the computer ─────────────────────────────────── */
|
|
1373
|
+
|
|
1374
|
+
/**
|
|
1375
|
+
* What a computer check reads: the running Node, the release that answered
|
|
1376
|
+
* (`meta.answeredBy`), and the newest release the computer knows of.
|
|
1377
|
+
* @typedef {object} ComputerContext
|
|
1378
|
+
* @property {string} nodeVersion
|
|
1379
|
+
* @property {{cli: string, core: string | null, copy: string}} answeredBy
|
|
1380
|
+
* @property {string | null} latest the newest release known, or null
|
|
1381
|
+
* @property {Array<{path: string, state: import('../../foundation/agent-docs/computer-agent-text.mjs').ComputerAgentTextState}>} [agentText]
|
|
1382
|
+
* each file of the computer-level agent text against this release's rendering
|
|
1383
|
+
* @property {import('../../foundation/env/user-settings.mjs').ComputerAgentTextSettings} [agentTextSettings]
|
|
1384
|
+
* the person's choices about the computer-level agent text
|
|
1385
|
+
* @property {string} [cwd] the folder doctor runs in, for the printed fix
|
|
1386
|
+
* @property {import('../../foundation/release/notices.mjs').GlobalBehind | null} [globalBehind]
|
|
1387
|
+
* the CLI installed for the computer, when it is older than the newest
|
|
1388
|
+
* release (outside a project)
|
|
1389
|
+
* @property {import('../../foundation/release/notices.mjs').ProjectLag | null} [projectLag]
|
|
1390
|
+
* the project's release, when it is behind the newest (inside a project)
|
|
1391
|
+
* @property {{key: string, reason: string, at: number} | null} [lastNoticeSkip]
|
|
1392
|
+
* @property {{at: number, reason: string} | null} [lastCheckFailure] why the
|
|
1393
|
+
* last update check did not reach the registry, after the last that did
|
|
1394
|
+
* the newest update notice that did not print, and why (diagnostic only)
|
|
1395
|
+
* @property {{pid: number | null, host: string | null, since: number} | null} [stateLock]
|
|
1396
|
+
* who holds the state file's lock now (diagnostic only)
|
|
1397
|
+
* @property {Array<import('../../foundation/env/search-path.mjs').SearchPathCommand & {upgrade?: string | null}>} [searchPathCommands]
|
|
1398
|
+
* every `astryx` on the search path, with the command that upgrades it
|
|
1399
|
+
* the `astryx` commands on the search path, in order
|
|
1400
|
+
* @property {import('../../foundation/integrations/computer-integrations.mjs').ComputerIntegrationCandidate[]} [computerIntegrations]
|
|
1401
|
+
* the integrations installed beside the running CLI
|
|
1402
|
+
* @property {string[]} [loadedComputerIntegrations] the names of those that
|
|
1403
|
+
* loaded outside a project
|
|
1404
|
+
* @property {string[]} [folderIntegrations] the names of the integrations the
|
|
1405
|
+
* folder loads itself, whose copies win over the computer's
|
|
1406
|
+
*/
|
|
1407
|
+
|
|
1408
|
+
/**
|
|
1409
|
+
* The release that answered this run outside a project, and the Core it
|
|
1410
|
+
* reads from.
|
|
1411
|
+
* @param {ComputerContext} ctx
|
|
1412
|
+
* @returns {DoctorCheck}
|
|
1413
|
+
*/
|
|
1414
|
+
export function checkAnsweringRelease(ctx) {
|
|
1415
|
+
const {cli, core} = ctx.answeredBy;
|
|
1416
|
+
return {
|
|
1417
|
+
id: 'answering-release',
|
|
1418
|
+
label: 'Release that answered',
|
|
1419
|
+
status: core ? 'pass' : 'info',
|
|
1420
|
+
message: `${
|
|
1421
|
+
core
|
|
1422
|
+
? `CLI ${cli} with Core ${core} answered, outside a project.`
|
|
1423
|
+
: `CLI ${cli} answered, outside a project. It installs Core ${cli} into the per-user cache the first time a command needs it.`
|
|
1424
|
+
} How each folder is answered: \`${formatCliCommand('astryx docs global', ctx.cwd)}\`.`,
|
|
1425
|
+
};
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
/**
|
|
1429
|
+
* The newest release this computer knows of, beside the one that answered
|
|
1430
|
+
* (spec AST-081 FR10). Runs inside and outside a project, and is always
|
|
1431
|
+
* info. Inside one, a release behind the newest names the install and
|
|
1432
|
+
* upgrade commands; outside one, a CLI installed for the computer that is
|
|
1433
|
+
* behind names the command of the package manager that installed it, after
|
|
1434
|
+
* the Node it needs when the computer runs an older one. Doctor installs
|
|
1435
|
+
* nothing.
|
|
1436
|
+
* @param {ComputerContext} ctx
|
|
1437
|
+
* @returns {DoctorCheck}
|
|
1438
|
+
*/
|
|
1439
|
+
export function checkNewestRelease(ctx) {
|
|
1440
|
+
const check = newestReleaseCheck(ctx);
|
|
1441
|
+
const notes = [
|
|
1442
|
+
checkFailureNote(ctx.lastCheckFailure),
|
|
1443
|
+
skipNote(ctx.lastNoticeSkip),
|
|
1444
|
+
lockNote(ctx.stateLock),
|
|
1445
|
+
].filter(Boolean);
|
|
1446
|
+
return notes.length > 0 ? {...check, message: [check.message, ...notes].join(' ')} : check;
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
/**
|
|
1450
|
+
* The note on a state-file lock held right now, which keeps notices from
|
|
1451
|
+
* being recorded (diagnostic only).
|
|
1452
|
+
* @param {{pid: number | null, host: string | null, since: number} | null | undefined} lock
|
|
1453
|
+
* @returns {string | null}
|
|
1454
|
+
*/
|
|
1455
|
+
function lockNote(lock) {
|
|
1456
|
+
if (!lock) return null;
|
|
1457
|
+
const by = lock.pid == null ? '' : ` by process ${lock.pid}${lock.host ? ` on ${lock.host}` : ''}`;
|
|
1458
|
+
return `The state file's lock is held${by} since ${new Date(lock.since).toISOString()}.`;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
/**
|
|
1462
|
+
* The note on an update check that did not reach the registry (diagnostic
|
|
1463
|
+
* only): no check, no notices.
|
|
1464
|
+
* @param {{at: number, reason: string} | null | undefined} failed
|
|
1465
|
+
* @returns {string | null}
|
|
1466
|
+
*/
|
|
1467
|
+
function checkFailureNote(failed) {
|
|
1468
|
+
if (!failed) return null;
|
|
1469
|
+
const why =
|
|
1470
|
+
failed.reason === 'npm-missing'
|
|
1471
|
+
? 'npm could not be started'
|
|
1472
|
+
: failed.reason === 'bad-reply'
|
|
1473
|
+
? "npm's answer named no release"
|
|
1474
|
+
: failed.reason.startsWith('npm-failed: ')
|
|
1475
|
+
? `npm failed (${failed.reason.slice('npm-failed: '.length)}); its registry and proxy settings decide where it asks`
|
|
1476
|
+
: failed.reason;
|
|
1477
|
+
return `The last update check, ${new Date(failed.at).toISOString()}, did not reach the registry: ${why}.`;
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
/** What a recorded notice skip's reason means, for doctor's update line. */
|
|
1481
|
+
const SKIP_REASONS = {
|
|
1482
|
+
'already-shown': 'it had already printed that day',
|
|
1483
|
+
'no-newer': 'no newer release was known',
|
|
1484
|
+
};
|
|
1485
|
+
|
|
1486
|
+
/**
|
|
1487
|
+
* The note on the last update notice that did not print, for diagnosis
|
|
1488
|
+
* (diagnostic state, not a contract).
|
|
1489
|
+
* @param {{key: string, reason: string, at: number} | null | undefined} skip
|
|
1490
|
+
* @returns {string | null}
|
|
1491
|
+
*/
|
|
1492
|
+
function skipNote(skip) {
|
|
1493
|
+
if (!skip) return null;
|
|
1494
|
+
const why = /** @type {Record<string, string>} */ (SKIP_REASONS)[skip.reason] ?? skip.reason;
|
|
1495
|
+
return `Last update notice skipped ${new Date(skip.at).toISOString()} (${skip.key}): ${why}.`;
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
/**
|
|
1499
|
+
* {@link checkNewestRelease} without the skip note.
|
|
1500
|
+
* @param {ComputerContext} ctx
|
|
1501
|
+
* @returns {DoctorCheck}
|
|
1502
|
+
*/
|
|
1503
|
+
function newestReleaseCheck(ctx) {
|
|
1504
|
+
const {latest, globalBehind: behind, projectLag: lag} = ctx;
|
|
1505
|
+
const {cli} = ctx.answeredBy;
|
|
1506
|
+
const base = {id: 'newest-release', label: 'Newest release', status: /** @type {const} */ ('info')};
|
|
1507
|
+
if (behind) {
|
|
1508
|
+
return {
|
|
1509
|
+
...base,
|
|
1510
|
+
message: `${availableLine(behind.current, behind.newest)}. The CLI installed for the computer stays on its release until you upgrade it.`,
|
|
1511
|
+
fix: `${upgradeLine(behind.command, behind.node)}.`,
|
|
1512
|
+
};
|
|
1513
|
+
}
|
|
1514
|
+
if (lag) {
|
|
1515
|
+
return {
|
|
1516
|
+
...base,
|
|
1517
|
+
message: `This project uses Astryx ${lag.current}; ${lag.newest} is the newest.`,
|
|
1518
|
+
fix: `${upgradeLine(`${lag.install}, then ${lag.upgrade}`, lag.node)}.`,
|
|
1519
|
+
};
|
|
1520
|
+
}
|
|
1521
|
+
if (!latest) {
|
|
1522
|
+
return {
|
|
1523
|
+
...base,
|
|
1524
|
+
message: 'Update check: not run yet, so the newest release is not known here; it runs in the background once a day, after a command.',
|
|
1525
|
+
};
|
|
1526
|
+
}
|
|
1527
|
+
if (isValidSemver(latest) && isValidSemver(cli) && semverCompare(latest, cli) > 0) {
|
|
1528
|
+
return {
|
|
1529
|
+
...base,
|
|
1530
|
+
message: `Release ${latest} is newer than ${cli}, the release that answered.`,
|
|
1531
|
+
};
|
|
1532
|
+
}
|
|
1533
|
+
return {...base, message: `No newer release is known: the newest is ${latest}.`};
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
/**
|
|
1537
|
+
* The `astryx` commands on the search path (spec AST-081 FR11): the first is
|
|
1538
|
+
* the one a shell runs. Warns when it is not the Astryx CLI, or is a release
|
|
1539
|
+
* that predates the hand-off and so answers every folder itself.
|
|
1540
|
+
* @param {ComputerContext} ctx
|
|
1541
|
+
* @returns {DoctorCheck}
|
|
1542
|
+
*/
|
|
1543
|
+
export function checkCliOnPath(ctx) {
|
|
1544
|
+
const rows = ctx.searchPathCommands ?? [];
|
|
1545
|
+
const base = {id: 'cli-on-path', label: '`astryx` on the search path'};
|
|
1546
|
+
const describe = (/** @type {import('../../foundation/env/search-path.mjs').SearchPathCommand} */ row) =>
|
|
1547
|
+
row.astryx ? `${row.file} (CLI ${row.version ?? 'of unknown version'})` : `${row.file} (not the Astryx CLI)`;
|
|
1548
|
+
const others = rows.slice(1);
|
|
1549
|
+
const othersNote = others.length > 0 ? ` Later on the search path: ${others.map(describe).join(', ')}.` : '';
|
|
1550
|
+
const [first] = rows;
|
|
1551
|
+
if (!first) {
|
|
1552
|
+
return {
|
|
1553
|
+
...base,
|
|
1554
|
+
status: 'info',
|
|
1555
|
+
message: 'No `astryx` command on the search path, so `astryx` runs only through a package manager.',
|
|
1556
|
+
fix: 'To run the CLI in any folder, install it for the computer: `npm i -g @astryxdesign/cli`.',
|
|
1557
|
+
};
|
|
1558
|
+
}
|
|
1559
|
+
if (!first.astryx) {
|
|
1560
|
+
return {
|
|
1561
|
+
...base,
|
|
1562
|
+
status: 'warn',
|
|
1563
|
+
message: `The first \`astryx\` on the search path, ${first.file}, is not the Astryx CLI, so \`astryx\` runs another program.${othersNote}`,
|
|
1564
|
+
fix: 'Remove that program from the search path, or put the folder of the CLI installed for the computer before it.',
|
|
1565
|
+
};
|
|
1566
|
+
}
|
|
1567
|
+
if (first.handsOff === false) {
|
|
1568
|
+
return {
|
|
1569
|
+
...base,
|
|
1570
|
+
status: 'warn',
|
|
1571
|
+
message: `The first \`astryx\` on the search path, ${first.file}, runs CLI ${first.version ?? 'of unknown version'}, which predates the hand-off and answers every folder itself.${othersNote}`,
|
|
1572
|
+
fix: `To upgrade, run: \`${first.upgrade ?? 'npm i -g @astryxdesign/cli@latest'}\`.`,
|
|
1573
|
+
};
|
|
1574
|
+
}
|
|
1575
|
+
return {
|
|
1576
|
+
...base,
|
|
1577
|
+
status: 'pass',
|
|
1578
|
+
message: `\`astryx\` runs ${describe(first)}.${othersNote}`,
|
|
1579
|
+
};
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
/**
|
|
1583
|
+
* The computer-level agent text (spec AST-081 FR4, FR8): turned off, present
|
|
1584
|
+
* and equal to this release's rendering, present but different, or absent,
|
|
1585
|
+
* for the files the chosen agents read. Always `info`: the text is optional,
|
|
1586
|
+
* so it never warns or fails. A file Astryx did not write counts as absent,
|
|
1587
|
+
* and a file a person edited is named; both are kept as they are.
|
|
1588
|
+
* @param {ComputerContext} ctx
|
|
1589
|
+
* @returns {DoctorCheck}
|
|
1590
|
+
*/
|
|
1591
|
+
export function checkComputerAgentText(ctx) {
|
|
1592
|
+
const state = ctx.agentTextSettings && ctx.agentText ? null : computerAgentTextState();
|
|
1593
|
+
const settings = ctx.agentTextSettings ?? /** @type {NonNullable<typeof state>} */ (state).settings;
|
|
1594
|
+
const base = {
|
|
1595
|
+
id: 'computer-agent-text',
|
|
1596
|
+
label: 'Computer-level agent text',
|
|
1597
|
+
status: /** @type {const} */ ('info'),
|
|
1598
|
+
};
|
|
1599
|
+
if (!settings.install) {
|
|
1600
|
+
return {
|
|
1601
|
+
...base,
|
|
1602
|
+
message: 'The computer-level agent text is turned off (`astryx init --user --remove-agents`), so the CLI installed for the computer does not write it.',
|
|
1603
|
+
fix: `To turn it back on, run \`${formatCliCommand('astryx init --user', ctx.cwd)}\`.`,
|
|
1604
|
+
};
|
|
1605
|
+
}
|
|
1606
|
+
const entries = ctx.agentText ?? /** @type {NonNullable<typeof state>} */ (state).entries;
|
|
1607
|
+
const fix = `Run \`${formatCliCommand('astryx init --user', ctx.cwd)}\`.`;
|
|
1608
|
+
const [file, ...links] = entries;
|
|
1609
|
+
const home = (/** @type {{path: string}} */ e) => displayHomePath(e.path);
|
|
1610
|
+
const linked = links.filter(l => l.state === 'linked').map(home);
|
|
1611
|
+
const copied = links.filter(l => l.state === 'current').map(home);
|
|
1612
|
+
const skipped = links.filter(l => l.state === 'foreign' || l.state === 'edited').map(home);
|
|
1613
|
+
const dangling = links.filter(l => l.state === 'dangling').map(home);
|
|
1614
|
+
const missing = links.filter(l => l.state === 'absent' || l.state === 'differs').map(home);
|
|
1615
|
+
const linkNote =
|
|
1616
|
+
(linked.length > 0 ? ` Linked into: ${linked.join(', ')}.` : '') +
|
|
1617
|
+
(copied.length > 0 ? ` Copied into: ${copied.join(', ')}.` : '') +
|
|
1618
|
+
(skipped.length > 0 ? ` Not linked, because something Astryx did not create is there: ${skipped.join(', ')}.` : '') +
|
|
1619
|
+
(dangling.length > 0 ? ` Linked, but the skill folder the link points to is not there, so agents reading it see nothing (as in a container that mounts only that folder): ${dangling.join(', ')}.` : '') +
|
|
1620
|
+
(missing.length > 0 ? ` Not linked yet: ${missing.join(', ')}.` : '');
|
|
1621
|
+
if (file.state === 'foreign' || file.state === 'edited') {
|
|
1622
|
+
return {
|
|
1623
|
+
...base,
|
|
1624
|
+
message: `${home(file)} ${file.state === 'edited' ? 'was edited since Astryx wrote it' : 'was not written by Astryx'}, so it is left as it is (delete it to get the current text).${linkNote}`,
|
|
1625
|
+
};
|
|
1626
|
+
}
|
|
1627
|
+
if (file.state === 'absent') {
|
|
1628
|
+
return {
|
|
1629
|
+
...base,
|
|
1630
|
+
message: `No computer-level agent text: agents outside a project with Astryx agent docs do not know Astryx is here.${linkNote}`,
|
|
1631
|
+
fix,
|
|
1632
|
+
};
|
|
1633
|
+
}
|
|
1634
|
+
const current = file.state === 'current';
|
|
1635
|
+
return {
|
|
1636
|
+
...base,
|
|
1637
|
+
message: `${current ? 'The computer-level agent text matches this release' : "The computer-level agent text differs from this release's"}: ${home(file)}.${linkNote}`,
|
|
1638
|
+
...(!current || missing.length > 0 || dangling.length > 0 ? {fix} : {}),
|
|
1639
|
+
};
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
/**
|
|
1643
|
+
* The integrations installed for the computer (spec AST-081 FR12). Outside a
|
|
1644
|
+
* project: each one that loads, and a warning for each that is skipped
|
|
1645
|
+
* because its peer ranges exclude the answering release, or fails to load.
|
|
1646
|
+
* @param {ComputerContext} ctx
|
|
1647
|
+
* @returns {DoctorCheck}
|
|
1648
|
+
*/
|
|
1649
|
+
export function checkComputerIntegrations(ctx) {
|
|
1650
|
+
const found = ctx.computerIntegrations ?? [];
|
|
1651
|
+
const loaded = new Set(ctx.loadedComputerIntegrations ?? []);
|
|
1652
|
+
const base = {id: 'computer-integrations', label: 'Integrations installed for this computer'};
|
|
1653
|
+
if (found.length === 0) {
|
|
1654
|
+
return {
|
|
1655
|
+
...base,
|
|
1656
|
+
status: 'info',
|
|
1657
|
+
message: 'No integration is installed beside the CLI installed for this computer.',
|
|
1658
|
+
};
|
|
1659
|
+
}
|
|
1660
|
+
const label = (/** @type {{name: string, version?: string}} */ c) => (c.version ? `${c.name}@${c.version}` : c.name);
|
|
1661
|
+
const own = new Set(ctx.folderIntegrations ?? []);
|
|
1662
|
+
const shadowed = found.filter(c => own.has(c.name));
|
|
1663
|
+
const rest = found.filter(c => !own.has(c.name));
|
|
1664
|
+
const used = rest.filter(c => !c.incompatible && loaded.has(c.name));
|
|
1665
|
+
const skipped = rest.filter(c => c.incompatible);
|
|
1666
|
+
const failed = rest.filter(c => !c.incompatible && !loaded.has(c.name));
|
|
1667
|
+
const notes = [
|
|
1668
|
+
used.length > 0 ? `Used outside a project: ${used.map(label).join(', ')}.` : '',
|
|
1669
|
+
...shadowed.map(c => `${label(c)} is not used here: this folder loads its own copy of ${c.name}.`),
|
|
1670
|
+
...skipped.map(c => `Skipped ${label(c)}: ${c.incompatible}.`),
|
|
1671
|
+
...failed.map(c => `${label(c)} could not be loaded.`),
|
|
1672
|
+
].filter(Boolean);
|
|
1673
|
+
const fixes = [
|
|
1674
|
+
...skipped.map(c => `install a release of ${c.name} that supports this CLI`),
|
|
1675
|
+
...failed.map(c => `run \`${formatCliCommand(`astryx doctor integration validate ${c.name}`, ctx.cwd)}\``),
|
|
1676
|
+
];
|
|
1677
|
+
return {
|
|
1678
|
+
...base,
|
|
1679
|
+
status: skipped.length + failed.length > 0 ? 'warn' : 'pass',
|
|
1680
|
+
message: notes.join(' '),
|
|
1681
|
+
...(fixes.length > 0 ? {fix: `To fix: ${fixes.join('; ')}.`} : {}),
|
|
1682
|
+
};
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
/**
|
|
1686
|
+
* Inside a project, the integrations installed for the computer that the
|
|
1687
|
+
* project does not install: available, never used (spec AST-081 FR12).
|
|
1688
|
+
* Always info.
|
|
1689
|
+
* @param {{installed: Set<string>, candidates: import('../../foundation/integrations/computer-integrations.mjs').ComputerIntegrationCandidate[], install: (name: string) => string}} input
|
|
1690
|
+
* `install`: the command that adds a package with the project's package
|
|
1691
|
+
* manager (read by the adapter)
|
|
1692
|
+
* @returns {DoctorCheck}
|
|
1693
|
+
*/
|
|
1694
|
+
export function checkComputerIntegrationsAvailable({installed, candidates, install}) {
|
|
1695
|
+
const available = candidates.filter(c => !installed.has(c.name));
|
|
1696
|
+
const base = {id: 'computer-integrations', label: 'Integrations installed for this computer', status: /** @type {const} */ ('info')};
|
|
1697
|
+
if (available.length === 0) {
|
|
1698
|
+
return {...base, message: 'No integration installed for this computer is missing from this project.'};
|
|
1699
|
+
}
|
|
1700
|
+
const add = install;
|
|
1701
|
+
return {
|
|
1702
|
+
...base,
|
|
1703
|
+
message: `Installed for this computer but not in this project, so not used here: ${available.map(c => c.name).join(', ')}.`,
|
|
1704
|
+
fix: `To use one in this project, run ${available.map(c => `\`${add(c.name)}\``).join(' or ')}.`,
|
|
1705
|
+
};
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
/**
|
|
1709
|
+
* The checks doctor runs outside a project, in order.
|
|
1710
|
+
* @type {Array<(ctx: ComputerContext) => DoctorCheck>}
|
|
1711
|
+
*/
|
|
1712
|
+
export const COMPUTER_CHECKS = [
|
|
1713
|
+
ctx =>
|
|
1714
|
+
checkNodeVersion({
|
|
1715
|
+
cwd: '',
|
|
1716
|
+
nodeVersion: ctx.nodeVersion,
|
|
1717
|
+
coreDir: null,
|
|
1718
|
+
configPath: null,
|
|
1719
|
+
}),
|
|
1720
|
+
checkAnsweringRelease,
|
|
1721
|
+
checkNewestRelease,
|
|
1722
|
+
checkCliOnPath,
|
|
1723
|
+
checkComputerIntegrations,
|
|
1724
|
+
checkComputerAgentText,
|
|
1725
|
+
];
|
|
1726
|
+
|
|
1727
|
+
/**
|
|
1728
|
+
* Doctor outside a project: the computer, never the folder.
|
|
1729
|
+
* @param {string} cwd
|
|
1730
|
+
* @returns {Promise<DoctorReport>}
|
|
1731
|
+
*/
|
|
1732
|
+
async function runComputerChecks(cwd) {
|
|
1733
|
+
/** @type {ComputerContext} */
|
|
1734
|
+
const ctx = {
|
|
1735
|
+
nodeVersion: process.versions.node,
|
|
1736
|
+
cwd,
|
|
1737
|
+
...releaseFacts(cwd, {project: false}),
|
|
1738
|
+
};
|
|
1739
|
+
Object.assign(ctx, await computerIntegrationsOutside(cwd));
|
|
1740
|
+
const checks = COMPUTER_CHECKS.map(fn => fn(ctx));
|
|
1741
|
+
const summary = {pass: 0, warn: 0, fail: 0, info: 0};
|
|
1742
|
+
for (const c of checks) summary[c.status] += 1;
|
|
1743
|
+
return {checks, summary};
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1281
1746
|
/**
|
|
1282
1747
|
* Ordered list of synchronous check functions. Append here to add a check.
|
|
1283
1748
|
* (checkConfig is async and is awaited separately by {@link runChecks}.)
|
|
@@ -1294,6 +1759,7 @@ export const SYNC_CHECKS = [
|
|
|
1294
1759
|
checkAgentDocs,
|
|
1295
1760
|
checkPeerDeps,
|
|
1296
1761
|
checkPackageManager,
|
|
1762
|
+
checkCliCommand,
|
|
1297
1763
|
];
|
|
1298
1764
|
|
|
1299
1765
|
/**
|
|
@@ -1305,7 +1771,8 @@ export const SYNC_CHECKS = [
|
|
|
1305
1771
|
*/
|
|
1306
1772
|
export async function runChecks(options = {}) {
|
|
1307
1773
|
const cwd = options.cwd ?? process.cwd();
|
|
1308
|
-
|
|
1774
|
+
if (outsideProject(cwd)) return runComputerChecks(cwd);
|
|
1775
|
+
const coreDir = findProjectCoreDir(cwd);
|
|
1309
1776
|
// findConfigPath throws when multiple config files coexist. That's a
|
|
1310
1777
|
// misconfiguration doctor exists to report — catch it and surface it through
|
|
1311
1778
|
// checkConfig as a FAIL rather than crashing the whole diagnostic engine.
|
|
@@ -1339,7 +1806,9 @@ export async function runChecks(options = {}) {
|
|
|
1339
1806
|
/** @type {import('../../foundation/config/project.mjs').Project | null} */
|
|
1340
1807
|
let project = null;
|
|
1341
1808
|
try {
|
|
1342
|
-
project
|
|
1809
|
+
// Doctor judges the project, so it reads only the Core the project
|
|
1810
|
+
// installed, never a carried one (spec AST-081 FR3).
|
|
1811
|
+
project = await Project.load(cwd, {core: 'project'});
|
|
1343
1812
|
} catch (err) {
|
|
1344
1813
|
// A project the CLI cannot load leaves the checks that need it
|
|
1345
1814
|
// skipped. The reason is kept: those checks and the config
|
|
@@ -1442,6 +1911,8 @@ export async function runChecks(options = {}) {
|
|
|
1442
1911
|
cwd,
|
|
1443
1912
|
nodeVersion: process.versions.node,
|
|
1444
1913
|
coreDir,
|
|
1914
|
+
ownCli: projectHasOwnCli(cwd),
|
|
1915
|
+
projectCore: projectCoreVersion(cwd),
|
|
1445
1916
|
configPath,
|
|
1446
1917
|
integrations,
|
|
1447
1918
|
docsCatalog,
|
|
@@ -1466,6 +1937,31 @@ export async function runChecks(options = {}) {
|
|
|
1466
1937
|
checks.push(await checkConfig(ctx));
|
|
1467
1938
|
}
|
|
1468
1939
|
}
|
|
1940
|
+
const facts = releaseFacts(cwd, {project: true});
|
|
1941
|
+
checks.push(
|
|
1942
|
+
checkNewestRelease({
|
|
1943
|
+
nodeVersion: ctx.nodeVersion,
|
|
1944
|
+
answeredBy: facts.answeredBy,
|
|
1945
|
+
latest: facts.latest,
|
|
1946
|
+
projectLag: facts.projectLag,
|
|
1947
|
+
lastNoticeSkip: facts.lastNoticeSkip,
|
|
1948
|
+
lastCheckFailure: facts.lastCheckFailure,
|
|
1949
|
+
stateLock: facts.stateLock,
|
|
1950
|
+
}),
|
|
1951
|
+
);
|
|
1952
|
+
checks.push(
|
|
1953
|
+
checkCliOnPath({
|
|
1954
|
+
nodeVersion: ctx.nodeVersion,
|
|
1955
|
+
answeredBy: facts.answeredBy,
|
|
1956
|
+
latest: null,
|
|
1957
|
+
searchPathCommands: facts.searchPathCommands,
|
|
1958
|
+
}),
|
|
1959
|
+
);
|
|
1960
|
+
{
|
|
1961
|
+
const loadedNames = (project?.loadedIntegrations ?? []).map((/** @type {{name: string}} */ i) => i.name);
|
|
1962
|
+
const candidates = await computerIntegrationsToAdd(cwd, loadedNames);
|
|
1963
|
+
checks.push(checkComputerIntegrationsAvailable({installed: new Set(loadedNames), candidates, install: installCommandFor(cwd)}));
|
|
1964
|
+
}
|
|
1469
1965
|
checks.push(await checkAuthoringDocs(ctx));
|
|
1470
1966
|
checks.push(await checkCliDocs(ctx));
|
|
1471
1967
|
checks.push(await checkDocsTree(ctx));
|