@astryxdesign/cli 0.7.2-canary.fe2c655 → 0.7.3-canary.02f5fe4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +119 -0
- package/README.md +216 -162
- package/api/build/_adapter.d.mts +66 -0
- package/api/build/_adapter.mjs +139 -4
- package/api/build/blocks/blocks.d.mts +92 -0
- package/api/build/blocks/blocks.mjs +528 -0
- package/api/build/blocks/blocks.test.mjs +238 -0
- package/api/build/blocks/blocks.weights.json +1 -0
- package/api/build/build.doc.mjs +4 -0
- package/api/build/build.mjs +25 -6
- package/api/build/build.type.mjs +1 -1
- package/api/build/help/help.mjs +1 -1
- package/api/build/kit/answer.d.mts +18 -0
- package/api/build/kit/answer.mjs +195 -0
- package/api/build/kit/answer.test.mjs +108 -0
- package/api/build/kit/kind.d.mts +25 -0
- package/api/build/kit/kind.mjs +170 -0
- package/api/build/kit/kit.d.mts +2 -4
- package/api/build/kit/kit.mjs +8 -406
- package/api/build/kit/rank.d.mts +3 -32
- package/api/build/kit/rank.mjs +25 -342
- package/api/build/kit/rank.test.mjs +2 -1
- package/api/build/kit/signals.d.mts +79 -0
- package/api/build/kit/signals.mjs +295 -0
- package/api/build/kit/start.d.mts +32 -0
- package/api/build/kit/start.mjs +163 -0
- package/api/build/kit/words.d.mts +72 -0
- package/api/build/kit/words.mjs +202 -0
- package/api/build/tree.d.mts +20 -0
- package/api/build/tree.mjs +53 -0
- package/api/build/tree.test.mjs +185 -0
- package/api/build/tree.weights.json +1 -0
- package/api/component/_adapter.d.mts +72 -1
- package/api/component/_adapter.mjs +251 -23
- package/api/component/component-replacement.test.mjs +1 -0
- package/api/component/component.doc.mjs +6 -1
- package/api/component/component.mjs +97 -16
- package/api/component/component.test.mjs +95 -0
- package/api/component/doc-links.test.mjs +386 -0
- package/api/component/integration-export-name.test.mjs +644 -0
- package/api/component/list/list.mjs +42 -4
- package/api/discover/_adapter.d.mts +131 -12
- package/api/discover/_adapter.mjs +520 -34
- package/api/discover/_adapter.test.mjs +641 -17
- package/api/discover/_catalog-view.d.mts +16 -5
- package/api/discover/_catalog-view.mjs +32 -8
- package/api/discover/detail/doc/doc.mjs +9 -1
- package/api/discover/discover.d.mts +11 -0
- package/api/discover/discover.doc.mjs +9 -7
- package/api/discover/discover.mjs +120 -19
- package/api/discover/discover.type.d.mts +20 -7
- package/api/discover/discover.type.mjs +17 -7
- package/api/discover/list/list.d.mts +4 -3
- package/api/discover/list/list.mjs +17 -10
- package/api/docs/_adapter.d.mts +76 -2
- package/api/docs/_adapter.mjs +630 -34
- package/api/docs/docs-homes.test.mjs +127 -0
- package/api/docs/docs.doc.mjs +5 -4
- package/api/docs/docs.mjs +2 -1
- package/api/docs/docs.test.mjs +39 -20
- package/api/docs/integration-tree.test.mjs +42 -20
- package/api/docs/integrationDocs.test.mjs +125 -1
- package/api/docs/list/list.mjs +12 -2
- package/api/docs/namespace-section.test.mjs +6 -6
- package/api/docs/reference-blocks.test.mjs +3 -5
- package/api/doctor/_adapter.d.mts +128 -0
- package/api/doctor/_adapter.mjs +253 -4
- package/api/doctor/doctor.d.mts +217 -0
- package/api/doctor/doctor.doc.mjs +3 -2
- package/api/doctor/doctor.mjs +691 -52
- package/api/doctor/doctor.test.mjs +267 -18
- package/api/doctor/release-checks.test.mjs +156 -0
- package/api/doctor/theme-checks.mjs +17 -4
- package/api/doctor/theme-checks.test.mjs +223 -7
- package/api/error.d.mts +10 -0
- package/api/error.mjs +25 -0
- package/api/gap-report/gap-report.d.mts +3 -0
- package/api/gap-report/gap-report.doc.mjs +11 -3
- package/api/gap-report/gap-report.mjs +219 -52
- package/api/gap-report/gap-report.test.mjs +233 -0
- package/api/gap-report/gap-report.type.d.mts +41 -0
- package/api/gap-report/gap-report.type.mjs +18 -0
- package/api/hook/_adapter.mjs +3 -11
- package/api/hook/hook.doc.mjs +4 -0
- package/api/hook/hook.mjs +1 -1
- package/api/hook/list/list.d.mts +1 -1
- package/api/index.d.mts +2 -0
- package/api/index.mjs +2 -0
- package/api/init/_adapter.d.mts +22 -0
- package/api/init/_adapter.mjs +59 -0
- package/api/init/init.d.mts +7 -5
- package/api/init/init.doc.mjs +45 -10
- package/api/init/init.mjs +28 -4
- package/api/init/init.test.mjs +18 -2
- package/api/init/init.type.d.mts +50 -5
- package/api/init/init.type.mjs +39 -5
- package/api/init/remove/remove.mjs +17 -4
- package/api/init/remove/remove.test.mjs +114 -2
- package/api/init/run/run.d.mts +1 -1
- package/api/init/run/run.mjs +86 -12
- package/api/init/user/user.d.mts +14 -0
- package/api/init/user/user.mjs +87 -0
- package/api/init/user/user.test.mjs +232 -0
- package/api/integration/_adapter.d.mts +53 -0
- package/api/integration/_adapter.mjs +132 -0
- package/api/integration/add-contribution.component-names.test.mjs +66 -0
- package/api/integration/add-contribution.mjs +8 -4
- package/api/integration/add-contribution.test.mjs +4 -2
- package/api/integration/authoring-checks.mjs +192 -14
- package/api/integration/authoring-checks.test.mjs +1028 -0
- package/api/integration/authoring-checks.type.d.mts +143 -0
- package/api/integration/authoring-checks.type.mjs +74 -2
- package/api/integration/check/check.d.mts +96 -0
- package/api/integration/check/check.mjs +357 -0
- package/api/integration/check/check.test.mjs +489 -0
- package/api/integration/integration-check.type.d.mts +118 -0
- package/api/integration/integration-check.type.mjs +84 -0
- package/api/integration/integrationCheck.doc.d.mts +10 -0
- package/api/integration/integrationCheck.doc.mjs +73 -0
- package/api/integration/integrationComponentConflicts.doc.mjs +45 -6
- package/api/integration/integrationDocConflicts.doc.mjs +22 -5
- package/api/integration/pack-check.mjs +486 -123
- package/api/integration/pack-check.test.mjs +817 -10
- package/api/integration/validate-integration-case-disk.test.mjs +111 -0
- package/api/integration/validate-integration-fixes.test.mjs +73 -5
- package/api/integration/validate-integration-gaps.test.mjs +1975 -0
- package/api/integration/validate-integration.d.mts +23 -2
- package/api/integration/validate-integration.mjs +358 -45
- package/api/integration/validate-integration.test.mjs +88 -8
- package/api/integration/validate-integration.type.d.mts +105 -0
- package/api/integration/validate-integration.type.mjs +79 -1
- package/api/integration/validate-unread-theme-folders.test.mjs +3 -2
- package/api/integration/validateIntegration.doc.mjs +19 -3
- package/api/search/ORDERING.md +28 -0
- package/api/search/_adapter.d.mts +91 -0
- package/api/search/_adapter.mjs +172 -0
- package/api/search/_adapter.test.mjs +173 -0
- package/api/search/_candidate-score.d.mts +40 -0
- package/api/search/_candidate-score.mjs +238 -0
- package/api/search/_cards.json +6098 -0
- package/api/search/_compound.d.mts +50 -0
- package/api/search/_compound.mjs +170 -0
- package/api/search/_doc-searcher.d.mts +4 -0
- package/api/search/_doc-searcher.mjs +23 -0
- package/api/search/_doc-searcher.test.mjs +36 -0
- package/api/search/_doc-searcher.weights.json +1 -0
- package/api/search/_doc-text.d.mts +30 -0
- package/api/search/_doc-text.mjs +87 -0
- package/api/search/_entries.d.mts +63 -0
- package/api/search/_entries.mjs +232 -0
- package/api/search/_entries.test.mjs +48 -0
- package/api/search/_features.d.mts +35 -0
- package/api/search/_features.mjs +155 -0
- package/api/search/_gather-components.d.mts +26 -0
- package/api/search/_gather-components.mjs +284 -0
- package/api/search/_gather-docs.d.mts +20 -0
- package/api/search/_gather-docs.mjs +254 -0
- package/api/search/_gather-hooks.d.mts +12 -0
- package/api/search/_gather-hooks.mjs +52 -0
- package/api/search/_gather-templates.d.mts +25 -0
- package/api/search/_gather-templates.mjs +107 -0
- package/api/search/_lexical.d.mts +135 -0
- package/api/search/_lexical.mjs +351 -0
- package/api/search/_main-searcher.d.mts +19 -0
- package/api/search/_main-searcher.mjs +115 -0
- package/api/search/_main-searcher.test.mjs +106 -0
- package/api/search/_main-searcher.weights.json +1 -0
- package/api/search/_module-doc.d.mts +32 -0
- package/api/search/_module-doc.mjs +78 -0
- package/api/search/_order.d.mts +32 -0
- package/api/search/_order.mjs +162 -0
- package/api/search/_order.test.mjs +72 -0
- package/api/search/_priority.d.mts +50 -0
- package/api/search/_priority.mjs +139 -0
- package/api/search/_query-words.d.mts +25 -0
- package/api/search/_query-words.mjs +92 -0
- package/api/search/_query.d.mts +65 -0
- package/api/search/_query.mjs +176 -0
- package/api/search/_result.d.mts +97 -0
- package/api/search/_result.mjs +150 -0
- package/api/search/_score.d.mts +60 -0
- package/api/search/_score.mjs +283 -0
- package/api/search/_synonyms.d.mts +21 -0
- package/api/search/_synonyms.mjs +67 -0
- package/api/search/_template-searcher.d.mts +4 -0
- package/api/search/_template-searcher.mjs +23 -0
- package/api/search/_template-searcher.test.mjs +40 -0
- package/api/search/_template-searcher.weights.json +1 -0
- package/api/search/_titles.d.mts +33 -0
- package/api/search/_titles.mjs +65 -0
- package/api/search/_words.d.mts +64 -0
- package/api/search/_words.mjs +157 -0
- package/api/search/search.d.mts +22 -236
- package/api/search/search.doc.mjs +14 -7
- package/api/search/search.domain-priority.test.mjs +108 -18
- package/api/search/search.integration-check.test.mjs +24 -0
- package/api/search/search.mjs +59 -1904
- package/api/search/search.test.mjs +193 -15
- package/api/search/search.type.d.mts +20 -2
- package/api/search/search.type.mjs +12 -2
- package/api/search/tree.d.mts +15 -0
- package/api/search/tree.mjs +40 -0
- package/api/search/tree.test.mjs +66 -0
- package/api/search/tree.weights.json +1 -0
- package/api/swizzle/_adapter.mjs +2 -2
- package/api/swizzle/copy/copy.mjs +29 -15
- package/api/template/template-integration.test.mjs +1 -1
- package/api/template/template.mjs +5 -1
- package/api/template/template.test.mjs +120 -3
- package/api/theme/_adapter.d.mts +16 -0
- package/api/theme/_adapter.mjs +32 -5
- package/api/theme/build/build.d.mts +2 -1
- package/api/theme/build/build.family.test.mjs +64 -0
- package/api/theme/build/build.mjs +250 -38
- package/api/theme/build/build.packed-old-core.test.mjs +21 -3
- package/api/theme/build/font-warning.mjs +5 -3
- package/api/theme/build/font-warning.test.mjs +2 -1
- package/api/theme/remove/remove.test.mjs +2 -2
- package/api/theme/targets/targets.mjs +3 -10
- package/api/theme/themeBuild.doc.mjs +4 -4
- package/api/theme/themeTargets.doc.mjs +4 -0
- package/api/theme/use/use.test.mjs +1 -1
- package/api/upgrade/_adapter.d.mts +97 -11
- package/api/upgrade/_adapter.mjs +315 -32
- package/api/upgrade/registry/registry.d.mts +10 -4
- package/api/upgrade/registry/registry.mjs +33 -16
- package/api/upgrade/registry/registry.test.mjs +85 -0
- package/api/upgrade/run/cli-behind-core.test.mjs +438 -0
- package/api/upgrade/run/run.d.mts +4 -2
- package/api/upgrade/run/run.mjs +48 -4
- package/api/upgrade/run/run.test.mjs +417 -3
- package/api/upgrade/status/status.d.mts +21 -5
- package/api/upgrade/status/status.mjs +45 -8
- package/api/upgrade/upgrade.doc.mjs +16 -8
- package/api/upgrade/upgrade.mjs +18 -3
- package/api/upgrade/upgrade.test.mjs +194 -0
- package/api/upgrade/upgrade.type.d.mts +28 -3
- package/api/upgrade/upgrade.type.mjs +24 -7
- package/assets/codemods/__tests__/registry.test.mjs +1 -0
- package/assets/codemods/registry.mjs +1 -0
- package/assets/codemods/runner.mjs +7 -1
- package/assets/codemods/transforms/v0.7.0/__tests__/validate-data-token-ownership.test.mjs +11 -0
- package/assets/codemods/transforms/v0.7.0/validate-data-token-ownership.mjs +3 -3
- package/assets/codemods/transforms/v0.7.2/__tests__/migrate-list-edge-compensation-to-edge.test.mjs +120 -0
- package/assets/codemods/transforms/v0.7.2/index.mjs +20 -0
- package/assets/codemods/transforms/v0.7.2/migrate-list-edge-compensation-to-edge.mjs +198 -0
- package/assets/discover/official-packages.json +367 -0
- package/assets/docs/README.md +10 -0
- package/assets/docs/author-a-theme.doc.mjs +5 -5
- package/assets/docs/browser-support.doc.mjs +1 -1
- package/assets/docs/getting-started.doc.mjs +26 -6
- package/assets/docs/is-my-code-good.doc.mjs +287 -0
- package/assets/docs/styling-overview.doc.mjs +1 -1
- package/assets/docs/theme.doc.dense.mjs +1 -1
- package/assets/docs/theme.doc.mjs +2 -2
- package/assets/docs/theme.doc.zh.mjs +1 -1
- package/assets/docs/tree/add-a-component.doc.mjs +22 -2
- package/assets/docs/tree/add-a-theme.doc.mjs +14 -4
- package/assets/docs/tree/add-a-topic.doc.mjs +54 -9
- package/assets/docs/tree/agent-guidance.doc.mjs +19 -5
- package/assets/docs/tree/api.doc.mjs +6 -0
- package/assets/docs/tree/authoring.doc.mjs +61 -0
- package/assets/docs/tree/block-template.doc.mjs +8 -20
- package/assets/docs/tree/build-the-template.doc.mjs +1 -1
- package/assets/docs/tree/building-blocks.doc.mjs +6 -2
- package/assets/docs/tree/check-the-props.doc.mjs +201 -0
- package/assets/docs/tree/check-your-docs.doc.mjs +69 -11
- package/assets/docs/tree/checks.doc.mjs +32 -24
- package/assets/docs/tree/ci-and-containers.doc.mjs +101 -0
- package/assets/docs/tree/cli-command.doc.mjs +142 -0
- package/assets/docs/tree/cli.doc.mjs +7 -1
- package/assets/docs/tree/codemods.doc.mjs +17 -7
- package/assets/docs/tree/commands.doc.mjs +7 -1
- package/assets/docs/tree/component-family.doc.mjs +8 -6
- package/assets/docs/tree/component-imports.doc.mjs +21 -3
- package/assets/docs/tree/components.doc.mjs +7 -1
- package/assets/docs/tree/computer-agent-guide.doc.mjs +160 -0
- package/assets/docs/tree/computer-integrations.doc.mjs +93 -0
- package/assets/docs/tree/configuration.doc.mjs +8 -4
- package/assets/docs/tree/debug-and-gap-reports.doc.mjs +41 -22
- package/assets/docs/tree/define-the-theme.doc.mjs +7 -6
- package/assets/docs/tree/describe-the-component.doc.mjs +3 -3
- package/assets/docs/tree/docs.doc.mjs +9 -3
- package/assets/docs/tree/document-the-template.doc.mjs +1 -1
- package/assets/docs/tree/document-the-theme.doc.mjs +4 -4
- package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
- package/assets/docs/tree/extend-or-replace.doc.mjs +19 -9
- package/assets/docs/{authoring.doc.mjs → tree/field-reference.doc.mjs} +4 -3
- package/assets/docs/tree/fonts-and-assets.doc.mjs +3 -3
- package/assets/docs/tree/generate-a-palette.doc.mjs +8 -6
- package/assets/docs/tree/global-integrations.doc.mjs +124 -0
- package/assets/docs/tree/global.doc.mjs +131 -0
- package/assets/docs/tree/grade-template-with-agent.doc.mjs +5 -5
- package/assets/docs/tree/help.doc.mjs +2 -2
- package/assets/docs/tree/host-entry.doc.mjs +128 -0
- package/assets/docs/tree/install-once.doc.mjs +105 -0
- package/assets/docs/tree/layout-spacing.doc.mjs +2 -3
- package/assets/docs/tree/layout.doc.mjs +6 -6
- package/assets/docs/tree/links.doc.mjs +7 -6
- package/assets/docs/tree/migration-setup.doc.mjs +3 -2
- package/assets/docs/tree/migration-verification.doc.mjs +0 -1
- package/assets/docs/tree/migration.doc.mjs +0 -1
- package/assets/docs/tree/monorepos.doc.mjs +84 -0
- package/assets/docs/tree/package-and-test.doc.mjs +1 -1
- package/assets/docs/tree/page-template.doc.mjs +4 -8
- package/assets/docs/tree/problems.doc.mjs +205 -0
- package/assets/docs/tree/project-global-or-both.doc.mjs +131 -0
- package/assets/docs/tree/publishing.doc.mjs +6 -6
- package/assets/docs/tree/quick-start.doc.mjs +54 -28
- package/assets/docs/tree/reference.doc.mjs +192 -0
- package/assets/docs/tree/replace-a-core-component.doc.mjs +15 -7
- package/assets/docs/tree/replace-a-core-template.doc.mjs +10 -12
- package/assets/docs/tree/scaffold.doc.mjs +1 -1
- package/assets/docs/tree/sections-and-placement.doc.mjs +9 -11
- package/assets/docs/tree/see-it-in-an-app.doc.mjs +17 -5
- package/assets/docs/tree/ship.doc.mjs +2 -2
- package/assets/docs/tree/short-and-findable.doc.mjs +9 -8
- package/assets/docs/tree/single-component.doc.mjs +15 -6
- package/assets/docs/tree/start-a-template.doc.mjs +18 -8
- package/assets/docs/tree/subcomponent.doc.mjs +6 -6
- package/assets/docs/tree/template-assets.doc.mjs +2 -2
- package/assets/docs/tree/template-doc-overview.doc.mjs +6 -17
- package/assets/docs/tree/template-fonts.doc.mjs +1 -1
- package/assets/docs/tree/template-grading-rubric.doc.mjs +17 -38
- package/assets/docs/tree/template-icons.doc.mjs +1 -1
- package/assets/docs/tree/template-images-media.doc.mjs +1 -1
- package/assets/docs/tree/template-styles.doc.mjs +2 -2
- package/assets/docs/tree/templates.doc.mjs +7 -1
- package/assets/docs/tree/test-in-an-app.doc.mjs +7 -7
- package/assets/docs/tree/test-template-in-app.doc.mjs +5 -5
- package/assets/docs/tree/themes.doc.mjs +5 -1
- package/assets/docs/tree/tokens-and-setup.doc.mjs +19 -15
- package/assets/docs/tree/tokens-data.doc.mjs +2 -2
- package/assets/docs/tree/troubleshooting.doc.mjs +29 -13
- package/assets/docs/tree/type-scale.doc.mjs +3 -3
- package/assets/docs/tree/uninstall.doc.mjs +109 -0
- package/assets/docs/tree/updates.doc.mjs +92 -0
- package/assets/docs/tree/upgrading.doc.mjs +6 -6
- package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +15 -3
- package/assets/docs/tree/verify-packed-template.doc.mjs +3 -3
- package/assets/docs/tree/versioning.doc.mjs +14 -9
- package/assets/docs/tree/who-answers.doc.mjs +119 -0
- package/assets/docs/tree/write-good-templates.doc.mjs +1 -1
- package/assets/docs/tree/write-the-template-file.doc.mjs +7 -6
- package/assets/docs/use-a-theme.doc.mjs +2 -2
- package/assets/docs/use-integrations.doc.mjs +120 -0
- package/assets/docs/working-with-ai.doc.mjs +70 -13
- package/assets/templates/themes/butter/butterTheme.ts +4 -2
- package/assets/templates/themes/stone/stoneTheme.ts +4 -2
- package/assets/templates/themes/y2k/y2kTheme.ts +4 -2
- package/assets/theme.template.ts +1 -1
- package/authoring/codemod/codemod.doc.mjs +7 -3
- package/authoring/config/config.doc.mjs +9 -6
- package/authoring/config/type.ts +4 -2
- package/authoring/debug/parse.d.mts +5 -5
- package/authoring/discover/discover.doc.mjs +7 -1
- package/authoring/doctypes/_schema.d.mts +8 -3
- package/authoring/doctypes/_schema.mjs +1 -0
- package/authoring/doctypes/base/graph-fields.doc.mjs +6 -4
- package/authoring/doctypes/command/command.doc.mjs +20 -12
- package/authoring/doctypes/command/type.ts +14 -0
- package/authoring/doctypes/component/component.doc.mjs +30 -27
- package/authoring/doctypes/component/type.ts +21 -8
- package/authoring/doctypes/enum/enum.doc.mjs +7 -4
- package/authoring/doctypes/function/function.doc.mjs +9 -8
- package/authoring/doctypes/hook/hook.doc.mjs +5 -4
- package/authoring/doctypes/hook/type.ts +4 -0
- package/authoring/doctypes/namespace/namespace.doc.mjs +7 -6
- package/authoring/doctypes/reference/reference.doc.mjs +12 -11
- package/authoring/doctypes/schema/schema.doc.mjs +10 -10
- package/authoring/doctypes/template/integration-template.doc.d.mts +11 -0
- package/authoring/doctypes/template/integration-template.doc.mjs +49 -0
- package/authoring/doctypes/template/parse.d.mts +6 -2
- package/authoring/doctypes/template/parse.mjs +3 -1
- package/authoring/doctypes/template/template.doc.mjs +3 -3
- package/authoring/doctypes/template/type.ts +22 -0
- package/authoring/doctypes/theme/theme.doc.mjs +2 -2
- package/authoring/gap-report/gap-report.doc.mjs +2 -2
- package/authoring/identity/identity.doc.mjs +3 -3
- package/authoring/index.d.ts +2 -0
- package/authoring/integration/integration.doc.mjs +30 -6
- package/authoring/integration/parse.test.mjs +21 -0
- package/authoring/integration/schema.d.mts +16 -3
- package/authoring/integration/schema.mjs +34 -2
- package/authoring/integration/type.ts +13 -1
- package/clients/cli/bin/astryx.mjs +11 -65
- package/clients/cli/cli-command.test.mjs +166 -0
- package/clients/cli/command-result-coverage.test.mjs +6 -5
- package/clients/cli/commands/blog.doc.mjs +1 -0
- package/clients/cli/commands/build-theme.batch-report.test.mjs +17 -3
- package/clients/cli/commands/build-theme.color-scheme.test.mjs +1 -1
- package/clients/cli/commands/build-theme.font-warning.test.mjs +3 -3
- package/clients/cli/commands/build-theme.path-safety.test.mjs +224 -6
- package/clients/cli/commands/build-theme.registry.test.mjs +5 -2
- package/clients/cli/commands/build.doc.mjs +1 -0
- package/clients/cli/commands/build.exit-codes-doc.test.mjs +4 -0
- package/clients/cli/commands/cli-postinstall.test.mjs +49 -1
- package/clients/cli/commands/component.doc.mjs +1 -0
- package/clients/cli/commands/{component/index.mjs → component.mjs} +37 -37
- package/clients/cli/commands/component.test.mjs +6 -6
- package/clients/cli/commands/discover.broken-integration.test.mjs +11 -7
- package/clients/cli/commands/discover.doc.mjs +9 -1
- package/clients/cli/commands/discover.mjs +144 -93
- package/clients/cli/commands/discover.no-source.test.mjs +448 -33
- package/clients/cli/commands/discover.sources.test.mjs +20 -1
- package/clients/cli/commands/docs.doc.mjs +3 -2
- package/clients/cli/commands/docs.mjs +50 -20
- package/clients/cli/commands/docs.test.mjs +16 -16
- package/clients/cli/commands/doctor-integration-components.doc.mjs +19 -4
- package/clients/cli/commands/doctor-integration-docs.doc.mjs +20 -5
- package/clients/cli/commands/doctor-integration-templates.doc.mjs +1 -0
- package/clients/cli/commands/doctor-integration-validate.doc.mjs +22 -2
- package/clients/cli/commands/doctor-integration.test.mjs +936 -3
- package/clients/cli/commands/doctor.doc.mjs +12 -2
- package/clients/cli/commands/doctor.mjs +332 -7
- package/clients/cli/commands/doctor.test.mjs +75 -4
- package/clients/cli/commands/gap-report.doc.mjs +15 -2
- package/clients/cli/commands/gap-report.mjs +24 -2
- package/clients/cli/commands/gap-report.test.mjs +79 -0
- package/clients/cli/commands/hook.doc.mjs +1 -0
- package/clients/cli/commands/{hook/index.mjs → hook.mjs} +22 -22
- package/clients/cli/commands/import-hint-correctness.test.mjs +1 -1
- package/clients/cli/commands/init.behavior.test.mjs +235 -1
- package/clients/cli/commands/init.doc.mjs +55 -10
- package/clients/cli/commands/init.flag-help.test.mjs +1 -0
- package/clients/cli/commands/init.mjs +2 -2
- package/clients/cli/commands/integration-add.doc.mjs +7 -0
- package/clients/cli/commands/integration-authoring.test.mjs +49 -3
- package/clients/cli/commands/integration-check.doc.mjs +93 -0
- package/clients/cli/commands/integration-check.test.mjs +489 -0
- package/clients/cli/commands/integration-pack.doc.mjs +8 -1
- package/clients/cli/commands/integration-verify.doc.mjs +8 -1
- package/clients/cli/commands/integration.doc.mjs +6 -2
- package/clients/cli/commands/integration.mjs +119 -7
- package/clients/cli/commands/json-contract.test.mjs +11 -2
- package/clients/cli/commands/manifest.doc.mjs +2 -1
- package/clients/cli/commands/manifest.mjs +67 -0
- package/clients/cli/commands/outside-project.test.mjs +874 -0
- package/clients/cli/commands/postinstall.doc.mjs +23 -0
- package/clients/cli/commands/postinstall.mjs +31 -0
- package/clients/cli/commands/search.doc.mjs +1 -0
- package/clients/cli/commands/search.mjs +16 -11
- package/clients/cli/commands/search.test.mjs +429 -296
- package/clients/cli/commands/setup-nudge.test.mjs +180 -2
- package/clients/cli/commands/swizzle.doc.mjs +7 -0
- package/clients/cli/commands/swizzle.mjs +5 -3
- package/clients/cli/commands/swizzle.routing.test.mjs +19 -2
- package/clients/cli/commands/template.doc.mjs +1 -0
- package/clients/cli/commands/text-json-parity.test.mjs +5 -0
- package/clients/cli/commands/theme-add-lifecycle.test.mjs +3 -3
- package/clients/cli/commands/theme-add.doc.mjs +8 -1
- package/clients/cli/commands/theme-build.doc.mjs +3 -2
- package/clients/cli/commands/theme-eject.doc.mjs +1 -0
- package/clients/cli/commands/theme-list.behavior.test.mjs +6 -0
- package/clients/cli/commands/theme-list.doc.mjs +1 -0
- package/clients/cli/commands/theme-palette-generate.doc.mjs +1 -0
- package/clients/cli/commands/theme-remove.doc.mjs +7 -0
- package/clients/cli/commands/theme-targets.doc.mjs +1 -0
- package/clients/cli/commands/theme-template.doc.mjs +1 -0
- package/clients/cli/commands/theme-use.doc.mjs +7 -0
- package/clients/cli/commands/{build-theme.mjs → theme.mjs} +27 -14
- package/clients/cli/commands/upgrade.config-ordering.test.mjs +2 -1
- package/clients/cli/commands/upgrade.doc.mjs +26 -3
- package/clients/cli/commands/upgrade.file-protection.test.mjs +3 -2
- package/clients/cli/commands/upgrade.hook-output.test.mjs +2 -1
- package/clients/cli/commands/upgrade.mjs +9 -2
- package/clients/cli/commands/upgrade.older-cli.test.mjs +160 -0
- package/clients/cli/commands/upgrade.subfolder-path.test.mjs +97 -0
- package/clients/cli/index.mjs +156 -100
- package/clients/cli/lib/cli-error.mjs +4 -1
- package/clients/cli/lib/component-format.mjs +1 -1
- package/clients/cli/lib/component-format.test.mjs +1 -1
- package/clients/cli/lib/define-command.mjs +14 -9
- package/clients/cli/lib/exit-codes.test.mjs +5 -0
- package/clients/cli/lib/json-shim.mjs +3 -1
- package/clients/cli/lib/manifest.d.ts +9 -0
- package/clients/cli/lib/manifest.mjs +17 -1
- package/clients/cli/lib/manifest.test.mjs +37 -0
- package/clients/cli/lib/welcome-box.mjs +50 -0
- package/clients/cli/run.mjs +108 -0
- package/foundation/agent-docs/agent-doc-state.d.mts +67 -13
- package/foundation/agent-docs/agent-doc-state.mjs +123 -14
- package/foundation/agent-docs/agent-docs.d.mts +104 -15
- package/foundation/agent-docs/agent-docs.mjs +1028 -114
- package/foundation/agent-docs/agent-docs.path-safety.test.mjs +1239 -17
- package/foundation/agent-docs/agent-docs.test.mjs +683 -39
- package/foundation/agent-docs/computer-agent-text.d.mts +170 -0
- package/foundation/agent-docs/computer-agent-text.mjs +750 -0
- package/foundation/agent-docs/computer-agent-text.test.mjs +699 -0
- package/foundation/config/project.d.mts +35 -3
- package/foundation/config/project.mjs +243 -26
- package/foundation/config/project.test.mjs +122 -0
- package/foundation/config/theme-state.mjs +5 -4
- package/foundation/discovery/authoring-self-docs.d.mts +7 -0
- package/foundation/discovery/authoring-self-docs.mjs +17 -4
- package/foundation/discovery/authoring-self-docs.test.mjs +15 -3
- package/foundation/discovery/authoring-surface.d.mts +1 -1
- package/foundation/discovery/authoring-surface.mjs +2 -2
- package/foundation/discovery/authoring-surface.test.mjs +1 -1
- package/foundation/discovery/cli-self-docs.d.mts +2 -1
- package/foundation/discovery/cli-self-docs.mjs +22 -4
- package/foundation/discovery/cli-self-docs.test.mjs +3 -2
- package/foundation/discovery/component-discovery.d.mts +227 -10
- package/foundation/discovery/component-discovery.export-names.test.mjs +760 -0
- package/foundation/discovery/component-discovery.mjs +940 -57
- package/foundation/discovery/component-discovery.test.mjs +96 -0
- package/foundation/discovery/component-loader.d.mts +1 -1
- package/foundation/discovery/component-replacement.mjs +20 -1
- package/foundation/discovery/component-replacement.test.mjs +40 -0
- package/foundation/discovery/copied-passages.d.mts +216 -0
- package/foundation/discovery/copied-passages.mjs +720 -0
- package/foundation/discovery/copied-passages.test.mjs +124 -0
- package/foundation/discovery/doc-consistency.d.mts +34 -0
- package/foundation/discovery/doc-consistency.mjs +513 -0
- package/foundation/discovery/doc-consistency.test.mjs +347 -0
- package/foundation/discovery/doc-fluff.d.mts +112 -0
- package/foundation/discovery/doc-fluff.mjs +328 -0
- package/foundation/discovery/doc-fluff.test.mjs +142 -0
- package/foundation/discovery/doc-types.d.mts +157 -0
- package/foundation/discovery/doc-types.mjs +1231 -0
- package/foundation/discovery/doc-types.test.mjs +744 -0
- package/foundation/discovery/docs-discovery.d.mts +88 -0
- package/foundation/discovery/docs-discovery.mjs +97 -3
- package/foundation/discovery/integration-doc-files.d.mts +22 -0
- package/foundation/discovery/integration-doc-files.mjs +231 -0
- package/foundation/discovery/integration-doc-files.test.mjs +246 -0
- package/foundation/discovery/module-exports.d.mts +68 -0
- package/foundation/discovery/module-exports.mjs +609 -31
- package/foundation/discovery/module-exports.test.mjs +172 -0
- package/foundation/discovery/package-tsconfig.d.mts +14 -0
- package/foundation/discovery/package-tsconfig.mjs +228 -0
- package/foundation/discovery/package-tsconfig.test.mjs +210 -0
- package/foundation/discovery/project-typescript.d.mts +32 -0
- package/foundation/discovery/project-typescript.mjs +89 -0
- package/foundation/discovery/prop-drift.d.mts +297 -0
- package/foundation/discovery/prop-drift.mjs +2428 -0
- package/foundation/discovery/prop-drift.test.mjs +2337 -0
- package/foundation/discovery/runner-allowlist.d.mts +38 -0
- package/foundation/discovery/runner-allowlist.mjs +51 -0
- package/foundation/discovery/runner-commands.d.mts +77 -0
- package/foundation/discovery/runner-commands.mjs +294 -0
- package/foundation/discovery/runner-commands.test.mjs +128 -0
- package/foundation/discovery/stray-pointers.d.mts +52 -0
- package/foundation/discovery/stray-pointers.mjs +293 -0
- package/foundation/discovery/stray-pointers.test.mjs +86 -0
- package/foundation/discovery/template-adapter.mjs +92 -6
- package/foundation/discovery/template-needs.mjs +6 -46
- package/foundation/discovery/theme-discovery.mjs +147 -3
- package/foundation/discovery/theme-imports.mjs +8 -4
- package/foundation/discovery/theme-imports.test.mjs +1 -1
- package/foundation/discovery/type-match.d.mts +53 -0
- package/foundation/discovery/type-match.mjs +660 -0
- package/foundation/discovery/type-match.test.mjs +169 -0
- package/foundation/discovery/type-text.d.mts +68 -0
- package/foundation/discovery/type-text.mjs +658 -0
- package/foundation/discovery/type-text.test.mjs +196 -0
- package/foundation/discovery/unresolved-references.d.mts +62 -0
- package/foundation/discovery/unresolved-references.mjs +790 -0
- package/foundation/discovery/unresolved-references.test.mjs +567 -0
- package/foundation/doc-compiler/doc-loads.test.mjs +84 -10
- package/foundation/doc-compiler/inputs.mjs +27 -1
- package/foundation/doc-compiler/inputs.test.mjs +0 -1
- package/foundation/doc-compiler/links.d.mts +41 -5
- package/foundation/doc-compiler/links.mjs +167 -28
- package/foundation/doc-compiler/links.test.mjs +97 -4
- package/foundation/doc-compiler/read.d.mts +1 -1
- package/foundation/doc-compiler/read.mjs +59 -1
- package/foundation/doc-compiler/read.test.mjs +11 -2
- package/foundation/doc-compiler/split-topic-keywords.test.mjs +3 -2
- package/foundation/doc-compiler/tree.d.mts +32 -6
- package/foundation/doc-compiler/tree.mjs +107 -44
- package/foundation/doc-compiler/tree.test.mjs +14 -7
- package/foundation/env/cli-command.d.mts +83 -0
- package/foundation/env/cli-command.mjs +152 -0
- package/foundation/env/cli-command.test.mjs +129 -0
- package/foundation/env/node-version.test.mjs +15 -3
- package/foundation/env/package-manager.d.mts +93 -9
- package/foundation/env/package-manager.global.test.mjs +66 -0
- package/foundation/env/package-manager.mjs +184 -13
- package/foundation/env/package-manager.test.mjs +341 -15
- package/foundation/env/project-scope.d.mts +9 -0
- package/foundation/env/project-scope.mjs +33 -0
- package/foundation/env/search-path.d.mts +42 -0
- package/foundation/env/search-path.mjs +205 -0
- package/foundation/env/search-path.test.mjs +122 -0
- package/foundation/env/user-dirs.d.mts +39 -0
- package/foundation/env/user-dirs.mjs +93 -0
- package/foundation/env/user-dirs.test.mjs +72 -0
- package/foundation/env/user-settings.d.mts +46 -0
- package/foundation/env/user-settings.mjs +106 -0
- package/foundation/env/user-settings.test.mjs +64 -0
- package/foundation/fs/file-protection.mjs +15 -1
- package/foundation/fs/module-loader.d.mts +2 -1
- package/foundation/fs/module-loader.mjs +60 -4
- package/foundation/fs/module-loader.stdout.test.mjs +3 -2
- package/foundation/fs/module-loader.test.mjs +194 -0
- package/foundation/fs/path-compare.d.mts +33 -0
- package/foundation/fs/path-compare.mjs +73 -0
- package/foundation/fs/paths.d.mts +122 -4
- package/foundation/fs/paths.mjs +675 -29
- package/foundation/fs/paths.test.mjs +439 -54
- package/foundation/fs/read-record.d.mts +18 -0
- package/foundation/fs/read-record.mjs +131 -0
- package/foundation/fs/read-record.test.mjs +77 -0
- package/foundation/integrations/autolink.d.mts +2 -1
- package/foundation/integrations/autolink.mjs +4 -13
- package/foundation/integrations/cli-peer-version.d.mts +36 -0
- package/foundation/integrations/cli-peer-version.mjs +132 -0
- package/foundation/integrations/cli-peer-version.test.mjs +354 -0
- package/foundation/integrations/computer-integrations.d.mts +81 -0
- package/foundation/integrations/computer-integrations.mjs +345 -0
- package/foundation/integrations/computer-integrations.test.mjs +292 -0
- package/foundation/integrations/contribution-inventory.d.mts +26 -20
- package/foundation/integrations/contribution-inventory.mjs +97 -8
- package/foundation/integrations/exports-subpaths.d.mts +57 -0
- package/foundation/integrations/exports-subpaths.mjs +113 -0
- package/foundation/integrations/integration-warnings.mjs +3 -2
- package/foundation/integrations/integration-warnings.test.mjs +8 -9
- package/foundation/integrations/integrations.d.mts +51 -1
- package/foundation/integrations/integrations.mjs +106 -4
- package/foundation/integrations/issue.ts +6 -0
- package/foundation/integrations/public-imports.d.mts +118 -0
- package/foundation/integrations/public-imports.mjs +1769 -0
- package/foundation/integrations/public-imports.test.mjs +1793 -0
- package/foundation/integrations/validate-contributions.d.mts +117 -0
- package/foundation/integrations/validate-contributions.mjs +1209 -14
- package/foundation/release/agent-text-worker.d.mts +4 -0
- package/foundation/release/agent-text-worker.mjs +52 -0
- package/foundation/release/cache.d.mts +310 -0
- package/foundation/release/cache.mjs +1216 -0
- package/foundation/release/cache.test.mjs +923 -0
- package/foundation/release/choose.d.mts +207 -0
- package/foundation/release/choose.mjs +677 -0
- package/foundation/release/choose.test.mjs +427 -0
- package/foundation/release/core-worker.d.mts +4 -0
- package/foundation/release/core-worker.mjs +38 -0
- package/foundation/release/global-state.d.mts +263 -0
- package/foundation/release/global-state.mjs +474 -0
- package/foundation/release/global-state.test.mjs +381 -0
- package/foundation/release/handoff.d.mts +79 -0
- package/foundation/release/handoff.e2e.test.mjs +278 -0
- package/foundation/release/handoff.mjs +524 -0
- package/foundation/release/lock-lease.d.mts +23 -0
- package/foundation/release/lock-lease.mjs +80 -0
- package/foundation/release/notices.d.mts +307 -0
- package/foundation/release/notices.mjs +707 -0
- package/foundation/release/notices.test.mjs +586 -0
- package/foundation/release/npm-guard.d.mts +4 -0
- package/foundation/release/npm-guard.mjs +126 -0
- package/foundation/release/project.d.mts +141 -0
- package/foundation/release/project.mjs +466 -0
- package/foundation/release/project.test.mjs +288 -0
- package/foundation/release/refresh-worker.d.mts +4 -0
- package/foundation/release/refresh-worker.mjs +27 -0
- package/foundation/release/run-context.d.mts +47 -0
- package/foundation/release/run-context.mjs +163 -0
- package/foundation/release/update-notice-env.d.mts +28 -0
- package/foundation/release/update-notice-env.mjs +39 -0
- package/foundation/response/base.d.ts +26 -3
- package/foundation/response/error-codes.d.mts +3 -1
- package/foundation/response/error-codes.doc.mjs +12 -0
- package/foundation/response/error-codes.mjs +17 -0
- package/foundation/response/error-codes.test.mjs +2 -0
- package/foundation/response/json-contract.test.mjs +7 -2
- package/foundation/response/json.mjs +4 -1
- package/foundation/response/response-types.doc.mjs +22 -11
- package/foundation/response/response-types.doc.test.mjs +46 -0
- package/foundation/response/response.doc.mjs +3 -3
- package/foundation/route/route.d.mts +285 -0
- package/foundation/route/route.mjs +324 -0
- package/foundation/route/route.test.mjs +153 -0
- package/foundation/runtime/hosted-runtime.test.mjs +403 -0
- package/foundation/runtime/locked-versions.d.mts +32 -0
- package/foundation/runtime/locked-versions.mjs +65 -0
- package/foundation/runtime/package-root.d.mts +91 -0
- package/foundation/runtime/package-root.mjs +174 -0
- package/foundation/runtime/package-set.d.mts +62 -0
- package/foundation/runtime/package-set.mjs +130 -0
- package/foundation/runtime/package-set.test.mjs +432 -0
- package/foundation/text/string-utils.d.mts +2 -1
- package/foundation/text/string-utils.mjs +16 -5
- package/foundation/text/suggest-order.d.mts +72 -0
- package/foundation/text/suggest-order.mjs +363 -0
- package/foundation/text/suggest-order.test.mjs +259 -0
- package/foundation/xle/browser-imports.test.mjs +74 -0
- package/foundation/xle/registry.mjs +4 -0
- package/foundation/xle/registry.test.mjs +28 -0
- package/host/door-conformance.test.mjs +274 -0
- package/host/index.d.ts +116 -0
- package/host/index.mjs +295 -0
- package/host/index.test.mjs +302 -0
- package/package.json +16 -11
- package/scripts/postinstall.mjs +24 -5
- package/assets/docs/tree/integrations.doc.mjs +0 -40
|
@@ -1,12 +1,124 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
import {describe, it, expect, beforeEach, afterEach, vi} from 'vitest';
|
|
3
|
-
import * as fs from 'node:fs'; import * as path from 'node:path';
|
|
3
|
+
import * as fs from 'node:fs'; import * as path from 'node:path'; import * as os from 'node:os';
|
|
4
4
|
import {init} from '../init.mjs'; import {remove} from './remove.mjs'; import {logger} from '../../logger.mjs';
|
|
5
5
|
let dir;
|
|
6
|
-
beforeEach(() => { dir = fs.mkdtempSync(path.join(
|
|
6
|
+
beforeEach(() => { dir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-rm-')); fs.writeFileSync(path.join(dir,'package.json'),JSON.stringify({name:'c',version:'1.0.0'})); });
|
|
7
7
|
afterEach(() => { fs.rmSync(dir,{recursive:true,force:true}); logger.setSilent(true); });
|
|
8
8
|
describe('init.remove says whether anything was removed', () => {
|
|
9
9
|
it('false on clean', async () => { const r=await remove({cwd:dir}); expect(r.type).toBe('init.remove'); expect(r.data.removed).toBe(false); });
|
|
10
10
|
it('true then false', async () => { await init({features:['agents']},{cwd:dir}); expect(fs.readFileSync(path.join(dir,'AGENTS.md'),'utf8')).toContain('<!-- ASTRYX:START -->'); const a=await remove({cwd:dir}); expect(a.data.removed).toBe(true); const b=await remove({cwd:dir}); expect(b.data.removed).toBe(false); });
|
|
11
11
|
it('human line', async () => { const l=[]; const s=vi.spyOn(console,'log').mockImplementation((...a)=>l.push(a.join(' '))); logger.setSilent(false); try{await remove({cwd:dir});}finally{logger.setSilent(true);s.mockRestore();} expect(l.join('\n')).toContain('Nothing to remove'); });
|
|
12
12
|
});
|
|
13
|
+
|
|
14
|
+
describe('init.remove acts where init writes, the project root, and in the folder it runs in', () => {
|
|
15
|
+
/** @type {string} */
|
|
16
|
+
let project;
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
project = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-rm-root-'));
|
|
19
|
+
fs.writeFileSync(
|
|
20
|
+
path.join(project, 'package.json'),
|
|
21
|
+
JSON.stringify({name: 'app', dependencies: {'@astryxdesign/core': '1.0.0'}}),
|
|
22
|
+
);
|
|
23
|
+
fs.mkdirSync(path.join(project, 'src', 'app'), {recursive: true});
|
|
24
|
+
});
|
|
25
|
+
afterEach(() => { fs.rmSync(project, {recursive: true, force: true}); });
|
|
26
|
+
const block = '<!-- ASTRYX:START -->\nAstryx v0.7.0 · old\n<!-- ASTRYX:END -->\n';
|
|
27
|
+
|
|
28
|
+
it('removes from a subfolder what init wrote at the project root', async () => {
|
|
29
|
+
const sub = path.join(project, 'src', 'app');
|
|
30
|
+
const written = await init({features: ['agents']}, {cwd: sub});
|
|
31
|
+
expect(written.data.docsWritten).toEqual(['../../AGENTS.md', '../../GEMINI.md']);
|
|
32
|
+
|
|
33
|
+
const r = await remove({cwd: sub});
|
|
34
|
+
expect(r).toEqual({type: 'init.remove', data: {removed: true}});
|
|
35
|
+
// Both files held only what init wrote, so they are deleted.
|
|
36
|
+
expect(fs.existsSync(path.join(project, 'AGENTS.md'))).toBe(false);
|
|
37
|
+
expect(fs.existsSync(path.join(project, 'GEMINI.md'))).toBe(false);
|
|
38
|
+
expect((await remove({cwd: sub})).data.removed).toBe(false);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('removes a block an earlier version left in the subfolder, and keeps the files\' own text', async () => {
|
|
42
|
+
const sub = path.join(project, 'src', 'app');
|
|
43
|
+
fs.writeFileSync(path.join(project, 'AGENTS.md'), `# Agents\n\nRoot rules.\n\n${block}`);
|
|
44
|
+
fs.writeFileSync(path.join(sub, 'AGENTS.md'), `# App\n\nApp rules.\n\n${block}`);
|
|
45
|
+
|
|
46
|
+
expect((await remove({cwd: sub})).data.removed).toBe(true);
|
|
47
|
+
expect(fs.readFileSync(path.join(project, 'AGENTS.md'), 'utf8').trimEnd()).toBe('# Agents\n\nRoot rules.');
|
|
48
|
+
expect(fs.readFileSync(path.join(sub, 'AGENTS.md'), 'utf8').trimEnd()).toBe('# App\n\nApp rules.');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('run at the project root, leaves a subfolder alone', async () => {
|
|
52
|
+
const sub = path.join(project, 'src', 'app');
|
|
53
|
+
fs.writeFileSync(path.join(project, 'AGENTS.md'), `# Agents\n\n${block}`);
|
|
54
|
+
fs.writeFileSync(path.join(sub, 'AGENTS.md'), `# App\n\n${block}`);
|
|
55
|
+
|
|
56
|
+
expect((await remove({cwd: project})).data.removed).toBe(true);
|
|
57
|
+
expect(fs.readFileSync(path.join(sub, 'AGENTS.md'), 'utf8')).toContain('<!-- ASTRYX:START -->');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('below the root, leaves a root agent file linked outside the project with a note, and removes the rest (0.7.x exited 0)', async () => {
|
|
61
|
+
// A workspace member whose CLAUDE.md links to the monorepo's.
|
|
62
|
+
const monorepo = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-rm-mono-'));
|
|
63
|
+
try {
|
|
64
|
+
const web = path.join(monorepo, 'apps', 'web');
|
|
65
|
+
const sub = path.join(web, 'src');
|
|
66
|
+
fs.mkdirSync(sub, {recursive: true});
|
|
67
|
+
fs.writeFileSync(
|
|
68
|
+
path.join(web, 'package.json'),
|
|
69
|
+
JSON.stringify({name: 'web', dependencies: {'@astryxdesign/core': '1.0.0'}}),
|
|
70
|
+
);
|
|
71
|
+
fs.writeFileSync(path.join(monorepo, 'CLAUDE.md'), `# Shared\n\n${block}`);
|
|
72
|
+
fs.symlinkSync('../../CLAUDE.md', path.join(web, 'CLAUDE.md'));
|
|
73
|
+
fs.writeFileSync(path.join(web, 'AGENTS.md'), `# Web\n\n${block}`);
|
|
74
|
+
fs.writeFileSync(path.join(sub, 'AGENTS.md'), `# Src\n\n${block}`);
|
|
75
|
+
const warned = [];
|
|
76
|
+
const warn = vi.spyOn(console, 'error').mockImplementation((...a) => warned.push(a.join(' ')));
|
|
77
|
+
logger.setSilent(false);
|
|
78
|
+
let r;
|
|
79
|
+
try {
|
|
80
|
+
r = await remove({cwd: sub});
|
|
81
|
+
} finally {
|
|
82
|
+
logger.setSilent(true);
|
|
83
|
+
warn.mockRestore();
|
|
84
|
+
}
|
|
85
|
+
expect(r).toEqual({type: 'init.remove', data: {removed: true}});
|
|
86
|
+
expect(fs.readFileSync(path.join(web, 'AGENTS.md'), 'utf8').trimEnd()).toBe('# Web');
|
|
87
|
+
expect(fs.readFileSync(path.join(sub, 'AGENTS.md'), 'utf8').trimEnd()).toBe('# Src');
|
|
88
|
+
// The file outside the project keeps its block.
|
|
89
|
+
expect(fs.readFileSync(path.join(monorepo, 'CLAUDE.md'), 'utf8')).toContain('<!-- ASTRYX:START -->');
|
|
90
|
+
expect(warned.join('\n')).toMatch(/Note: Left as it is: \.\.\/CLAUDE\.md \(/u);
|
|
91
|
+
} finally {
|
|
92
|
+
fs.rmSync(monorepo, {recursive: true, force: true});
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('at the root, a root agent file linked outside the project still refuses the run', async () => {
|
|
97
|
+
const outside = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-rm-outside-'));
|
|
98
|
+
try {
|
|
99
|
+
fs.writeFileSync(path.join(outside, 'CLAUDE.md'), `# Shared\n\n${block}`);
|
|
100
|
+
fs.symlinkSync(path.join(outside, 'CLAUDE.md'), path.join(project, 'CLAUDE.md'));
|
|
101
|
+
fs.writeFileSync(path.join(project, 'AGENTS.md'), `# Agents\n\n${block}`);
|
|
102
|
+
await expect(remove({cwd: project})).rejects.toMatchObject({code: 'ERR_PATH_TRAVERSAL'});
|
|
103
|
+
expect(fs.readFileSync(path.join(project, 'AGENTS.md'), 'utf8')).toContain('<!-- ASTRYX:START -->');
|
|
104
|
+
} finally {
|
|
105
|
+
fs.rmSync(outside, {recursive: true, force: true});
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('a link in the subfolder that escapes it refuses the run before anything is written', async () => {
|
|
110
|
+
const sub = path.join(project, 'src', 'app');
|
|
111
|
+
const outside = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-rm-outside-'));
|
|
112
|
+
try {
|
|
113
|
+
fs.writeFileSync(path.join(project, 'AGENTS.md'), `# Agents\n\n${block}`);
|
|
114
|
+
fs.writeFileSync(path.join(outside, 'CLAUDE.md'), `# Shared\n\n${block}`);
|
|
115
|
+
fs.symlinkSync(path.join(outside, 'CLAUDE.md'), path.join(sub, 'CLAUDE.md'));
|
|
116
|
+
|
|
117
|
+
await expect(remove({cwd: sub})).rejects.toMatchObject({code: 'ERR_PATH_TRAVERSAL'});
|
|
118
|
+
expect(fs.readFileSync(path.join(project, 'AGENTS.md'), 'utf8')).toContain('<!-- ASTRYX:START -->');
|
|
119
|
+
expect(fs.readFileSync(path.join(outside, 'CLAUDE.md'), 'utf8')).toContain('<!-- ASTRYX:START -->');
|
|
120
|
+
} finally {
|
|
121
|
+
fs.rmSync(outside, {recursive: true, force: true});
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
});
|
package/api/init/run/run.d.mts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* installed built themes and imports their production and font stylesheets. The
|
|
9
9
|
* app imports that module once and passes its default to <Theme>.
|
|
10
10
|
*
|
|
11
|
-
* @param {string} invocation install-aware CLI invocation stem (e.g. `
|
|
11
|
+
* @param {string} invocation install-aware CLI invocation stem (e.g. `pnpm exec astryx`, `yarn astryx`, or `npx @astryxdesign/cli` for one-off runs)
|
|
12
12
|
* @returns {string[]} ordered list of human-facing lines
|
|
13
13
|
*/
|
|
14
14
|
export function getNextSteps(invocation: string): string[];
|
package/api/init/run/run.mjs
CHANGED
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
* @file init.run leaf — non-interactive project setup + feature installer.
|
|
5
5
|
*
|
|
6
6
|
* `run(options, ctx)` is the default / `--features` / `--all` path behind
|
|
7
|
-
* `astryx init`. It installs the
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* `astryx init`. It installs the agent-docs cheat sheet at the project root so
|
|
8
|
+
* every agent reads it (AGENTS.md, a copy in the project's Claude Code file, and
|
|
9
|
+
* a GEMINI.md import), points at the theme + page-building workflows, and
|
|
10
|
+
* (optionally) scaffolds a starter template — with NO prompts, so it behaves
|
|
11
|
+
* identically for humans, agents, CI, and piped I/O. It performs the side
|
|
12
|
+
* effects and returns an
|
|
11
13
|
* `init.run` receipt. Hard errors (unknown feature/template) throw AstryxError
|
|
12
14
|
* with a stable code. Human output is emitted through the shared `logger`
|
|
13
15
|
* (silent by default) so the CLI keeps its exact plain output and a
|
|
@@ -19,9 +21,13 @@ import * as fs from 'node:fs';
|
|
|
19
21
|
import {CLI_ROOT} from '../../../foundation/fs/paths.mjs';
|
|
20
22
|
import {PathSafetyError, assertWithin} from '../../../foundation/fs/path-safety.mjs';
|
|
21
23
|
import {getCliInvocation} from '../../../foundation/env/package-manager.mjs';
|
|
24
|
+
import {isOutsideProject} from '../../../foundation/env/project-scope.mjs';
|
|
22
25
|
import {
|
|
26
|
+
AgentDocsHomeError,
|
|
27
|
+
assertAgentDocsTarget,
|
|
23
28
|
installAgentDocs,
|
|
24
29
|
renderAgentDocsBlock,
|
|
30
|
+
agentDocsTargetDir,
|
|
25
31
|
} from '../../../foundation/agent-docs/agent-docs.mjs';
|
|
26
32
|
import {themeTemplate} from '../../theme/template/template.mjs';
|
|
27
33
|
import {listTemplates} from '../../template/template.mjs';
|
|
@@ -39,7 +45,7 @@ const VALID_AGENTS = ['claude', 'cursor', 'codex', 'hermes', 'muse', 'all'];
|
|
|
39
45
|
* installed built themes and imports their production and font stylesheets. The
|
|
40
46
|
* app imports that module once and passes its default to <Theme>.
|
|
41
47
|
*
|
|
42
|
-
* @param {string} invocation install-aware CLI invocation stem (e.g. `
|
|
48
|
+
* @param {string} invocation install-aware CLI invocation stem (e.g. `pnpm exec astryx`, `yarn astryx`, or `npx @astryxdesign/cli` for one-off runs)
|
|
43
49
|
* @returns {string[]} ordered list of human-facing lines
|
|
44
50
|
*/
|
|
45
51
|
export function getNextSteps(invocation) {
|
|
@@ -50,11 +56,11 @@ export function getNextSteps(invocation) {
|
|
|
50
56
|
` (run \`${invocation} doctor\` to verify)`,
|
|
51
57
|
" 2. Import base styles: import '@astryxdesign/core/reset.css'",
|
|
52
58
|
" and import '@astryxdesign/core/astryx.css'",
|
|
53
|
-
" 3. Import components: import { Button } from '@astryxdesign/core'",
|
|
59
|
+
" 3. Import components: import { Button } from '@astryxdesign/core/Button'",
|
|
54
60
|
' 4. Add and wire a theme:',
|
|
55
61
|
' npm install @astryxdesign/theme-neutral',
|
|
56
62
|
` ${invocation} theme add neutral`,
|
|
57
|
-
" import { Theme } from '@astryxdesign/core'",
|
|
63
|
+
" import { Theme } from '@astryxdesign/core/theme'",
|
|
58
64
|
" import { themes, defaultThemeSlug } from './astryx-themes'",
|
|
59
65
|
' <Theme theme={themes[defaultThemeSlug]}>...</Theme>',
|
|
60
66
|
` Extend an imported theme to customize it. Run \`${invocation} theme eject <slug>\` only to fork source.`,
|
|
@@ -63,6 +69,24 @@ export function getNextSteps(invocation) {
|
|
|
63
69
|
];
|
|
64
70
|
}
|
|
65
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Whether two paths name one folder, links resolved.
|
|
74
|
+
* @param {string} a
|
|
75
|
+
* @param {string} b
|
|
76
|
+
* @returns {boolean}
|
|
77
|
+
*/
|
|
78
|
+
function sameFolder(a, b) {
|
|
79
|
+
/** @param {string} p */
|
|
80
|
+
const real = p => {
|
|
81
|
+
try {
|
|
82
|
+
return fs.realpathSync(p);
|
|
83
|
+
} catch {
|
|
84
|
+
return path.resolve(p);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
return real(a) === real(b);
|
|
88
|
+
}
|
|
89
|
+
|
|
66
90
|
/**
|
|
67
91
|
* Install the agent-docs block; records the outcome (or soft error) on `data`.
|
|
68
92
|
* Mirrors the CLI's historical soft-error policy: a PathSafetyError surfaces its
|
|
@@ -91,14 +115,46 @@ async function applyAgents(cwd, options, invocation, data) {
|
|
|
91
115
|
? options.agentDocsPath
|
|
92
116
|
: [options.agentDocsPath]
|
|
93
117
|
: undefined;
|
|
94
|
-
|
|
95
|
-
|
|
118
|
+
// The docs belong at the project root, not in the subfolder init ran in;
|
|
119
|
+
// with no project above, they go where init ran, as before. Explicit
|
|
120
|
+
// --agent-docs-path entries stay relative to where init ran.
|
|
121
|
+
const root = agentDocsTargetDir(cwd);
|
|
122
|
+
const targetDir = paths ? cwd : root;
|
|
123
|
+
// With explicit paths, installAgentDocs checks each file's own folder.
|
|
124
|
+
if (!paths) assertAgentDocsTarget(targetDir);
|
|
125
|
+
const renderedBlock = await renderAgentDocsBlock(root);
|
|
126
|
+
/** @type {string[]} */
|
|
127
|
+
const skipped = [];
|
|
128
|
+
const files = installAgentDocs(targetDir, {
|
|
96
129
|
agent: options.agent,
|
|
97
130
|
paths,
|
|
98
131
|
renderedBlock,
|
|
132
|
+
onSkipped: (rel, reason) => skipped.push(`${rel} (${reason})`),
|
|
133
|
+
// Below the project root, 0.7.1 wrote in the folder init ran in, so a
|
|
134
|
+
// project-root file that escapes the project is skipped and reported,
|
|
135
|
+
// not refused.
|
|
136
|
+
refuseEscapes: sameFolder(targetDir, cwd),
|
|
99
137
|
});
|
|
138
|
+
// Each file is reported from where init ran, as before.
|
|
139
|
+
const written =
|
|
140
|
+
path.resolve(targetDir) === path.resolve(cwd)
|
|
141
|
+
? files
|
|
142
|
+
: files.map(rel =>
|
|
143
|
+
path.relative(cwd, path.join(targetDir, rel)).split(path.sep).join('/'),
|
|
144
|
+
);
|
|
100
145
|
data.docsWritten = written;
|
|
101
146
|
logger.log(`[ok] AI agent docs installed -> ${written.join(', ')}`);
|
|
147
|
+
// A file 0.7.1 did not write (GEMINI.md, or a project-root file when init
|
|
148
|
+
// runs below the root) that resolves outside the project is left as it
|
|
149
|
+
// is, reported in docsError with one note; the exit code stays 0. A file
|
|
150
|
+
// 0.7.1 wrote whose path escapes the project still fails the run (below).
|
|
151
|
+
if (skipped.length > 0) {
|
|
152
|
+
const message =
|
|
153
|
+
`Left as ${skipped.length === 1 ? 'it is' : 'they are'}: ${skipped.join('; ')}. ` +
|
|
154
|
+
'To have init write the Astryx block there, make it a regular file inside the project, or copy the block from AGENTS.md by hand.';
|
|
155
|
+
logger.warn(`Note: ${message}`);
|
|
156
|
+
data.docsError = {kind: 'install-failed', message};
|
|
157
|
+
}
|
|
102
158
|
} catch (err) {
|
|
103
159
|
// PathSafetyError carries a precise, user-actionable message — surface it
|
|
104
160
|
// (and flag exit 1) instead of the generic "could not install" warning so
|
|
@@ -108,6 +164,14 @@ async function applyAgents(cwd, options, invocation, data) {
|
|
|
108
164
|
data.docsError = {kind: 'path-safety', message: err.message};
|
|
109
165
|
return;
|
|
110
166
|
}
|
|
167
|
+
// The home folder, and a settings folder in it outside a project, are
|
|
168
|
+
// refused: nothing is written, the reason is printed as a note, and the
|
|
169
|
+
// exit code stays 0.
|
|
170
|
+
if (err instanceof AgentDocsHomeError) {
|
|
171
|
+
logger.warn(`Note: ${err.message}`);
|
|
172
|
+
data.docsError = {kind: 'install-failed', message: err.message};
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
111
175
|
logger.error(
|
|
112
176
|
`Could not install agent docs. Try again with \`${invocation} init --features agents\`.`,
|
|
113
177
|
);
|
|
@@ -140,8 +204,11 @@ function applyTheme(cwd, invocation, data) {
|
|
|
140
204
|
data.themeTemplate = 'failed';
|
|
141
205
|
logger.error('Could not write the theme template.');
|
|
142
206
|
}
|
|
207
|
+
// Outside a project there is no app to add a theme to (spec AST-081 FR3).
|
|
143
208
|
logger.log(
|
|
144
|
-
|
|
209
|
+
isOutsideProject(cwd)
|
|
210
|
+
? ` Edit the blank template for a new theme, or run \`${invocation} theme eject <slug>\` to start from the source of a built theme (\`${invocation} theme list\` to browse).`
|
|
211
|
+
: ` Edit the blank template for a new theme, or run \`${invocation} theme add <slug>\` to import an installed built theme (\`${invocation} theme list\` to browse). Extend an imported theme for ordinary customization; use \`${invocation} theme eject <slug>\` only to fork source.`,
|
|
145
212
|
);
|
|
146
213
|
}
|
|
147
214
|
|
|
@@ -276,7 +343,10 @@ export async function run(options = {}, {cwd = process.cwd()} = {}) {
|
|
|
276
343
|
}
|
|
277
344
|
|
|
278
345
|
// No flags: TTY-free default — install the AI agent cheat sheet with NO
|
|
279
|
-
// prompts, then print the getting-started guidance.
|
|
346
|
+
// prompts, then print the getting-started guidance. Outside a project the
|
|
347
|
+
// steps would set up a project the folder does not have, so they are left
|
|
348
|
+
// out (spec AST-081 FR3).
|
|
349
|
+
const outside = isOutsideProject(cwd);
|
|
280
350
|
/** @type {import('../init.type.mjs').InitRunData} */
|
|
281
351
|
const data = {
|
|
282
352
|
mode: 'default',
|
|
@@ -288,13 +358,17 @@ export async function run(options = {}, {cwd = process.cwd()} = {}) {
|
|
|
288
358
|
themeTemplatePath: null,
|
|
289
359
|
template: null,
|
|
290
360
|
templatePath: null,
|
|
291
|
-
nextSteps:
|
|
361
|
+
nextSteps: !outside,
|
|
292
362
|
};
|
|
293
363
|
await applyAgents(cwd, options, invocation, data);
|
|
294
364
|
logger.log('');
|
|
295
365
|
logger.log(
|
|
296
366
|
` Tip: \`${invocation} init --all\` also points you to the theme and page-building workflows.`,
|
|
297
367
|
);
|
|
368
|
+
if (outside) {
|
|
369
|
+
logger.log('');
|
|
370
|
+
return {type: 'init.run', data};
|
|
371
|
+
}
|
|
298
372
|
for (const line of getNextSteps(invocation)) logger.log(line);
|
|
299
373
|
return {type: 'init.run', data};
|
|
300
374
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// @generated by scripts/sync-api-types.mjs from the JSDoc in api/**/*.mjs.
|
|
2
|
+
// DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Write or remove the computer-level agent text and return an `init.user`
|
|
6
|
+
* receipt. Progress is emitted through the shared `logger` (silent by
|
|
7
|
+
* default); warnings go to its warn channel.
|
|
8
|
+
*
|
|
9
|
+
* @param {{remove?: boolean}} [options]
|
|
10
|
+
* @returns {Promise<import('../init.type.mjs').InitUserResponse>}
|
|
11
|
+
*/
|
|
12
|
+
export function user({ remove }?: {
|
|
13
|
+
remove?: boolean;
|
|
14
|
+
}): Promise<import("../init.type.mjs").InitUserResponse>;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file init.user leaf — the `--user` path behind `astryx init`.
|
|
5
|
+
*
|
|
6
|
+
* `user(options)` writes, refreshes, or (with `remove`) removes the
|
|
7
|
+
* computer-level agent text: one skill file in the home folder, linked into
|
|
8
|
+
* the skill folders agents read (spec AST-081 FR7, FR8). It records the
|
|
9
|
+
* setting and the links it made in the settings file, so the global copy,
|
|
10
|
+
* which keeps the text current in the background, does the same, or, after
|
|
11
|
+
* `remove`, writes nothing. The adapter does every file access. It works in any
|
|
12
|
+
* folder and never touches a project's agent docs. A file without the Astryx
|
|
13
|
+
* markers, one a person edited, or a symlinked one is kept as it is. When no
|
|
14
|
+
* `astryx` on the computer's search path runs the Astryx CLI, the text is
|
|
15
|
+
* still written and the receipt warns that the CLI should be installed for
|
|
16
|
+
* the computer.
|
|
17
|
+
*
|
|
18
|
+
* @input `remove`; the home folder, search path, and settings of
|
|
19
|
+
* the computer
|
|
20
|
+
* @output an `init.user` receipt
|
|
21
|
+
* @position packages/cli/api/init — dispatched by init.mjs
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import {
|
|
25
|
+
COMPUTER_COMMAND,
|
|
26
|
+
COMPUTER_INSTALL_STEP,
|
|
27
|
+
applyComputerAgentText,
|
|
28
|
+
displayHomePath,
|
|
29
|
+
} from '../_adapter.mjs';
|
|
30
|
+
import {logger} from '../../logger.mjs';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {string} file
|
|
34
|
+
* @param {string} home
|
|
35
|
+
* @returns {string}
|
|
36
|
+
*/
|
|
37
|
+
const display = (file, home) => displayHomePath(file, home);
|
|
38
|
+
|
|
39
|
+
/** @type {Record<import('../init.type.mjs').InitUserAction, string>} */
|
|
40
|
+
const ACTION_LINES = {
|
|
41
|
+
written: '[ok] Wrote',
|
|
42
|
+
linked: '[ok] Linked',
|
|
43
|
+
unchanged: '[ok] Already current:',
|
|
44
|
+
removed: '[ok] Removed',
|
|
45
|
+
absent: '[ok] Nothing to remove:',
|
|
46
|
+
kept: '[skip] Kept',
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/** @type {Record<'edited' | 'not-astryx', string>} */
|
|
50
|
+
const KEPT_REASONS = {
|
|
51
|
+
edited: '(edited since Astryx wrote it; delete it to get the current text):',
|
|
52
|
+
'not-astryx': '(not created by Astryx):',
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Write or remove the computer-level agent text and return an `init.user`
|
|
57
|
+
* receipt. Progress is emitted through the shared `logger` (silent by
|
|
58
|
+
* default); warnings go to its warn channel.
|
|
59
|
+
*
|
|
60
|
+
* @param {{remove?: boolean}} [options]
|
|
61
|
+
* @returns {Promise<import('../init.type.mjs').InitUserResponse>}
|
|
62
|
+
*/
|
|
63
|
+
export async function user({remove = false} = {}) {
|
|
64
|
+
const {home, command, files, cliOnSearchPath} = applyComputerAgentText({
|
|
65
|
+
remove,
|
|
66
|
+
});
|
|
67
|
+
/** @type {string[]} */
|
|
68
|
+
const warnings = [];
|
|
69
|
+
// A host's door is its own command; only the plain `astryx` needs a copy of
|
|
70
|
+
// the CLI installed for the computer.
|
|
71
|
+
if (!remove && command === COMPUTER_COMMAND && !cliOnSearchPath) {
|
|
72
|
+
warnings.push(
|
|
73
|
+
`No \`${COMPUTER_COMMAND}\` command on this computer runs the Astryx CLI, so agents cannot run the commands this text names. Install the CLI for the computer: ${COMPUTER_INSTALL_STEP}`,
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
for (const file of files) {
|
|
77
|
+
const reason = file.reason ? ` ${KEPT_REASONS[file.reason]}` : '';
|
|
78
|
+
logger.log(
|
|
79
|
+
`${ACTION_LINES[file.action]}${reason || (file.action === 'kept' ? ':' : '')} ${display(file.path, home)}`,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
for (const warning of warnings) logger.warn(`[warn] ${warning}`);
|
|
83
|
+
return {
|
|
84
|
+
type: 'init.user',
|
|
85
|
+
data: {files, command, warnings},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file `init({user})` and `astryx init --user`: the `init.user` receipt, the
|
|
5
|
+
* install warning, the refused combinations, and that it touches nothing in
|
|
6
|
+
* the folder it runs in. Every test uses a temporary home folder and search
|
|
7
|
+
* path.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import * as fs from 'node:fs';
|
|
11
|
+
import * as os from 'node:os';
|
|
12
|
+
import * as path from 'node:path';
|
|
13
|
+
import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
|
|
14
|
+
import {init} from '../init.mjs';
|
|
15
|
+
import {user} from './user.mjs';
|
|
16
|
+
import {runWithCliDoor} from '../../../foundation/env/cli-command.mjs';
|
|
17
|
+
import {renderComputerAgentText} from '../../../foundation/agent-docs/computer-agent-text.mjs';
|
|
18
|
+
import {runCli} from '../../../test-utils/run-cli.mjs';
|
|
19
|
+
import {settingsFile} from '../../../foundation/env/user-settings.mjs';
|
|
20
|
+
import {readGlobalState} from '../../../foundation/release/global-state.mjs';
|
|
21
|
+
import {cliVersion} from '../../../foundation/release/run-context.mjs';
|
|
22
|
+
|
|
23
|
+
/** @type {string[]} */
|
|
24
|
+
const dirs = [];
|
|
25
|
+
/** @param {string} label */
|
|
26
|
+
function tmp(label) {
|
|
27
|
+
const dir = fs.mkdtempSync(
|
|
28
|
+
path.join(os.tmpdir(), `astryx-init-user-${label}-`),
|
|
29
|
+
);
|
|
30
|
+
dirs.push(dir);
|
|
31
|
+
return dir;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let home = '';
|
|
35
|
+
let emptyPath = '';
|
|
36
|
+
beforeEach(() => {
|
|
37
|
+
home = tmp('home');
|
|
38
|
+
emptyPath = tmp('path');
|
|
39
|
+
vi.stubEnv('HOME', home);
|
|
40
|
+
vi.stubEnv('USERPROFILE', home);
|
|
41
|
+
vi.stubEnv('PATH', emptyPath);
|
|
42
|
+
// The settings file and the cache live under this home folder too.
|
|
43
|
+
vi.stubEnv('XDG_CONFIG_HOME', path.join(home, '.config'));
|
|
44
|
+
vi.stubEnv('XDG_CACHE_HOME', path.join(home, '.cache'));
|
|
45
|
+
vi.stubEnv('APPDATA', path.join(home, 'AppData', 'Roaming'));
|
|
46
|
+
vi.stubEnv('LOCALAPPDATA', path.join(home, 'AppData', 'Local'));
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
/** The settings file under the temporary home folder. */
|
|
50
|
+
const settings = () => {
|
|
51
|
+
try {
|
|
52
|
+
return JSON.parse(fs.readFileSync(settingsFile(), 'utf8'));
|
|
53
|
+
} catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
afterEach(() => {
|
|
58
|
+
vi.unstubAllEnvs();
|
|
59
|
+
while (dirs.length) {
|
|
60
|
+
fs.rmSync(/** @type {string} */ (dirs.pop()), {
|
|
61
|
+
recursive: true,
|
|
62
|
+
force: true,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const FILE = path.join('.agents', 'skills', 'astryx', 'SKILL.md');
|
|
68
|
+
const CLAUDE = path.join('.claude', 'skills', 'astryx');
|
|
69
|
+
|
|
70
|
+
/** Put a linked Astryx CLI first on the search path. */
|
|
71
|
+
function installCliOnPath() {
|
|
72
|
+
const prefix = tmp('prefix');
|
|
73
|
+
const pkg = path.join(prefix, 'lib', 'node_modules', '@astryxdesign', 'cli');
|
|
74
|
+
fs.mkdirSync(pkg, {recursive: true});
|
|
75
|
+
fs.writeFileSync(
|
|
76
|
+
path.join(pkg, 'package.json'),
|
|
77
|
+
'{"name":"@astryxdesign/cli"}',
|
|
78
|
+
);
|
|
79
|
+
fs.writeFileSync(path.join(pkg, 'bin.mjs'), '#!/usr/bin/env node\n');
|
|
80
|
+
fs.chmodSync(path.join(pkg, 'bin.mjs'), 0o755);
|
|
81
|
+
fs.mkdirSync(path.join(prefix, 'bin'));
|
|
82
|
+
fs.symlinkSync(path.join(pkg, 'bin.mjs'), path.join(prefix, 'bin', 'astryx'));
|
|
83
|
+
vi.stubEnv('PATH', path.join(prefix, 'bin'));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
describe('init({user: true})', () => {
|
|
87
|
+
it('writes the file, links Claude Code to it, and returns the init.user receipt, warning when no astryx runs the CLI', async () => {
|
|
88
|
+
const r = await init({user: true}, {cwd: tmp('cwd')});
|
|
89
|
+
expect(r.type).toBe('init.user');
|
|
90
|
+
if (r.type !== 'init.user') return;
|
|
91
|
+
expect(r.data.files).toEqual([
|
|
92
|
+
{path: path.join(home, FILE), action: 'written'},
|
|
93
|
+
{path: path.join(home, CLAUDE), action: 'linked'},
|
|
94
|
+
]);
|
|
95
|
+
expect(r.data.command).toBe('astryx');
|
|
96
|
+
expect(r.data.warnings).toHaveLength(1);
|
|
97
|
+
expect(r.data.warnings[0]).toContain('npm i -g @astryxdesign/cli');
|
|
98
|
+
expect(fs.readFileSync(path.join(home, FILE), 'utf8')).toBe(
|
|
99
|
+
renderComputerAgentText({command: 'astryx'}),
|
|
100
|
+
);
|
|
101
|
+
expect(fs.readFileSync(path.join(home, CLAUDE, 'SKILL.md'), 'utf8')).toBe(
|
|
102
|
+
renderComputerAgentText({command: 'astryx'}),
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it.skipIf(process.platform === 'win32')(
|
|
107
|
+
'does not warn when the astryx on the search path is the Astryx CLI',
|
|
108
|
+
async () => {
|
|
109
|
+
installCliOnPath();
|
|
110
|
+
const r = await user();
|
|
111
|
+
expect(r.data.warnings).toEqual([]);
|
|
112
|
+
},
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
it("names the host's door and does not ask for a global install", async () => {
|
|
116
|
+
const r = await runWithCliDoor('acme astryx', () => user());
|
|
117
|
+
expect(r.data.command).toBe('acme astryx');
|
|
118
|
+
expect(r.data.warnings).toEqual([]);
|
|
119
|
+
expect(fs.readFileSync(path.join(home, FILE), 'utf8')).toContain(
|
|
120
|
+
"`acme astryx search '<what you need>'`",
|
|
121
|
+
);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('works inside a project and writes nothing in it', async () => {
|
|
125
|
+
const dir = tmp('project');
|
|
126
|
+
fs.writeFileSync(
|
|
127
|
+
path.join(dir, 'package.json'),
|
|
128
|
+
'{"name":"app","dependencies":{"@astryxdesign/core":"*"}}',
|
|
129
|
+
);
|
|
130
|
+
const before = fs.readdirSync(dir).sort();
|
|
131
|
+
const r = await init({user: true}, {cwd: dir});
|
|
132
|
+
expect(r.type).toBe('init.user');
|
|
133
|
+
expect(fs.readdirSync(dir).sort()).toEqual(before);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('records the links it made, and the release that wrote the text', async () => {
|
|
137
|
+
await init({user: true});
|
|
138
|
+
expect(settings()).toEqual({
|
|
139
|
+
computerAgentText: {install: true, links: [path.join(home, CLAUDE)]},
|
|
140
|
+
});
|
|
141
|
+
expect(readGlobalState().agentText).toEqual({writtenBy: cliVersion()});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('keeps every other setting when it records the choice', async () => {
|
|
145
|
+
fs.mkdirSync(path.dirname(settingsFile()), {recursive: true});
|
|
146
|
+
fs.writeFileSync(settingsFile(), '{"other": 1}');
|
|
147
|
+
await init({user: true, removeAgents: true});
|
|
148
|
+
expect(settings()).toEqual({
|
|
149
|
+
other: 1,
|
|
150
|
+
computerAgentText: {install: false, links: []},
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('with removeAgents removes the file and the links it made, and records that the text is not wanted', async () => {
|
|
155
|
+
await init({user: true});
|
|
156
|
+
const r = await init({user: true, removeAgents: true});
|
|
157
|
+
expect(r.type).toBe('init.user');
|
|
158
|
+
if (r.type !== 'init.user') return;
|
|
159
|
+
expect(r.data.files).toEqual([
|
|
160
|
+
{path: path.join(home, FILE), action: 'removed'},
|
|
161
|
+
{path: path.join(home, CLAUDE), action: 'removed'},
|
|
162
|
+
]);
|
|
163
|
+
expect(r.data.warnings).toEqual([]);
|
|
164
|
+
expect(fs.existsSync(path.join(home, FILE))).toBe(false);
|
|
165
|
+
expect(fs.existsSync(path.join(home, CLAUDE))).toBe(false);
|
|
166
|
+
expect(settings()).toEqual({
|
|
167
|
+
computerAgentText: {install: false, links: []},
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it.each([
|
|
172
|
+
[{features: 'agents'}, '--features'],
|
|
173
|
+
[{all: true}, '--all'],
|
|
174
|
+
[{agentDocsPath: 'X.md'}, '--agent-docs-path'],
|
|
175
|
+
[{agent: 'claude'}, '--agent'],
|
|
176
|
+
[{removeAgents: true, agent: 'claude'}, '--agent'],
|
|
177
|
+
])(
|
|
178
|
+
'refuses %o with ERR_INVALID_ARGUMENT and writes nothing',
|
|
179
|
+
async (extra, flag) => {
|
|
180
|
+
await expect(init({user: true, ...extra})).rejects.toMatchObject({
|
|
181
|
+
code: 'ERR_INVALID_ARGUMENT',
|
|
182
|
+
message: expect.stringContaining(flag),
|
|
183
|
+
});
|
|
184
|
+
expect(fs.existsSync(path.join(home, '.agents'))).toBe(false);
|
|
185
|
+
expect(fs.existsSync(path.join(home, '.claude'))).toBe(false);
|
|
186
|
+
},
|
|
187
|
+
);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
describe('astryx init --user', () => {
|
|
191
|
+
it('prints the file, the link, and the install warning in text mode', async () => {
|
|
192
|
+
const r = await runCli(['init', '--user'], tmp('cwd'));
|
|
193
|
+
expect(r.status).toBe(0);
|
|
194
|
+
expect(r.stdout).toContain(`Wrote ~${path.sep}${FILE}`);
|
|
195
|
+
expect(r.stdout).toContain(`Linked ~${path.sep}${CLAUDE}`);
|
|
196
|
+
expect(r.stderr).toContain('npm i -g @astryxdesign/cli');
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('emits the init.user envelope under --json', async () => {
|
|
200
|
+
const r = await runCli(['--json', 'init', '--user'], tmp('cwd'));
|
|
201
|
+
expect(r.status).toBe(0);
|
|
202
|
+
const env = JSON.parse(r.stdout);
|
|
203
|
+
expect(env.type).toBe('init.user');
|
|
204
|
+
expect(
|
|
205
|
+
env.data.files.map((/** @type {{action: string}} */ f) => f.action),
|
|
206
|
+
).toEqual(['written', 'linked']);
|
|
207
|
+
expect(env.data.command).toBe('astryx');
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('names a file a person edited as kept, and why', async () => {
|
|
211
|
+
await runCli(['init', '--user'], tmp('cwd'));
|
|
212
|
+
const file = path.join(home, FILE);
|
|
213
|
+
fs.appendFileSync(file, 'my note\n');
|
|
214
|
+
const r = await runCli(['init', '--user'], tmp('cwd'));
|
|
215
|
+
expect(r.status).toBe(0);
|
|
216
|
+
expect(r.stdout).toContain(
|
|
217
|
+
`Kept (edited since Astryx wrote it; delete it to get the current text): ~${path.sep}${FILE}`,
|
|
218
|
+
);
|
|
219
|
+
expect(fs.readFileSync(file, 'utf8')).toMatch(/my note\n$/u);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('exits 1 with ERR_INVALID_ARGUMENT when combined with --all or --agent', async () => {
|
|
223
|
+
for (const extra of [['--all'], ['--agent', 'claude']]) {
|
|
224
|
+
const r = await runCli(
|
|
225
|
+
['--json', 'init', '--user', ...extra],
|
|
226
|
+
tmp('cwd'),
|
|
227
|
+
);
|
|
228
|
+
expect(r.status).toBe(1);
|
|
229
|
+
expect(JSON.parse(r.stdout).code).toBe('ERR_INVALID_ARGUMENT');
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
});
|