@astryxdesign/cli 0.7.2-canary.fe2c655 → 0.7.3-canary.02f5fe4
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 +216 -162
- package/api/build/_adapter.d.mts +66 -0
- package/api/build/_adapter.mjs +139 -4
- package/api/build/blocks/blocks.d.mts +92 -0
- package/api/build/blocks/blocks.mjs +528 -0
- package/api/build/blocks/blocks.test.mjs +238 -0
- package/api/build/blocks/blocks.weights.json +1 -0
- package/api/build/build.doc.mjs +4 -0
- package/api/build/build.mjs +25 -6
- package/api/build/build.type.mjs +1 -1
- package/api/build/help/help.mjs +1 -1
- package/api/build/kit/answer.d.mts +18 -0
- package/api/build/kit/answer.mjs +195 -0
- package/api/build/kit/answer.test.mjs +108 -0
- package/api/build/kit/kind.d.mts +25 -0
- package/api/build/kit/kind.mjs +170 -0
- package/api/build/kit/kit.d.mts +2 -4
- package/api/build/kit/kit.mjs +8 -406
- package/api/build/kit/rank.d.mts +3 -32
- package/api/build/kit/rank.mjs +25 -342
- package/api/build/kit/rank.test.mjs +2 -1
- package/api/build/kit/signals.d.mts +79 -0
- package/api/build/kit/signals.mjs +295 -0
- package/api/build/kit/start.d.mts +32 -0
- package/api/build/kit/start.mjs +163 -0
- package/api/build/kit/words.d.mts +72 -0
- package/api/build/kit/words.mjs +202 -0
- package/api/build/tree.d.mts +20 -0
- package/api/build/tree.mjs +53 -0
- package/api/build/tree.test.mjs +185 -0
- package/api/build/tree.weights.json +1 -0
- package/api/component/_adapter.d.mts +72 -1
- package/api/component/_adapter.mjs +251 -23
- package/api/component/component-replacement.test.mjs +1 -0
- package/api/component/component.doc.mjs +6 -1
- package/api/component/component.mjs +97 -16
- package/api/component/component.test.mjs +95 -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 +131 -12
- package/api/discover/_adapter.mjs +520 -34
- package/api/discover/_adapter.test.mjs +641 -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 +120 -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 +76 -2
- package/api/docs/_adapter.mjs +630 -34
- package/api/docs/docs-homes.test.mjs +127 -0
- package/api/docs/docs.doc.mjs +5 -4
- package/api/docs/docs.mjs +2 -1
- package/api/docs/docs.test.mjs +39 -20
- package/api/docs/integration-tree.test.mjs +42 -20
- package/api/docs/integrationDocs.test.mjs +125 -1
- package/api/docs/list/list.mjs +12 -2
- package/api/docs/namespace-section.test.mjs +6 -6
- package/api/docs/reference-blocks.test.mjs +3 -5
- package/api/doctor/_adapter.d.mts +128 -0
- package/api/doctor/_adapter.mjs +253 -4
- package/api/doctor/doctor.d.mts +217 -0
- package/api/doctor/doctor.doc.mjs +3 -2
- package/api/doctor/doctor.mjs +691 -52
- package/api/doctor/doctor.test.mjs +267 -18
- 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/hook.mjs +1 -1
- 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 +45 -10
- package/api/init/init.mjs +28 -4
- package/api/init/init.test.mjs +18 -2
- package/api/init/init.type.d.mts +50 -5
- package/api/init/init.type.mjs +39 -5
- package/api/init/remove/remove.mjs +17 -4
- package/api/init/remove/remove.test.mjs +114 -2
- package/api/init/run/run.d.mts +1 -1
- package/api/init/run/run.mjs +86 -12
- 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 +53 -0
- package/api/integration/_adapter.mjs +132 -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 +192 -14
- package/api/integration/authoring-checks.test.mjs +1028 -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 +486 -123
- package/api/integration/pack-check.test.mjs +817 -10
- package/api/integration/validate-integration-case-disk.test.mjs +111 -0
- package/api/integration/validate-integration-fixes.test.mjs +73 -5
- package/api/integration/validate-integration-gaps.test.mjs +1975 -0
- package/api/integration/validate-integration.d.mts +23 -2
- package/api/integration/validate-integration.mjs +358 -45
- package/api/integration/validate-integration.test.mjs +88 -8
- package/api/integration/validate-integration.type.d.mts +105 -0
- package/api/integration/validate-integration.type.mjs +79 -1
- package/api/integration/validate-unread-theme-folders.test.mjs +3 -2
- package/api/integration/validateIntegration.doc.mjs +19 -3
- package/api/search/ORDERING.md +28 -0
- package/api/search/_adapter.d.mts +91 -0
- package/api/search/_adapter.mjs +172 -0
- package/api/search/_adapter.test.mjs +173 -0
- package/api/search/_candidate-score.d.mts +40 -0
- package/api/search/_candidate-score.mjs +238 -0
- package/api/search/_cards.json +6098 -0
- package/api/search/_compound.d.mts +50 -0
- package/api/search/_compound.mjs +170 -0
- package/api/search/_doc-searcher.d.mts +4 -0
- package/api/search/_doc-searcher.mjs +23 -0
- package/api/search/_doc-searcher.test.mjs +36 -0
- package/api/search/_doc-searcher.weights.json +1 -0
- package/api/search/_doc-text.d.mts +30 -0
- package/api/search/_doc-text.mjs +87 -0
- package/api/search/_entries.d.mts +63 -0
- package/api/search/_entries.mjs +232 -0
- package/api/search/_entries.test.mjs +48 -0
- package/api/search/_features.d.mts +35 -0
- package/api/search/_features.mjs +155 -0
- package/api/search/_gather-components.d.mts +26 -0
- package/api/search/_gather-components.mjs +284 -0
- package/api/search/_gather-docs.d.mts +20 -0
- package/api/search/_gather-docs.mjs +254 -0
- package/api/search/_gather-hooks.d.mts +12 -0
- package/api/search/_gather-hooks.mjs +52 -0
- package/api/search/_gather-templates.d.mts +25 -0
- package/api/search/_gather-templates.mjs +107 -0
- package/api/search/_lexical.d.mts +135 -0
- package/api/search/_lexical.mjs +351 -0
- package/api/search/_main-searcher.d.mts +19 -0
- package/api/search/_main-searcher.mjs +115 -0
- package/api/search/_main-searcher.test.mjs +106 -0
- package/api/search/_main-searcher.weights.json +1 -0
- package/api/search/_module-doc.d.mts +32 -0
- package/api/search/_module-doc.mjs +78 -0
- package/api/search/_order.d.mts +32 -0
- package/api/search/_order.mjs +162 -0
- package/api/search/_order.test.mjs +72 -0
- package/api/search/_priority.d.mts +50 -0
- package/api/search/_priority.mjs +139 -0
- package/api/search/_query-words.d.mts +25 -0
- package/api/search/_query-words.mjs +92 -0
- package/api/search/_query.d.mts +65 -0
- package/api/search/_query.mjs +176 -0
- package/api/search/_result.d.mts +97 -0
- package/api/search/_result.mjs +150 -0
- package/api/search/_score.d.mts +60 -0
- package/api/search/_score.mjs +283 -0
- package/api/search/_synonyms.d.mts +21 -0
- package/api/search/_synonyms.mjs +67 -0
- package/api/search/_template-searcher.d.mts +4 -0
- package/api/search/_template-searcher.mjs +23 -0
- package/api/search/_template-searcher.test.mjs +40 -0
- package/api/search/_template-searcher.weights.json +1 -0
- package/api/search/_titles.d.mts +33 -0
- package/api/search/_titles.mjs +65 -0
- package/api/search/_words.d.mts +64 -0
- package/api/search/_words.mjs +157 -0
- package/api/search/search.d.mts +22 -236
- package/api/search/search.doc.mjs +14 -7
- 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 +59 -1904
- package/api/search/search.test.mjs +193 -15
- package/api/search/search.type.d.mts +20 -2
- package/api/search/search.type.mjs +12 -2
- package/api/search/tree.d.mts +15 -0
- package/api/search/tree.mjs +40 -0
- package/api/search/tree.test.mjs +66 -0
- package/api/search/tree.weights.json +1 -0
- 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.mjs +5 -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 +21 -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 +97 -11
- package/api/upgrade/_adapter.mjs +315 -32
- package/api/upgrade/registry/registry.d.mts +10 -4
- package/api/upgrade/registry/registry.mjs +33 -16
- package/api/upgrade/registry/registry.test.mjs +85 -0
- package/api/upgrade/run/cli-behind-core.test.mjs +438 -0
- package/api/upgrade/run/run.d.mts +4 -2
- package/api/upgrade/run/run.mjs +48 -4
- package/api/upgrade/run/run.test.mjs +417 -3
- package/api/upgrade/status/status.d.mts +21 -5
- package/api/upgrade/status/status.mjs +45 -8
- package/api/upgrade/upgrade.doc.mjs +16 -8
- package/api/upgrade/upgrade.mjs +18 -3
- package/api/upgrade/upgrade.test.mjs +194 -0
- package/api/upgrade/upgrade.type.d.mts +28 -3
- package/api/upgrade/upgrade.type.mjs +24 -7
- 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.0/__tests__/validate-data-token-ownership.test.mjs +11 -0
- package/assets/codemods/transforms/v0.7.0/validate-data-token-ownership.mjs +3 -3
- 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 +5 -5
- package/assets/docs/browser-support.doc.mjs +1 -1
- package/assets/docs/getting-started.doc.mjs +26 -6
- package/assets/docs/is-my-code-good.doc.mjs +287 -0
- 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 +14 -4
- 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/api.doc.mjs +6 -0
- package/assets/docs/tree/authoring.doc.mjs +61 -0
- 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 +6 -2
- 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 +101 -0
- package/assets/docs/tree/cli-command.doc.mjs +142 -0
- package/assets/docs/tree/cli.doc.mjs +7 -1
- 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 +8 -4
- package/assets/docs/tree/debug-and-gap-reports.doc.mjs +41 -22
- package/assets/docs/tree/define-the-theme.doc.mjs +7 -6
- 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 +4 -4
- 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/{authoring.doc.mjs → tree/field-reference.doc.mjs} +4 -3
- package/assets/docs/tree/fonts-and-assets.doc.mjs +3 -3
- package/assets/docs/tree/generate-a-palette.doc.mjs +8 -6
- 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/help.doc.mjs +2 -2
- package/assets/docs/tree/host-entry.doc.mjs +128 -0
- package/assets/docs/tree/install-once.doc.mjs +105 -0
- 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 +54 -28
- 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/ship.doc.mjs +2 -2
- 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-grading-rubric.doc.mjs +17 -38
- 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 +5 -1
- package/assets/docs/tree/tokens-and-setup.doc.mjs +19 -15
- package/assets/docs/tree/tokens-data.doc.mjs +2 -2
- 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 +15 -3
- package/assets/docs/tree/verify-packed-template.doc.mjs +3 -3
- package/assets/docs/tree/versioning.doc.mjs +14 -9
- package/assets/docs/tree/who-answers.doc.mjs +119 -0
- package/assets/docs/tree/write-good-templates.doc.mjs +1 -1
- 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/use-integrations.doc.mjs +120 -0
- package/assets/docs/working-with-ai.doc.mjs +70 -13
- package/assets/templates/themes/butter/butterTheme.ts +4 -2
- package/assets/templates/themes/stone/stoneTheme.ts +4 -2
- package/assets/templates/themes/y2k/y2kTheme.ts +4 -2
- 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 +10 -10
- 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 +13 -1
- package/clients/cli/bin/astryx.mjs +11 -65
- package/clients/cli/cli-command.test.mjs +166 -0
- package/clients/cli/command-result-coverage.test.mjs +6 -5
- 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.color-scheme.test.mjs +1 -1
- package/clients/cli/commands/build-theme.font-warning.test.mjs +3 -3
- 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/{component/index.mjs → component.mjs} +37 -37
- package/clients/cli/commands/component.test.mjs +6 -6
- 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 +3 -2
- package/clients/cli/commands/docs.mjs +50 -20
- package/clients/cli/commands/docs.test.mjs +16 -16
- 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 +936 -3
- package/clients/cli/commands/doctor.doc.mjs +12 -2
- package/clients/cli/commands/doctor.mjs +332 -7
- package/clients/cli/commands/doctor.test.mjs +75 -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/{hook/index.mjs → hook.mjs} +22 -22
- package/clients/cli/commands/import-hint-correctness.test.mjs +1 -1
- package/clients/cli/commands/init.behavior.test.mjs +235 -1
- package/clients/cli/commands/init.doc.mjs +55 -10
- package/clients/cli/commands/init.flag-help.test.mjs +1 -0
- package/clients/cli/commands/init.mjs +2 -2
- 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 +489 -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 +2 -1
- package/clients/cli/commands/manifest.mjs +67 -0
- package/clients/cli/commands/outside-project.test.mjs +874 -0
- package/clients/cli/commands/postinstall.doc.mjs +23 -0
- package/clients/cli/commands/postinstall.mjs +31 -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 +180 -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/{build-theme.mjs → theme.mjs} +27 -14
- package/clients/cli/commands/upgrade.config-ordering.test.mjs +2 -1
- package/clients/cli/commands/upgrade.doc.mjs +26 -3
- 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.mjs +9 -2
- package/clients/cli/commands/upgrade.older-cli.test.mjs +160 -0
- package/clients/cli/commands/upgrade.subfolder-path.test.mjs +97 -0
- package/clients/cli/index.mjs +156 -100
- package/clients/cli/lib/cli-error.mjs +4 -1
- package/clients/cli/lib/component-format.mjs +1 -1
- package/clients/cli/lib/component-format.test.mjs +1 -1
- package/clients/cli/lib/define-command.mjs +14 -9
- package/clients/cli/lib/exit-codes.test.mjs +5 -0
- 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 +37 -0
- package/clients/cli/lib/welcome-box.mjs +50 -0
- package/clients/cli/run.mjs +108 -0
- package/foundation/agent-docs/agent-doc-state.d.mts +67 -13
- package/foundation/agent-docs/agent-doc-state.mjs +123 -14
- package/foundation/agent-docs/agent-docs.d.mts +104 -15
- package/foundation/agent-docs/agent-docs.mjs +1028 -114
- package/foundation/agent-docs/agent-docs.path-safety.test.mjs +1239 -17
- package/foundation/agent-docs/agent-docs.test.mjs +683 -39
- package/foundation/agent-docs/computer-agent-text.d.mts +170 -0
- package/foundation/agent-docs/computer-agent-text.mjs +750 -0
- package/foundation/agent-docs/computer-agent-text.test.mjs +699 -0
- package/foundation/config/project.d.mts +35 -3
- package/foundation/config/project.mjs +243 -26
- package/foundation/config/project.test.mjs +122 -0
- package/foundation/config/theme-state.mjs +5 -4
- package/foundation/discovery/authoring-self-docs.d.mts +7 -0
- package/foundation/discovery/authoring-self-docs.mjs +17 -4
- package/foundation/discovery/authoring-self-docs.test.mjs +15 -3
- package/foundation/discovery/authoring-surface.d.mts +1 -1
- package/foundation/discovery/authoring-surface.mjs +2 -2
- package/foundation/discovery/authoring-surface.test.mjs +1 -1
- package/foundation/discovery/cli-self-docs.d.mts +2 -1
- package/foundation/discovery/cli-self-docs.mjs +22 -4
- package/foundation/discovery/cli-self-docs.test.mjs +3 -2
- package/foundation/discovery/component-discovery.d.mts +227 -10
- package/foundation/discovery/component-discovery.export-names.test.mjs +760 -0
- package/foundation/discovery/component-discovery.mjs +940 -57
- package/foundation/discovery/component-discovery.test.mjs +96 -0
- package/foundation/discovery/component-loader.d.mts +1 -1
- 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 +97 -3
- 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 +68 -0
- package/foundation/discovery/module-exports.mjs +609 -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 +38 -0
- package/foundation/discovery/runner-allowlist.mjs +51 -0
- package/foundation/discovery/runner-commands.d.mts +77 -0
- package/foundation/discovery/runner-commands.mjs +294 -0
- package/foundation/discovery/runner-commands.test.mjs +128 -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 +92 -6
- package/foundation/discovery/template-needs.mjs +6 -46
- package/foundation/discovery/theme-discovery.mjs +147 -3
- 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 +84 -10
- 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/read.mjs +59 -1
- package/foundation/doc-compiler/read.test.mjs +11 -2
- package/foundation/doc-compiler/split-topic-keywords.test.mjs +3 -2
- package/foundation/doc-compiler/tree.d.mts +32 -6
- package/foundation/doc-compiler/tree.mjs +107 -44
- package/foundation/doc-compiler/tree.test.mjs +14 -7
- 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 +122 -4
- package/foundation/fs/paths.mjs +675 -29
- package/foundation/fs/paths.test.mjs +439 -54
- package/foundation/fs/read-record.d.mts +18 -0
- package/foundation/fs/read-record.mjs +131 -0
- package/foundation/fs/read-record.test.mjs +77 -0
- package/foundation/integrations/autolink.d.mts +2 -1
- package/foundation/integrations/autolink.mjs +4 -13
- package/foundation/integrations/cli-peer-version.d.mts +36 -0
- package/foundation/integrations/cli-peer-version.mjs +132 -0
- package/foundation/integrations/cli-peer-version.test.mjs +354 -0
- package/foundation/integrations/computer-integrations.d.mts +81 -0
- package/foundation/integrations/computer-integrations.mjs +345 -0
- package/foundation/integrations/computer-integrations.test.mjs +292 -0
- package/foundation/integrations/contribution-inventory.d.mts +26 -20
- package/foundation/integrations/contribution-inventory.mjs +97 -8
- package/foundation/integrations/exports-subpaths.d.mts +57 -0
- package/foundation/integrations/exports-subpaths.mjs +113 -0
- package/foundation/integrations/integration-warnings.mjs +3 -2
- package/foundation/integrations/integration-warnings.test.mjs +8 -9
- package/foundation/integrations/integrations.d.mts +51 -1
- package/foundation/integrations/integrations.mjs +106 -4
- package/foundation/integrations/issue.ts +6 -0
- package/foundation/integrations/public-imports.d.mts +118 -0
- package/foundation/integrations/public-imports.mjs +1769 -0
- package/foundation/integrations/public-imports.test.mjs +1793 -0
- package/foundation/integrations/validate-contributions.d.mts +117 -0
- package/foundation/integrations/validate-contributions.mjs +1209 -14
- 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 +923 -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 +263 -0
- package/foundation/release/global-state.mjs +474 -0
- package/foundation/release/global-state.test.mjs +381 -0
- package/foundation/release/handoff.d.mts +79 -0
- package/foundation/release/handoff.e2e.test.mjs +278 -0
- package/foundation/release/handoff.mjs +524 -0
- package/foundation/release/lock-lease.d.mts +23 -0
- package/foundation/release/lock-lease.mjs +80 -0
- package/foundation/release/notices.d.mts +307 -0
- package/foundation/release/notices.mjs +707 -0
- package/foundation/release/notices.test.mjs +586 -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 +163 -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/route/route.d.mts +285 -0
- package/foundation/route/route.mjs +324 -0
- package/foundation/route/route.test.mjs +153 -0
- package/foundation/runtime/hosted-runtime.test.mjs +403 -0
- package/foundation/runtime/locked-versions.d.mts +32 -0
- package/foundation/runtime/locked-versions.mjs +65 -0
- package/foundation/runtime/package-root.d.mts +91 -0
- package/foundation/runtime/package-root.mjs +174 -0
- package/foundation/runtime/package-set.d.mts +62 -0
- package/foundation/runtime/package-set.mjs +130 -0
- package/foundation/runtime/package-set.test.mjs +432 -0
- package/foundation/text/string-utils.d.mts +2 -1
- package/foundation/text/string-utils.mjs +16 -5
- package/foundation/text/suggest-order.d.mts +72 -0
- package/foundation/text/suggest-order.mjs +363 -0
- package/foundation/text/suggest-order.test.mjs +259 -0
- 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/host/door-conformance.test.mjs +274 -0
- package/host/index.d.ts +116 -0
- package/host/index.mjs +295 -0
- package/host/index.test.mjs +302 -0
- package/package.json +16 -11
- package/scripts/postinstall.mjs +24 -5
- package/assets/docs/tree/integrations.doc.mjs +0 -40
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
|
*
|
|
@@ -24,9 +28,18 @@ import * as fs from 'node:fs';
|
|
|
24
28
|
import * as path from 'node:path';
|
|
25
29
|
|
|
26
30
|
import {MIN_NODE_VERSION, isNodeVersionSupported} from '../../foundation/env/node-version.mjs';
|
|
27
|
-
import {
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
import {
|
|
32
|
+
AGENT_DOC_PATHS,
|
|
33
|
+
holdsAstryxBlock,
|
|
34
|
+
} from '../../foundation/agent-docs/agent-doc-state.mjs';
|
|
35
|
+
import {
|
|
36
|
+
agentDocsTargetDir,
|
|
37
|
+
assertAgentDocsTarget,
|
|
38
|
+
resolveAgentDocsRoot,
|
|
39
|
+
} from '../../foundation/agent-docs/agent-docs.mjs';
|
|
40
|
+
import {CLI_ROOT, findProjectCoreDir, findInstalledPackage} from '../../foundation/fs/paths.mjs';
|
|
41
|
+
import {explainPackageManager, formatCliCommand, getCliInvocation, guessCliInvocation} from '../../foundation/env/package-manager.mjs';
|
|
42
|
+
import {chooseDeclaredCliCommand, declaredCliCommandsOf} from '../../foundation/env/cli-command.mjs';
|
|
30
43
|
import {
|
|
31
44
|
findConfigPath,
|
|
32
45
|
Project,
|
|
@@ -52,6 +65,9 @@ import {typedEdges} from '../docs/node/node.mjs';
|
|
|
52
65
|
import {detailView, indexView} from '../../foundation/doc-compiler/lenses.mjs';
|
|
53
66
|
import {semverCompare, isValidSemver, satisfiesRange} from '../../foundation/env/semver.mjs';
|
|
54
67
|
import {checkAppThemes, checkThemes} from './theme-checks.mjs';
|
|
68
|
+
import {availableLine, RUN_FROM_PROJECT, upgradeLine} from '../../foundation/release/notices.mjs';
|
|
69
|
+
import {COMPUTER_COMMAND, COMPUTER_INSTALL_STEP} from '../../foundation/agent-docs/computer-agent-text.mjs';
|
|
70
|
+
import {alignCommand, addCliCommandFor, computerAgentTextState, installCommandFor, insideProjectElsewhere, projectCoreVersion, projectHasOwnCli, computerIntegrationsOutside, computerIntegrationsToAdd, displayHomePath, outsideProject, releaseFacts} from './_adapter.mjs';
|
|
55
71
|
|
|
56
72
|
/**
|
|
57
73
|
* @typedef {'pass'|'warn'|'fail'|'info'} DoctorStatus
|
|
@@ -71,6 +87,10 @@ import {checkAppThemes, checkThemes} from './theme-checks.mjs';
|
|
|
71
87
|
* @property {string} cwd - Directory to diagnose.
|
|
72
88
|
* @property {string} nodeVersion - Running Node version.
|
|
73
89
|
* @property {string|null} coreDir - Resolved core package directory, or null.
|
|
90
|
+
* @property {boolean} [ownCli] - Whether the project installs its own CLI;
|
|
91
|
+
* false means the copy that started the run answered it (spec AST-081 FR2).
|
|
92
|
+
* @property {string|null} [projectCore] - The Core release the project names
|
|
93
|
+
* (installed, else locked, else declared), as the daily hint reads it.
|
|
74
94
|
* @property {string|null} configPath - Resolved astryx.config.mjs path, or null.
|
|
75
95
|
* @property {import('../../foundation/integrations/integrations.mjs').LoadedIntegration[]|null} [integrations]
|
|
76
96
|
* Every integration the project loaded, or null when the project could not be
|
|
@@ -229,7 +249,12 @@ export function checkCoreInstalled(ctx) {
|
|
|
229
249
|
* @returns {DoctorCheck}
|
|
230
250
|
*/
|
|
231
251
|
export function checkVersionAlignment(ctx) {
|
|
232
|
-
|
|
252
|
+
// A project with no CLI of its own and no Core installed yet (a fresh
|
|
253
|
+
// clone) is compared by the Core it locks or declares, as the daily hint
|
|
254
|
+
// compares it (spec AST-081 FR2).
|
|
255
|
+
const coreVersion =
|
|
256
|
+
pkgVersion(ctx.coreDir) ??
|
|
257
|
+
(ctx.ownCli === false ? (ctx.projectCore ?? null) : null);
|
|
233
258
|
const cliPkg = readPkg(path.join(CLI_ROOT, 'package.json'));
|
|
234
259
|
const cliVersion = cliPkg?.version ?? null;
|
|
235
260
|
|
|
@@ -258,28 +283,67 @@ export function checkVersionAlignment(ctx) {
|
|
|
258
283
|
};
|
|
259
284
|
}
|
|
260
285
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
286
|
+
// A project with no CLI of its own is answered by the copy that started
|
|
287
|
+
// the run (spec AST-081 FR2): say so, and how to add the CLI at Core's
|
|
288
|
+
// version.
|
|
289
|
+
if (ctx.ownCli === false) {
|
|
290
|
+
// The same comparison as the daily hint: the CLI against the Core the
|
|
291
|
+
// run reads (spec AST-081 FR2). The command adds the CLI in the project
|
|
292
|
+
// spec:AST-040 FR9 defines; from a folder inside it whose package.json
|
|
293
|
+
// is not the project's, or in no project, the fix says how to reach one.
|
|
294
|
+
const add = addCliCommandFor(ctx.cwd, coreVersion);
|
|
295
|
+
const matches = coreVersion === cliVersion;
|
|
296
|
+
const fix = add
|
|
297
|
+
? `${matches ? 'To pin it for the team and CI' : 'To match'}, run: ${add.command}.`
|
|
298
|
+
: matches
|
|
299
|
+
? null
|
|
300
|
+
: NO_PROJECT_FIX;
|
|
301
|
+
return {
|
|
302
|
+
id: 'version-alignment',
|
|
303
|
+
label: '@astryxdesign/core <-> @astryxdesign/cli alignment',
|
|
304
|
+
status: matches ? 'info' : 'warn',
|
|
305
|
+
message: matches
|
|
306
|
+
? `This project has no Astryx CLI installed; CLI ${cliVersion}, the one you started, answered and matches its Core.`
|
|
307
|
+
: `This project has no Astryx CLI installed; CLI ${cliVersion}, the one you started, answered while its Core is ${coreVersion}.`,
|
|
308
|
+
...(fix ? {fix} : {}),
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
// The project's own CLI answers this project whatever its version
|
|
312
|
+
// (spec AST-081 FR2), so any difference means templates, docs, and agent
|
|
313
|
+
// text come from one release and components from another.
|
|
314
|
+
const drift = coreVersion !== cliVersion;
|
|
265
315
|
return {
|
|
266
316
|
id: 'version-alignment',
|
|
267
317
|
label: '@astryxdesign/core <-> @astryxdesign/cli alignment',
|
|
268
318
|
status: drift ? 'warn' : 'pass',
|
|
269
319
|
message: drift
|
|
270
|
-
?
|
|
320
|
+
? `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
321
|
: `@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
|
-
: {}),
|
|
322
|
+
...(drift ? alignFix(ctx.cwd, cliVersion, coreVersion) : {}),
|
|
280
323
|
};
|
|
281
324
|
}
|
|
282
325
|
|
|
326
|
+
/**
|
|
327
|
+
* The fix for a CLI and Core on different releases, when a command fits.
|
|
328
|
+
* @param {string} cwd
|
|
329
|
+
* @param {string} cli
|
|
330
|
+
* @param {string} core
|
|
331
|
+
* @returns {{fix?: string}}
|
|
332
|
+
*/
|
|
333
|
+
function alignFix(cwd, cli, core) {
|
|
334
|
+
// From a folder inside a project whose package.json is not the project's,
|
|
335
|
+
// aligning the project would leave this warning in place, so no command
|
|
336
|
+
// fits there (alignCommand returns none): point at the project instead.
|
|
337
|
+
const command = alignCommand(cwd, cli, core);
|
|
338
|
+
return {fix: command ? `To align them, run: ${command}.` : NO_PROJECT_FIX};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* The fix where no install command fits: the folder's package.json is not an
|
|
343
|
+
* Astryx project's (spec AST-040 FR9), and adding there would make it one.
|
|
344
|
+
*/
|
|
345
|
+
const NO_PROJECT_FIX = RUN_FROM_PROJECT;
|
|
346
|
+
|
|
283
347
|
/**
|
|
284
348
|
* Check 5 — astryx.config.mjs (if present) loads and has a valid shape.
|
|
285
349
|
* @param {DoctorContext} ctx
|
|
@@ -331,7 +395,7 @@ export async function checkConfig(ctx) {
|
|
|
331
395
|
label: 'astryx.config.mjs',
|
|
332
396
|
status: 'fail',
|
|
333
397
|
message: `astryx.config.mjs loads, but the CLI could not load the project from it: ${firstLine(ctx.projectError)}`,
|
|
334
|
-
fix:
|
|
398
|
+
fix: `Fix what the message names. \`${formatCliCommand('docs authoring config', ctx.cwd)}\` lists every field astryx.config accepts.`,
|
|
335
399
|
};
|
|
336
400
|
}
|
|
337
401
|
return {
|
|
@@ -351,6 +415,26 @@ export async function checkConfig(ctx) {
|
|
|
351
415
|
}
|
|
352
416
|
}
|
|
353
417
|
|
|
418
|
+
/**
|
|
419
|
+
* Why no integration is implicitly linked, from what actually loaded. A
|
|
420
|
+
* configured integration is named in astryx.config; the package's own manifest
|
|
421
|
+
* loads as itself (`__local`). Only the first may be described as named in
|
|
422
|
+
* astryx.config: a package with no config that loads its own manifest has no
|
|
423
|
+
* config file to name it.
|
|
424
|
+
*
|
|
425
|
+
* @param {Array<{name?: string, __local?: boolean}>} integrations loaded, none
|
|
426
|
+
* autolinked and none that failed to load
|
|
427
|
+
* @returns {string}
|
|
428
|
+
*/
|
|
429
|
+
function describeNoImplicit(integrations) {
|
|
430
|
+
const own = integrations.filter(integration => integration.__local);
|
|
431
|
+
const configured = integrations.length - own.length;
|
|
432
|
+
const ownNames = own.map(integration => integration.name ?? 'this package').join(', ');
|
|
433
|
+
if (own.length === 0) return 'None — every loaded integration is named in astryx.config.';
|
|
434
|
+
if (configured === 0) return `None — the only loaded integration is this package's own manifest (${ownNames}).`;
|
|
435
|
+
return `None — every loaded integration is named in astryx.config or is this package's own manifest (${ownNames}).`;
|
|
436
|
+
}
|
|
437
|
+
|
|
354
438
|
/**
|
|
355
439
|
* Check 6 — integrations that are loaded without an astryx.config entry.
|
|
356
440
|
*
|
|
@@ -395,14 +479,18 @@ export function checkImplicitIntegrations(ctx) {
|
|
|
395
479
|
const unreadable = describeUnreadableManifests(ctx.autolinkFailures ?? []);
|
|
396
480
|
|
|
397
481
|
if (implicit.length === 0) {
|
|
482
|
+
// A record that carries `__loadError` (the package's own manifest, or a
|
|
483
|
+
// configured one, that failed to load) loaded nothing, so it is not named
|
|
484
|
+
// as loaded beside the line reporting that it could not be loaded.
|
|
485
|
+
const loaded = ctx.integrations.filter(integration => !integration.__loadError);
|
|
398
486
|
return {
|
|
399
487
|
id,
|
|
400
488
|
label,
|
|
401
489
|
status: 'info',
|
|
402
490
|
message:
|
|
403
|
-
(
|
|
404
|
-
?
|
|
405
|
-
: unreadable
|
|
491
|
+
(loaded.length > 0
|
|
492
|
+
? describeNoImplicit(loaded)
|
|
493
|
+
: ctx.integrations.length > 0 || unreadable
|
|
406
494
|
? 'None loaded.'
|
|
407
495
|
: 'None — no installed dependency ships an astryx.integration.* manifest.') +
|
|
408
496
|
unreadable,
|
|
@@ -476,7 +564,7 @@ function describeUnreadableManifests(failures) {
|
|
|
476
564
|
return (
|
|
477
565
|
` ${failures.length} installed ${one ? 'dependency ships' : 'dependencies ship'} ` +
|
|
478
566
|
`an astryx.integration.* manifest that could not be loaded, so ${one ? 'it contributes' : 'they contribute'} ` +
|
|
479
|
-
`nothing: ${listed}. Run
|
|
567
|
+
`nothing: ${listed}. Run \`${formatCliCommand('doctor integration validate <package>')}\` for details.`
|
|
480
568
|
);
|
|
481
569
|
}
|
|
482
570
|
|
|
@@ -550,7 +638,7 @@ export function checkConfiguredIntegrations(ctx) {
|
|
|
550
638
|
`${withdrawn.length} of ${configured.length} integration${plural} named in astryx.config could not be loaded, ` +
|
|
551
639
|
`so ${withdrawn.length === 1 ? 'it contributes' : 'they contribute'} nothing: ${listed}.`,
|
|
552
640
|
fix:
|
|
553
|
-
|
|
641
|
+
`Install each one, fix its astryx.integration.* manifest (\`${formatCliCommand('doctor integration validate <package>', ctx.cwd)}\` says what is wrong), ` +
|
|
554
642
|
'or remove it from `integrations` in astryx.config.',
|
|
555
643
|
};
|
|
556
644
|
}
|
|
@@ -562,6 +650,21 @@ export function checkConfiguredIntegrations(ctx) {
|
|
|
562
650
|
};
|
|
563
651
|
}
|
|
564
652
|
|
|
653
|
+
/**
|
|
654
|
+
* Why init writes no agent docs for `cwd`, or null when it does: the folder
|
|
655
|
+
* it would write to is the home folder or the top of a settings folder in it.
|
|
656
|
+
* @param {string} cwd
|
|
657
|
+
* @returns {string | null}
|
|
658
|
+
*/
|
|
659
|
+
function agentDocsRefusal(cwd) {
|
|
660
|
+
try {
|
|
661
|
+
assertAgentDocsTarget(agentDocsTargetDir(cwd));
|
|
662
|
+
return null;
|
|
663
|
+
} catch (err) {
|
|
664
|
+
return err instanceof Error && err.name === 'AgentDocsHomeError' ? err.message : null;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
565
668
|
/**
|
|
566
669
|
* Check 7 — agent docs exist and contain the Astryx section markers.
|
|
567
670
|
* @param {DoctorContext} ctx
|
|
@@ -569,8 +672,15 @@ export function checkConfiguredIntegrations(ctx) {
|
|
|
569
672
|
*/
|
|
570
673
|
export function checkAgentDocs(ctx) {
|
|
571
674
|
// Every file init can write (one shared list), looked for in the working
|
|
572
|
-
// directory
|
|
573
|
-
|
|
675
|
+
// directory, the project root, and the folder init writes them to: run from
|
|
676
|
+
// src/ or a nested package, the docs sit at the root.
|
|
677
|
+
const dirs = [
|
|
678
|
+
...new Set(
|
|
679
|
+
[ctx.cwd, projectRootOf(ctx), resolveAgentDocsRoot(ctx.cwd) ?? ctx.cwd].map(dir =>
|
|
680
|
+
path.resolve(dir),
|
|
681
|
+
),
|
|
682
|
+
),
|
|
683
|
+
];
|
|
574
684
|
const present = dirs.flatMap(dir =>
|
|
575
685
|
AGENT_DOC_PATHS.map(rel => path.join(dir, rel)).filter(abs =>
|
|
576
686
|
fs.existsSync(abs),
|
|
@@ -578,6 +688,15 @@ export function checkAgentDocs(ctx) {
|
|
|
578
688
|
);
|
|
579
689
|
/** @param {string} abs */
|
|
580
690
|
const shown = abs => path.relative(ctx.cwd, abs) || path.basename(abs);
|
|
691
|
+
// In the home folder, or at the top of a settings folder in it, init
|
|
692
|
+
// writes no agent docs (INV31), so the fix is moving the project or a hand
|
|
693
|
+
// edit, never init.
|
|
694
|
+
const refusal = agentDocsRefusal(ctx.cwd);
|
|
695
|
+
/** @param {string} initFix */
|
|
696
|
+
const fixFor = initFix =>
|
|
697
|
+
refusal
|
|
698
|
+
? `${refusal} Move the project into a folder of its own, or edit the Astryx block in its agent file by hand.`
|
|
699
|
+
: initFix;
|
|
581
700
|
|
|
582
701
|
if (present.length === 0) {
|
|
583
702
|
return {
|
|
@@ -585,29 +704,64 @@ export function checkAgentDocs(ctx) {
|
|
|
585
704
|
label: 'AI agent docs',
|
|
586
705
|
status: 'info',
|
|
587
706
|
message: `No agent docs found: looked for ${AGENT_DOC_PATHS.join(', ')} in ${dirs.map(dir => path.relative(ctx.cwd, dir) || '.').join(' and ')}.`,
|
|
588
|
-
fix:
|
|
707
|
+
fix: fixFor(
|
|
708
|
+
`Generate agent docs with \`${getCliInvocation(ctx.cwd)} init --features agents\`.`,
|
|
709
|
+
),
|
|
589
710
|
};
|
|
590
711
|
}
|
|
591
712
|
|
|
592
|
-
|
|
713
|
+
/** @param {string} abs */
|
|
714
|
+
const read = abs => {
|
|
593
715
|
try {
|
|
594
|
-
|
|
595
|
-
return (
|
|
596
|
-
(content.includes('<!-- ASTRYX:START -->') || content.includes('<!-- XDS:START -->')) &&
|
|
597
|
-
(content.includes('<!-- ASTRYX:END -->') || content.includes('<!-- XDS:END -->'))
|
|
598
|
-
);
|
|
716
|
+
return fs.readFileSync(abs, 'utf-8');
|
|
599
717
|
} catch {
|
|
600
|
-
return
|
|
718
|
+
return '';
|
|
601
719
|
}
|
|
720
|
+
};
|
|
721
|
+
const withMarkers = present.filter(abs => {
|
|
722
|
+
const content = read(abs);
|
|
723
|
+
return (
|
|
724
|
+
(content.includes('<!-- ASTRYX:START -->') || content.includes('<!-- XDS:START -->')) &&
|
|
725
|
+
(content.includes('<!-- ASTRYX:END -->') || content.includes('<!-- XDS:END -->')) &&
|
|
726
|
+
holdsAstryxBlock(content)
|
|
727
|
+
);
|
|
602
728
|
});
|
|
603
729
|
|
|
730
|
+
// A managed block that only imports another file (init's GEMINI.md import
|
|
731
|
+
// of AGENTS.md) is broken when that file holds no block: the agents that
|
|
732
|
+
// read either file get no Astryx docs.
|
|
733
|
+
const dangling = present.flatMap(abs => {
|
|
734
|
+
const match = /<!-- ASTRYX:START -->\s*@(\S+)\s*<!-- ASTRYX:END -->/.exec(read(abs));
|
|
735
|
+
if (match == null) return [];
|
|
736
|
+
const target = path.resolve(path.dirname(abs), match[1]);
|
|
737
|
+
return holdsAstryxBlock(read(target)) ? [] : [{abs, target}];
|
|
738
|
+
});
|
|
739
|
+
if (dangling.length > 0) {
|
|
740
|
+
return {
|
|
741
|
+
id: 'agent-docs',
|
|
742
|
+
label: 'AI agent docs',
|
|
743
|
+
status: 'fail',
|
|
744
|
+
message: dangling
|
|
745
|
+
.map(
|
|
746
|
+
({abs, target}) =>
|
|
747
|
+
`${shown(abs)} imports ${shown(target)}, which holds no Astryx block, so agents that read them get no Astryx docs.`,
|
|
748
|
+
)
|
|
749
|
+
.join(' '),
|
|
750
|
+
fix: fixFor(
|
|
751
|
+
`Write the block again with \`${getCliInvocation(ctx.cwd)} init --features agents\`.`,
|
|
752
|
+
),
|
|
753
|
+
};
|
|
754
|
+
}
|
|
755
|
+
|
|
604
756
|
if (withMarkers.length === 0) {
|
|
605
757
|
return {
|
|
606
758
|
id: 'agent-docs',
|
|
607
759
|
label: 'AI agent docs',
|
|
608
760
|
status: 'warn',
|
|
609
761
|
message: `Agent docs present (${present.map(shown).join(', ')}) but no Astryx section markers found.`,
|
|
610
|
-
fix:
|
|
762
|
+
fix: fixFor(
|
|
763
|
+
`Add the Astryx section to your agent docs with \`${getCliInvocation(ctx.cwd)} init --features agents\`.`,
|
|
764
|
+
),
|
|
611
765
|
};
|
|
612
766
|
}
|
|
613
767
|
|
|
@@ -748,7 +902,7 @@ export function checkIntegrationIssues(ctx) {
|
|
|
748
902
|
label: 'Integration contributions',
|
|
749
903
|
status: 'warn',
|
|
750
904
|
message: `${issues.length} integration issue(s)${errors > 0 ? `, ${errors} of them errors` : ''}: ${details}`,
|
|
751
|
-
fix:
|
|
905
|
+
fix: `Run \`${formatCliCommand('doctor integration', ctx.cwd)}\` for package-specific diagnostics and resolve cross-package precedence in astryx.config.`,
|
|
752
906
|
};
|
|
753
907
|
}
|
|
754
908
|
|
|
@@ -926,16 +1080,20 @@ function nameTypes(names) {
|
|
|
926
1080
|
}
|
|
927
1081
|
|
|
928
1082
|
/**
|
|
929
|
-
* The section keys
|
|
930
|
-
* command reads them.
|
|
1083
|
+
* The section keys the field reference lists (`astryx docs
|
|
1084
|
+
* authoring/field-reference --index`), read the way that command reads them.
|
|
931
1085
|
* @returns {Promise<{keys: Set<string>} | {keys: null, error: string}>}
|
|
932
1086
|
*/
|
|
933
1087
|
async function authoringTopicKeys() {
|
|
934
1088
|
try {
|
|
1089
|
+
const {AUTHORING_REFERENCE_ROUTE} =
|
|
1090
|
+
await import('../../foundation/discovery/authoring-self-docs.mjs');
|
|
935
1091
|
const catalog = DocsCatalog.fromBuiltins();
|
|
936
|
-
const
|
|
937
|
-
if (!
|
|
938
|
-
|
|
1092
|
+
const node = (await projectTree(catalog)).get(AUTHORING_REFERENCE_ROUTE);
|
|
1093
|
+
if (!node?.ref?.topicFile) {
|
|
1094
|
+
return {keys: null, error: 'the docs tree has no field reference'};
|
|
1095
|
+
}
|
|
1096
|
+
const index = indexView(await lowerTopic(catalog, guideEntry(node)));
|
|
939
1097
|
return {keys: new Set(index.sections.map(section => section.id))};
|
|
940
1098
|
} catch (err) {
|
|
941
1099
|
return {
|
|
@@ -954,7 +1112,7 @@ function surfaceProblems(surface) {
|
|
|
954
1112
|
const problems = [];
|
|
955
1113
|
if (surface.types === 0 && surface.untraced.length === 0) {
|
|
956
1114
|
problems.push(
|
|
957
|
-
|
|
1115
|
+
`@astryxdesign/cli/authoring exports no types, so nothing was compared with \`${formatCliCommand('docs authoring/field-reference')}\``,
|
|
958
1116
|
);
|
|
959
1117
|
}
|
|
960
1118
|
for (const {module, names, reason, source, key} of surface.unreadable) {
|
|
@@ -967,7 +1125,7 @@ function surfaceProblems(surface) {
|
|
|
967
1125
|
? `${source} does not load`
|
|
968
1126
|
: `${source} renders section "${key}", which the topic's index does not list`;
|
|
969
1127
|
problems.push(
|
|
970
|
-
`${nameTypes(names)} from ${module} ${names.length === 1 ? 'has' : 'have'} no doc in
|
|
1128
|
+
`${nameTypes(names)} from ${module} ${names.length === 1 ? 'has' : 'have'} no doc in \`${formatCliCommand('docs authoring/field-reference')}\`: ${why}`,
|
|
971
1129
|
);
|
|
972
1130
|
}
|
|
973
1131
|
for (const {name, reason} of surface.untraced) {
|
|
@@ -1008,7 +1166,7 @@ export async function checkAuthoringDocs(_ctx, options = {}) {
|
|
|
1008
1166
|
const audit = await auditAuthoringSelfDocs({root, sources});
|
|
1009
1167
|
const problems = [
|
|
1010
1168
|
...audit.unreachable.map(
|
|
1011
|
-
source => `${source} is not in
|
|
1169
|
+
source => `${source} is not in \`${formatCliCommand('docs authoring/field-reference')}\``,
|
|
1012
1170
|
),
|
|
1013
1171
|
...audit.failed.map(
|
|
1014
1172
|
({source, error}) => `${source} failed to load: ${error}`,
|
|
@@ -1024,7 +1182,7 @@ export async function checkAuthoringDocs(_ctx, options = {}) {
|
|
|
1024
1182
|
: {keys: options.topicKeys};
|
|
1025
1183
|
const surface = [
|
|
1026
1184
|
...('error' in topic
|
|
1027
|
-
? [
|
|
1185
|
+
? [`\`${formatCliCommand('docs authoring/field-reference')}\` could not be read: ${topic.error}`]
|
|
1028
1186
|
: []),
|
|
1029
1187
|
...surfaceProblems(
|
|
1030
1188
|
await auditAuthoringSurface({root, sources, topicKeys: topic.keys}),
|
|
@@ -1048,7 +1206,7 @@ export async function checkAuthoringDocs(_ctx, options = {}) {
|
|
|
1048
1206
|
id,
|
|
1049
1207
|
label,
|
|
1050
1208
|
status: 'pass',
|
|
1051
|
-
message: `All ${audit.sections} authoring schemas are readable in
|
|
1209
|
+
message: `All ${audit.sections} authoring schemas are readable in \`${formatCliCommand('docs authoring/field-reference')}\`.`,
|
|
1052
1210
|
};
|
|
1053
1211
|
} catch (err) {
|
|
1054
1212
|
return {
|
|
@@ -1088,11 +1246,11 @@ export async function checkCliDocs(_ctx, options = {}) {
|
|
|
1088
1246
|
const problems = [
|
|
1089
1247
|
...audit.missing.map(
|
|
1090
1248
|
source =>
|
|
1091
|
-
`${source} has no namespace, so no
|
|
1249
|
+
`${source} has no namespace, so no \`${formatCliCommand('docs')}\` topic reads it`,
|
|
1092
1250
|
),
|
|
1093
1251
|
...audit.unknown.map(
|
|
1094
1252
|
({source, namespace}) =>
|
|
1095
|
-
`${source} has namespace "${namespace}", which no
|
|
1253
|
+
`${source} has namespace "${namespace}", which no \`${formatCliCommand('docs')}\` topic reads`,
|
|
1096
1254
|
),
|
|
1097
1255
|
...audit.misfiled.map(({message}) => message),
|
|
1098
1256
|
...audit.failed.map(
|
|
@@ -1116,7 +1274,7 @@ export async function checkCliDocs(_ctx, options = {}) {
|
|
|
1116
1274
|
id,
|
|
1117
1275
|
label,
|
|
1118
1276
|
status: 'pass',
|
|
1119
|
-
message: `All ${audit.docs} CLI docs are readable: ${audit.tree} in the
|
|
1277
|
+
message: `All ${audit.docs} CLI docs are readable: ${audit.tree} in the \`${formatCliCommand('docs cli')}\` tree and ${audit.authoring} in \`${formatCliCommand('docs authoring/field-reference')}\`.`,
|
|
1120
1278
|
};
|
|
1121
1279
|
} catch (err) {
|
|
1122
1280
|
return {
|
|
@@ -1233,7 +1391,7 @@ export async function checkDocsProgressiveDisclosure(ctx) {
|
|
|
1233
1391
|
// A guide the docs tree places is a topic read by its route; it is held
|
|
1234
1392
|
// to the same budget as every flat topic.
|
|
1235
1393
|
const guides = [...(await projectTree(catalog)).nodes.values()]
|
|
1236
|
-
// A flat topic in
|
|
1394
|
+
// A flat topic in a topic level is checked above, as a topic.
|
|
1237
1395
|
.filter(node => node.kind === 'generic' && !node.ref?.flatTopic)
|
|
1238
1396
|
.map(guideEntry);
|
|
1239
1397
|
for (const entry of [...catalog.entries(), ...guides]) {
|
|
@@ -1278,6 +1436,456 @@ export async function checkDocsProgressiveDisclosure(ctx) {
|
|
|
1278
1436
|
};
|
|
1279
1437
|
}
|
|
1280
1438
|
|
|
1439
|
+
/**
|
|
1440
|
+
* Check 11 — the command every printed command starts with, and a warning when
|
|
1441
|
+
* loaded integrations declare different ones (their `cliCommand`). Then the
|
|
1442
|
+
* picker uses neither, so commands fall back to the package-manager guess.
|
|
1443
|
+
*
|
|
1444
|
+
* @param {DoctorContext} ctx
|
|
1445
|
+
* @returns {DoctorCheck}
|
|
1446
|
+
*/
|
|
1447
|
+
export function checkCliCommand(ctx) {
|
|
1448
|
+
const id = 'cli-command';
|
|
1449
|
+
const label = 'CLI command';
|
|
1450
|
+
const {command, conflict, declared} = chooseDeclaredCliCommand(
|
|
1451
|
+
declaredCliCommandsOf(ctx.integrations ?? []),
|
|
1452
|
+
);
|
|
1453
|
+
if (conflict) {
|
|
1454
|
+
const claims = declared
|
|
1455
|
+
.map(entry => `${entry.package} (\`${entry.command}\`)`)
|
|
1456
|
+
.join(', ');
|
|
1457
|
+
return {
|
|
1458
|
+
id,
|
|
1459
|
+
label,
|
|
1460
|
+
status: 'warn',
|
|
1461
|
+
message: `Loaded integrations declare different CLI commands: ${claims}. Neither is used, so printed commands start with \`${guessCliInvocation(ctx.cwd)}\`.`,
|
|
1462
|
+
fix: 'Remove the integration that does not belong here, or have every package declare the same `cliCommand` in its astryx.integration manifest.',
|
|
1463
|
+
};
|
|
1464
|
+
}
|
|
1465
|
+
if (command) {
|
|
1466
|
+
const packages = declared.map(entry => entry.package).join(', ');
|
|
1467
|
+
return {
|
|
1468
|
+
id,
|
|
1469
|
+
label,
|
|
1470
|
+
status: 'pass',
|
|
1471
|
+
message: `Printed commands start with \`${command}\`, the cliCommand of ${packages}.`,
|
|
1472
|
+
};
|
|
1473
|
+
}
|
|
1474
|
+
return {
|
|
1475
|
+
id,
|
|
1476
|
+
label,
|
|
1477
|
+
status: 'info',
|
|
1478
|
+
message: `No loaded integration declares a cliCommand, so printed commands start with \`${getCliInvocation(ctx.cwd)}\`.`,
|
|
1479
|
+
};
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
/* ── outside a project: the computer ─────────────────────────────────── */
|
|
1483
|
+
|
|
1484
|
+
/**
|
|
1485
|
+
* What a computer check reads: the running Node, the release that answered
|
|
1486
|
+
* (`meta.answeredBy`), and the newest release the computer knows of.
|
|
1487
|
+
* @typedef {object} ComputerContext
|
|
1488
|
+
* @property {string} nodeVersion
|
|
1489
|
+
* @property {{cli: string, core: string | null, copy: string}} answeredBy
|
|
1490
|
+
* @property {string | null} latest the newest release known, or null
|
|
1491
|
+
* @property {Array<{path: string, state: import('../../foundation/agent-docs/computer-agent-text.mjs').ComputerAgentTextState}>} [agentText]
|
|
1492
|
+
* each file of the computer-level agent text against this release's rendering
|
|
1493
|
+
* @property {import('../../foundation/env/user-settings.mjs').ComputerAgentTextSettings} [agentTextSettings]
|
|
1494
|
+
* the person's choices about the computer-level agent text
|
|
1495
|
+
* @property {string | null} [agentTextCommand] the command the skill file
|
|
1496
|
+
* tells agents to run, or null
|
|
1497
|
+
* @property {string | null} [agentTextInstall] the install step the skill
|
|
1498
|
+
* file records for when that command is not found, or null
|
|
1499
|
+
* @property {string} [cwd] the folder doctor runs in, for the printed fix
|
|
1500
|
+
* @property {import('../../foundation/release/notices.mjs').GlobalBehind | null} [globalBehind]
|
|
1501
|
+
* the CLI installed for the computer, when it is older than the newest
|
|
1502
|
+
* release (outside a project)
|
|
1503
|
+
* @property {import('../../foundation/release/notices.mjs').ProjectLag | null} [projectLag]
|
|
1504
|
+
* the project's release, when it is behind the newest (inside a project)
|
|
1505
|
+
* @property {{key: string, reason: string, at: number} | null} [lastNoticeSkip]
|
|
1506
|
+
* @property {{at: number, reason: string} | null} [lastCheckFailure] why the
|
|
1507
|
+
* last update check did not reach the registry, after the last that did
|
|
1508
|
+
* the newest update notice that did not print, and why (diagnostic only)
|
|
1509
|
+
* @property {{pid: number | null, host: string | null, since: number} | null} [stateLock]
|
|
1510
|
+
* who holds the state file's lock now (diagnostic only)
|
|
1511
|
+
* @property {Array<import('../../foundation/env/search-path.mjs').SearchPathCommand & {upgrade?: string | null, runner?: boolean}>} [searchPathCommands]
|
|
1512
|
+
* every `astryx` on the search path, with the command that upgrades it
|
|
1513
|
+
* the `astryx` commands on the search path, in order
|
|
1514
|
+
* @property {import('../../foundation/integrations/computer-integrations.mjs').ComputerIntegrationCandidate[]} [computerIntegrations]
|
|
1515
|
+
* the integrations installed beside the running CLI
|
|
1516
|
+
* @property {string[]} [loadedComputerIntegrations] the names of those that
|
|
1517
|
+
* loaded outside a project
|
|
1518
|
+
* @property {string[]} [folderIntegrations] the names of the integrations the
|
|
1519
|
+
* folder loads itself, whose copies win over the computer's
|
|
1520
|
+
*/
|
|
1521
|
+
|
|
1522
|
+
/**
|
|
1523
|
+
* The release that answered this run outside a project, and the Core it
|
|
1524
|
+
* reads from.
|
|
1525
|
+
* @param {ComputerContext} ctx
|
|
1526
|
+
* @returns {DoctorCheck}
|
|
1527
|
+
*/
|
|
1528
|
+
export function checkAnsweringRelease(ctx) {
|
|
1529
|
+
const {cli, core} = ctx.answeredBy;
|
|
1530
|
+
return {
|
|
1531
|
+
id: 'answering-release',
|
|
1532
|
+
label: 'Release that answered',
|
|
1533
|
+
status: core ? 'pass' : 'info',
|
|
1534
|
+
message: `${
|
|
1535
|
+
core
|
|
1536
|
+
? `CLI ${cli} with Core ${core} answered, outside a project.`
|
|
1537
|
+
: `CLI ${cli} answered, outside a project. It installs Core ${cli} into the per-user cache the first time a command needs it.`
|
|
1538
|
+
} How each folder is answered: \`${formatCliCommand('astryx docs global', ctx.cwd)}\`.`,
|
|
1539
|
+
};
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
/**
|
|
1543
|
+
* The newest release this computer knows of, beside the one that answered
|
|
1544
|
+
* (spec AST-081 FR10). Runs inside and outside a project, and is always
|
|
1545
|
+
* info. Inside one, a release behind the newest names the install and
|
|
1546
|
+
* upgrade commands; outside one, a CLI installed for the computer that is
|
|
1547
|
+
* behind names the command of the package manager that installed it, after
|
|
1548
|
+
* the Node it needs when the computer runs an older one. Doctor installs
|
|
1549
|
+
* nothing.
|
|
1550
|
+
* @param {ComputerContext} ctx
|
|
1551
|
+
* @returns {DoctorCheck}
|
|
1552
|
+
*/
|
|
1553
|
+
export function checkNewestRelease(ctx) {
|
|
1554
|
+
const check = newestReleaseCheck(ctx);
|
|
1555
|
+
const notes = [
|
|
1556
|
+
checkFailureNote(ctx.lastCheckFailure),
|
|
1557
|
+
skipNote(ctx.lastNoticeSkip),
|
|
1558
|
+
lockNote(ctx.stateLock),
|
|
1559
|
+
].filter(Boolean);
|
|
1560
|
+
return notes.length > 0 ? {...check, message: [check.message, ...notes].join(' ')} : check;
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
/**
|
|
1564
|
+
* The note on a state-file lock held right now, which keeps notices from
|
|
1565
|
+
* being recorded (diagnostic only).
|
|
1566
|
+
* @param {{pid: number | null, host: string | null, since: number} | null | undefined} lock
|
|
1567
|
+
* @returns {string | null}
|
|
1568
|
+
*/
|
|
1569
|
+
function lockNote(lock) {
|
|
1570
|
+
if (!lock) return null;
|
|
1571
|
+
const by = lock.pid == null ? '' : ` by process ${lock.pid}${lock.host ? ` on ${lock.host}` : ''}`;
|
|
1572
|
+
return `The state file's lock is held${by} since ${new Date(lock.since).toISOString()}.`;
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
/**
|
|
1576
|
+
* The note on an update check that did not reach the registry (diagnostic
|
|
1577
|
+
* only): no check, no notices.
|
|
1578
|
+
* @param {{at: number, reason: string} | null | undefined} failed
|
|
1579
|
+
* @returns {string | null}
|
|
1580
|
+
*/
|
|
1581
|
+
function checkFailureNote(failed) {
|
|
1582
|
+
if (!failed) return null;
|
|
1583
|
+
const why =
|
|
1584
|
+
failed.reason === 'npm-missing'
|
|
1585
|
+
? 'npm could not be started'
|
|
1586
|
+
: failed.reason === 'bad-reply'
|
|
1587
|
+
? "npm's answer named no release"
|
|
1588
|
+
: failed.reason.startsWith('npm-failed: ')
|
|
1589
|
+
? `npm failed (${failed.reason.slice('npm-failed: '.length)}); its registry and proxy settings decide where it asks`
|
|
1590
|
+
: failed.reason;
|
|
1591
|
+
return `The last update check, ${new Date(failed.at).toISOString()}, did not reach the registry: ${why}.`;
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
/** What a recorded notice skip's reason means, for doctor's update line. */
|
|
1595
|
+
const SKIP_REASONS = {
|
|
1596
|
+
'already-shown': 'it had already printed that day',
|
|
1597
|
+
'no-newer': 'no newer release was known',
|
|
1598
|
+
'no-project': 'the folder belongs to no Astryx project, so no install command fits',
|
|
1599
|
+
};
|
|
1600
|
+
|
|
1601
|
+
/**
|
|
1602
|
+
* The note on the last update notice that did not print, for diagnosis
|
|
1603
|
+
* (diagnostic state, not a contract).
|
|
1604
|
+
* @param {{key: string, reason: string, at: number} | null | undefined} skip
|
|
1605
|
+
* @returns {string | null}
|
|
1606
|
+
*/
|
|
1607
|
+
function skipNote(skip) {
|
|
1608
|
+
if (!skip) return null;
|
|
1609
|
+
const why = /** @type {Record<string, string>} */ (SKIP_REASONS)[skip.reason] ?? skip.reason;
|
|
1610
|
+
return `Last update notice skipped ${new Date(skip.at).toISOString()} (${skip.key}): ${why}.`;
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
/**
|
|
1614
|
+
* {@link checkNewestRelease} without the skip note.
|
|
1615
|
+
* @param {ComputerContext} ctx
|
|
1616
|
+
* @returns {DoctorCheck}
|
|
1617
|
+
*/
|
|
1618
|
+
function newestReleaseCheck(ctx) {
|
|
1619
|
+
const {latest, globalBehind: behind, projectLag: lag} = ctx;
|
|
1620
|
+
const {cli} = ctx.answeredBy;
|
|
1621
|
+
const base = {id: 'newest-release', label: 'Newest release', status: /** @type {const} */ ('info')};
|
|
1622
|
+
if (behind) {
|
|
1623
|
+
return {
|
|
1624
|
+
...base,
|
|
1625
|
+
message: `${availableLine(behind.current, behind.newest)}. The CLI installed for the computer stays on its release until you upgrade it.`,
|
|
1626
|
+
fix: `${upgradeLine(behind.command, behind.node)}.`,
|
|
1627
|
+
};
|
|
1628
|
+
}
|
|
1629
|
+
if (lag) {
|
|
1630
|
+
return {
|
|
1631
|
+
...base,
|
|
1632
|
+
message: `This project uses Astryx ${lag.current}; ${lag.newest} is the newest.`,
|
|
1633
|
+
fix: `${upgradeLine(`${lag.install}, then ${lag.upgrade}`, lag.node)}.`,
|
|
1634
|
+
};
|
|
1635
|
+
}
|
|
1636
|
+
if (!latest) {
|
|
1637
|
+
return {
|
|
1638
|
+
...base,
|
|
1639
|
+
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.',
|
|
1640
|
+
};
|
|
1641
|
+
}
|
|
1642
|
+
if (isValidSemver(latest) && isValidSemver(cli) && semverCompare(latest, cli) > 0) {
|
|
1643
|
+
return {
|
|
1644
|
+
...base,
|
|
1645
|
+
message: `Release ${latest} is newer than ${cli}, the release that answered.`,
|
|
1646
|
+
};
|
|
1647
|
+
}
|
|
1648
|
+
return {...base, message: `No newer release is known: the newest is ${latest}.`};
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
/**
|
|
1652
|
+
* The `astryx` commands on the search path (spec AST-081 FR11): the first is
|
|
1653
|
+
* the one a shell runs. Warns when it is not the Astryx CLI, or is a release
|
|
1654
|
+
* that predates the hand-off and so answers every folder itself.
|
|
1655
|
+
* @param {ComputerContext} ctx
|
|
1656
|
+
* @returns {DoctorCheck}
|
|
1657
|
+
*/
|
|
1658
|
+
export function checkCliOnPath(ctx) {
|
|
1659
|
+
const rows = ctx.searchPathCommands ?? [];
|
|
1660
|
+
const base = {id: 'cli-on-path', label: '`astryx` on the search path'};
|
|
1661
|
+
const describe = (/** @type {import('../../foundation/env/search-path.mjs').SearchPathCommand} */ row) =>
|
|
1662
|
+
row.astryx ? `${row.file} (CLI ${row.version ?? 'of unknown version'})` : `${row.file} (not the Astryx CLI)`;
|
|
1663
|
+
const others = rows.slice(1);
|
|
1664
|
+
const othersNote = others.length > 0 ? ` Later on the search path: ${others.map(describe).join(', ')}.` : '';
|
|
1665
|
+
const [first] = rows;
|
|
1666
|
+
if (!first) {
|
|
1667
|
+
return {
|
|
1668
|
+
...base,
|
|
1669
|
+
status: 'info',
|
|
1670
|
+
message: 'No `astryx` command on the search path, so `astryx` runs only through a package manager.',
|
|
1671
|
+
fix: 'To run the CLI in any folder, install it for the computer: `npm i -g @astryxdesign/cli`.',
|
|
1672
|
+
};
|
|
1673
|
+
}
|
|
1674
|
+
if (!first.astryx) {
|
|
1675
|
+
return {
|
|
1676
|
+
...base,
|
|
1677
|
+
status: 'warn',
|
|
1678
|
+
message: `The first \`astryx\` on the search path, ${first.file}, is not the Astryx CLI, so \`astryx\` runs another program.${othersNote}`,
|
|
1679
|
+
fix: 'Remove that program from the search path, or put the folder of the CLI installed for the computer before it.',
|
|
1680
|
+
};
|
|
1681
|
+
}
|
|
1682
|
+
if (first.handsOff === false) {
|
|
1683
|
+
return {
|
|
1684
|
+
...base,
|
|
1685
|
+
status: 'warn',
|
|
1686
|
+
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}`,
|
|
1687
|
+
fix: `To upgrade, run: \`${first.upgrade ?? 'npm i -g @astryxdesign/cli@latest'}\`.`,
|
|
1688
|
+
};
|
|
1689
|
+
}
|
|
1690
|
+
return {
|
|
1691
|
+
...base,
|
|
1692
|
+
status: 'pass',
|
|
1693
|
+
message: `\`astryx\` runs ${describe(first)}.${othersNote}`,
|
|
1694
|
+
};
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
/**
|
|
1698
|
+
* The computer-level agent text (spec AST-081 FR4, FR8): turned off, present
|
|
1699
|
+
* and equal to this release's rendering, present but different, or absent,
|
|
1700
|
+
* for the files the chosen agents read. Always `info`: the text is optional,
|
|
1701
|
+
* so it never warns or fails. A file Astryx did not write counts as absent,
|
|
1702
|
+
* and a file a person edited is named; both are kept as they are.
|
|
1703
|
+
* @param {ComputerContext} ctx
|
|
1704
|
+
* @returns {DoctorCheck}
|
|
1705
|
+
*/
|
|
1706
|
+
export function checkComputerAgentText(ctx) {
|
|
1707
|
+
const state = ctx.agentTextSettings && ctx.agentText ? null : computerAgentTextState();
|
|
1708
|
+
const settings = ctx.agentTextSettings ?? /** @type {NonNullable<typeof state>} */ (state).settings;
|
|
1709
|
+
const base = {
|
|
1710
|
+
id: 'computer-agent-text',
|
|
1711
|
+
label: 'Computer-level agent text',
|
|
1712
|
+
status: /** @type {const} */ ('info'),
|
|
1713
|
+
};
|
|
1714
|
+
if (!settings.install) {
|
|
1715
|
+
return {
|
|
1716
|
+
...base,
|
|
1717
|
+
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.',
|
|
1718
|
+
fix: `To turn it back on, run \`${formatCliCommand('astryx init --user', ctx.cwd)}\`.`,
|
|
1719
|
+
};
|
|
1720
|
+
}
|
|
1721
|
+
const entries = ctx.agentText ?? /** @type {NonNullable<typeof state>} */ (state).entries;
|
|
1722
|
+
const command = ctx.agentText ? (ctx.agentTextCommand ?? null) : /** @type {NonNullable<typeof state>} */ (state).command;
|
|
1723
|
+
const recorded = (ctx.agentText ? ctx.agentTextInstall : /** @type {NonNullable<typeof state>} */ (state).install) ?? null;
|
|
1724
|
+
const fix = `Run \`${formatCliCommand('astryx init --user', ctx.cwd)}\`.`;
|
|
1725
|
+
const [file, ...links] = entries;
|
|
1726
|
+
const home = (/** @type {{path: string}} */ e) => displayHomePath(e.path);
|
|
1727
|
+
const linked = links.filter(l => l.state === 'linked').map(home);
|
|
1728
|
+
const copied = links.filter(l => l.state === 'current').map(home);
|
|
1729
|
+
const skipped = links.filter(l => l.state === 'foreign' || l.state === 'edited').map(home);
|
|
1730
|
+
const dangling = links.filter(l => l.state === 'dangling').map(home);
|
|
1731
|
+
const missing = links.filter(l => l.state === 'absent' || l.state === 'differs').map(home);
|
|
1732
|
+
const linkNote =
|
|
1733
|
+
(linked.length > 0 ? ` Linked into: ${linked.join(', ')}.` : '') +
|
|
1734
|
+
(copied.length > 0 ? ` Copied into: ${copied.join(', ')}.` : '') +
|
|
1735
|
+
(skipped.length > 0 ? ` Not linked, because something Astryx did not create is there: ${skipped.join(', ')}.` : '') +
|
|
1736
|
+
(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(', ')}.` : '') +
|
|
1737
|
+
(missing.length > 0 ? ` Not linked yet: ${missing.join(', ')}.` : '');
|
|
1738
|
+
if (file.state === 'foreign' || file.state === 'edited') {
|
|
1739
|
+
return {
|
|
1740
|
+
...base,
|
|
1741
|
+
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}`,
|
|
1742
|
+
};
|
|
1743
|
+
}
|
|
1744
|
+
if (file.state === 'absent') {
|
|
1745
|
+
return {
|
|
1746
|
+
...base,
|
|
1747
|
+
message: `No computer-level agent text: agents outside a project with Astryx agent docs do not know Astryx is here.${linkNote}`,
|
|
1748
|
+
fix,
|
|
1749
|
+
};
|
|
1750
|
+
}
|
|
1751
|
+
const current = file.state === 'current';
|
|
1752
|
+
const status = `${current ? 'The computer-level agent text matches this release' : "The computer-level agent text differs from this release's"}: ${home(file)}.`;
|
|
1753
|
+
// The skill outlives the CLI it names when the home folder outlasts the
|
|
1754
|
+
// folder the CLI is installed in, as on a machine whose system folders
|
|
1755
|
+
// reset on restart. Reported only when no `astryx` command is on the search
|
|
1756
|
+
// path at all, apart from a package runner's own copy, which it puts first
|
|
1757
|
+
// only for the run it starts (the way back when the global CLI is gone).
|
|
1758
|
+
// Any other `astryx`, even one the scan cannot trace to the package, such
|
|
1759
|
+
// as the shim of Volta, asdf or mise, may well run the CLI, so doctor stays
|
|
1760
|
+
// quiet here and cli-on-path reports what it can; never a false "gone".
|
|
1761
|
+
// The reinstalled copy refreshes the text too.
|
|
1762
|
+
const rows = ctx.searchPathCommands;
|
|
1763
|
+
if (command === COMPUTER_COMMAND && rows && !rows.some(r => !r.runner)) {
|
|
1764
|
+
return {
|
|
1765
|
+
...base,
|
|
1766
|
+
message: `${status} It tells agents to run \`${COMPUTER_COMMAND}\`, but no \`${COMPUTER_COMMAND}\` command is on the search path, so agents that read it find no CLI to run (as when a restart removes the CLI installed for the computer and keeps the home folder).${linkNote}`,
|
|
1767
|
+
fix: recorded
|
|
1768
|
+
? `Run \`${recorded}\`, the step the skill names for when \`${COMPUTER_COMMAND}\` is not found.`
|
|
1769
|
+
: `Install it for the computer: \`${COMPUTER_INSTALL_STEP}\`.`,
|
|
1770
|
+
};
|
|
1771
|
+
}
|
|
1772
|
+
return {
|
|
1773
|
+
...base,
|
|
1774
|
+
message: `${status}${linkNote}`,
|
|
1775
|
+
...(!current || missing.length > 0 || dangling.length > 0 ? {fix} : {}),
|
|
1776
|
+
};
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
/**
|
|
1780
|
+
* The integrations installed for the computer (spec AST-081 FR12). Outside a
|
|
1781
|
+
* project: each one that loads, and a warning for each that is skipped
|
|
1782
|
+
* because its peer ranges exclude the answering release, or fails to load.
|
|
1783
|
+
* @param {ComputerContext} ctx
|
|
1784
|
+
* @returns {DoctorCheck}
|
|
1785
|
+
*/
|
|
1786
|
+
export function checkComputerIntegrations(ctx) {
|
|
1787
|
+
const found = ctx.computerIntegrations ?? [];
|
|
1788
|
+
const loaded = new Set(ctx.loadedComputerIntegrations ?? []);
|
|
1789
|
+
const base = {id: 'computer-integrations', label: 'Integrations installed for this computer'};
|
|
1790
|
+
if (found.length === 0) {
|
|
1791
|
+
return {
|
|
1792
|
+
...base,
|
|
1793
|
+
status: 'info',
|
|
1794
|
+
message: 'No integration is installed beside the CLI installed for this computer.',
|
|
1795
|
+
};
|
|
1796
|
+
}
|
|
1797
|
+
const label = (/** @type {{name: string, version?: string}} */ c) => (c.version ? `${c.name}@${c.version}` : c.name);
|
|
1798
|
+
const own = new Set(ctx.folderIntegrations ?? []);
|
|
1799
|
+
const shadowed = found.filter(c => own.has(c.name));
|
|
1800
|
+
const rest = found.filter(c => !own.has(c.name));
|
|
1801
|
+
const used = rest.filter(c => !c.incompatible && loaded.has(c.name));
|
|
1802
|
+
const skipped = rest.filter(c => c.incompatible);
|
|
1803
|
+
const failed = rest.filter(c => !c.incompatible && !loaded.has(c.name));
|
|
1804
|
+
const notes = [
|
|
1805
|
+
used.length > 0 ? `Used outside a project: ${used.map(label).join(', ')}.` : '',
|
|
1806
|
+
...shadowed.map(c => `${label(c)} is not used here: this folder loads its own copy of ${c.name}.`),
|
|
1807
|
+
...skipped.map(c => `Skipped ${label(c)}: ${c.incompatible}.`),
|
|
1808
|
+
...failed.map(c => `${label(c)} could not be loaded.`),
|
|
1809
|
+
].filter(Boolean);
|
|
1810
|
+
const fixes = [
|
|
1811
|
+
...skipped.map(c => `install a release of ${c.name} that supports this CLI`),
|
|
1812
|
+
...failed.map(c => `run \`${formatCliCommand(`astryx doctor integration validate ${c.name}`, ctx.cwd)}\``),
|
|
1813
|
+
];
|
|
1814
|
+
return {
|
|
1815
|
+
...base,
|
|
1816
|
+
status: skipped.length + failed.length > 0 ? 'warn' : 'pass',
|
|
1817
|
+
message: notes.join(' '),
|
|
1818
|
+
...(fixes.length > 0 ? {fix: `To fix: ${fixes.join('; ')}.`} : {}),
|
|
1819
|
+
};
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
/**
|
|
1823
|
+
* Inside a project, the integrations installed for the computer that the
|
|
1824
|
+
* project does not install: available, never used (spec AST-081 FR12).
|
|
1825
|
+
* Always info.
|
|
1826
|
+
* @param {{installed: Set<string>, candidates: import('../../foundation/integrations/computer-integrations.mjs').ComputerIntegrationCandidate[], install: ((name: string) => string) | null, elsewhere?: boolean}} input
|
|
1827
|
+
* `install`: the command that adds a package with the project's package
|
|
1828
|
+
* manager (read by the adapter); null when the folder belongs to no
|
|
1829
|
+
* project, or `elsewhere`: its package.json is not the project's, where the
|
|
1830
|
+
* fix points at the project's folder
|
|
1831
|
+
* @returns {DoctorCheck}
|
|
1832
|
+
*/
|
|
1833
|
+
export function checkComputerIntegrationsAvailable({installed, candidates, install, elsewhere = false}) {
|
|
1834
|
+
const available = candidates.filter(c => !installed.has(c.name));
|
|
1835
|
+
const base = {id: 'computer-integrations', label: 'Integrations installed for this computer', status: /** @type {const} */ ('info')};
|
|
1836
|
+
if (available.length === 0) {
|
|
1837
|
+
return {...base, message: 'No integration installed for this computer is missing from this project.'};
|
|
1838
|
+
}
|
|
1839
|
+
const add = install;
|
|
1840
|
+
return {
|
|
1841
|
+
...base,
|
|
1842
|
+
message: `Installed for this computer but not in this project, so not used here: ${available.map(c => c.name).join(', ')}.`,
|
|
1843
|
+
...(add
|
|
1844
|
+
? {fix: `To use one in this project, run ${available.map(c => `\`${add(c.name)}\``).join(' or ')}.`}
|
|
1845
|
+
: elsewhere
|
|
1846
|
+
? {fix: NO_PROJECT_FIX}
|
|
1847
|
+
: {}),
|
|
1848
|
+
};
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
/**
|
|
1852
|
+
* The checks doctor runs outside a project, in order.
|
|
1853
|
+
* @type {Array<(ctx: ComputerContext) => DoctorCheck>}
|
|
1854
|
+
*/
|
|
1855
|
+
export const COMPUTER_CHECKS = [
|
|
1856
|
+
ctx =>
|
|
1857
|
+
checkNodeVersion({
|
|
1858
|
+
cwd: '',
|
|
1859
|
+
nodeVersion: ctx.nodeVersion,
|
|
1860
|
+
coreDir: null,
|
|
1861
|
+
configPath: null,
|
|
1862
|
+
}),
|
|
1863
|
+
checkAnsweringRelease,
|
|
1864
|
+
checkNewestRelease,
|
|
1865
|
+
checkCliOnPath,
|
|
1866
|
+
checkComputerIntegrations,
|
|
1867
|
+
checkComputerAgentText,
|
|
1868
|
+
];
|
|
1869
|
+
|
|
1870
|
+
/**
|
|
1871
|
+
* Doctor outside a project: the computer, never the folder.
|
|
1872
|
+
* @param {string} cwd
|
|
1873
|
+
* @returns {Promise<DoctorReport>}
|
|
1874
|
+
*/
|
|
1875
|
+
async function runComputerChecks(cwd) {
|
|
1876
|
+
/** @type {ComputerContext} */
|
|
1877
|
+
const ctx = {
|
|
1878
|
+
nodeVersion: process.versions.node,
|
|
1879
|
+
cwd,
|
|
1880
|
+
...releaseFacts(cwd, {project: false}),
|
|
1881
|
+
};
|
|
1882
|
+
Object.assign(ctx, await computerIntegrationsOutside(cwd));
|
|
1883
|
+
const checks = COMPUTER_CHECKS.map(fn => fn(ctx));
|
|
1884
|
+
const summary = {pass: 0, warn: 0, fail: 0, info: 0};
|
|
1885
|
+
for (const c of checks) summary[c.status] += 1;
|
|
1886
|
+
return {checks, summary};
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1281
1889
|
/**
|
|
1282
1890
|
* Ordered list of synchronous check functions. Append here to add a check.
|
|
1283
1891
|
* (checkConfig is async and is awaited separately by {@link runChecks}.)
|
|
@@ -1294,6 +1902,7 @@ export const SYNC_CHECKS = [
|
|
|
1294
1902
|
checkAgentDocs,
|
|
1295
1903
|
checkPeerDeps,
|
|
1296
1904
|
checkPackageManager,
|
|
1905
|
+
checkCliCommand,
|
|
1297
1906
|
];
|
|
1298
1907
|
|
|
1299
1908
|
/**
|
|
@@ -1305,7 +1914,8 @@ export const SYNC_CHECKS = [
|
|
|
1305
1914
|
*/
|
|
1306
1915
|
export async function runChecks(options = {}) {
|
|
1307
1916
|
const cwd = options.cwd ?? process.cwd();
|
|
1308
|
-
|
|
1917
|
+
if (outsideProject(cwd)) return runComputerChecks(cwd);
|
|
1918
|
+
const coreDir = findProjectCoreDir(cwd);
|
|
1309
1919
|
// findConfigPath throws when multiple config files coexist. That's a
|
|
1310
1920
|
// misconfiguration doctor exists to report — catch it and surface it through
|
|
1311
1921
|
// checkConfig as a FAIL rather than crashing the whole diagnostic engine.
|
|
@@ -1339,7 +1949,9 @@ export async function runChecks(options = {}) {
|
|
|
1339
1949
|
/** @type {import('../../foundation/config/project.mjs').Project | null} */
|
|
1340
1950
|
let project = null;
|
|
1341
1951
|
try {
|
|
1342
|
-
project
|
|
1952
|
+
// Doctor judges the project, so it reads only the Core the project
|
|
1953
|
+
// installed, never a carried one (spec AST-081 FR3).
|
|
1954
|
+
project = await Project.load(cwd, {core: 'project'});
|
|
1343
1955
|
} catch (err) {
|
|
1344
1956
|
// A project the CLI cannot load leaves the checks that need it
|
|
1345
1957
|
// skipped. The reason is kept: those checks and the config
|
|
@@ -1442,6 +2054,8 @@ export async function runChecks(options = {}) {
|
|
|
1442
2054
|
cwd,
|
|
1443
2055
|
nodeVersion: process.versions.node,
|
|
1444
2056
|
coreDir,
|
|
2057
|
+
ownCli: projectHasOwnCli(cwd),
|
|
2058
|
+
projectCore: projectCoreVersion(cwd),
|
|
1445
2059
|
configPath,
|
|
1446
2060
|
integrations,
|
|
1447
2061
|
docsCatalog,
|
|
@@ -1466,6 +2080,31 @@ export async function runChecks(options = {}) {
|
|
|
1466
2080
|
checks.push(await checkConfig(ctx));
|
|
1467
2081
|
}
|
|
1468
2082
|
}
|
|
2083
|
+
const facts = releaseFacts(cwd, {project: true});
|
|
2084
|
+
checks.push(
|
|
2085
|
+
checkNewestRelease({
|
|
2086
|
+
nodeVersion: ctx.nodeVersion,
|
|
2087
|
+
answeredBy: facts.answeredBy,
|
|
2088
|
+
latest: facts.latest,
|
|
2089
|
+
projectLag: facts.projectLag,
|
|
2090
|
+
lastNoticeSkip: facts.lastNoticeSkip,
|
|
2091
|
+
lastCheckFailure: facts.lastCheckFailure,
|
|
2092
|
+
stateLock: facts.stateLock,
|
|
2093
|
+
}),
|
|
2094
|
+
);
|
|
2095
|
+
checks.push(
|
|
2096
|
+
checkCliOnPath({
|
|
2097
|
+
nodeVersion: ctx.nodeVersion,
|
|
2098
|
+
answeredBy: facts.answeredBy,
|
|
2099
|
+
latest: null,
|
|
2100
|
+
searchPathCommands: facts.searchPathCommands,
|
|
2101
|
+
}),
|
|
2102
|
+
);
|
|
2103
|
+
{
|
|
2104
|
+
const loadedNames = (project?.loadedIntegrations ?? []).map((/** @type {{name: string}} */ i) => i.name);
|
|
2105
|
+
const candidates = await computerIntegrationsToAdd(cwd, loadedNames);
|
|
2106
|
+
checks.push(checkComputerIntegrationsAvailable({installed: new Set(loadedNames), candidates, install: installCommandFor(cwd), elsewhere: insideProjectElsewhere(cwd)}));
|
|
2107
|
+
}
|
|
1469
2108
|
checks.push(await checkAuthoringDocs(ctx));
|
|
1470
2109
|
checks.push(await checkCliDocs(ctx));
|
|
1471
2110
|
checks.push(await checkDocsTree(ctx));
|