@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
|
@@ -0,0 +1,524 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file The first thing every run does: choose the release that answers and,
|
|
5
|
+
* when it is not this copy, hand the run to it (spec AST-081 FR2, FR6, FR9).
|
|
6
|
+
*
|
|
7
|
+
* Runs in the bin right after the Node version gate, before the CLI loads
|
|
8
|
+
* the folder's `astryx.config`, its integrations, or its Core. A hand-off
|
|
9
|
+
* starts the chosen CLI with exactly this run's arguments, working folder, and
|
|
10
|
+
* standard streams, adds nothing to its environment, options, or
|
|
11
|
+
* configuration, and ends this process with that CLI's exit status. The
|
|
12
|
+
* chosen copy makes the same choice and finds itself, so a run is handed off
|
|
13
|
+
* at most once.
|
|
14
|
+
*
|
|
15
|
+
* In text mode a run that a copy other than the project's own CLI answers
|
|
16
|
+
* prints one line on standard error naming the CLI and Core that answered; a
|
|
17
|
+
* run with `--json` prints none and carries `meta.answeredBy` instead. After a
|
|
18
|
+
* successful command, the copy that started the run prints any update notice
|
|
19
|
+
* (notices.mjs); a global copy also starts the daily update check, which
|
|
20
|
+
* installs nothing (global-state.mjs).
|
|
21
|
+
*
|
|
22
|
+
* A programmatic host that found the project's own CLI and did not run it
|
|
23
|
+
* passes the reason (spec AST-081 FR1, FR2). That run is never handed to the
|
|
24
|
+
* project's CLI: this copy answers in its place when it is that CLI's release,
|
|
25
|
+
* saying so in a line of its own; a package set of the host's whose CLI is
|
|
26
|
+
* that release answers through its own host entry; and otherwise this copy
|
|
27
|
+
* answers as for a release that cannot be obtained, with the warning naming
|
|
28
|
+
* the reason.
|
|
29
|
+
*
|
|
30
|
+
* A hosted run installs nothing (architecture:cli-surface INV30): a release
|
|
31
|
+
* other than this copy comes only from the first of the host's package sets
|
|
32
|
+
* that qualifies. When that CLI ships a host entry, the entry runs in this
|
|
33
|
+
* process with the same inputs, discover sources included, and the host's
|
|
34
|
+
* call settles with its result; otherwise its bin takes the run. With no such
|
|
35
|
+
* set, this copy answers, announced.
|
|
36
|
+
*
|
|
37
|
+
* @input the running copy, argv, the working folder, and a host's
|
|
38
|
+
* declined-project-CLI reason
|
|
39
|
+
* @output returns when this copy answers, or with another release's result
|
|
40
|
+
* when its host entry answered; never returns after a hand-off to a bin
|
|
41
|
+
* @position foundation/release — called once per run by clients/cli/run.mjs.
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
import {spawn} from 'node:child_process';
|
|
45
|
+
import {writeSync} from 'node:fs';
|
|
46
|
+
import {
|
|
47
|
+
chooseRelease,
|
|
48
|
+
isComputerLevel,
|
|
49
|
+
isGlobalCopy,
|
|
50
|
+
namesWhoAnswered,
|
|
51
|
+
packageRootOf,
|
|
52
|
+
projectRootOf,
|
|
53
|
+
runningCopy,
|
|
54
|
+
} from './choose.mjs';
|
|
55
|
+
import {readReleaseFacts} from './project.mjs';
|
|
56
|
+
import {ensureRelease, userCacheDir} from './cache.mjs';
|
|
57
|
+
import {
|
|
58
|
+
maybeFetchCore,
|
|
59
|
+
maybeKeepAgentText,
|
|
60
|
+
maybeStartCheck,
|
|
61
|
+
} from './global-state.mjs';
|
|
62
|
+
import {recordRunChoice} from './run-context.mjs';
|
|
63
|
+
import {noticeLines} from './notices.mjs';
|
|
64
|
+
import {cliDoor, runWithCliDoor} from '../env/cli-command.mjs';
|
|
65
|
+
import {hostedRun} from '../runtime/package-root.mjs';
|
|
66
|
+
import {qualifyingRoot} from '../runtime/package-set.mjs';
|
|
67
|
+
|
|
68
|
+
/** Where each release's notes are published. */
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The who-answered line for a run a copy other than the project's own CLI
|
|
72
|
+
* answers.
|
|
73
|
+
* @param {import('./choose.mjs').ReleaseChoice} choice
|
|
74
|
+
* @param {boolean} [computer] the command acts on the computer, not the folder
|
|
75
|
+
* @returns {string}
|
|
76
|
+
*/
|
|
77
|
+
export function whoAnsweredLine(choice, computer = false) {
|
|
78
|
+
const core = choice.coreVersion ?? choice.version;
|
|
79
|
+
if (computer) {
|
|
80
|
+
return `astryx: answered by CLI ${choice.version} with Core ${core}, for this computer`;
|
|
81
|
+
}
|
|
82
|
+
return choice.copy === 'matched'
|
|
83
|
+
? `astryx: answered by CLI ${choice.version} with Core ${core}, the release that matches this project's Core`
|
|
84
|
+
: `astryx: answered by CLI ${choice.version} with Core ${core}, outside a project`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The line for a run this copy answers in place of the project's own CLI,
|
|
89
|
+
* which a host declined, when this copy is that CLI's release (FR2).
|
|
90
|
+
* @param {string} version
|
|
91
|
+
* @param {string} reason the reason, as {@link declinedReasonText} words it
|
|
92
|
+
* @returns {string}
|
|
93
|
+
*/
|
|
94
|
+
export function inPlaceOfProjectLine(version, reason) {
|
|
95
|
+
return `astryx: answered by CLI ${version}, the release of this project's CLI, in its place (${reason})`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The line for a run handed to the project's own CLI.
|
|
100
|
+
* @param {string} projectVersion
|
|
101
|
+
* @param {string} startedIn the version of the copy the run started in
|
|
102
|
+
* @returns {string}
|
|
103
|
+
*/
|
|
104
|
+
export function handedToProjectLine(projectVersion, startedIn) {
|
|
105
|
+
return `astryx: answered by this project's CLI ${projectVersion}, handed over from CLI ${startedIn}`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* One line on standard error while a release installs, so a slow download
|
|
110
|
+
* never looks like a hang. Text mode only.
|
|
111
|
+
* @param {'install' | 'wait'} event
|
|
112
|
+
* @param {string} version
|
|
113
|
+
*/
|
|
114
|
+
export function progressLine(event, version) {
|
|
115
|
+
console.error(progressText(event, version));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* The text of {@link progressLine}.
|
|
120
|
+
* @param {'install' | 'wait'} event
|
|
121
|
+
* @param {string} version
|
|
122
|
+
* @returns {string}
|
|
123
|
+
*/
|
|
124
|
+
export function progressText(event, version) {
|
|
125
|
+
return event === 'install'
|
|
126
|
+
? `astryx: installing CLI release ${version} into the per-user cache (once)...`
|
|
127
|
+
: `astryx: waiting for another run to finish installing CLI release ${version}...`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* The warning a run prints, in text mode, when the release that matches the
|
|
132
|
+
* project's Core cannot be obtained and the copy that answered before global
|
|
133
|
+
* mode answers instead (spec AST-081 FR2).
|
|
134
|
+
* @param {string} wanted the matched release, or the range it was read from
|
|
135
|
+
* @param {string} reason why it cannot be obtained
|
|
136
|
+
* @param {string} answering the version that answers instead
|
|
137
|
+
* @returns {string}
|
|
138
|
+
*/
|
|
139
|
+
export function fallbackLine(wanted, reason, answering) {
|
|
140
|
+
return `astryx: could not get Astryx ${wanted} to match this project's Core (${reason}); answering with CLI ${answering} instead`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Fail the run before any command starts, in the shape every command fails
|
|
145
|
+
* in: the JSON error envelope on stdout with `--json`, else `Error: …` on
|
|
146
|
+
* standard error. Exit status 1.
|
|
147
|
+
* @param {string} message
|
|
148
|
+
* @param {boolean} json
|
|
149
|
+
* @returns {never}
|
|
150
|
+
*/
|
|
151
|
+
function failUnavailable(message, json) {
|
|
152
|
+
if (json) {
|
|
153
|
+
process.stdout.write(
|
|
154
|
+
`${JSON.stringify(
|
|
155
|
+
{apiVersion: 1, error: message, code: 'ERR_VERSIONS_UNAVAILABLE'},
|
|
156
|
+
null,
|
|
157
|
+
2,
|
|
158
|
+
)}\n`,
|
|
159
|
+
);
|
|
160
|
+
} else {
|
|
161
|
+
console.error(`Error: ${message}`);
|
|
162
|
+
}
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* The fallback warning's reason for a project CLI a host declined.
|
|
168
|
+
* @param {string} reason the host's own words
|
|
169
|
+
* @returns {string}
|
|
170
|
+
*/
|
|
171
|
+
export function declinedReasonText(reason) {
|
|
172
|
+
return `project CLI skipped: ${reason}`;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Choose who answers and hand off when it is not this copy.
|
|
177
|
+
* @param {{cliRoot: string, argv: string[], declinedProjectCli?: string}} input
|
|
178
|
+
* argv after `node astryx`; the reason a programmatic host declined the
|
|
179
|
+
* project's own CLI, when it did
|
|
180
|
+
* @returns {Promise<import('../../host/index.js').HostedCliResult | undefined>}
|
|
181
|
+
* resolves with nothing when this copy answers, and with that release's
|
|
182
|
+
* result when another package set's host entry answered a hosted run
|
|
183
|
+
*/
|
|
184
|
+
export async function startRun({cliRoot, argv, declinedProjectCli}) {
|
|
185
|
+
const json = argv.includes('--json');
|
|
186
|
+
const self = runningCopy(cliRoot);
|
|
187
|
+
const cacheDir = userCacheDir();
|
|
188
|
+
// A host carries its own CLI and keeps it current itself: a hosted copy
|
|
189
|
+
// runs none of the global copy's background work, and installs nothing.
|
|
190
|
+
const hosted = hostedRun();
|
|
191
|
+
const global = !hosted && isGlobalCopy(cliRoot, cacheDir);
|
|
192
|
+
if (global) {
|
|
193
|
+
try {
|
|
194
|
+
maybeStartCheck();
|
|
195
|
+
} catch {
|
|
196
|
+
// A check that cannot start never fails a run.
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
// The global copy keeps the computer-level agent text on its own
|
|
200
|
+
// release's text, so it follows each upgrade of the copy (FR8).
|
|
201
|
+
maybeKeepAgentText({release: self});
|
|
202
|
+
} catch {
|
|
203
|
+
// Nor does the agent text.
|
|
204
|
+
}
|
|
205
|
+
// And its own Core, so component reads work offline outside a project
|
|
206
|
+
// after one online run (FR3). Started as the run ends, so it never takes
|
|
207
|
+
// the install lock from this run's own Core read, nor holds anything the
|
|
208
|
+
// command's caller waits on while the command runs.
|
|
209
|
+
process.once('exit', () => {
|
|
210
|
+
try {
|
|
211
|
+
maybeFetchCore({release: self, cacheDir});
|
|
212
|
+
} catch {
|
|
213
|
+
// Nor does the Core download.
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const computer = isComputerLevel(argv);
|
|
219
|
+
/** @type {import('./choose.mjs').ReleaseChoice} */
|
|
220
|
+
let choice;
|
|
221
|
+
try {
|
|
222
|
+
choice = chooseRelease({
|
|
223
|
+
cwd: process.cwd(),
|
|
224
|
+
self,
|
|
225
|
+
cacheDir,
|
|
226
|
+
computer,
|
|
227
|
+
});
|
|
228
|
+
} catch {
|
|
229
|
+
choice = {
|
|
230
|
+
copy: 'carried',
|
|
231
|
+
answer: 'self',
|
|
232
|
+
version: self.version,
|
|
233
|
+
bin: null,
|
|
234
|
+
coreVersion: null,
|
|
235
|
+
inProject: false,
|
|
236
|
+
unavailable: null,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// A host declined the project's own CLI (FR2): the run is never handed to
|
|
241
|
+
// it. The release equal to that CLI's version answers in its place when
|
|
242
|
+
// this copy is that release, or when a package set of the host's holds it
|
|
243
|
+
// with a host entry; otherwise this copy answers, announced as for a release
|
|
244
|
+
// that cannot be obtained, naming the reason.
|
|
245
|
+
let declined = null;
|
|
246
|
+
/** Set when this copy answers in place of the declined CLI, its release. */
|
|
247
|
+
let inPlace = null;
|
|
248
|
+
if (
|
|
249
|
+
declinedProjectCli &&
|
|
250
|
+
choice.copy === 'project' &&
|
|
251
|
+
choice.answer !== 'self'
|
|
252
|
+
) {
|
|
253
|
+
if (choice.version === self.version) {
|
|
254
|
+
// Still the project CLI's release (`copy` stays `project`), never the
|
|
255
|
+
// release matched to the project's Core, which can be another.
|
|
256
|
+
choice = {...choice, answer: 'self', bin: null, unavailable: null};
|
|
257
|
+
inPlace = declinedReasonText(declinedProjectCli);
|
|
258
|
+
} else {
|
|
259
|
+
const served = hosted
|
|
260
|
+
? qualifyingRoot({
|
|
261
|
+
release: choice.version,
|
|
262
|
+
projectDir: projectDirOf(process.cwd()),
|
|
263
|
+
roots: hosted.roots,
|
|
264
|
+
needsHostEntry: true,
|
|
265
|
+
})
|
|
266
|
+
: null;
|
|
267
|
+
if (served && 'root' in served && served.hostEntry) {
|
|
268
|
+
const answered = await answerInPackageSet(
|
|
269
|
+
served.hostEntry,
|
|
270
|
+
served.root,
|
|
271
|
+
{argv, declinedProjectCli},
|
|
272
|
+
);
|
|
273
|
+
if (answered) return answered;
|
|
274
|
+
}
|
|
275
|
+
declined = declinedReasonText(declinedProjectCli);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (!declined && choice.unavailable && choice.copy === 'project') {
|
|
280
|
+
failUnavailable(
|
|
281
|
+
`This project's CLI ${choice.version} could not be started: ${choice.unavailable}. Reinstall the project's dependencies.`,
|
|
282
|
+
json,
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// A host's door holds only inside the call that set it; notices print as
|
|
287
|
+
// the process exits, outside it, so the door this run started under is
|
|
288
|
+
// kept and set again for them (FR5).
|
|
289
|
+
const door = cliDoor();
|
|
290
|
+
/** FR10: after a successful command, at most once a day per notice. */
|
|
291
|
+
const notify = () => {
|
|
292
|
+
const print = () => {
|
|
293
|
+
for (const line of noticeLines({
|
|
294
|
+
cwd: process.cwd(),
|
|
295
|
+
self,
|
|
296
|
+
choice: computer ? {...choice, inProject: false} : choice,
|
|
297
|
+
json,
|
|
298
|
+
cacheDir,
|
|
299
|
+
})) {
|
|
300
|
+
// Synchronous: the process is exiting.
|
|
301
|
+
writeSync(2, `${line}\n`);
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
try {
|
|
305
|
+
if (door) runWithCliDoor(door, print);
|
|
306
|
+
else print();
|
|
307
|
+
} catch {
|
|
308
|
+
// A notice never fails a run.
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
/**
|
|
312
|
+
* The matched release cannot be obtained: the copy that started the run
|
|
313
|
+
* answers instead, as before global mode, announced (FR2).
|
|
314
|
+
* @param {string} reason
|
|
315
|
+
* @returns {Promise<void>}
|
|
316
|
+
*/
|
|
317
|
+
const fallBack = async reason => {
|
|
318
|
+
recordRunChoice({
|
|
319
|
+
...choice,
|
|
320
|
+
copy: 'fallback',
|
|
321
|
+
answer: 'self',
|
|
322
|
+
version: self.version,
|
|
323
|
+
bin: null,
|
|
324
|
+
coreVersion: null,
|
|
325
|
+
unavailable: null,
|
|
326
|
+
});
|
|
327
|
+
if (!json) {
|
|
328
|
+
console.error(fallbackLine(choice.version, reason, self.version));
|
|
329
|
+
}
|
|
330
|
+
process.once('exit', code => {
|
|
331
|
+
if (code === 0) notify();
|
|
332
|
+
});
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
if (declined) {
|
|
336
|
+
await fallBack(declined);
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (choice.unavailable) {
|
|
341
|
+
await fallBack(choice.unavailable);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (choice.answer === 'self') {
|
|
346
|
+
recordRunChoice(choice);
|
|
347
|
+
// A project with no CLI of its own is answered as released, with no
|
|
348
|
+
// line; a hint after the command, once a day, says how to match it.
|
|
349
|
+
if (!json && (choice.copy === 'matched' || choice.copy === 'carried'))
|
|
350
|
+
console.error(whoAnsweredLine(choice, computer));
|
|
351
|
+
else if (!json && inPlace)
|
|
352
|
+
console.error(inPlaceOfProjectLine(choice.version, inPlace));
|
|
353
|
+
process.once('exit', code => {
|
|
354
|
+
if (code === 0) notify();
|
|
355
|
+
});
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
let bin = choice.bin;
|
|
360
|
+
if (!bin && hosted) {
|
|
361
|
+
const served = qualifyingRoot({
|
|
362
|
+
release: choice.version,
|
|
363
|
+
projectDir: projectDirOf(process.cwd()),
|
|
364
|
+
roots: hosted.roots,
|
|
365
|
+
});
|
|
366
|
+
if (!('root' in served)) {
|
|
367
|
+
await fallBack(served.reason);
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
if (served.hostEntry) {
|
|
371
|
+
const answered = await answerInPackageSet(served.hostEntry, served.root, {
|
|
372
|
+
argv,
|
|
373
|
+
});
|
|
374
|
+
if (answered) return answered;
|
|
375
|
+
}
|
|
376
|
+
// A hosted run installs nothing (INV30): a set whose CLI starts through
|
|
377
|
+
// neither its host entry nor a bin leaves this copy to answer.
|
|
378
|
+
if (!served.bin) {
|
|
379
|
+
await fallBack(
|
|
380
|
+
`the CLI ${choice.version} in the package set at ${served.root} could not be started`,
|
|
381
|
+
);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
bin = served.bin;
|
|
385
|
+
}
|
|
386
|
+
if (!bin) {
|
|
387
|
+
const release = ensureRelease(choice.version, {
|
|
388
|
+
cacheDir,
|
|
389
|
+
onProgress: json ? undefined : progressLine,
|
|
390
|
+
});
|
|
391
|
+
if (!('bin' in release)) {
|
|
392
|
+
await fallBack(release.reason);
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
bin = release.bin;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (!json) {
|
|
399
|
+
if (choice.copy === 'project') {
|
|
400
|
+
console.error(handedToProjectLine(choice.version, self.version));
|
|
401
|
+
} else if (!namesWhoAnswered(packageRootOf(bin))) {
|
|
402
|
+
console.error(whoAnsweredLine(choice, computer));
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
await handOff(bin, argv, choice, json, notify);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* How long a hand-off waits after an interrupt before passing it on to a CLI
|
|
411
|
+
* that is still running. An interrupt sent to the whole process group (a
|
|
412
|
+
* terminal's Ctrl-C, a process manager) already reached that CLI, and one that
|
|
413
|
+
* stops within this time is never interrupted twice; one sent to this process
|
|
414
|
+
* alone (an agent's `kill('SIGINT')`) stops the run once it is passed on.
|
|
415
|
+
*/
|
|
416
|
+
export const INTERRUPT_GRACE_MS = 5000;
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* The project folder a run in `cwd` belongs to, or null outside a project.
|
|
420
|
+
* @param {string} cwd
|
|
421
|
+
* @returns {string | null}
|
|
422
|
+
*/
|
|
423
|
+
function projectDirOf(cwd) {
|
|
424
|
+
try {
|
|
425
|
+
return projectRootOf(readReleaseFacts(cwd));
|
|
426
|
+
} catch {
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Hand a hosted run over to the CLI of one of the host's package sets,
|
|
433
|
+
* through that CLI's own host entry, in this process, with the inputs this run
|
|
434
|
+
* got: the arguments, the folder, the command name, the approved integrations,
|
|
435
|
+
* the discover sources, and the reason the host declined the project's CLI.
|
|
436
|
+
* Its roots are that package set alone. That CLI prints its own who-answered
|
|
437
|
+
* line and notices, and the host's call settles with its result.
|
|
438
|
+
* @param {string} hostEntry the package set's `host/index.mjs`
|
|
439
|
+
* @param {string} root the package set
|
|
440
|
+
* @param {{argv: string[], declinedProjectCli?: string}} run
|
|
441
|
+
* @returns {Promise<import('../../host/index.js').HostedCliResult | null>} null
|
|
442
|
+
* when the entry cannot be loaded, before anything ran
|
|
443
|
+
*/
|
|
444
|
+
async function answerInPackageSet(hostEntry, root, {argv, declinedProjectCli}) {
|
|
445
|
+
const hosted = hostedRun();
|
|
446
|
+
if (!hosted?.loadHostEntry) return null;
|
|
447
|
+
let answer;
|
|
448
|
+
try {
|
|
449
|
+
answer = await hosted.loadHostEntry(hostEntry);
|
|
450
|
+
} catch {
|
|
451
|
+
return null;
|
|
452
|
+
}
|
|
453
|
+
const door = cliDoor();
|
|
454
|
+
return answer({
|
|
455
|
+
argv,
|
|
456
|
+
cwd: process.cwd(),
|
|
457
|
+
roots: [root],
|
|
458
|
+
integrations: [...hosted.integrations],
|
|
459
|
+
discoverSources: [...hosted.discoverSources],
|
|
460
|
+
...(door ? {cliCommand: door} : {}),
|
|
461
|
+
...(declinedProjectCli ? {declinedProjectCli} : {}),
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Run `bin` as this run and end with its exit status.
|
|
467
|
+
* @param {string} bin
|
|
468
|
+
* @param {string[]} argv
|
|
469
|
+
* @param {import('./choose.mjs').ReleaseChoice} choice
|
|
470
|
+
* @param {boolean} json
|
|
471
|
+
* @param {() => void} [notify] prints update notices after a successful run
|
|
472
|
+
* @returns {Promise<never>}
|
|
473
|
+
*/
|
|
474
|
+
function handOff(bin, argv, choice, json, notify = () => {}) {
|
|
475
|
+
return new Promise(() => {
|
|
476
|
+
const child = spawn(process.execPath, [bin, ...argv], {
|
|
477
|
+
stdio: 'inherit',
|
|
478
|
+
windowsHide: false,
|
|
479
|
+
});
|
|
480
|
+
/** @param {NodeJS.Signals} signal */
|
|
481
|
+
const forward = signal => {
|
|
482
|
+
try {
|
|
483
|
+
child.kill(signal);
|
|
484
|
+
} catch {
|
|
485
|
+
// The child is already gone.
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
const running = () => child.exitCode === null && child.signalCode === null;
|
|
489
|
+
// An interrupt is passed on only to a CLI still running after the grace
|
|
490
|
+
// (see INTERRUPT_GRACE_MS): one sent to this process alone then stops the
|
|
491
|
+
// run, and one the whole process group got is not delivered twice to a CLI
|
|
492
|
+
// that stops in time. On Windows, Ctrl-C reaches every process in the
|
|
493
|
+
// console and a forwarded SIGINT would end the child abruptly, so this
|
|
494
|
+
// process only outlives it.
|
|
495
|
+
const onInterrupt = () => {
|
|
496
|
+
if (process.platform === 'win32' || !running()) return;
|
|
497
|
+
setTimeout(() => {
|
|
498
|
+
if (running()) forward('SIGINT');
|
|
499
|
+
}, INTERRUPT_GRACE_MS).unref();
|
|
500
|
+
};
|
|
501
|
+
process.on('SIGINT', onInterrupt);
|
|
502
|
+
process.on('SIGTERM', forward);
|
|
503
|
+
process.on('SIGHUP', forward);
|
|
504
|
+
child.on('error', error => {
|
|
505
|
+
failUnavailable(
|
|
506
|
+
choice.copy === 'project'
|
|
507
|
+
? `This project's CLI ${choice.version} could not be started: ${error.message}. Reinstall the project's dependencies.`
|
|
508
|
+
: `CLI release ${choice.version} could not be started: ${error.message}.`,
|
|
509
|
+
json,
|
|
510
|
+
);
|
|
511
|
+
});
|
|
512
|
+
child.on('exit', (code, signal) => {
|
|
513
|
+
process.off('SIGINT', onInterrupt);
|
|
514
|
+
process.off('SIGTERM', forward);
|
|
515
|
+
process.off('SIGHUP', forward);
|
|
516
|
+
if (signal) {
|
|
517
|
+
process.kill(process.pid, signal);
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
if (code === 0) notify();
|
|
521
|
+
process.exit(code ?? 1);
|
|
522
|
+
});
|
|
523
|
+
});
|
|
524
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// @generated by scripts/sync-api-types.mjs from the JSDoc in foundation/**/*.mjs.
|
|
2
|
+
// DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Renew the holder's record: the same process and computer, with a counter
|
|
6
|
+
* that changes on every renewal. Never throws.
|
|
7
|
+
* @param {string} lockDir
|
|
8
|
+
*/
|
|
9
|
+
export function renewLock(lockDir: string): void;
|
|
10
|
+
/**
|
|
11
|
+
* Whether a lock held from another computer has gone silent: its record has
|
|
12
|
+
* not changed for `LEASE_SILENCE_MS` of this process's own observation.
|
|
13
|
+
* @param {string} lockDir
|
|
14
|
+
* @param {number} [now]
|
|
15
|
+
* @returns {boolean}
|
|
16
|
+
*/
|
|
17
|
+
export function foreignLockIsSilent(lockDir: string, now?: number): boolean;
|
|
18
|
+
/** Forget what this process observed (tests). */
|
|
19
|
+
export function forgetObservedLocks(): void;
|
|
20
|
+
/** How often the holder renews its record while the package manager works. */
|
|
21
|
+
export const LEASE_RENEW_MS: 10000;
|
|
22
|
+
/** How long a record from another computer may go unrenewed, as observed. */
|
|
23
|
+
export const LEASE_SILENCE_MS: 60000;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file The lease on a release install's lock in the per-user cache (spec
|
|
5
|
+
* AST-081 FR11).
|
|
6
|
+
*
|
|
7
|
+
* A lock folder records its holder in `owner.json`: the process id and the
|
|
8
|
+
* computer's name. On the same computer a waiting run checks whether that
|
|
9
|
+
* process still runs. A cache shared between computers cannot check another
|
|
10
|
+
* computer's processes, so the holder renews its record every
|
|
11
|
+
* `LEASE_RENEW_MS` while the package manager works, and a waiting run takes
|
|
12
|
+
* a lock from another computer over once it has seen the record go unrenewed
|
|
13
|
+
* for `LEASE_SILENCE_MS`. The waiting run judges by change it observes, never
|
|
14
|
+
* by comparing clocks, so computers whose clocks differ agree.
|
|
15
|
+
*
|
|
16
|
+
* @input the lock folder
|
|
17
|
+
* @output the renewed record, and whether a foreign record has gone silent
|
|
18
|
+
* @position foundation/release — renewed by npm-guard.mjs, read by cache.mjs.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import * as fs from 'node:fs';
|
|
22
|
+
import * as path from 'node:path';
|
|
23
|
+
|
|
24
|
+
/** How often the holder renews its record while the package manager works. */
|
|
25
|
+
export const LEASE_RENEW_MS = 10_000;
|
|
26
|
+
|
|
27
|
+
/** How long a record from another computer may go unrenewed, as observed. */
|
|
28
|
+
export const LEASE_SILENCE_MS = 60_000;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Renew the holder's record: the same process and computer, with a counter
|
|
32
|
+
* that changes on every renewal. Never throws.
|
|
33
|
+
* @param {string} lockDir
|
|
34
|
+
*/
|
|
35
|
+
export function renewLock(lockDir) {
|
|
36
|
+
const file = path.join(lockDir, 'owner.json');
|
|
37
|
+
try {
|
|
38
|
+
const owner = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
39
|
+
const next = {...owner, beat: (Number(owner.beat) || 0) + 1};
|
|
40
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
41
|
+
fs.writeFileSync(tmp, JSON.stringify(next));
|
|
42
|
+
fs.renameSync(tmp, file);
|
|
43
|
+
} catch {
|
|
44
|
+
// A lock that was taken over or removed has no record to renew.
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* What this process last saw of each foreign lock: the record's text and
|
|
50
|
+
* when that text was first seen.
|
|
51
|
+
* @type {Map<string, {text: string, since: number}>}
|
|
52
|
+
*/
|
|
53
|
+
const observed = new Map();
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Whether a lock held from another computer has gone silent: its record has
|
|
57
|
+
* not changed for `LEASE_SILENCE_MS` of this process's own observation.
|
|
58
|
+
* @param {string} lockDir
|
|
59
|
+
* @param {number} [now]
|
|
60
|
+
* @returns {boolean}
|
|
61
|
+
*/
|
|
62
|
+
export function foreignLockIsSilent(lockDir, now = Date.now()) {
|
|
63
|
+
let text;
|
|
64
|
+
try {
|
|
65
|
+
text = fs.readFileSync(path.join(lockDir, 'owner.json'), 'utf-8');
|
|
66
|
+
} catch {
|
|
67
|
+
text = '';
|
|
68
|
+
}
|
|
69
|
+
const seen = observed.get(lockDir);
|
|
70
|
+
if (!seen || seen.text !== text) {
|
|
71
|
+
observed.set(lockDir, {text, since: now});
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return now - seen.since >= LEASE_SILENCE_MS;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Forget what this process observed (tests). */
|
|
78
|
+
export function forgetObservedLocks() {
|
|
79
|
+
observed.clear();
|
|
80
|
+
}
|