@astryxdesign/cli 0.7.2 → 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/README.md +104 -71
- package/api/build/_adapter.d.mts +58 -0
- package/api/build/_adapter.mjs +127 -3
- 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.mjs +25 -6
- package/api/build/build.type.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 -398
- 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.mjs +39 -5
- package/api/component/component-replacement.test.mjs +1 -0
- package/api/component/component.mjs +17 -3
- package/api/component/component.test.mjs +15 -0
- package/api/component/doc-links.test.mjs +2 -2
- package/api/discover/_adapter.d.mts +1 -2
- package/api/discover/_adapter.mjs +42 -17
- package/api/discover/_adapter.test.mjs +42 -0
- package/api/discover/discover.mjs +0 -1
- package/api/docs/_adapter.d.mts +2 -2
- package/api/docs/_adapter.mjs +82 -23
- package/api/docs/docs-homes.test.mjs +127 -0
- package/api/docs/docs.doc.mjs +3 -3
- package/api/docs/docs.test.mjs +35 -19
- package/api/docs/integration-tree.test.mjs +20 -20
- package/api/docs/integrationDocs.test.mjs +1 -1
- package/api/docs/namespace-section.test.mjs +6 -6
- package/api/docs/reference-blocks.test.mjs +2 -2
- package/api/doctor/_adapter.d.mts +33 -13
- package/api/doctor/_adapter.mjs +55 -25
- package/api/doctor/doctor.d.mts +23 -5
- package/api/doctor/doctor.mjs +183 -40
- package/api/doctor/doctor.test.mjs +95 -12
- package/api/hook/hook.mjs +1 -1
- package/api/init/init.doc.mjs +20 -6
- package/api/init/init.test.mjs +18 -2
- package/api/init/init.type.d.mts +3 -3
- package/api/init/init.type.mjs +3 -3
- package/api/init/remove/remove.mjs +17 -4
- package/api/init/remove/remove.test.mjs +114 -2
- package/api/init/run/run.mjs +69 -6
- package/api/integration/_adapter.d.mts +8 -0
- package/api/integration/_adapter.mjs +21 -1
- package/api/integration/authoring-checks.mjs +83 -9
- package/api/integration/authoring-checks.test.mjs +220 -0
- package/api/integration/pack-check.mjs +123 -4
- package/api/integration/pack-check.test.mjs +87 -0
- package/api/integration/validate-integration-case-disk.test.mjs +111 -0
- package/api/integration/validate-integration-fixes.test.mjs +6 -5
- package/api/integration/validate-integration-gaps.test.mjs +1975 -0
- package/api/integration/validate-integration.d.mts +15 -2
- package/api/integration/validate-integration.mjs +298 -39
- package/api/integration/validate-integration.type.d.mts +90 -1
- package/api/integration/validate-integration.type.mjs +67 -2
- package/api/integration/validateIntegration.doc.mjs +1 -1
- package/api/search/ORDERING.md +28 -0
- package/api/search/_adapter.d.mts +82 -2
- package/api/search/_adapter.mjs +157 -10
- 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 -305
- package/api/search/search.doc.mjs +8 -6
- package/api/search/search.mjs +56 -2482
- package/api/search/search.test.mjs +14 -14
- package/api/search/search.type.d.mts +6 -1
- package/api/search/search.type.mjs +6 -1
- 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/template/template.mjs +5 -1
- package/api/theme/build/build.packed-old-core.test.mjs +1 -0
- package/api/upgrade/_adapter.d.mts +57 -9
- package/api/upgrade/_adapter.mjs +198 -28
- 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/run.d.mts +4 -2
- package/api/upgrade/run/run.mjs +13 -2
- package/api/upgrade/run/run.test.mjs +417 -3
- package/api/upgrade/upgrade.doc.mjs +10 -5
- package/api/upgrade/upgrade.mjs +13 -2
- package/api/upgrade/upgrade.test.mjs +194 -0
- package/api/upgrade/upgrade.type.d.mts +5 -3
- package/api/upgrade/upgrade.type.mjs +8 -6
- 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/docs/author-a-theme.doc.mjs +2 -2
- package/assets/docs/is-my-code-good.doc.mjs +287 -0
- package/assets/docs/tree/add-a-component.doc.mjs +1 -1
- package/assets/docs/tree/add-a-theme.doc.mjs +1 -1
- package/assets/docs/tree/add-a-topic.doc.mjs +2 -2
- package/assets/docs/tree/agent-guidance.doc.mjs +1 -1
- package/assets/docs/tree/api.doc.mjs +6 -0
- package/assets/docs/tree/{integrations.doc.mjs → authoring.doc.mjs} +15 -6
- package/assets/docs/tree/block-template.doc.mjs +1 -1
- package/assets/docs/tree/build-the-template.doc.mjs +1 -1
- package/assets/docs/tree/building-blocks.doc.mjs +2 -2
- package/assets/docs/tree/check-the-props.doc.mjs +1 -1
- package/assets/docs/tree/check-your-docs.doc.mjs +2 -2
- package/assets/docs/tree/checks.doc.mjs +3 -3
- package/assets/docs/tree/ci-and-containers.doc.mjs +13 -0
- package/assets/docs/tree/cli-command.doc.mjs +1 -1
- package/assets/docs/tree/cli.doc.mjs +1 -1
- package/assets/docs/tree/codemods.doc.mjs +1 -1
- package/assets/docs/tree/component-family.doc.mjs +1 -1
- package/assets/docs/tree/component-imports.doc.mjs +1 -1
- package/assets/docs/tree/components.doc.mjs +1 -1
- package/assets/docs/tree/configuration.doc.mjs +1 -1
- package/assets/docs/tree/debug-and-gap-reports.doc.mjs +1 -1
- package/assets/docs/tree/define-the-theme.doc.mjs +1 -1
- package/assets/docs/tree/describe-the-component.doc.mjs +1 -1
- package/assets/docs/tree/docs.doc.mjs +1 -1
- package/assets/docs/tree/document-the-template.doc.mjs +1 -1
- package/assets/docs/tree/document-the-theme.doc.mjs +1 -1
- package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
- package/assets/docs/tree/extend-or-replace.doc.mjs +1 -1
- package/assets/docs/{authoring.doc.mjs → tree/field-reference.doc.mjs} +4 -3
- package/assets/docs/tree/fonts-and-assets.doc.mjs +1 -1
- package/assets/docs/tree/generate-a-palette.doc.mjs +1 -1
- package/assets/docs/tree/global-integrations.doc.mjs +2 -2
- package/assets/docs/tree/grade-template-with-agent.doc.mjs +4 -4
- package/assets/docs/tree/help.doc.mjs +2 -2
- package/assets/docs/tree/host-entry.doc.mjs +128 -0
- package/assets/docs/tree/links.doc.mjs +1 -1
- package/assets/docs/tree/package-and-test.doc.mjs +1 -1
- package/assets/docs/tree/page-template.doc.mjs +1 -1
- package/assets/docs/tree/publishing.doc.mjs +1 -1
- package/assets/docs/tree/quick-start.doc.mjs +1 -1
- package/assets/docs/tree/replace-a-core-component.doc.mjs +1 -1
- package/assets/docs/tree/replace-a-core-template.doc.mjs +1 -1
- package/assets/docs/tree/sections-and-placement.doc.mjs +1 -1
- package/assets/docs/tree/see-it-in-an-app.doc.mjs +1 -1
- package/assets/docs/tree/ship.doc.mjs +2 -2
- package/assets/docs/tree/short-and-findable.doc.mjs +1 -1
- package/assets/docs/tree/single-component.doc.mjs +1 -1
- package/assets/docs/tree/start-a-template.doc.mjs +1 -1
- package/assets/docs/tree/subcomponent.doc.mjs +1 -1
- package/assets/docs/tree/template-assets.doc.mjs +1 -1
- package/assets/docs/tree/template-doc-overview.doc.mjs +2 -2
- 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 +1 -1
- package/assets/docs/tree/templates.doc.mjs +1 -1
- package/assets/docs/tree/test-in-an-app.doc.mjs +1 -1
- package/assets/docs/tree/test-template-in-app.doc.mjs +1 -1
- package/assets/docs/tree/themes.doc.mjs +1 -1
- package/assets/docs/tree/tokens-data.doc.mjs +2 -2
- package/assets/docs/tree/troubleshooting.doc.mjs +1 -1
- package/assets/docs/tree/upgrading.doc.mjs +1 -1
- package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +1 -1
- package/assets/docs/tree/verify-packed-template.doc.mjs +1 -1
- package/assets/docs/tree/versioning.doc.mjs +5 -1
- package/assets/docs/tree/write-good-templates.doc.mjs +1 -1
- package/assets/docs/tree/write-the-template-file.doc.mjs +1 -1
- package/assets/docs/use-integrations.doc.mjs +120 -0
- package/assets/docs/working-with-ai.doc.mjs +6 -2
- 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/authoring/debug/parse.d.mts +1 -1
- package/authoring/doctypes/schema/schema.doc.mjs +1 -1
- package/authoring/integration/integration.doc.mjs +1 -1
- package/authoring/integration/type.ts +1 -1
- package/clients/cli/bin/astryx.mjs +7 -78
- package/clients/cli/command-result-coverage.test.mjs +6 -5
- package/clients/cli/commands/build-theme.color-scheme.test.mjs +1 -1
- package/clients/cli/commands/{component/index.mjs → component.mjs} +37 -37
- package/clients/cli/commands/component.test.mjs +6 -6
- package/clients/cli/commands/docs.doc.mjs +2 -2
- package/clients/cli/commands/docs.mjs +1 -1
- package/clients/cli/commands/docs.test.mjs +14 -14
- package/clients/cli/commands/doctor-integration.test.mjs +49 -1
- package/clients/cli/commands/doctor.doc.mjs +1 -1
- package/clients/cli/commands/doctor.mjs +40 -0
- package/clients/cli/commands/doctor.test.mjs +65 -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 +230 -1
- package/clients/cli/commands/init.doc.mjs +28 -9
- package/clients/cli/commands/init.flag-help.test.mjs +1 -0
- package/clients/cli/commands/init.mjs +2 -2
- package/clients/cli/commands/integration-check.test.mjs +48 -0
- package/clients/cli/commands/integration.doc.mjs +1 -1
- package/clients/cli/commands/manifest.doc.mjs +1 -1
- package/clients/cli/commands/manifest.mjs +67 -0
- package/clients/cli/commands/outside-project.test.mjs +101 -1
- package/clients/cli/commands/postinstall.doc.mjs +23 -0
- package/clients/cli/commands/postinstall.mjs +31 -0
- package/clients/cli/commands/setup-nudge.test.mjs +78 -0
- package/clients/cli/commands/{build-theme.mjs → theme.mjs} +1 -1
- package/clients/cli/commands/upgrade.doc.mjs +4 -2
- package/clients/cli/commands/upgrade.mjs +9 -2
- package/clients/cli/commands/upgrade.subfolder-path.test.mjs +97 -0
- package/clients/cli/index.mjs +54 -94
- package/clients/cli/lib/component-format.mjs +1 -1
- package/clients/cli/lib/define-command.mjs +12 -7
- package/clients/cli/lib/exit-codes.test.mjs +5 -0
- package/clients/cli/lib/manifest.test.mjs +12 -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 +32 -7
- package/foundation/agent-docs/agent-doc-state.mjs +58 -9
- package/foundation/agent-docs/agent-docs.d.mts +100 -12
- package/foundation/agent-docs/agent-docs.mjs +1017 -105
- 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 +39 -2
- package/foundation/agent-docs/computer-agent-text.mjs +135 -8
- package/foundation/agent-docs/computer-agent-text.test.mjs +99 -2
- package/foundation/config/project.mjs +20 -22
- package/foundation/config/project.test.mjs +56 -0
- package/foundation/discovery/authoring-self-docs.d.mts +7 -0
- package/foundation/discovery/authoring-self-docs.mjs +16 -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 +4 -3
- package/foundation/discovery/cli-self-docs.test.mjs +2 -2
- package/foundation/discovery/component-discovery.d.mts +37 -0
- package/foundation/discovery/component-discovery.mjs +80 -5
- package/foundation/discovery/component-loader.d.mts +1 -1
- package/foundation/discovery/docs-discovery.mjs +14 -1
- package/foundation/discovery/module-exports.d.mts +41 -0
- package/foundation/discovery/module-exports.mjs +253 -0
- package/foundation/discovery/runner-allowlist.d.mts +2 -4
- package/foundation/discovery/runner-allowlist.mjs +2 -4
- 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.test.mjs +1 -1
- package/foundation/discovery/template-adapter.mjs +18 -1
- package/foundation/discovery/template-needs.mjs +1 -44
- package/foundation/discovery/theme-discovery.mjs +147 -3
- package/foundation/doc-compiler/doc-loads.test.mjs +33 -9
- 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 +77 -43
- package/foundation/doc-compiler/tree.test.mjs +7 -7
- package/foundation/fs/paths.d.mts +70 -8
- package/foundation/fs/paths.mjs +556 -38
- package/foundation/fs/paths.test.mjs +430 -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 +6 -3
- package/foundation/integrations/computer-integrations.mjs +38 -9
- package/foundation/integrations/contribution-inventory.d.mts +15 -20
- package/foundation/integrations/contribution-inventory.mjs +41 -5
- package/foundation/integrations/exports-subpaths.d.mts +57 -0
- package/foundation/integrations/exports-subpaths.mjs +113 -0
- package/foundation/integrations/integrations.d.mts +27 -1
- package/foundation/integrations/integrations.mjs +61 -2
- 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 +115 -0
- package/foundation/integrations/validate-contributions.mjs +1168 -13
- package/foundation/release/cache.test.mjs +24 -21
- package/foundation/release/global-state.d.mts +8 -4
- package/foundation/release/global-state.mjs +4 -2
- package/foundation/release/handoff.d.mts +23 -4
- package/foundation/release/handoff.mjs +175 -8
- package/foundation/release/notices.d.mts +62 -8
- package/foundation/release/notices.mjs +136 -25
- package/foundation/release/notices.test.mjs +21 -0
- package/foundation/release/run-context.mjs +14 -0
- package/foundation/response/response-types.doc.mjs +1 -1
- 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/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 +14 -9
package/api/doctor/doctor.mjs
CHANGED
|
@@ -28,7 +28,15 @@ import * as fs from 'node:fs';
|
|
|
28
28
|
import * as path from 'node:path';
|
|
29
29
|
|
|
30
30
|
import {MIN_NODE_VERSION, isNodeVersionSupported} from '../../foundation/env/node-version.mjs';
|
|
31
|
-
import {
|
|
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';
|
|
32
40
|
import {CLI_ROOT, findProjectCoreDir, findInstalledPackage} from '../../foundation/fs/paths.mjs';
|
|
33
41
|
import {explainPackageManager, formatCliCommand, getCliInvocation, guessCliInvocation} from '../../foundation/env/package-manager.mjs';
|
|
34
42
|
import {chooseDeclaredCliCommand, declaredCliCommandsOf} from '../../foundation/env/cli-command.mjs';
|
|
@@ -57,8 +65,9 @@ import {typedEdges} from '../docs/node/node.mjs';
|
|
|
57
65
|
import {detailView, indexView} from '../../foundation/doc-compiler/lenses.mjs';
|
|
58
66
|
import {semverCompare, isValidSemver, satisfiesRange} from '../../foundation/env/semver.mjs';
|
|
59
67
|
import {checkAppThemes, checkThemes} from './theme-checks.mjs';
|
|
60
|
-
import {availableLine, upgradeLine} from '../../foundation/release/notices.mjs';
|
|
61
|
-
import {
|
|
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';
|
|
62
71
|
|
|
63
72
|
/**
|
|
64
73
|
* @typedef {'pass'|'warn'|'fail'|'info'} DoctorStatus
|
|
@@ -278,15 +287,25 @@ export function checkVersionAlignment(ctx) {
|
|
|
278
287
|
// the run (spec AST-081 FR2): say so, and how to add the CLI at Core's
|
|
279
288
|
// version.
|
|
280
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;
|
|
281
301
|
return {
|
|
282
302
|
id: 'version-alignment',
|
|
283
303
|
label: '@astryxdesign/core <-> @astryxdesign/cli alignment',
|
|
284
|
-
status:
|
|
285
|
-
message:
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
fix: `${coreVersion === cliVersion ? 'To pin it for the team and CI' : 'To match'}, run: ${addCliCommandFor(ctx.cwd, coreVersion)}.`,
|
|
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} : {}),
|
|
290
309
|
};
|
|
291
310
|
}
|
|
292
311
|
// The project's own CLI answers this project whatever its version
|
|
@@ -300,10 +319,31 @@ export function checkVersionAlignment(ctx) {
|
|
|
300
319
|
message: drift
|
|
301
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}.`
|
|
302
321
|
: `@astryxdesign/core v${coreVersion} is in step with @astryxdesign/cli v${cliVersion}.`,
|
|
303
|
-
...(drift ?
|
|
322
|
+
...(drift ? alignFix(ctx.cwd, cliVersion, coreVersion) : {}),
|
|
304
323
|
};
|
|
305
324
|
}
|
|
306
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
|
+
|
|
307
347
|
/**
|
|
308
348
|
* Check 5 — astryx.config.mjs (if present) loads and has a valid shape.
|
|
309
349
|
* @param {DoctorContext} ctx
|
|
@@ -610,6 +650,21 @@ export function checkConfiguredIntegrations(ctx) {
|
|
|
610
650
|
};
|
|
611
651
|
}
|
|
612
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
|
+
|
|
613
668
|
/**
|
|
614
669
|
* Check 7 — agent docs exist and contain the Astryx section markers.
|
|
615
670
|
* @param {DoctorContext} ctx
|
|
@@ -617,8 +672,15 @@ export function checkConfiguredIntegrations(ctx) {
|
|
|
617
672
|
*/
|
|
618
673
|
export function checkAgentDocs(ctx) {
|
|
619
674
|
// Every file init can write (one shared list), looked for in the working
|
|
620
|
-
// directory
|
|
621
|
-
|
|
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
|
+
];
|
|
622
684
|
const present = dirs.flatMap(dir =>
|
|
623
685
|
AGENT_DOC_PATHS.map(rel => path.join(dir, rel)).filter(abs =>
|
|
624
686
|
fs.existsSync(abs),
|
|
@@ -626,6 +688,15 @@ export function checkAgentDocs(ctx) {
|
|
|
626
688
|
);
|
|
627
689
|
/** @param {string} abs */
|
|
628
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;
|
|
629
700
|
|
|
630
701
|
if (present.length === 0) {
|
|
631
702
|
return {
|
|
@@ -633,29 +704,64 @@ export function checkAgentDocs(ctx) {
|
|
|
633
704
|
label: 'AI agent docs',
|
|
634
705
|
status: 'info',
|
|
635
706
|
message: `No agent docs found: looked for ${AGENT_DOC_PATHS.join(', ')} in ${dirs.map(dir => path.relative(ctx.cwd, dir) || '.').join(' and ')}.`,
|
|
636
|
-
fix:
|
|
707
|
+
fix: fixFor(
|
|
708
|
+
`Generate agent docs with \`${getCliInvocation(ctx.cwd)} init --features agents\`.`,
|
|
709
|
+
),
|
|
637
710
|
};
|
|
638
711
|
}
|
|
639
712
|
|
|
640
|
-
|
|
713
|
+
/** @param {string} abs */
|
|
714
|
+
const read = abs => {
|
|
641
715
|
try {
|
|
642
|
-
|
|
643
|
-
return (
|
|
644
|
-
(content.includes('<!-- ASTRYX:START -->') || content.includes('<!-- XDS:START -->')) &&
|
|
645
|
-
(content.includes('<!-- ASTRYX:END -->') || content.includes('<!-- XDS:END -->'))
|
|
646
|
-
);
|
|
716
|
+
return fs.readFileSync(abs, 'utf-8');
|
|
647
717
|
} catch {
|
|
648
|
-
return
|
|
718
|
+
return '';
|
|
649
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
|
+
);
|
|
650
728
|
});
|
|
651
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
|
+
|
|
652
756
|
if (withMarkers.length === 0) {
|
|
653
757
|
return {
|
|
654
758
|
id: 'agent-docs',
|
|
655
759
|
label: 'AI agent docs',
|
|
656
760
|
status: 'warn',
|
|
657
761
|
message: `Agent docs present (${present.map(shown).join(', ')}) but no Astryx section markers found.`,
|
|
658
|
-
fix:
|
|
762
|
+
fix: fixFor(
|
|
763
|
+
`Add the Astryx section to your agent docs with \`${getCliInvocation(ctx.cwd)} init --features agents\`.`,
|
|
764
|
+
),
|
|
659
765
|
};
|
|
660
766
|
}
|
|
661
767
|
|
|
@@ -974,16 +1080,20 @@ function nameTypes(names) {
|
|
|
974
1080
|
}
|
|
975
1081
|
|
|
976
1082
|
/**
|
|
977
|
-
* The section keys
|
|
978
|
-
* 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.
|
|
979
1085
|
* @returns {Promise<{keys: Set<string>} | {keys: null, error: string}>}
|
|
980
1086
|
*/
|
|
981
1087
|
async function authoringTopicKeys() {
|
|
982
1088
|
try {
|
|
1089
|
+
const {AUTHORING_REFERENCE_ROUTE} =
|
|
1090
|
+
await import('../../foundation/discovery/authoring-self-docs.mjs');
|
|
983
1091
|
const catalog = DocsCatalog.fromBuiltins();
|
|
984
|
-
const
|
|
985
|
-
if (!
|
|
986
|
-
|
|
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)));
|
|
987
1097
|
return {keys: new Set(index.sections.map(section => section.id))};
|
|
988
1098
|
} catch (err) {
|
|
989
1099
|
return {
|
|
@@ -1002,7 +1112,7 @@ function surfaceProblems(surface) {
|
|
|
1002
1112
|
const problems = [];
|
|
1003
1113
|
if (surface.types === 0 && surface.untraced.length === 0) {
|
|
1004
1114
|
problems.push(
|
|
1005
|
-
`@astryxdesign/cli/authoring exports no types, so nothing was compared with \`${formatCliCommand('docs authoring')}\``,
|
|
1115
|
+
`@astryxdesign/cli/authoring exports no types, so nothing was compared with \`${formatCliCommand('docs authoring/field-reference')}\``,
|
|
1006
1116
|
);
|
|
1007
1117
|
}
|
|
1008
1118
|
for (const {module, names, reason, source, key} of surface.unreadable) {
|
|
@@ -1015,7 +1125,7 @@ function surfaceProblems(surface) {
|
|
|
1015
1125
|
? `${source} does not load`
|
|
1016
1126
|
: `${source} renders section "${key}", which the topic's index does not list`;
|
|
1017
1127
|
problems.push(
|
|
1018
|
-
`${nameTypes(names)} from ${module} ${names.length === 1 ? 'has' : 'have'} no doc in \`${formatCliCommand('docs authoring')}\`: ${why}`,
|
|
1128
|
+
`${nameTypes(names)} from ${module} ${names.length === 1 ? 'has' : 'have'} no doc in \`${formatCliCommand('docs authoring/field-reference')}\`: ${why}`,
|
|
1019
1129
|
);
|
|
1020
1130
|
}
|
|
1021
1131
|
for (const {name, reason} of surface.untraced) {
|
|
@@ -1056,7 +1166,7 @@ export async function checkAuthoringDocs(_ctx, options = {}) {
|
|
|
1056
1166
|
const audit = await auditAuthoringSelfDocs({root, sources});
|
|
1057
1167
|
const problems = [
|
|
1058
1168
|
...audit.unreachable.map(
|
|
1059
|
-
source => `${source} is not in \`${formatCliCommand('docs authoring')}\``,
|
|
1169
|
+
source => `${source} is not in \`${formatCliCommand('docs authoring/field-reference')}\``,
|
|
1060
1170
|
),
|
|
1061
1171
|
...audit.failed.map(
|
|
1062
1172
|
({source, error}) => `${source} failed to load: ${error}`,
|
|
@@ -1072,7 +1182,7 @@ export async function checkAuthoringDocs(_ctx, options = {}) {
|
|
|
1072
1182
|
: {keys: options.topicKeys};
|
|
1073
1183
|
const surface = [
|
|
1074
1184
|
...('error' in topic
|
|
1075
|
-
? [`\`${formatCliCommand('docs authoring')}\` could not be read: ${topic.error}`]
|
|
1185
|
+
? [`\`${formatCliCommand('docs authoring/field-reference')}\` could not be read: ${topic.error}`]
|
|
1076
1186
|
: []),
|
|
1077
1187
|
...surfaceProblems(
|
|
1078
1188
|
await auditAuthoringSurface({root, sources, topicKeys: topic.keys}),
|
|
@@ -1096,7 +1206,7 @@ export async function checkAuthoringDocs(_ctx, options = {}) {
|
|
|
1096
1206
|
id,
|
|
1097
1207
|
label,
|
|
1098
1208
|
status: 'pass',
|
|
1099
|
-
message: `All ${audit.sections} authoring schemas are readable in \`${formatCliCommand('docs authoring')}\`.`,
|
|
1209
|
+
message: `All ${audit.sections} authoring schemas are readable in \`${formatCliCommand('docs authoring/field-reference')}\`.`,
|
|
1100
1210
|
};
|
|
1101
1211
|
} catch (err) {
|
|
1102
1212
|
return {
|
|
@@ -1164,7 +1274,7 @@ export async function checkCliDocs(_ctx, options = {}) {
|
|
|
1164
1274
|
id,
|
|
1165
1275
|
label,
|
|
1166
1276
|
status: 'pass',
|
|
1167
|
-
message: `All ${audit.docs} CLI docs are readable: ${audit.tree} in the \`${formatCliCommand('docs cli')}\` tree and ${audit.authoring} in \`${formatCliCommand('docs authoring')}\`.`,
|
|
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')}\`.`,
|
|
1168
1278
|
};
|
|
1169
1279
|
} catch (err) {
|
|
1170
1280
|
return {
|
|
@@ -1281,7 +1391,7 @@ export async function checkDocsProgressiveDisclosure(ctx) {
|
|
|
1281
1391
|
// A guide the docs tree places is a topic read by its route; it is held
|
|
1282
1392
|
// to the same budget as every flat topic.
|
|
1283
1393
|
const guides = [...(await projectTree(catalog)).nodes.values()]
|
|
1284
|
-
// A flat topic in
|
|
1394
|
+
// A flat topic in a topic level is checked above, as a topic.
|
|
1285
1395
|
.filter(node => node.kind === 'generic' && !node.ref?.flatTopic)
|
|
1286
1396
|
.map(guideEntry);
|
|
1287
1397
|
for (const entry of [...catalog.entries(), ...guides]) {
|
|
@@ -1382,6 +1492,10 @@ export function checkCliCommand(ctx) {
|
|
|
1382
1492
|
* each file of the computer-level agent text against this release's rendering
|
|
1383
1493
|
* @property {import('../../foundation/env/user-settings.mjs').ComputerAgentTextSettings} [agentTextSettings]
|
|
1384
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
|
|
1385
1499
|
* @property {string} [cwd] the folder doctor runs in, for the printed fix
|
|
1386
1500
|
* @property {import('../../foundation/release/notices.mjs').GlobalBehind | null} [globalBehind]
|
|
1387
1501
|
* the CLI installed for the computer, when it is older than the newest
|
|
@@ -1394,7 +1508,7 @@ export function checkCliCommand(ctx) {
|
|
|
1394
1508
|
* the newest update notice that did not print, and why (diagnostic only)
|
|
1395
1509
|
* @property {{pid: number | null, host: string | null, since: number} | null} [stateLock]
|
|
1396
1510
|
* who holds the state file's lock now (diagnostic only)
|
|
1397
|
-
* @property {Array<import('../../foundation/env/search-path.mjs').SearchPathCommand & {upgrade?: string | null}>} [searchPathCommands]
|
|
1511
|
+
* @property {Array<import('../../foundation/env/search-path.mjs').SearchPathCommand & {upgrade?: string | null, runner?: boolean}>} [searchPathCommands]
|
|
1398
1512
|
* every `astryx` on the search path, with the command that upgrades it
|
|
1399
1513
|
* the `astryx` commands on the search path, in order
|
|
1400
1514
|
* @property {import('../../foundation/integrations/computer-integrations.mjs').ComputerIntegrationCandidate[]} [computerIntegrations]
|
|
@@ -1481,6 +1595,7 @@ function checkFailureNote(failed) {
|
|
|
1481
1595
|
const SKIP_REASONS = {
|
|
1482
1596
|
'already-shown': 'it had already printed that day',
|
|
1483
1597
|
'no-newer': 'no newer release was known',
|
|
1598
|
+
'no-project': 'the folder belongs to no Astryx project, so no install command fits',
|
|
1484
1599
|
};
|
|
1485
1600
|
|
|
1486
1601
|
/**
|
|
@@ -1604,6 +1719,8 @@ export function checkComputerAgentText(ctx) {
|
|
|
1604
1719
|
};
|
|
1605
1720
|
}
|
|
1606
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;
|
|
1607
1724
|
const fix = `Run \`${formatCliCommand('astryx init --user', ctx.cwd)}\`.`;
|
|
1608
1725
|
const [file, ...links] = entries;
|
|
1609
1726
|
const home = (/** @type {{path: string}} */ e) => displayHomePath(e.path);
|
|
@@ -1632,9 +1749,29 @@ export function checkComputerAgentText(ctx) {
|
|
|
1632
1749
|
};
|
|
1633
1750
|
}
|
|
1634
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
|
+
}
|
|
1635
1772
|
return {
|
|
1636
1773
|
...base,
|
|
1637
|
-
message: `${
|
|
1774
|
+
message: `${status}${linkNote}`,
|
|
1638
1775
|
...(!current || missing.length > 0 || dangling.length > 0 ? {fix} : {}),
|
|
1639
1776
|
};
|
|
1640
1777
|
}
|
|
@@ -1686,12 +1823,14 @@ export function checkComputerIntegrations(ctx) {
|
|
|
1686
1823
|
* Inside a project, the integrations installed for the computer that the
|
|
1687
1824
|
* project does not install: available, never used (spec AST-081 FR12).
|
|
1688
1825
|
* Always info.
|
|
1689
|
-
* @param {{installed: Set<string>, candidates: import('../../foundation/integrations/computer-integrations.mjs').ComputerIntegrationCandidate[], install: (name: string) => string}} input
|
|
1826
|
+
* @param {{installed: Set<string>, candidates: import('../../foundation/integrations/computer-integrations.mjs').ComputerIntegrationCandidate[], install: ((name: string) => string) | null, elsewhere?: boolean}} input
|
|
1690
1827
|
* `install`: the command that adds a package with the project's package
|
|
1691
|
-
* manager (read by the adapter)
|
|
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
|
|
1692
1831
|
* @returns {DoctorCheck}
|
|
1693
1832
|
*/
|
|
1694
|
-
export function checkComputerIntegrationsAvailable({installed, candidates, install}) {
|
|
1833
|
+
export function checkComputerIntegrationsAvailable({installed, candidates, install, elsewhere = false}) {
|
|
1695
1834
|
const available = candidates.filter(c => !installed.has(c.name));
|
|
1696
1835
|
const base = {id: 'computer-integrations', label: 'Integrations installed for this computer', status: /** @type {const} */ ('info')};
|
|
1697
1836
|
if (available.length === 0) {
|
|
@@ -1701,7 +1840,11 @@ export function checkComputerIntegrationsAvailable({installed, candidates, insta
|
|
|
1701
1840
|
return {
|
|
1702
1841
|
...base,
|
|
1703
1842
|
message: `Installed for this computer but not in this project, so not used here: ${available.map(c => c.name).join(', ')}.`,
|
|
1704
|
-
|
|
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
|
+
: {}),
|
|
1705
1848
|
};
|
|
1706
1849
|
}
|
|
1707
1850
|
|
|
@@ -1960,7 +2103,7 @@ export async function runChecks(options = {}) {
|
|
|
1960
2103
|
{
|
|
1961
2104
|
const loadedNames = (project?.loadedIntegrations ?? []).map((/** @type {{name: string}} */ i) => i.name);
|
|
1962
2105
|
const candidates = await computerIntegrationsToAdd(cwd, loadedNames);
|
|
1963
|
-
checks.push(checkComputerIntegrationsAvailable({installed: new Set(loadedNames), candidates, install: installCommandFor(cwd)}));
|
|
2106
|
+
checks.push(checkComputerIntegrationsAvailable({installed: new Set(loadedNames), candidates, install: installCommandFor(cwd), elsewhere: insideProjectElsewhere(cwd)}));
|
|
1964
2107
|
}
|
|
1965
2108
|
checks.push(await checkAuthoringDocs(ctx));
|
|
1966
2109
|
checks.push(await checkCliDocs(ctx));
|
|
@@ -31,7 +31,9 @@ import {
|
|
|
31
31
|
checkIntegrationIssues,
|
|
32
32
|
checkVersionAlignment,
|
|
33
33
|
checkPackageManager,
|
|
34
|
+
checkComputerIntegrationsAvailable,
|
|
34
35
|
} from './doctor.mjs';
|
|
36
|
+
import {installCommandFor} from './_adapter.mjs';
|
|
35
37
|
import {formatCliCommand} from '../../foundation/env/package-manager.mjs';
|
|
36
38
|
import {Project} from '../../foundation/config/project.mjs';
|
|
37
39
|
|
|
@@ -223,7 +225,13 @@ describe("doctor — the project's own CLI and Core on different releases", () =
|
|
|
223
225
|
).version;
|
|
224
226
|
/** @param {string} core */
|
|
225
227
|
const at = core => {
|
|
228
|
+
// A project as spec:AST-040 FR9 defines it: its package.json declares
|
|
229
|
+
// an Astryx package.
|
|
226
230
|
const dir = mkProject({
|
|
231
|
+
'package.json': JSON.stringify({
|
|
232
|
+
name: 'app',
|
|
233
|
+
dependencies: {'@astryxdesign/core': core},
|
|
234
|
+
}),
|
|
227
235
|
'package-lock.json': '{}',
|
|
228
236
|
'node_modules/@astryxdesign/core/package.json': JSON.stringify({
|
|
229
237
|
name: '@astryxdesign/core',
|
|
@@ -257,6 +265,10 @@ describe("doctor — the project's own CLI and Core on different releases", () =
|
|
|
257
265
|
|
|
258
266
|
it('in a project with no CLI of its own, warns that the started copy answered and names the command that adds the CLI at Core', () => {
|
|
259
267
|
const dir = mkProject({
|
|
268
|
+
'package.json': JSON.stringify({
|
|
269
|
+
name: 'app',
|
|
270
|
+
dependencies: {'@astryxdesign/core': '0.0.1'},
|
|
271
|
+
}),
|
|
260
272
|
'package-lock.json': '{}',
|
|
261
273
|
'node_modules/@astryxdesign/core/package.json': JSON.stringify({
|
|
262
274
|
name: '@astryxdesign/core',
|
|
@@ -279,6 +291,52 @@ describe("doctor — the project's own CLI and Core on different releases", () =
|
|
|
279
291
|
});
|
|
280
292
|
});
|
|
281
293
|
|
|
294
|
+
describe('the command that adds an integration installed for the computer', () => {
|
|
295
|
+
const app = () =>
|
|
296
|
+
mkProject({
|
|
297
|
+
'package.json': JSON.stringify({
|
|
298
|
+
name: 'app',
|
|
299
|
+
dependencies: {'@astryxdesign/core': '0.7.0'},
|
|
300
|
+
}),
|
|
301
|
+
'pnpm-lock.yaml': '',
|
|
302
|
+
'tools/codegen/package.json': JSON.stringify({name: 'codegen'}),
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it('adds it in the project, with its package manager', () => {
|
|
306
|
+
const dir = app();
|
|
307
|
+
expect(installCommandFor(dir)?.('@acme/a')).toBe('pnpm add @acme/a');
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// A package.json that is not the project's (spec AST-040 FR9): a run
|
|
311
|
+
// there loads integrations from it, so a package added to the project
|
|
312
|
+
// stays unused there. No command; the fix points at the project.
|
|
313
|
+
it("from a tool folder inside the project, names no command and points at the project's folder", () => {
|
|
314
|
+
const dir = app();
|
|
315
|
+
expect(installCommandFor(path.join(dir, 'tools', 'codegen'))).toBeNull();
|
|
316
|
+
const c = checkComputerIntegrationsAvailable({
|
|
317
|
+
installed: new Set(),
|
|
318
|
+
candidates: [/** @type {any} */ ({name: '@acme/a'})],
|
|
319
|
+
install: null,
|
|
320
|
+
elsewhere: true,
|
|
321
|
+
});
|
|
322
|
+
expect(c.fix).toBe(
|
|
323
|
+
"Run this from the Astryx project's folder, or declare an Astryx package in this folder's package.json to make it a project of its own.",
|
|
324
|
+
);
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
it('in a folder that belongs to no project, names no command', () => {
|
|
328
|
+
const dir = mkProject({'package.json': JSON.stringify({name: 'tool'})});
|
|
329
|
+
expect(installCommandFor(dir)).toBeNull();
|
|
330
|
+
const c = checkComputerIntegrationsAvailable({
|
|
331
|
+
installed: new Set(),
|
|
332
|
+
candidates: [/** @type {any} */ ({name: '@acme/a'})],
|
|
333
|
+
install: null,
|
|
334
|
+
});
|
|
335
|
+
expect(c.status).toBe('info');
|
|
336
|
+
expect(c).not.toHaveProperty('fix');
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
|
|
282
340
|
describe('checkCliCommand', () => {
|
|
283
341
|
it('is informational when no integration declares a command', () => {
|
|
284
342
|
const dir = mkProject({'pnpm-lock.yaml': ''});
|
|
@@ -652,7 +710,7 @@ describe('checkAuthoringDocs', () => {
|
|
|
652
710
|
it('passes when every authoring self-doc is reachable and fits one read', async () => {
|
|
653
711
|
const c = await checkAuthoringDocs();
|
|
654
712
|
expect(c).toMatchObject({id: 'authoring-docs', status: 'pass'});
|
|
655
|
-
expect(c.message).toContain(formatCliCommand('docs authoring'));
|
|
713
|
+
expect(c.message).toContain(formatCliCommand('docs authoring/field-reference'));
|
|
656
714
|
}, SLOW);
|
|
657
715
|
});
|
|
658
716
|
|
|
@@ -680,7 +738,7 @@ describe('checkCliDocs', () => {
|
|
|
680
738
|
id: 'cli-docs',
|
|
681
739
|
label: 'CLI docs',
|
|
682
740
|
status: 'pass',
|
|
683
|
-
message: `All ${audit.docs} CLI docs are readable: ${audit.tree} in the \`${formatCliCommand('docs cli')}\` tree and ${audit.authoring} in \`${formatCliCommand('docs authoring')}\`.`,
|
|
741
|
+
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')}\`.`,
|
|
684
742
|
});
|
|
685
743
|
},
|
|
686
744
|
SLOW,
|
|
@@ -790,7 +848,7 @@ describe('checkDocsTree', () => {
|
|
|
790
848
|
describe('checkAuthoringDocs against the public authoring surface', () => {
|
|
791
849
|
const NAMESPACE = 'doctypes/namespace/namespace.doc.mjs';
|
|
792
850
|
const NAMESPACE_TYPES =
|
|
793
|
-
`NamespaceDoc, NamespaceProviderScope, NamespaceSlotAcceptance, NamespaceSlot, NamespaceAdoptionSource, NamespaceAdoptionRule from doctypes/namespace/type.ts have no doc in \`${formatCliCommand('docs authoring')}\``;
|
|
851
|
+
`NamespaceDoc, NamespaceProviderScope, NamespaceSlotAcceptance, NamespaceSlot, NamespaceAdoptionSource, NamespaceAdoptionRule from doctypes/namespace/type.ts have no doc in \`${formatCliCommand('docs authoring/field-reference')}\``;
|
|
794
852
|
const SURFACE_FIX =
|
|
795
853
|
'Put a self-doc beside each module whose types @astryxdesign/cli/authoring exports and list it in AUTHORING_SELF_DOCS; export what each listed self-doc documents, or remove that self-doc.';
|
|
796
854
|
|
|
@@ -820,7 +878,7 @@ describe('checkAuthoringDocs against the public authoring surface', () => {
|
|
|
820
878
|
id: 'authoring-docs',
|
|
821
879
|
label: 'Authoring docs',
|
|
822
880
|
status: 'pass',
|
|
823
|
-
message: `All ${AUTHORING_SELF_DOCS.length} authoring schemas are readable in \`${formatCliCommand('docs authoring')}\`.`,
|
|
881
|
+
message: `All ${AUTHORING_SELF_DOCS.length} authoring schemas are readable in \`${formatCliCommand('docs authoring/field-reference')}\`.`,
|
|
824
882
|
});
|
|
825
883
|
},
|
|
826
884
|
SLOW,
|
|
@@ -849,7 +907,7 @@ describe('checkAuthoringDocs against the public authoring surface', () => {
|
|
|
849
907
|
});
|
|
850
908
|
expect(c.status).toBe('fail');
|
|
851
909
|
expect(c.message).toBe(
|
|
852
|
-
`2 problems: ${NAMESPACE} is not in \`${formatCliCommand('docs authoring')}\`; ${NAMESPACE_TYPES}: ${NAMESPACE} is not listed in AUTHORING_SELF_DOCS`,
|
|
910
|
+
`2 problems: ${NAMESPACE} is not in \`${formatCliCommand('docs authoring/field-reference')}\`; ${NAMESPACE_TYPES}: ${NAMESPACE} is not listed in AUTHORING_SELF_DOCS`,
|
|
853
911
|
);
|
|
854
912
|
},
|
|
855
913
|
SLOW,
|
|
@@ -858,7 +916,7 @@ describe('checkAuthoringDocs against the public authoring surface', () => {
|
|
|
858
916
|
it(
|
|
859
917
|
"fails when the topic's index no longer exposes the NamespaceDoc section",
|
|
860
918
|
async () => {
|
|
861
|
-
const index = await docs('authoring', undefined, {index: true});
|
|
919
|
+
const index = await docs('authoring/field-reference', undefined, {index: true});
|
|
862
920
|
const topicKeys = new Set(
|
|
863
921
|
index.data.sections
|
|
864
922
|
.map((/** @type {any} */ s) => s.id)
|
|
@@ -947,7 +1005,7 @@ describe('checkAuthoringDocs against the public authoring surface', () => {
|
|
|
947
1005
|
expect(c.fix).toBe(SURFACE_FIX);
|
|
948
1006
|
expect(c.message).toMatch(
|
|
949
1007
|
new RegExp(
|
|
950
|
-
`^[A-Za-z, ]+ from ${escape(module)} have no doc in \`${escape(formatCliCommand('docs authoring'))}\`: no self-doc sits beside ${escape(module)}$`,
|
|
1008
|
+
`^[A-Za-z, ]+ from ${escape(module)} have no doc in \`${escape(formatCliCommand('docs authoring/field-reference'))}\`: no self-doc sits beside ${escape(module)}$`,
|
|
951
1009
|
),
|
|
952
1010
|
);
|
|
953
1011
|
for (const name of names) {
|
|
@@ -990,7 +1048,7 @@ describe('checkAuthoringDocs against the public authoring surface', () => {
|
|
|
990
1048
|
expect(await checkAuthoringDocs()).toMatchObject({
|
|
991
1049
|
status: 'fail',
|
|
992
1050
|
message:
|
|
993
|
-
`\`${formatCliCommand('docs authoring')}\` could not be read: no built-in docs`,
|
|
1051
|
+
`\`${formatCliCommand('docs authoring/field-reference')}\` could not be read: no built-in docs`,
|
|
994
1052
|
fix: SURFACE_FIX,
|
|
995
1053
|
});
|
|
996
1054
|
} finally {
|
|
@@ -1011,7 +1069,7 @@ describe('checkAuthoringDocs against the public authoring surface', () => {
|
|
|
1011
1069
|
const c = await checkAuthoringDocs(undefined, {root});
|
|
1012
1070
|
expect(c.status).toBe('fail');
|
|
1013
1071
|
expect(c.message).toContain(
|
|
1014
|
-
`@astryxdesign/cli/authoring exports no types, so nothing was compared with \`${formatCliCommand('docs authoring')}\``,
|
|
1072
|
+
`@astryxdesign/cli/authoring exports no types, so nothing was compared with \`${formatCliCommand('docs authoring/field-reference')}\``,
|
|
1015
1073
|
);
|
|
1016
1074
|
},
|
|
1017
1075
|
SLOW,
|
|
@@ -1317,8 +1375,12 @@ describe('a configured integration that cannot load fails the gate', () => {
|
|
|
1317
1375
|
'astryx.config.mjs': "export default { integrations: ['@acme/widgets'] };\n",
|
|
1318
1376
|
};
|
|
1319
1377
|
|
|
1320
|
-
/**
|
|
1321
|
-
|
|
1378
|
+
/**
|
|
1379
|
+
* Run doctor on a project under the working directory, in its folder `at`.
|
|
1380
|
+
* @param {Record<string, string>} files
|
|
1381
|
+
* @param {string} [at]
|
|
1382
|
+
*/
|
|
1383
|
+
async function report(files, at = '.') {
|
|
1322
1384
|
const dir = fs.mkdtempSync(path.join(process.cwd(), '.astryx-doctor-gate-'));
|
|
1323
1385
|
tmpDirs.push(dir);
|
|
1324
1386
|
for (const [rel, content] of Object.entries(files)) {
|
|
@@ -1326,7 +1388,7 @@ describe('a configured integration that cannot load fails the gate', () => {
|
|
|
1326
1388
|
fs.mkdirSync(path.dirname(abs), {recursive: true});
|
|
1327
1389
|
fs.writeFileSync(abs, content);
|
|
1328
1390
|
}
|
|
1329
|
-
const {checks, summary} = (await doctor({cwd: dir})).data;
|
|
1391
|
+
const {checks, summary} = (await doctor({cwd: path.join(dir, at)})).data;
|
|
1330
1392
|
return {by: Object.fromEntries(checks.map(c => [c.id, c])), summary};
|
|
1331
1393
|
}
|
|
1332
1394
|
|
|
@@ -1354,6 +1416,27 @@ describe('a configured integration that cannot load fails the gate', () => {
|
|
|
1354
1416
|
SLOW,
|
|
1355
1417
|
);
|
|
1356
1418
|
|
|
1419
|
+
it(
|
|
1420
|
+
'passes in a workspace member whose configured integration is hoisted to the root',
|
|
1421
|
+
async () => {
|
|
1422
|
+
const {by} = await report(
|
|
1423
|
+
{
|
|
1424
|
+
'package.json': JSON.stringify({name: 'root', private: true, workspaces: ['apps/*']}),
|
|
1425
|
+
...CORE_STUB,
|
|
1426
|
+
...widgets(),
|
|
1427
|
+
'apps/web/package.json': '{"name":"web"}',
|
|
1428
|
+
'apps/web/astryx.config.mjs': "export default { integrations: ['@acme/widgets'] };\n",
|
|
1429
|
+
},
|
|
1430
|
+
'apps/web',
|
|
1431
|
+
);
|
|
1432
|
+
expect(by['configured-integrations'].status).toBe('pass');
|
|
1433
|
+
expect(by['configured-integrations'].message).toBe(
|
|
1434
|
+
'1 integration named in astryx.config loaded: @acme/widgets.',
|
|
1435
|
+
);
|
|
1436
|
+
},
|
|
1437
|
+
SLOW,
|
|
1438
|
+
);
|
|
1439
|
+
|
|
1357
1440
|
it(
|
|
1358
1441
|
'counts the package being authored when its own config names it',
|
|
1359
1442
|
async () => {
|
package/api/hook/hook.mjs
CHANGED
|
@@ -43,7 +43,7 @@ export async function hook(name, options = {}) {
|
|
|
43
43
|
zh = false,
|
|
44
44
|
} = options;
|
|
45
45
|
|
|
46
|
-
// Default detail level mirrors the CLI (see commands/hook
|
|
46
|
+
// Default detail level mirrors the CLI (see commands/hook.mjs):
|
|
47
47
|
// single-hook views default to 'full', list-style views (--list,
|
|
48
48
|
// --category, or no name) default to 'brief' (scannable name lists).
|
|
49
49
|
// Keeping this in sync with the CLI is what the API↔CLI parity test checks.
|