@astryxdesign/cli 0.7.2 → 0.7.3-canary.0bf23bd
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 +115 -3
- package/api/build/blocks/blocks.d.mts +42 -0
- package/api/build/blocks/blocks.mjs +169 -0
- package/api/build/blocks/blocks.test.mjs +108 -0
- package/api/build/blocks/blocks.weights.json +1 -0
- package/api/build/build.mjs +25 -6
- package/api/build/kit/answer.d.mts +14 -0
- package/api/build/kit/answer.mjs +85 -0
- package/api/build/kit/answer.test.mjs +38 -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 +60 -0
- package/api/build/kit/signals.mjs +284 -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 +52 -0
- package/api/build/tree.test.mjs +177 -0
- package/api/build/tree.weights.json +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.mjs +36 -9
- package/api/discover/_adapter.test.mjs +42 -0
- package/api/docs/_adapter.d.mts +2 -2
- package/api/docs/_adapter.mjs +78 -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/doctor.mjs +102 -24
- package/api/doctor/doctor.test.mjs +37 -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-gaps.test.mjs +1964 -0
- package/api/integration/validate-integration.d.mts +11 -2
- package/api/integration/validate-integration.mjs +250 -32
- package/api/integration/validate-integration.type.d.mts +59 -1
- package/api/integration/validate-integration.type.mjs +46 -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 +52 -0
- package/api/search/_entries.mjs +214 -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/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 +2 -2
- 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 +1 -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.mjs +30 -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 +2 -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 +61 -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 +29 -86
- 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 +20 -7
- package/foundation/agent-docs/agent-doc-state.mjs +35 -8
- package/foundation/agent-docs/agent-docs.d.mts +100 -12
- package/foundation/agent-docs/agent-docs.mjs +1012 -100
- package/foundation/agent-docs/agent-docs.path-safety.test.mjs +1239 -17
- package/foundation/agent-docs/agent-docs.test.mjs +683 -39
- 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/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/integrations.d.mts +27 -1
- package/foundation/integrations/integrations.mjs +61 -2
- package/foundation/integrations/validate-contributions.d.mts +115 -0
- package/foundation/integrations/validate-contributions.mjs +1168 -13
- package/foundation/release/handoff.d.mts +23 -4
- package/foundation/release/handoff.mjs +175 -8
- 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/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
|
@@ -16,10 +16,24 @@ export const doc = {
|
|
|
16
16
|
summary: 'Initialize the design system in your project',
|
|
17
17
|
description:
|
|
18
18
|
'Non-interactive project setup (no prompts, so it behaves the same for humans, ' +
|
|
19
|
-
'agents, and CI). By default it
|
|
20
|
-
'
|
|
21
|
-
|
|
22
|
-
'
|
|
19
|
+
'agents, and CI). By default it writes the agent-docs block, including guidance ' +
|
|
20
|
+
'from configured integrations, to AGENTS.md and to the Claude Code file the project ' +
|
|
21
|
+
'has (CLAUDE.md, else .claude/CLAUDE.md; when CLAUDE.md exists, a block in ' +
|
|
22
|
+
'.claude/CLAUDE.md is removed, unless the project ignores CLAUDE.md, in which case a .claude/CLAUDE.md the ' +
|
|
23
|
+
'project commits keeps a copy), and a one-line import of AGENTS.md to GEMINI.md ' +
|
|
24
|
+
'unless GEMINI.md already imports it. It then prints getting-started steps. Agent ' +
|
|
25
|
+
'docs go to the project root: the nearest folder at or above this one whose ' +
|
|
26
|
+
'package.json declares an @astryxdesign package, else the nearest with any ' +
|
|
27
|
+
'package.json, else this folder. The search stops at a repository root and never ' +
|
|
28
|
+
'counts the home folder. In the home folder, or in a settings folder in it ' +
|
|
29
|
+
'such as ~/.gemini outside a project, no agent docs are written. Every folder of the ' +
|
|
30
|
+
'home folder whose name starts with a dot is a settings folder, and such a folder ' +
|
|
31
|
+
'itself never counts as a project, even with a package.json; a project inside one, ' +
|
|
32
|
+
'such as an agent worktree with its own package.json, works. The managed block is ' +
|
|
33
|
+
'written whatever ignore rules or generated markers say; the text around it is never changed. ' +
|
|
34
|
+
'--features and --all print only ' +
|
|
35
|
+
"the chosen features' " +
|
|
36
|
+
'guidance (no getting-started steps); the theme feature also writes an annotated theme template. ' +
|
|
23
37
|
'Outside a project it writes the same files but prints no step that sets up a project: ' +
|
|
24
38
|
'no getting-started steps, and no step that adds a theme to an app. ' +
|
|
25
39
|
'--user writes the computer-level agent text instead (see the flag), in any folder, and touches nothing in the folder. ' +
|
|
@@ -44,8 +58,10 @@ export const doc = {
|
|
|
44
58
|
flag: '--remove-agents',
|
|
45
59
|
param: 'options.removeAgents',
|
|
46
60
|
description:
|
|
47
|
-
'Remove the managed block from AGENTS.md, CLAUDE.md, .claude/CLAUDE.md, .cursorrules, .hermes.md and HERMES.md ' +
|
|
48
|
-
|
|
61
|
+
'Remove the managed block from AGENTS.md, CLAUDE.md, .claude/CLAUDE.md, GEMINI.md, .cursorrules, .hermes.md and HERMES.md, ' +
|
|
62
|
+
'at the project root (where init writes them) and in this folder ' +
|
|
63
|
+
"(deleting AGENTS.md or .claude/CLAUDE.md when only init's heading is left, and GEMINI.md when nothing is left) and do nothing else. " +
|
|
64
|
+
'Below the project root, a project-root agent file whose block resolves outside the project is left as it is, with a note. ' +
|
|
49
65
|
'--features, --all, --agent and --agent-docs-path are refused; a file written with --agent-docs-path keeps its block',
|
|
50
66
|
},
|
|
51
67
|
{
|
|
@@ -66,7 +82,9 @@ export const doc = {
|
|
|
66
82
|
choices: ['claude', 'cursor', 'codex', 'hermes', 'muse', 'all'],
|
|
67
83
|
description:
|
|
68
84
|
'Target AI tool for agent docs: claude (CLAUDE.md or .claude/CLAUDE.md, else creates .claude/CLAUDE.md), cursor (.cursorrules if present, else AGENTS.md), ' +
|
|
69
|
-
'codex and muse (AGENTS.md), hermes (.hermes.md or HERMES.md if present, else AGENTS.md), all (every existing agent doc
|
|
85
|
+
'codex and muse (AGENTS.md), hermes (.hermes.md or HERMES.md if present, else AGENTS.md), all (every existing agent doc except GEMINI.md, which keeps its ' +
|
|
86
|
+
'one-line import of AGENTS.md, else AGENTS.md and .claude/CLAUDE.md). With claude and all, when CLAUDE.md gets the block, .claude/CLAUDE.md gets none and ' +
|
|
87
|
+
'a block already there is removed, unless the project ignores CLAUDE.md: then a .claude/CLAUDE.md the project commits gets a copy too, with claude and all alike. ' +
|
|
70
88
|
'An unknown tool exits 1 with ERR_UNKNOWN_AGENT. ' +
|
|
71
89
|
'Used only when agent docs are installed (the default, --all, or --features agents); --agent-docs-path takes precedence.',
|
|
72
90
|
},
|
|
@@ -76,6 +94,7 @@ export const doc = {
|
|
|
76
94
|
description:
|
|
77
95
|
'Explicit file path(s) for agent docs, inside the project; takes precedence over --agent. ' +
|
|
78
96
|
'If any path is outside the project, no agent docs are written and the command exits 1. ' +
|
|
97
|
+
'A path in the home folder itself, or in a settings folder in it outside a project (such as ~/.claude or ~/.claude/hooks), is refused with a note (exit 0), and nothing is written. ' +
|
|
79
98
|
'Used only when agent docs are installed',
|
|
80
99
|
},
|
|
81
100
|
],
|
|
@@ -90,11 +109,11 @@ export const doc = {
|
|
|
90
109
|
exitCodes: [
|
|
91
110
|
{
|
|
92
111
|
code: 0,
|
|
93
|
-
when:
|
|
112
|
+
when: "success, including agent docs left unwritten in five soft cases, each reported as docsError with one note: running in the home folder, or in a settings folder in it outside a project; a GEMINI.md that resolves outside the project; when init runs below the project root, a project-root agent file that resolves outside the project; the project's Claude Code file (root CLAUDE.md, or .claude/CLAUDE.md when there is no root one) when it resolves outside the project and is a block-less import of an existing AGENTS.md, which 0.7.1 left alone; and a .claude/CLAUDE.md that resolves outside the project and that 0.7.1 did not write: beside a CLAUDE.md the project ignores, the one --agent claude adds or a block-less import of an existing AGENTS.md; with --agent claude beside a CLAUDE.md, one whose block it would remove",
|
|
94
113
|
},
|
|
95
114
|
{
|
|
96
115
|
code: 1,
|
|
97
|
-
|
|
116
|
+
when: 'an unknown --agent (ERR_UNKNOWN_AGENT) or feature, an --agent-docs-path outside the project, --remove-agents combined with install options, --user combined with --features, --all, --agent or --agent-docs-path, or --all with --features (ERR_INVALID_ARGUMENT); or, when init runs at the project root, an agent file 0.7.1 also wrote there that resolves outside the project (ERR_PATH_TRAVERSAL, docsError path-safety, nothing written)',
|
|
98
117
|
},
|
|
99
118
|
],
|
|
100
119
|
related: ['doctor', 'upgrade', 'build', 'theme'],
|
|
@@ -67,6 +67,7 @@ describe('astryx init flag interactions', () => {
|
|
|
67
67
|
expect(help).toContain(file);
|
|
68
68
|
}
|
|
69
69
|
expect(help).toMatch(/--agent-docs-path are refused/);
|
|
70
|
+
expect(help).toMatch(/at the project root \(where init writes them\) and in this folder/);
|
|
70
71
|
|
|
71
72
|
await initJson(['--agent-docs-path', 'docs/AI.md']);
|
|
72
73
|
await initJson([]);
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* @file init command — thin wrapper around the init API.
|
|
5
5
|
*
|
|
6
|
-
* `astryx init` is non-interactive by default: it installs the
|
|
7
|
-
*
|
|
6
|
+
* `astryx init` is non-interactive by default: it installs the agent-docs
|
|
7
|
+
* cheat sheet with NO prompts, so it behaves identically for humans,
|
|
8
8
|
* AI agents, CI, and piped I/O — it never hangs or errors on a missing TTY.
|
|
9
9
|
* Non-interactive feature install: `astryx init --features agents,theme,template`
|
|
10
10
|
* Re-runnable: safe to run multiple times, idempotent.
|
|
@@ -439,3 +439,51 @@ describe('a stray doc pointer', () => {
|
|
|
439
439
|
expect(strict.stdout).toContain('stray_doc_pointer');
|
|
440
440
|
});
|
|
441
441
|
});
|
|
442
|
+
describe('a command written with a runner', () => {
|
|
443
|
+
it('is a note in doctor integration validate, and integration check --strict still passes', async () => {
|
|
444
|
+
fs.writeFileSync(
|
|
445
|
+
path.join(tmpDir, 'package.json'),
|
|
446
|
+
JSON.stringify({name: '@acme/widgets', version: '1.2.3'}),
|
|
447
|
+
);
|
|
448
|
+
fs.writeFileSync(
|
|
449
|
+
path.join(tmpDir, 'astryx.integration.mjs'),
|
|
450
|
+
`export default {docs: './docs'};\n`,
|
|
451
|
+
);
|
|
452
|
+
fs.mkdirSync(path.join(tmpDir, 'docs'));
|
|
453
|
+
const doc = {
|
|
454
|
+
type: 'generic',
|
|
455
|
+
name: 'acme-setup',
|
|
456
|
+
title: 'Fixture',
|
|
457
|
+
description: 'Fixture topic.',
|
|
458
|
+
sections: [
|
|
459
|
+
{
|
|
460
|
+
title: 'Overview',
|
|
461
|
+
content: [{type: 'code', lang: 'bash', code: 'npx astryx doctor'}],
|
|
462
|
+
},
|
|
463
|
+
],
|
|
464
|
+
};
|
|
465
|
+
fs.writeFileSync(
|
|
466
|
+
path.join(tmpDir, 'docs', 'acme-setup.doc.mjs'),
|
|
467
|
+
`export default ${JSON.stringify(doc)};\n`,
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
const doctor = await runCli(['doctor', 'integration', 'validate'], tmpDir);
|
|
471
|
+
expect(doctor.status).toBe(0);
|
|
472
|
+
expect(doctor.stdout).toContain(
|
|
473
|
+
'note (runner_command): docs/acme-setup.doc.mjs:',
|
|
474
|
+
);
|
|
475
|
+
expect(doctor.stdout).toContain('Write `astryx doctor`');
|
|
476
|
+
|
|
477
|
+
const strict = await runCli(
|
|
478
|
+
['--json', 'integration', 'check', '--strict'],
|
|
479
|
+
tmpDir,
|
|
480
|
+
);
|
|
481
|
+
expect(strict.status).toBe(0);
|
|
482
|
+
const validate = JSON.parse(strict.stdout).data.checks.find(
|
|
483
|
+
(/** @type {any} */ each) => each.check === 'validate',
|
|
484
|
+
).response.data;
|
|
485
|
+
expect(validate.notes.map((/** @type {any} */ note) => note.code)).toEqual([
|
|
486
|
+
'runner_command',
|
|
487
|
+
]);
|
|
488
|
+
});
|
|
489
|
+
});
|
|
@@ -8,7 +8,7 @@ export const doc = {
|
|
|
8
8
|
namespace: 'cli/commands',
|
|
9
9
|
summary: 'Author and verify an Astryx integration package',
|
|
10
10
|
description:
|
|
11
|
-
'Add contributions to your package, check them on every build with `integration check --strict`, then check the packed package the way an app receives it. The guides start at {@link namespace:
|
|
11
|
+
'Add contributions to your package, check them on every build with `integration check --strict`, then check the packed package the way an app receives it. The guides start at {@link namespace:authoring}.',
|
|
12
12
|
subcommands: ['add', 'check', 'verify', 'pack'],
|
|
13
13
|
examples: [
|
|
14
14
|
{
|
|
@@ -13,7 +13,7 @@ export const doc = {
|
|
|
13
13
|
name: 'manifest',
|
|
14
14
|
displayName: 'astryx manifest',
|
|
15
15
|
namespace: 'cli/commands',
|
|
16
|
-
summary: 'Print the full CLI capability manifest (use with --json)
|
|
16
|
+
summary: 'Print the full CLI capability manifest (use with --json)',
|
|
17
17
|
description:
|
|
18
18
|
'Emits the complete CLI surface: every command with its arguments, options, ' +
|
|
19
19
|
'subcommands, and JSON response types, as a single typed envelope for agents and ' +
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file manifest command — `astryx manifest`, the CLI capability manifest.
|
|
5
|
+
*
|
|
6
|
+
* A single, self-describing view of the whole CLI so agents can discover every
|
|
7
|
+
* command, argument, flag, and response type without scraping `--help`.
|
|
8
|
+
* `astryx manifest --json` is the dedicated surface; the bare `astryx --json`
|
|
9
|
+
* embeds the same payload under data.manifest for convenience.
|
|
10
|
+
*
|
|
11
|
+
* Intentionally CLI-special — no `api/manifest`. It introspects the live
|
|
12
|
+
* Commander `program`, so extracting it to `api/` would create an `api → cli`
|
|
13
|
+
* cycle. `buildManifest(program)` lives in lib/; see its header. Register it
|
|
14
|
+
* after every other command: the manifest lists commands in registration order.
|
|
15
|
+
*
|
|
16
|
+
* The command surface comes from the colocated CommandDoc via `defineCommand`.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import {getCliInvocation} from '../../../foundation/env/package-manager.mjs';
|
|
20
|
+
import {jsonOut} from '../../../foundation/response/json.mjs';
|
|
21
|
+
import {emit, section, text, records} from '../formatters/index.mjs';
|
|
22
|
+
import {buildManifest} from '../lib/manifest.mjs';
|
|
23
|
+
import {defineCommand} from '../lib/define-command.mjs';
|
|
24
|
+
import {resultSet} from '../../../foundation/debug/index.mjs';
|
|
25
|
+
import {doc as manifestCommand} from './manifest.doc.mjs';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {import('commander').Command} program the root program
|
|
29
|
+
* @param {{jsonSupported: Set<string>, version: string}} context the commands
|
|
30
|
+
* that accept --json, and the CLI's version
|
|
31
|
+
*/
|
|
32
|
+
export function registerManifest(program, {jsonSupported, version}) {
|
|
33
|
+
defineCommand(program, manifestCommand, {
|
|
34
|
+
action: () => {
|
|
35
|
+
const manifest = buildManifest(program, {jsonSupported, version});
|
|
36
|
+
// The manifest IS a result set: one entry per command the CLI ships.
|
|
37
|
+
const answered = resultSet({
|
|
38
|
+
count: manifest.commands.length,
|
|
39
|
+
resultKind: 'command',
|
|
40
|
+
});
|
|
41
|
+
if (program.opts().json) {
|
|
42
|
+
jsonOut({type: 'manifest', data: manifest});
|
|
43
|
+
return answered;
|
|
44
|
+
}
|
|
45
|
+
// Human-readable summary as greppable records (agents should use --json).
|
|
46
|
+
// One record per command: name, whether it supports --json, and the
|
|
47
|
+
// description. Field names are the manifest entry's own keys.
|
|
48
|
+
emit(
|
|
49
|
+
section(
|
|
50
|
+
`${manifest.name} v${manifest.version} (${manifest.commands.length} commands)`,
|
|
51
|
+
),
|
|
52
|
+
records(
|
|
53
|
+
manifest.commands.map(c => ({
|
|
54
|
+
name: c.name,
|
|
55
|
+
json: c.json ? 'yes' : '',
|
|
56
|
+
description: c.description || '',
|
|
57
|
+
})),
|
|
58
|
+
{fields: ['name', 'json', 'description']},
|
|
59
|
+
),
|
|
60
|
+
text(
|
|
61
|
+
`Run \`${getCliInvocation()} manifest --json\` for the full structured manifest.`,
|
|
62
|
+
),
|
|
63
|
+
);
|
|
64
|
+
return answered;
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
}
|
|
@@ -541,7 +541,8 @@ describe('init outside a project (own)', () => {
|
|
|
541
541
|
const dir = tmpDir('init');
|
|
542
542
|
const json = await answer(['--json', 'init'], dir);
|
|
543
543
|
expect(json.status).toBe(0);
|
|
544
|
-
|
|
544
|
+
// GEMINI.md gets its one-line import of AGENTS.md (spec cli-surface INV31).
|
|
545
|
+
expect(json.written).toEqual(['AGENTS.md', 'GEMINI.md']);
|
|
545
546
|
expect(json.envelope.data.nextSteps).toBe(false);
|
|
546
547
|
const text = await runCli(['init'], tmpDir('init-text'));
|
|
547
548
|
expect(text.stdout).not.toContain('Next steps');
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file CommandDoc for `astryx postinstall`. A hidden, CLI-only hook with no
|
|
5
|
+
* wrapped API function (so no `fn`): it prints the welcome box.
|
|
6
|
+
* @position packages/cli/clients/cli/commands — command documentation
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** @type {import('@astryxdesign/cli/authoring').CommandDoc} */
|
|
10
|
+
export const doc = {
|
|
11
|
+
type: 'command',
|
|
12
|
+
name: 'postinstall',
|
|
13
|
+
displayName: 'astryx postinstall',
|
|
14
|
+
namespace: 'cli/commands',
|
|
15
|
+
summary: 'Print the welcome message shown after install',
|
|
16
|
+
description:
|
|
17
|
+
'Prints a short welcome box that names the first commands to run. It is hidden ' +
|
|
18
|
+
'from help and the manifest, looks nothing up, and does not support --json.',
|
|
19
|
+
examples: [{label: 'Print the welcome box', cli: 'astryx postinstall'}],
|
|
20
|
+
outsideProject: 'same',
|
|
21
|
+
exitCodes: [{code: 0, when: 'success'}],
|
|
22
|
+
related: ['init'],
|
|
23
|
+
};
|
|
@@ -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,48 @@ 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
|
+
// Inside a git repository the project-root check above adds nothing to the
|
|
206
|
+
// walk up to the repository root: the same outcomes as without it.
|
|
207
|
+
it('inside a repository, is quiet in a nested package once init has written the docs at the project root', async () => {
|
|
208
|
+
fs.mkdirSync(path.join(tmp, '.git'));
|
|
209
|
+
write('package.json', JSON.stringify({name: 'app', dependencies: {'@astryxdesign/core': '0.7.0'}}));
|
|
210
|
+
write('AGENTS.md', MARKER);
|
|
211
|
+
write('functions/package.json', '{"name":"functions"}');
|
|
212
|
+
const r = await runCli(['docs', 'tokens'], path.join(tmp, 'functions'));
|
|
213
|
+
expect(r.stderr).not.toMatch(NUDGE);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('inside a repository, still nudges when the only docs lie above the repository root', async () => {
|
|
217
|
+
write('package.json', JSON.stringify({name: 'outer', dependencies: {'@astryxdesign/core': '0.7.0'}}));
|
|
218
|
+
write('AGENTS.md', MARKER);
|
|
219
|
+
fs.mkdirSync(path.join(tmp, 'repo', '.git'), {recursive: true});
|
|
220
|
+
write('repo/package.json', '{"name":"repo"}');
|
|
221
|
+
// It declares Astryx: a folder that declares nothing is outside a
|
|
222
|
+
// project, where no reminder prints (spec AST-081 FR3).
|
|
223
|
+
write(
|
|
224
|
+
'repo/functions/package.json',
|
|
225
|
+
JSON.stringify({name: 'functions', dependencies: {'@astryxdesign/core': '0.7.0'}}),
|
|
226
|
+
);
|
|
227
|
+
const r = await runCli(['docs', 'tokens'], path.join(tmp, 'repo', 'functions'));
|
|
228
|
+
expect(r.stderr).toMatch(NUDGE);
|
|
229
|
+
});
|
|
230
|
+
|
|
170
231
|
it('does not nudge for the installer command itself', async () => {
|
|
171
232
|
asProject();
|
|
172
233
|
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
|
+
});
|