@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
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file postinstall command — the hidden `astryx postinstall` hook.
|
|
5
|
+
*
|
|
6
|
+
* Prints the welcome box (lib/welcome-box.mjs). Hidden from help and the
|
|
7
|
+
* manifest; it looks nothing up and does not support --json.
|
|
8
|
+
*
|
|
9
|
+
* The command surface comes from the colocated CommandDoc via `defineCommand`.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {getCliInvocation} from '../../../foundation/env/package-manager.mjs';
|
|
13
|
+
import {emit, code} from '../formatters/index.mjs';
|
|
14
|
+
import {defineCommand} from '../lib/define-command.mjs';
|
|
15
|
+
import {welcomeBox} from '../lib/welcome-box.mjs';
|
|
16
|
+
import {NO_RESULT_SET} from '../../../foundation/debug/index.mjs';
|
|
17
|
+
import {doc as postinstallCommand} from './postinstall.doc.mjs';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {import('commander').Command} program
|
|
21
|
+
*/
|
|
22
|
+
export function registerPostinstall(program) {
|
|
23
|
+
defineCommand(program, postinstallCommand, {
|
|
24
|
+
hidden: true,
|
|
25
|
+
action: () => {
|
|
26
|
+
emit(code(welcomeBox(getCliInvocation())));
|
|
27
|
+
// Prints the welcome box. Nothing is looked up.
|
|
28
|
+
return NO_RESULT_SET;
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -121,6 +121,25 @@ describe('enforcement layer 3 — per-command setup nudge', () => {
|
|
|
121
121
|
expect(r.stderr).toMatch(NUDGE);
|
|
122
122
|
});
|
|
123
123
|
|
|
124
|
+
it.each([
|
|
125
|
+
['in the home folder', ''],
|
|
126
|
+
['at the top of a settings folder in it', '.dotfiles'],
|
|
127
|
+
])('stays quiet %s, where init writes no agent docs', async (_label, rel) => {
|
|
128
|
+
const saved = {HOME: process.env.HOME, USERPROFILE: process.env.USERPROFILE};
|
|
129
|
+
process.env.HOME = tmp;
|
|
130
|
+
process.env.USERPROFILE = tmp;
|
|
131
|
+
try {
|
|
132
|
+
write(path.join(rel, 'package.json'), '{"name":"t"}');
|
|
133
|
+
const r = await runCli(['docs', 'tokens'], path.join(tmp, rel));
|
|
134
|
+
expect(r.stderr).not.toMatch(NUDGE);
|
|
135
|
+
} finally {
|
|
136
|
+
for (const [key, value] of Object.entries(saved)) {
|
|
137
|
+
if (value === undefined) delete process.env[key];
|
|
138
|
+
else process.env[key] = value;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
124
143
|
it("in a project with only Core of another release, names adding the CLI at Core's version first, as the daily hint does", async () => {
|
|
125
144
|
write(
|
|
126
145
|
'package.json',
|
|
@@ -167,6 +186,65 @@ describe('enforcement layer 3 — per-command setup nudge', () => {
|
|
|
167
186
|
expect((await runCli(['docs', 'tokens'], tmp)).stderr).not.toMatch(NUDGE);
|
|
168
187
|
});
|
|
169
188
|
|
|
189
|
+
it('is quiet in a nested package once init has written the docs at the project root', async () => {
|
|
190
|
+
// init run in functions/ writes at the root that declares Astryx.
|
|
191
|
+
write('package.json', JSON.stringify({name: 'app', dependencies: {'@astryxdesign/core': '0.7.0'}}));
|
|
192
|
+
write('AGENTS.md', MARKER);
|
|
193
|
+
write('functions/package.json', '{"name":"functions"}');
|
|
194
|
+
const r = await runCli(['docs', 'tokens'], path.join(tmp, 'functions'));
|
|
195
|
+
expect(r.stderr).not.toMatch(NUDGE);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('nudges in a nested package while the project root has no docs', async () => {
|
|
199
|
+
write('package.json', JSON.stringify({name: 'app', dependencies: {'@astryxdesign/core': '0.7.0'}}));
|
|
200
|
+
write('functions/package.json', '{"name":"functions"}');
|
|
201
|
+
const r = await runCli(['docs', 'tokens'], path.join(tmp, 'functions'));
|
|
202
|
+
expect(r.stderr).toMatch(NUDGE);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// A nested package.json that is not the project's (spec AST-040 FR9): the
|
|
206
|
+
// reminder sends the person to the project's folder, never adds the CLI to
|
|
207
|
+
// the nested package.json (spec AST-081 FR2).
|
|
208
|
+
it("in a nested package whose package.json is not the project's, says to run from the project's folder", async () => {
|
|
209
|
+
write('package.json', JSON.stringify({name: 'app', dependencies: {'@astryxdesign/core': '0.7.0'}}));
|
|
210
|
+
write('package-lock.json', '{}');
|
|
211
|
+
write('functions/package.json', '{"name":"functions"}');
|
|
212
|
+
const r = await runCli(['docs', 'tokens'], path.join(tmp, 'functions'));
|
|
213
|
+
// Only `cd` comes first, so the app has no CLI of its own yet: the
|
|
214
|
+
// command is the scoped package at the answering release, never the bare
|
|
215
|
+
// `astryx` name a package runner would fetch from the registry.
|
|
216
|
+
const {version} = JSON.parse(fs.readFileSync(new URL('../../../package.json', import.meta.url), 'utf8'));
|
|
217
|
+
expect(r.stderr.trim()).toBe(
|
|
218
|
+
`Next step: run \`cd ${tmp}\`, then \`npx @astryxdesign/cli@${version} init\` to finish setup and install the Astryx agent prompt.`,
|
|
219
|
+
);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// Inside a git repository the project-root check above adds nothing to the
|
|
223
|
+
// walk up to the repository root: the same outcomes as without it.
|
|
224
|
+
it('inside a repository, is quiet in a nested package once init has written the docs at the project root', async () => {
|
|
225
|
+
fs.mkdirSync(path.join(tmp, '.git'));
|
|
226
|
+
write('package.json', JSON.stringify({name: 'app', dependencies: {'@astryxdesign/core': '0.7.0'}}));
|
|
227
|
+
write('AGENTS.md', MARKER);
|
|
228
|
+
write('functions/package.json', '{"name":"functions"}');
|
|
229
|
+
const r = await runCli(['docs', 'tokens'], path.join(tmp, 'functions'));
|
|
230
|
+
expect(r.stderr).not.toMatch(NUDGE);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('inside a repository, still nudges when the only docs lie above the repository root', async () => {
|
|
234
|
+
write('package.json', JSON.stringify({name: 'outer', dependencies: {'@astryxdesign/core': '0.7.0'}}));
|
|
235
|
+
write('AGENTS.md', MARKER);
|
|
236
|
+
fs.mkdirSync(path.join(tmp, 'repo', '.git'), {recursive: true});
|
|
237
|
+
write('repo/package.json', '{"name":"repo"}');
|
|
238
|
+
// It declares Astryx: a folder that declares nothing is outside a
|
|
239
|
+
// project, where no reminder prints (spec AST-081 FR3).
|
|
240
|
+
write(
|
|
241
|
+
'repo/functions/package.json',
|
|
242
|
+
JSON.stringify({name: 'functions', dependencies: {'@astryxdesign/core': '0.7.0'}}),
|
|
243
|
+
);
|
|
244
|
+
const r = await runCli(['docs', 'tokens'], path.join(tmp, 'repo', 'functions'));
|
|
245
|
+
expect(r.stderr).toMatch(NUDGE);
|
|
246
|
+
});
|
|
247
|
+
|
|
170
248
|
it('does not nudge for the installer command itself', async () => {
|
|
171
249
|
asProject();
|
|
172
250
|
expect((await runCli(['init'], tmp)).stderr).not.toMatch(NUDGE);
|
|
@@ -96,7 +96,7 @@ import {doc as themePaletteGenerateFn} from '../../../api/theme/themePaletteGene
|
|
|
96
96
|
|
|
97
97
|
/**
|
|
98
98
|
* Path to this CLI's real entry (clients/cli/bin/astryx.mjs), resolved from
|
|
99
|
-
* this module's location (clients/cli/commands/
|
|
99
|
+
* this module's location (clients/cli/commands/theme.mjs → ../bin/
|
|
100
100
|
* astryx.mjs). Used to re-invoke `theme build` as a child process in watch mode.
|
|
101
101
|
*/
|
|
102
102
|
function resolveCliBin() {
|
|
@@ -21,6 +21,7 @@ export const doc = {
|
|
|
21
21
|
'agent-docs block when Core or configured integration guidance changes. ' +
|
|
22
22
|
'Dry-run by default. --apply writes codemod and receipt changes, runs hooks, then refreshes agent docs. ' +
|
|
23
23
|
'Anything a post-codemod hook prints goes to stderr, so stdout carries only the result. ' +
|
|
24
|
+
'Run from a folder inside a project, it upgrades that project and names files in the result relative to the folder you ran it in. ' +
|
|
24
25
|
'ShadCN-copied compositions are checked automatically during a normal upgrade, or alone with --registry. ' +
|
|
25
26
|
'Outside a project, --list lists the codemods this release ships and --registry finds no copied compositions to update; ' +
|
|
26
27
|
'a migration writes nothing and fails with ERR_VERSION_DETECT, because no installed Core names its target.',
|
|
@@ -69,8 +70,9 @@ export const doc = {
|
|
|
69
70
|
{
|
|
70
71
|
flag: '--path <dir>',
|
|
71
72
|
param: 'options.path',
|
|
72
|
-
description:
|
|
73
|
-
|
|
73
|
+
description:
|
|
74
|
+
"Source directory to scan, relative to where you run the command, however you spell it. Without --path, the project's src folder, from any folder in the project",
|
|
75
|
+
default: './src at the project root',
|
|
74
76
|
},
|
|
75
77
|
{
|
|
76
78
|
flag: '--install-deps',
|
|
@@ -31,8 +31,9 @@ export function registerUpgrade(program) {
|
|
|
31
31
|
action:
|
|
32
32
|
/**
|
|
33
33
|
* @param {import('../../../api/upgrade/upgrade.mjs').UpgradeOptions} options
|
|
34
|
+
* @param {import('commander').Command} command
|
|
34
35
|
*/
|
|
35
|
-
async options => {
|
|
36
|
+
async (options, command) => {
|
|
36
37
|
const json = program.opts().json || false;
|
|
37
38
|
const isList = Boolean(options.list);
|
|
38
39
|
// Silence the logger for --list so the handler renders from the
|
|
@@ -42,8 +43,14 @@ export function registerUpgrade(program) {
|
|
|
42
43
|
|
|
43
44
|
/** @type {import('../../../api/upgrade/upgrade.type.mjs').UpgradeListResponse | import('../../../api/upgrade/upgrade.type.mjs').UpgradeRegistryResponse | import('../../../api/upgrade/upgrade.type.mjs').UpgradeStatusResponse | import('../../../api/upgrade/upgrade.type.mjs').UpgradeRunResponse} */
|
|
44
45
|
let result;
|
|
46
|
+
// `--path` shows its default in help, but a path nobody typed is the
|
|
47
|
+
// project's src, not one read from this folder: leave it unset.
|
|
48
|
+
const apiOptions =
|
|
49
|
+
command.getOptionValueSource('path') === 'default'
|
|
50
|
+
? {...options, path: undefined}
|
|
51
|
+
: options;
|
|
45
52
|
try {
|
|
46
|
-
result = await upgradeApi(
|
|
53
|
+
result = await upgradeApi(apiOptions, {cwd: process.cwd()});
|
|
47
54
|
} catch (e) {
|
|
48
55
|
// Re-enable the logger so the error is visible in text mode.
|
|
49
56
|
// For --list the logger was silent; for other modes the API
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file `astryx upgrade` from a folder inside a project: a `--path` you type
|
|
5
|
+
* is read from that folder, however you spell it, and without `--path` the
|
|
6
|
+
* upgrade scans the project's own src. The option's default must not read as
|
|
7
|
+
* a typed `./src`. The `--json` result names files relative to the folder the
|
|
8
|
+
* command ran in.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {describe, it, expect, beforeEach, afterEach} from 'vitest';
|
|
12
|
+
import * as fs from 'node:fs';
|
|
13
|
+
import * as os from 'node:os';
|
|
14
|
+
import * as path from 'node:path';
|
|
15
|
+
import {runCli} from '../../../test-utils/run-cli.mjs';
|
|
16
|
+
|
|
17
|
+
/** Core 0.7.0 renamed this prop; its codemod renames it on Typeahead. */
|
|
18
|
+
const OLD_PROP_SOURCE =
|
|
19
|
+
"import {Typeahead} from '@astryxdesign/core';\n" +
|
|
20
|
+
'export const App = () => <Typeahead label="Fruit" emptySearchResultsText="None" />;\n';
|
|
21
|
+
|
|
22
|
+
let root;
|
|
23
|
+
|
|
24
|
+
/** @param {string} rel @param {string} body */
|
|
25
|
+
function write(rel, body) {
|
|
26
|
+
const file = path.join(root, rel);
|
|
27
|
+
fs.mkdirSync(path.dirname(file), {recursive: true});
|
|
28
|
+
fs.writeFileSync(file, body);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** @param {string} rel */
|
|
32
|
+
const renamed = rel =>
|
|
33
|
+
fs
|
|
34
|
+
.readFileSync(path.join(root, rel), 'utf-8')
|
|
35
|
+
.includes('emptySearchText="None"');
|
|
36
|
+
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
root = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-upgrade-subfolder-'));
|
|
39
|
+
write(
|
|
40
|
+
'package.json',
|
|
41
|
+
JSON.stringify({
|
|
42
|
+
name: 'app',
|
|
43
|
+
private: true,
|
|
44
|
+
dependencies: {'@astryxdesign/core': '0.7.0'},
|
|
45
|
+
}),
|
|
46
|
+
);
|
|
47
|
+
write(
|
|
48
|
+
'node_modules/@astryxdesign/core/package.json',
|
|
49
|
+
JSON.stringify({name: '@astryxdesign/core', version: '0.7.0'}),
|
|
50
|
+
);
|
|
51
|
+
write('src/App.tsx', OLD_PROP_SOURCE);
|
|
52
|
+
// A folder inside the project with source of its own and no package.json.
|
|
53
|
+
write('frontend/src/App.tsx', OLD_PROP_SOURCE);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
afterEach(() => {
|
|
57
|
+
fs.rmSync(root, {recursive: true, force: true});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
/** @param {string[]} args @param {string} [folder] */
|
|
61
|
+
async function upgradeFrom(args, folder = 'frontend') {
|
|
62
|
+
const r = await runCli(
|
|
63
|
+
['upgrade', '--from', '0.6.8', ...args, '--apply', '--json'],
|
|
64
|
+
{
|
|
65
|
+
cwd: path.join(root, folder),
|
|
66
|
+
},
|
|
67
|
+
);
|
|
68
|
+
expect(r.status).toBe(0);
|
|
69
|
+
return JSON.parse(r.stdout);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
describe('upgrade --path from a folder inside the project', () => {
|
|
73
|
+
it.each([['./src'], ['src'], ['src/'], ['./src/']])(
|
|
74
|
+
'reads --path %s from the folder you ran in',
|
|
75
|
+
async spelling => {
|
|
76
|
+
const result = await upgradeFrom(['--path', spelling]);
|
|
77
|
+
|
|
78
|
+
expect(result.data.modifiedFiles).toEqual(['src/App.tsx']);
|
|
79
|
+
expect(renamed('frontend/src/App.tsx')).toBe(true);
|
|
80
|
+
expect(renamed('src/App.tsx')).toBe(false);
|
|
81
|
+
},
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
it("scans the project's src without --path", async () => {
|
|
85
|
+
const result = await upgradeFrom([]);
|
|
86
|
+
|
|
87
|
+
expect(result.data.modifiedFiles).toEqual(['../src/App.tsx']);
|
|
88
|
+
expect(renamed('src/App.tsx')).toBe(true);
|
|
89
|
+
expect(renamed('frontend/src/App.tsx')).toBe(false);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('names files from the project root when run there', async () => {
|
|
93
|
+
const result = await upgradeFrom([], '.');
|
|
94
|
+
|
|
95
|
+
expect(result.data.modifiedFiles).toEqual(['src/App.tsx']);
|
|
96
|
+
});
|
|
97
|
+
});
|
package/clients/cli/index.mjs
CHANGED
|
@@ -16,23 +16,25 @@ import {Command, Option} from 'commander';
|
|
|
16
16
|
import {fileURLToPath} from 'node:url';
|
|
17
17
|
import * as fs from 'node:fs';
|
|
18
18
|
import * as path from 'node:path';
|
|
19
|
-
import {formatCliCommand, getCliInvocation} from '../../foundation/env/package-manager.mjs';
|
|
19
|
+
import {formatCliCommand, getCliInvocation, quoteCommandArgument} from '../../foundation/env/package-manager.mjs';
|
|
20
20
|
import {hasRecordedProject} from '../../foundation/env/cli-command.mjs';
|
|
21
21
|
import {isOutsideProject} from '../../foundation/env/project-scope.mjs';
|
|
22
22
|
import {API_VERSION, setJsonMode} from '../../foundation/response/json.mjs';
|
|
23
23
|
import {answeredBy, runChoice} from '../../foundation/release/run-context.mjs';
|
|
24
|
-
import {
|
|
25
|
-
import {projectRootOf} from '../../foundation/release/choose.mjs';
|
|
26
|
-
import {readReleaseFacts} from '../../foundation/release/project.mjs';
|
|
24
|
+
import {cliInstallAdvice, installFolder} from '../../foundation/release/notices.mjs';
|
|
27
25
|
import {buildManifest} from './lib/manifest.mjs';
|
|
28
26
|
import {cliError} from './lib/cli-error.mjs';
|
|
29
|
-
import {
|
|
27
|
+
import {section, text, records} from './formatters/index.mjs';
|
|
30
28
|
import {ERROR_CODES} from '../../foundation/response/error-codes.mjs';
|
|
31
29
|
import {levenshteinDistance} from '../../foundation/text/string-utils.mjs';
|
|
32
30
|
import {installJsonShim} from './lib/json-shim.mjs';
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
|
|
31
|
+
import {markReportsResult} from './lib/define-command.mjs';
|
|
32
|
+
import {
|
|
33
|
+
agentDocsTargetDir,
|
|
34
|
+
assertAgentDocsTarget,
|
|
35
|
+
isAstryxInitialized,
|
|
36
|
+
isAstryxPromptInReach,
|
|
37
|
+
} from '../../foundation/agent-docs/agent-docs.mjs';
|
|
36
38
|
import {CLI_ROOT} from '../../foundation/fs/paths.mjs';
|
|
37
39
|
import {setupNudge} from '../../foundation/agent-docs/agent-doc-state.mjs';
|
|
38
40
|
import * as debug from '../../foundation/debug/index.mjs';
|
|
@@ -292,7 +294,7 @@ function captureInvocation(actionCommand, root) {
|
|
|
292
294
|
*/
|
|
293
295
|
const commands = [
|
|
294
296
|
{name: 'init', path: './commands/init.mjs', register: 'registerInit'},
|
|
295
|
-
{name: 'component', path: './commands/component
|
|
297
|
+
{name: 'component', path: './commands/component.mjs', register: 'registerComponent'},
|
|
296
298
|
{name: 'docs', path: './commands/docs.mjs', register: 'registerDocs'},
|
|
297
299
|
{name: 'blog', path: './commands/blog.mjs', register: 'registerBlog'},
|
|
298
300
|
{name: 'swizzle', path: './commands/swizzle.mjs', register: 'registerSwizzle'},
|
|
@@ -300,13 +302,17 @@ const commands = [
|
|
|
300
302
|
// agent-docs folded into init — functions still importable from agent-docs.mjs
|
|
301
303
|
{name: 'template', path: './commands/template.mjs', register: 'registerTemplate'},
|
|
302
304
|
{name: 'upgrade', path: './commands/upgrade.mjs', register: 'registerUpgrade'},
|
|
303
|
-
{name: 'theme', path: './commands/
|
|
305
|
+
{name: 'theme', path: './commands/theme.mjs', register: 'registerTheme'},
|
|
304
306
|
{name: 'integration', path: './commands/integration.mjs', register: 'registerIntegration'},
|
|
305
|
-
{name: 'hook', path: './commands/hook
|
|
307
|
+
{name: 'hook', path: './commands/hook.mjs', register: 'registerHook'},
|
|
306
308
|
{name: 'discover', path: './commands/discover.mjs', register: 'registerDiscover'},
|
|
307
309
|
{name: 'search', path: './commands/search.mjs', register: 'registerSearch'},
|
|
308
310
|
{name: 'build', path: './commands/build.mjs', register: 'registerBuild'},
|
|
309
311
|
{name: 'doctor', path: './commands/doctor.mjs', register: 'registerDoctor'},
|
|
312
|
+
// Registered after every other command: the manifest lists the commands in
|
|
313
|
+
// registration order.
|
|
314
|
+
{name: 'manifest', path: './commands/manifest.mjs', register: 'registerManifest'},
|
|
315
|
+
{name: 'postinstall', path: './commands/postinstall.mjs', register: 'registerPostinstall'},
|
|
310
316
|
];
|
|
311
317
|
|
|
312
318
|
const SETUP_NUDGE_EXEMPT = new Set(['init', 'agent-docs']);
|
|
@@ -635,6 +641,19 @@ export async function createProgram() {
|
|
|
635
641
|
if (INTEGRATION_MANIFEST_FILES.some(file => fs.existsSync(path.join(cwd, file)))) return;
|
|
636
642
|
if (inOwnSourceCheckout(cwd)) return; // developing Astryx itself, not an app
|
|
637
643
|
if (isAstryxPromptInReach(cwd)) return; // already set up — stay quiet
|
|
644
|
+
// Where init writes the docs, by init's own rule: the project root, which
|
|
645
|
+
// can sit above a nested package such as functions/. Inside a git
|
|
646
|
+
// repository the walk above already reaches it (the root never lies
|
|
647
|
+
// above the repository root), so this changes nothing there; outside a
|
|
648
|
+
// repository the walk checks only cwd, and this finds the root.
|
|
649
|
+
if (isAstryxInitialized(agentDocsTargetDir(cwd))) return;
|
|
650
|
+
// In the home folder, or at the top of a settings folder in it, init
|
|
651
|
+
// writes no agent docs, so naming it would repeat on every command.
|
|
652
|
+
try {
|
|
653
|
+
assertAgentDocsTarget(agentDocsTargetDir(cwd));
|
|
654
|
+
} catch {
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
638
657
|
// Same wording as the core/cli postinstall nudges. getCliInvocation()
|
|
639
658
|
// renders the correct form for THIS project — an integration's cliCommand,
|
|
640
659
|
// scoped `npx @astryxdesign/cli` one-off, or `<pm> astryx` when installed —
|
|
@@ -642,14 +661,33 @@ export async function createProgram() {
|
|
|
642
661
|
// A project with no CLI of its own, answered by another release than its
|
|
643
662
|
// Core's: add the CLI at Core's version first, as the daily hint says,
|
|
644
663
|
// then run that CLI's init (spec AST-081 FR2).
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
664
|
+
// A folder that belongs to no project spec:AST-040 FR9 defines gets no
|
|
665
|
+
// reminder, as outside a project.
|
|
666
|
+
const target = installFolder(cwd);
|
|
667
|
+
if (target == null) return;
|
|
668
|
+
// From a folder inside the project whose package.json is not the
|
|
669
|
+
// project's, init runs from the project's folder. Only `cd` comes
|
|
670
|
+
// before it, so the command is the picker's for that folder, never the
|
|
671
|
+
// bare `astryx` name a package runner would fetch from the registry
|
|
672
|
+
// (spec AST-081 FR5).
|
|
673
|
+
if (target.moved) {
|
|
648
674
|
console.error(
|
|
649
|
-
setupNudge(getCliInvocation(
|
|
675
|
+
setupNudge(getCliInvocation(target.dir), {before: `cd ${quoteCommandArgument(target.dir)}`}).trimEnd(),
|
|
650
676
|
);
|
|
651
677
|
return;
|
|
652
678
|
}
|
|
679
|
+
const choice = runChoice(cwd);
|
|
680
|
+
if (choice.copy === 'starting' && choice.coreVersion && choice.coreVersion !== choice.version) {
|
|
681
|
+
// The daily hint's comparison and command: add the CLI at Core's
|
|
682
|
+
// version, then run that CLI's init.
|
|
683
|
+
const add = cliInstallAdvice({cwd, core: choice.coreVersion});
|
|
684
|
+
if (add?.command) {
|
|
685
|
+
console.error(
|
|
686
|
+
setupNudge(getCliInvocation(add.root, {installed: true}), {before: add.command}).trimEnd(),
|
|
687
|
+
);
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
653
691
|
console.error(setupNudge(getCliInvocation(cwd)).trimEnd());
|
|
654
692
|
} catch {
|
|
655
693
|
// Never let the nudge break a command.
|
|
@@ -659,7 +697,7 @@ export async function createProgram() {
|
|
|
659
697
|
for (const cmd of commands) {
|
|
660
698
|
try {
|
|
661
699
|
const mod = await import(cmd.path);
|
|
662
|
-
mod[cmd.register](program);
|
|
700
|
+
mod[cmd.register](program, {jsonSupported: JSON_SUPPORTED, version: pkg.version});
|
|
663
701
|
} catch (e) {
|
|
664
702
|
// Command fails to load but CLI still works
|
|
665
703
|
const reason = /** @type {any} */ (e).message;
|
|
@@ -679,84 +717,6 @@ export async function createProgram() {
|
|
|
679
717
|
}
|
|
680
718
|
}
|
|
681
719
|
|
|
682
|
-
// Capability manifest — a single, self-describing view of the whole CLI so
|
|
683
|
-
// agents can discover every command, argument, flag, and response type without
|
|
684
|
-
// scraping `--help`. `astryx manifest --json` is the dedicated surface; the bare
|
|
685
|
-
// `xds --json` embeds the same payload under data.manifest for convenience.
|
|
686
|
-
// Intentionally CLI-special — no `api/manifest`. It introspects the live
|
|
687
|
-
// Commander `program`, so extracting it to `api/` would create the `api → cli`
|
|
688
|
-
// cycle from #4302. `buildManifest(program)` lives in lib/; see its header.
|
|
689
|
-
const manifestCommand = program
|
|
690
|
-
.command('manifest')
|
|
691
|
-
.description('Print the full CLI capability manifest (use with --json)')
|
|
692
|
-
.action(() => {
|
|
693
|
-
const manifest = buildManifest(program, {
|
|
694
|
-
jsonSupported: JSON_SUPPORTED,
|
|
695
|
-
version: pkg.version,
|
|
696
|
-
});
|
|
697
|
-
// The manifest IS a result set: one entry per command the CLI ships.
|
|
698
|
-
debug.recordCommandResult(
|
|
699
|
-
debug.resultSet({
|
|
700
|
-
count: manifest.commands.length,
|
|
701
|
-
resultKind: 'command',
|
|
702
|
-
}),
|
|
703
|
-
);
|
|
704
|
-
if (program.opts().json) {
|
|
705
|
-
process.__xdsJsonHandled = true;
|
|
706
|
-
console.log(JSON.stringify({apiVersion: API_VERSION, type: 'manifest', data: manifest, meta: {answeredBy: answeredBy()}}, null, 2));
|
|
707
|
-
return;
|
|
708
|
-
}
|
|
709
|
-
// Human-readable summary as greppable records (agents should use --json).
|
|
710
|
-
// One record per command: name, whether it supports --json, and the
|
|
711
|
-
// description. Field names are the manifest entry's own keys.
|
|
712
|
-
emit(
|
|
713
|
-
section(`${manifest.name} v${manifest.version} (${manifest.commands.length} commands)`),
|
|
714
|
-
records(
|
|
715
|
-
manifest.commands.map(c => ({
|
|
716
|
-
name: c.name,
|
|
717
|
-
json: c.json ? 'yes' : '',
|
|
718
|
-
description: c.description || '',
|
|
719
|
-
})),
|
|
720
|
-
{fields: ['name', 'json', 'description']},
|
|
721
|
-
),
|
|
722
|
-
text(`Run \`${getCliInvocation()} manifest --json\` for the full structured manifest.`),
|
|
723
|
-
);
|
|
724
|
-
});
|
|
725
|
-
addDocHelp(manifestCommand, manifestDoc);
|
|
726
|
-
markReportsResult(manifestCommand);
|
|
727
|
-
|
|
728
|
-
// Hidden command used by package.json postinstall scripts
|
|
729
|
-
const postinstallCommand = program
|
|
730
|
-
.command('postinstall', {hidden: true})
|
|
731
|
-
.action(() => {
|
|
732
|
-
// Prints the welcome box. Nothing is looked up.
|
|
733
|
-
debug.recordCommandResult(debug.NO_RESULT_SET);
|
|
734
|
-
const r = getCliInvocation();
|
|
735
|
-
const pad = (/** @type {string} */ s, /** @type {number} */ len) => s + ' '.repeat(Math.max(0, len - s.length));
|
|
736
|
-
const W = 49; // inner width of the box
|
|
737
|
-
const line = (/** @type {string} */ s) => ` │ ${pad(s, W)}│`;
|
|
738
|
-
console.log(`
|
|
739
|
-
╭${'─'.repeat(W + 2)}╮
|
|
740
|
-
${line('')}
|
|
741
|
-
${line(' Design system installed!')}
|
|
742
|
-
${line('')}
|
|
743
|
-
${line(' Get started:')}
|
|
744
|
-
${line(` ${r} init Setup + AI agent docs`)}
|
|
745
|
-
${line(` ${r} --help See all commands`)}
|
|
746
|
-
${line('')}
|
|
747
|
-
${line(' Or run directly:')}
|
|
748
|
-
${line(` ${r} init Setup + AI agent docs`)}
|
|
749
|
-
${line(` ${r} component Browse component docs`)}
|
|
750
|
-
${line(` ${r} hook Browse hook docs`)}
|
|
751
|
-
${line(` ${r} docs Design system reference`)}
|
|
752
|
-
${line(` ${r} swizzle Customize a component`)}
|
|
753
|
-
${line(` ${r} template Add a page template`)}
|
|
754
|
-
${line('')}
|
|
755
|
-
╰${'─'.repeat(W + 2)}╯
|
|
756
|
-
`);
|
|
757
|
-
});
|
|
758
|
-
markReportsResult(postinstallCommand);
|
|
759
|
-
|
|
760
720
|
// Install the JSON shim AFTER all commands are registered so we can
|
|
761
721
|
// patch outputHelp on every command (root + subcommands). The shim
|
|
762
722
|
// extends the --json contract to cover Commander's parse-time short
|
|
@@ -21,7 +21,7 @@ import {getCliInvocation} from '../../../foundation/env/package-manager.mjs';
|
|
|
21
21
|
* (→ `.astryx-table-cell`), and `astryx-button` → key `button`.
|
|
22
22
|
*
|
|
23
23
|
* Keep the `astryx-` literal in sync with packages/core/src/naming.ts
|
|
24
|
-
* (NAMESPACE / classPrefix), the same way
|
|
24
|
+
* (NAMESPACE / classPrefix), the same way commands/theme.mjs mirrors it.
|
|
25
25
|
* <!-- SYNC: packages/core/src/naming.ts (namespace prefix source of truth) -->
|
|
26
26
|
* @param {import('@astryxdesign/cli/authoring').ComponentThemingTarget} target
|
|
27
27
|
* @returns {string}
|
|
@@ -63,10 +63,10 @@ export function reportsResultVia(cmd) {
|
|
|
63
63
|
/**
|
|
64
64
|
* Mark a hand-registered command as reporting its result.
|
|
65
65
|
*
|
|
66
|
-
* For
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
66
|
+
* For what does not come from a CommandDoc: the root program, and the stub
|
|
67
|
+
* left behind when a command module fails to load. Every command, `manifest`
|
|
68
|
+
* and the hidden `postinstall` hook included, registers through
|
|
69
|
+
* {@link defineCommand}. These call {@link recordCommandResult} themselves; this
|
|
70
70
|
* says so, and the coverage test pins the set of commands allowed to, so the
|
|
71
71
|
* mark cannot become a quiet way around the contract.
|
|
72
72
|
*
|
|
@@ -105,10 +105,12 @@ export function commandDocsOf(cmd) {
|
|
|
105
105
|
* fn?: import('@astryxdesign/cli/authoring').FunctionDoc,
|
|
106
106
|
* action?: (...args: any[]) => import('../../../foundation/debug/command-result.mjs').CommandResult
|
|
107
107
|
* | Promise<import('../../../foundation/debug/command-result.mjs').CommandResult>,
|
|
108
|
-
*
|
|
108
|
+
* hidden?: boolean,
|
|
109
|
+
* }} [impl] `hidden` keeps the command out of help and the manifest (a
|
|
110
|
+
* package-script hook, not a command for people or agents).
|
|
109
111
|
* @returns {import('commander').Command} the created command.
|
|
110
112
|
*/
|
|
111
|
-
export function defineCommand(parent, doc, {fn, action} = {}) {
|
|
113
|
+
export function defineCommand(parent, doc, {fn, action, hidden} = {}) {
|
|
112
114
|
// The command token is the last path segment ("theme build" -> "build"),
|
|
113
115
|
// since subcommands are added to their group command, not the program.
|
|
114
116
|
const token = doc.name.split(' ').pop() ?? doc.name;
|
|
@@ -119,7 +121,10 @@ export function defineCommand(parent, doc, {fn, action} = {}) {
|
|
|
119
121
|
})
|
|
120
122
|
.join(' ');
|
|
121
123
|
|
|
122
|
-
const cmd = parent.command(
|
|
124
|
+
const cmd = parent.command(
|
|
125
|
+
argSpec ? `${token} ${argSpec}` : token,
|
|
126
|
+
hidden ? {hidden: true} : {},
|
|
127
|
+
);
|
|
123
128
|
Object.defineProperty(cmd, COMMAND_DOCS, {value: {doc, fn}, configurable: true});
|
|
124
129
|
if (doc.summary) cmd.description(doc.summary);
|
|
125
130
|
if (doc.deprecated) {
|
|
@@ -24,6 +24,10 @@ for (const file of fs.readdirSync(COMMANDS).sort()) {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
const manifest = buildManifest(program, {jsonSupported: JSON_SUPPORTED, version: '0.0.0-test'});
|
|
27
|
+
/** Hidden commands (a package-script hook): documented, never in the manifest. */
|
|
28
|
+
const HIDDEN = new Set(
|
|
29
|
+
program.commands.filter((c) => /** @type {any} */ (c)._hidden).map((c) => c.name()),
|
|
30
|
+
);
|
|
27
31
|
/** @type {Map<string, any>} */
|
|
28
32
|
const entries = new Map();
|
|
29
33
|
const walk = (/** @type {any} */ c) => {
|
|
@@ -98,6 +102,7 @@ describe('command exit codes', () => {
|
|
|
98
102
|
|
|
99
103
|
it('the manifest carries every command exit code', () => {
|
|
100
104
|
for (const doc of commandDocs) {
|
|
105
|
+
if (HIDDEN.has(doc.name)) continue;
|
|
101
106
|
expect(entries.get(doc.name)?.exitCodes, doc.name).toEqual(
|
|
102
107
|
doc.exitCodes.map(({code, when}) => ({code, when})),
|
|
103
108
|
);
|
|
@@ -55,6 +55,10 @@ const CLI_LAYER_TYPES = {
|
|
|
55
55
|
};
|
|
56
56
|
|
|
57
57
|
const manifest = buildManifest(program, {jsonSupported: JSON_SUPPORTED, version: '0.0.0-test'});
|
|
58
|
+
/** Hidden commands (a package-script hook): documented, never in the manifest. */
|
|
59
|
+
const HIDDEN = new Set(
|
|
60
|
+
program.commands.filter((c) => /** @type {any} */ (c)._hidden).map((c) => c.name()),
|
|
61
|
+
);
|
|
58
62
|
|
|
59
63
|
/** Flatten the manifest command tree into fully-qualified names. */
|
|
60
64
|
function flatten(cmds, out = []) {
|
|
@@ -116,12 +120,19 @@ describe('manifest: drift guards', () => {
|
|
|
116
120
|
|
|
117
121
|
it('takes every command example from its CommandDoc', () => {
|
|
118
122
|
for (const [name, doc] of commandDocs) {
|
|
123
|
+
if (HIDDEN.has(name)) continue;
|
|
119
124
|
const entry = allEntries.find((c) => c.name === name);
|
|
120
125
|
expect(entry, `CommandDoc "${name}" has no manifest entry`).toBeDefined();
|
|
121
126
|
expect(entry.examples ?? [], name).toEqual((doc.examples ?? []).map((e) => e.cli));
|
|
122
127
|
}
|
|
123
128
|
});
|
|
124
129
|
|
|
130
|
+
it('documents the hidden postinstall hook and keeps it out of the manifest', () => {
|
|
131
|
+
expect([...HIDDEN]).toEqual(['postinstall']);
|
|
132
|
+
expect(commandDocs.has('postinstall')).toBe(true);
|
|
133
|
+
expect(allNames.has('postinstall')).toBe(false);
|
|
134
|
+
});
|
|
135
|
+
|
|
125
136
|
it('lists every response type the wrapped API function returns', () => {
|
|
126
137
|
for (const [name, doc] of commandDocs) {
|
|
127
138
|
if (!doc.fn) continue;
|
|
@@ -152,6 +163,7 @@ describe('manifest: drift guards', () => {
|
|
|
152
163
|
|
|
153
164
|
it('takes response types from the wrapped FunctionDoc, plus CLI-layer envelopes', () => {
|
|
154
165
|
for (const [name, doc] of commandDocs) {
|
|
166
|
+
if (HIDDEN.has(name)) continue;
|
|
155
167
|
const entry = allEntries.find((c) => c.name === name);
|
|
156
168
|
const returns = doc.fn ? functionDocs.get(doc.fn).returns.map((r) => r.type) : [];
|
|
157
169
|
const expected = [...returns, ...(CLI_LAYER_TYPES[name] ?? [])];
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file The welcome box `astryx postinstall` prints after the package installs.
|
|
5
|
+
*
|
|
6
|
+
* A fixed banner, not tabular output, so it is drawn here rather than with the
|
|
7
|
+
* formatter kit; the command prints it verbatim through `emit(code(...))`.
|
|
8
|
+
* @input The CLI invocation for this project (e.g. `pnpm exec astryx`).
|
|
9
|
+
* @output {@link welcomeBox}
|
|
10
|
+
* @position clients/cli/lib — presentation helper for commands/postinstall.mjs
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** Inner width of the box. */
|
|
14
|
+
const W = 49;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {string} s
|
|
18
|
+
* @param {number} len
|
|
19
|
+
*/
|
|
20
|
+
const pad = (s, len) => s + ' '.repeat(Math.max(0, len - s.length));
|
|
21
|
+
|
|
22
|
+
/** @param {string} s */
|
|
23
|
+
const line = s => ` │ ${pad(s, W)}│`;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The welcome box, with a blank line before and after it.
|
|
27
|
+
* @param {string} r the CLI invocation, e.g. `pnpm exec astryx`
|
|
28
|
+
* @returns {string}
|
|
29
|
+
*/
|
|
30
|
+
export function welcomeBox(r) {
|
|
31
|
+
return `
|
|
32
|
+
╭${'─'.repeat(W + 2)}╮
|
|
33
|
+
${line('')}
|
|
34
|
+
${line(' Design system installed!')}
|
|
35
|
+
${line('')}
|
|
36
|
+
${line(' Get started:')}
|
|
37
|
+
${line(` ${r} init Setup + AI agent docs`)}
|
|
38
|
+
${line(` ${r} --help See all commands`)}
|
|
39
|
+
${line('')}
|
|
40
|
+
${line(' Or run directly:')}
|
|
41
|
+
${line(` ${r} init Setup + AI agent docs`)}
|
|
42
|
+
${line(` ${r} component Browse component docs`)}
|
|
43
|
+
${line(` ${r} hook Browse hook docs`)}
|
|
44
|
+
${line(` ${r} docs Design system reference`)}
|
|
45
|
+
${line(` ${r} swizzle Customize a component`)}
|
|
46
|
+
${line(` ${r} template Add a page template`)}
|
|
47
|
+
${line('')}
|
|
48
|
+
╰${'─'.repeat(W + 2)}╯
|
|
49
|
+
`;
|
|
50
|
+
}
|