@astryxdesign/cli 0.7.2 → 0.7.3-canary.0bf23bd
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +104 -71
- package/api/build/_adapter.d.mts +58 -0
- package/api/build/_adapter.mjs +115 -3
- package/api/build/blocks/blocks.d.mts +42 -0
- package/api/build/blocks/blocks.mjs +169 -0
- package/api/build/blocks/blocks.test.mjs +108 -0
- package/api/build/blocks/blocks.weights.json +1 -0
- package/api/build/build.mjs +25 -6
- package/api/build/kit/answer.d.mts +14 -0
- package/api/build/kit/answer.mjs +85 -0
- package/api/build/kit/answer.test.mjs +38 -0
- package/api/build/kit/kind.d.mts +25 -0
- package/api/build/kit/kind.mjs +170 -0
- package/api/build/kit/kit.d.mts +2 -4
- package/api/build/kit/kit.mjs +8 -398
- package/api/build/kit/rank.d.mts +3 -32
- package/api/build/kit/rank.mjs +25 -342
- package/api/build/kit/rank.test.mjs +2 -1
- package/api/build/kit/signals.d.mts +60 -0
- package/api/build/kit/signals.mjs +284 -0
- package/api/build/kit/start.d.mts +32 -0
- package/api/build/kit/start.mjs +163 -0
- package/api/build/kit/words.d.mts +72 -0
- package/api/build/kit/words.mjs +202 -0
- package/api/build/tree.d.mts +20 -0
- package/api/build/tree.mjs +52 -0
- package/api/build/tree.test.mjs +177 -0
- package/api/build/tree.weights.json +1 -0
- package/api/component/component.mjs +17 -3
- package/api/component/component.test.mjs +15 -0
- package/api/component/doc-links.test.mjs +2 -2
- package/api/discover/_adapter.mjs +36 -9
- package/api/discover/_adapter.test.mjs +42 -0
- package/api/docs/_adapter.d.mts +2 -2
- package/api/docs/_adapter.mjs +78 -23
- package/api/docs/docs-homes.test.mjs +127 -0
- package/api/docs/docs.doc.mjs +3 -3
- package/api/docs/docs.test.mjs +35 -19
- package/api/docs/integration-tree.test.mjs +20 -20
- package/api/docs/integrationDocs.test.mjs +1 -1
- package/api/docs/namespace-section.test.mjs +6 -6
- package/api/docs/reference-blocks.test.mjs +2 -2
- package/api/doctor/doctor.mjs +102 -24
- package/api/doctor/doctor.test.mjs +37 -12
- package/api/hook/hook.mjs +1 -1
- package/api/init/init.doc.mjs +20 -6
- package/api/init/init.test.mjs +18 -2
- package/api/init/init.type.d.mts +3 -3
- package/api/init/init.type.mjs +3 -3
- package/api/init/remove/remove.mjs +17 -4
- package/api/init/remove/remove.test.mjs +114 -2
- package/api/init/run/run.mjs +69 -6
- package/api/integration/_adapter.d.mts +8 -0
- package/api/integration/_adapter.mjs +21 -1
- package/api/integration/authoring-checks.mjs +83 -9
- package/api/integration/authoring-checks.test.mjs +220 -0
- package/api/integration/pack-check.mjs +123 -4
- package/api/integration/pack-check.test.mjs +87 -0
- package/api/integration/validate-integration-case-disk.test.mjs +111 -0
- package/api/integration/validate-integration-gaps.test.mjs +1964 -0
- package/api/integration/validate-integration.d.mts +11 -2
- package/api/integration/validate-integration.mjs +250 -32
- package/api/integration/validate-integration.type.d.mts +59 -1
- package/api/integration/validate-integration.type.mjs +46 -2
- package/api/integration/validateIntegration.doc.mjs +1 -1
- package/api/search/ORDERING.md +28 -0
- package/api/search/_adapter.d.mts +82 -2
- package/api/search/_adapter.mjs +157 -10
- package/api/search/_adapter.test.mjs +173 -0
- package/api/search/_candidate-score.d.mts +40 -0
- package/api/search/_candidate-score.mjs +238 -0
- package/api/search/_cards.json +6098 -0
- package/api/search/_compound.d.mts +50 -0
- package/api/search/_compound.mjs +170 -0
- package/api/search/_doc-searcher.d.mts +4 -0
- package/api/search/_doc-searcher.mjs +23 -0
- package/api/search/_doc-searcher.test.mjs +36 -0
- package/api/search/_doc-searcher.weights.json +1 -0
- package/api/search/_doc-text.d.mts +30 -0
- package/api/search/_doc-text.mjs +87 -0
- package/api/search/_entries.d.mts +52 -0
- package/api/search/_entries.mjs +214 -0
- package/api/search/_features.d.mts +35 -0
- package/api/search/_features.mjs +155 -0
- package/api/search/_gather-components.d.mts +26 -0
- package/api/search/_gather-components.mjs +284 -0
- package/api/search/_gather-docs.d.mts +20 -0
- package/api/search/_gather-docs.mjs +254 -0
- package/api/search/_gather-hooks.d.mts +12 -0
- package/api/search/_gather-hooks.mjs +52 -0
- package/api/search/_gather-templates.d.mts +25 -0
- package/api/search/_gather-templates.mjs +107 -0
- package/api/search/_lexical.d.mts +135 -0
- package/api/search/_lexical.mjs +351 -0
- package/api/search/_main-searcher.d.mts +19 -0
- package/api/search/_main-searcher.mjs +115 -0
- package/api/search/_main-searcher.test.mjs +106 -0
- package/api/search/_main-searcher.weights.json +1 -0
- package/api/search/_module-doc.d.mts +32 -0
- package/api/search/_module-doc.mjs +78 -0
- package/api/search/_order.d.mts +32 -0
- package/api/search/_order.mjs +162 -0
- package/api/search/_order.test.mjs +72 -0
- package/api/search/_priority.d.mts +50 -0
- package/api/search/_priority.mjs +139 -0
- package/api/search/_query-words.d.mts +25 -0
- package/api/search/_query-words.mjs +92 -0
- package/api/search/_query.d.mts +65 -0
- package/api/search/_query.mjs +176 -0
- package/api/search/_result.d.mts +97 -0
- package/api/search/_result.mjs +150 -0
- package/api/search/_score.d.mts +60 -0
- package/api/search/_score.mjs +283 -0
- package/api/search/_synonyms.d.mts +21 -0
- package/api/search/_synonyms.mjs +67 -0
- package/api/search/_template-searcher.d.mts +4 -0
- package/api/search/_template-searcher.mjs +23 -0
- package/api/search/_template-searcher.test.mjs +40 -0
- package/api/search/_template-searcher.weights.json +1 -0
- package/api/search/_titles.d.mts +33 -0
- package/api/search/_titles.mjs +65 -0
- package/api/search/_words.d.mts +64 -0
- package/api/search/_words.mjs +157 -0
- package/api/search/search.d.mts +22 -305
- package/api/search/search.doc.mjs +8 -6
- package/api/search/search.mjs +56 -2482
- package/api/search/search.test.mjs +14 -14
- package/api/search/search.type.d.mts +6 -1
- package/api/search/search.type.mjs +6 -1
- package/api/search/tree.d.mts +15 -0
- package/api/search/tree.mjs +40 -0
- package/api/search/tree.test.mjs +66 -0
- package/api/search/tree.weights.json +1 -0
- package/api/theme/build/build.packed-old-core.test.mjs +1 -0
- package/api/upgrade/_adapter.d.mts +57 -9
- package/api/upgrade/_adapter.mjs +198 -28
- package/api/upgrade/registry/registry.d.mts +10 -4
- package/api/upgrade/registry/registry.mjs +33 -16
- package/api/upgrade/registry/registry.test.mjs +85 -0
- package/api/upgrade/run/run.d.mts +4 -2
- package/api/upgrade/run/run.mjs +13 -2
- package/api/upgrade/run/run.test.mjs +417 -3
- package/api/upgrade/upgrade.doc.mjs +10 -5
- package/api/upgrade/upgrade.mjs +13 -2
- package/api/upgrade/upgrade.test.mjs +194 -0
- package/api/upgrade/upgrade.type.d.mts +5 -3
- package/api/upgrade/upgrade.type.mjs +8 -6
- package/assets/codemods/transforms/v0.7.0/__tests__/validate-data-token-ownership.test.mjs +11 -0
- package/assets/codemods/transforms/v0.7.0/validate-data-token-ownership.mjs +3 -3
- package/assets/docs/author-a-theme.doc.mjs +2 -2
- package/assets/docs/is-my-code-good.doc.mjs +287 -0
- package/assets/docs/tree/add-a-component.doc.mjs +1 -1
- package/assets/docs/tree/add-a-theme.doc.mjs +1 -1
- package/assets/docs/tree/add-a-topic.doc.mjs +2 -2
- package/assets/docs/tree/agent-guidance.doc.mjs +1 -1
- package/assets/docs/tree/api.doc.mjs +6 -0
- package/assets/docs/tree/{integrations.doc.mjs → authoring.doc.mjs} +15 -6
- package/assets/docs/tree/block-template.doc.mjs +1 -1
- package/assets/docs/tree/build-the-template.doc.mjs +1 -1
- package/assets/docs/tree/building-blocks.doc.mjs +2 -2
- package/assets/docs/tree/check-the-props.doc.mjs +1 -1
- package/assets/docs/tree/check-your-docs.doc.mjs +2 -2
- package/assets/docs/tree/checks.doc.mjs +2 -2
- package/assets/docs/tree/cli-command.doc.mjs +1 -1
- package/assets/docs/tree/cli.doc.mjs +1 -1
- package/assets/docs/tree/codemods.doc.mjs +1 -1
- package/assets/docs/tree/component-family.doc.mjs +1 -1
- package/assets/docs/tree/component-imports.doc.mjs +1 -1
- package/assets/docs/tree/components.doc.mjs +1 -1
- package/assets/docs/tree/configuration.doc.mjs +1 -1
- package/assets/docs/tree/debug-and-gap-reports.doc.mjs +1 -1
- package/assets/docs/tree/define-the-theme.doc.mjs +1 -1
- package/assets/docs/tree/describe-the-component.doc.mjs +1 -1
- package/assets/docs/tree/docs.doc.mjs +1 -1
- package/assets/docs/tree/document-the-template.doc.mjs +1 -1
- package/assets/docs/tree/document-the-theme.doc.mjs +1 -1
- package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
- package/assets/docs/tree/extend-or-replace.doc.mjs +1 -1
- package/assets/docs/{authoring.doc.mjs → tree/field-reference.doc.mjs} +4 -3
- package/assets/docs/tree/fonts-and-assets.doc.mjs +1 -1
- package/assets/docs/tree/generate-a-palette.doc.mjs +1 -1
- package/assets/docs/tree/global-integrations.doc.mjs +2 -2
- package/assets/docs/tree/grade-template-with-agent.doc.mjs +4 -4
- package/assets/docs/tree/help.doc.mjs +2 -2
- package/assets/docs/tree/host-entry.doc.mjs +128 -0
- package/assets/docs/tree/links.doc.mjs +1 -1
- package/assets/docs/tree/package-and-test.doc.mjs +1 -1
- package/assets/docs/tree/page-template.doc.mjs +1 -1
- package/assets/docs/tree/publishing.doc.mjs +1 -1
- package/assets/docs/tree/quick-start.doc.mjs +1 -1
- package/assets/docs/tree/replace-a-core-component.doc.mjs +1 -1
- package/assets/docs/tree/replace-a-core-template.doc.mjs +1 -1
- package/assets/docs/tree/sections-and-placement.doc.mjs +1 -1
- package/assets/docs/tree/see-it-in-an-app.doc.mjs +1 -1
- package/assets/docs/tree/ship.doc.mjs +2 -2
- package/assets/docs/tree/short-and-findable.doc.mjs +1 -1
- package/assets/docs/tree/single-component.doc.mjs +1 -1
- package/assets/docs/tree/start-a-template.doc.mjs +1 -1
- package/assets/docs/tree/subcomponent.doc.mjs +1 -1
- package/assets/docs/tree/template-assets.doc.mjs +1 -1
- package/assets/docs/tree/template-doc-overview.doc.mjs +2 -2
- package/assets/docs/tree/template-fonts.doc.mjs +1 -1
- package/assets/docs/tree/template-grading-rubric.doc.mjs +17 -38
- package/assets/docs/tree/template-icons.doc.mjs +1 -1
- package/assets/docs/tree/template-images-media.doc.mjs +1 -1
- package/assets/docs/tree/template-styles.doc.mjs +1 -1
- package/assets/docs/tree/templates.doc.mjs +1 -1
- package/assets/docs/tree/test-in-an-app.doc.mjs +1 -1
- package/assets/docs/tree/test-template-in-app.doc.mjs +1 -1
- package/assets/docs/tree/themes.doc.mjs +1 -1
- package/assets/docs/tree/tokens-data.doc.mjs +2 -2
- package/assets/docs/tree/troubleshooting.doc.mjs +1 -1
- package/assets/docs/tree/upgrading.doc.mjs +1 -1
- package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +1 -1
- package/assets/docs/tree/verify-packed-template.doc.mjs +1 -1
- package/assets/docs/tree/versioning.doc.mjs +1 -1
- package/assets/docs/tree/write-good-templates.doc.mjs +1 -1
- package/assets/docs/tree/write-the-template-file.doc.mjs +1 -1
- package/assets/docs/use-integrations.doc.mjs +120 -0
- package/assets/docs/working-with-ai.doc.mjs +6 -2
- package/assets/templates/themes/butter/butterTheme.ts +4 -2
- package/assets/templates/themes/stone/stoneTheme.ts +4 -2
- package/assets/templates/themes/y2k/y2kTheme.ts +4 -2
- package/authoring/debug/parse.d.mts +1 -1
- package/authoring/doctypes/schema/schema.doc.mjs +1 -1
- package/authoring/integration/integration.doc.mjs +1 -1
- package/authoring/integration/type.ts +1 -1
- package/clients/cli/bin/astryx.mjs +7 -78
- package/clients/cli/command-result-coverage.test.mjs +6 -5
- package/clients/cli/commands/build-theme.color-scheme.test.mjs +1 -1
- package/clients/cli/commands/{component/index.mjs → component.mjs} +37 -37
- package/clients/cli/commands/component.test.mjs +6 -6
- package/clients/cli/commands/docs.doc.mjs +2 -2
- package/clients/cli/commands/docs.mjs +1 -1
- package/clients/cli/commands/docs.test.mjs +14 -14
- package/clients/cli/commands/doctor.mjs +30 -0
- package/clients/cli/commands/doctor.test.mjs +65 -0
- package/clients/cli/commands/{hook/index.mjs → hook.mjs} +22 -22
- package/clients/cli/commands/import-hint-correctness.test.mjs +1 -1
- package/clients/cli/commands/init.behavior.test.mjs +230 -1
- package/clients/cli/commands/init.doc.mjs +28 -9
- package/clients/cli/commands/init.flag-help.test.mjs +1 -0
- package/clients/cli/commands/init.mjs +2 -2
- package/clients/cli/commands/integration-check.test.mjs +48 -0
- package/clients/cli/commands/integration.doc.mjs +1 -1
- package/clients/cli/commands/manifest.doc.mjs +1 -1
- package/clients/cli/commands/manifest.mjs +67 -0
- package/clients/cli/commands/outside-project.test.mjs +2 -1
- package/clients/cli/commands/postinstall.doc.mjs +23 -0
- package/clients/cli/commands/postinstall.mjs +31 -0
- package/clients/cli/commands/setup-nudge.test.mjs +61 -0
- package/clients/cli/commands/{build-theme.mjs → theme.mjs} +1 -1
- package/clients/cli/commands/upgrade.doc.mjs +4 -2
- package/clients/cli/commands/upgrade.mjs +9 -2
- package/clients/cli/commands/upgrade.subfolder-path.test.mjs +97 -0
- package/clients/cli/index.mjs +29 -86
- package/clients/cli/lib/component-format.mjs +1 -1
- package/clients/cli/lib/define-command.mjs +12 -7
- package/clients/cli/lib/exit-codes.test.mjs +5 -0
- package/clients/cli/lib/manifest.test.mjs +12 -0
- package/clients/cli/lib/welcome-box.mjs +50 -0
- package/clients/cli/run.mjs +108 -0
- package/foundation/agent-docs/agent-doc-state.d.mts +20 -7
- package/foundation/agent-docs/agent-doc-state.mjs +35 -8
- package/foundation/agent-docs/agent-docs.d.mts +100 -12
- package/foundation/agent-docs/agent-docs.mjs +1012 -100
- package/foundation/agent-docs/agent-docs.path-safety.test.mjs +1239 -17
- package/foundation/agent-docs/agent-docs.test.mjs +683 -39
- package/foundation/config/project.mjs +20 -22
- package/foundation/config/project.test.mjs +56 -0
- package/foundation/discovery/authoring-self-docs.d.mts +7 -0
- package/foundation/discovery/authoring-self-docs.mjs +16 -4
- package/foundation/discovery/authoring-self-docs.test.mjs +15 -3
- package/foundation/discovery/authoring-surface.d.mts +1 -1
- package/foundation/discovery/authoring-surface.mjs +2 -2
- package/foundation/discovery/authoring-surface.test.mjs +1 -1
- package/foundation/discovery/cli-self-docs.d.mts +2 -1
- package/foundation/discovery/cli-self-docs.mjs +4 -3
- package/foundation/discovery/cli-self-docs.test.mjs +2 -2
- package/foundation/discovery/component-discovery.d.mts +37 -0
- package/foundation/discovery/component-discovery.mjs +80 -5
- package/foundation/discovery/component-loader.d.mts +1 -1
- package/foundation/discovery/docs-discovery.mjs +14 -1
- package/foundation/discovery/module-exports.d.mts +41 -0
- package/foundation/discovery/module-exports.mjs +253 -0
- package/foundation/discovery/runner-allowlist.d.mts +2 -4
- package/foundation/discovery/runner-allowlist.mjs +2 -4
- package/foundation/discovery/runner-commands.d.mts +77 -0
- package/foundation/discovery/runner-commands.mjs +294 -0
- package/foundation/discovery/runner-commands.test.mjs +128 -0
- package/foundation/discovery/stray-pointers.test.mjs +1 -1
- package/foundation/discovery/template-adapter.mjs +18 -1
- package/foundation/discovery/template-needs.mjs +1 -44
- package/foundation/discovery/theme-discovery.mjs +147 -3
- package/foundation/doc-compiler/doc-loads.test.mjs +33 -9
- package/foundation/doc-compiler/read.mjs +59 -1
- package/foundation/doc-compiler/read.test.mjs +11 -2
- package/foundation/doc-compiler/split-topic-keywords.test.mjs +3 -2
- package/foundation/doc-compiler/tree.d.mts +32 -6
- package/foundation/doc-compiler/tree.mjs +77 -43
- package/foundation/doc-compiler/tree.test.mjs +7 -7
- package/foundation/fs/paths.d.mts +70 -8
- package/foundation/fs/paths.mjs +556 -38
- package/foundation/fs/paths.test.mjs +430 -54
- package/foundation/fs/read-record.d.mts +18 -0
- package/foundation/fs/read-record.mjs +131 -0
- package/foundation/fs/read-record.test.mjs +77 -0
- package/foundation/integrations/autolink.d.mts +2 -1
- package/foundation/integrations/autolink.mjs +4 -13
- package/foundation/integrations/computer-integrations.d.mts +6 -3
- package/foundation/integrations/computer-integrations.mjs +38 -9
- package/foundation/integrations/contribution-inventory.d.mts +15 -20
- package/foundation/integrations/contribution-inventory.mjs +41 -5
- package/foundation/integrations/integrations.d.mts +27 -1
- package/foundation/integrations/integrations.mjs +61 -2
- package/foundation/integrations/validate-contributions.d.mts +115 -0
- package/foundation/integrations/validate-contributions.mjs +1168 -13
- package/foundation/release/handoff.d.mts +23 -4
- package/foundation/release/handoff.mjs +175 -8
- package/foundation/release/run-context.mjs +14 -0
- package/foundation/response/response-types.doc.mjs +1 -1
- package/foundation/route/route.d.mts +285 -0
- package/foundation/route/route.mjs +324 -0
- package/foundation/route/route.test.mjs +153 -0
- package/foundation/runtime/hosted-runtime.test.mjs +403 -0
- package/foundation/runtime/locked-versions.d.mts +32 -0
- package/foundation/runtime/locked-versions.mjs +65 -0
- package/foundation/runtime/package-root.d.mts +91 -0
- package/foundation/runtime/package-root.mjs +174 -0
- package/foundation/runtime/package-set.d.mts +62 -0
- package/foundation/runtime/package-set.mjs +130 -0
- package/foundation/runtime/package-set.test.mjs +432 -0
- package/host/door-conformance.test.mjs +274 -0
- package/host/index.d.ts +116 -0
- package/host/index.mjs +295 -0
- package/host/index.test.mjs +302 -0
- package/package.json +14 -9
package/clients/cli/index.mjs
CHANGED
|
@@ -26,13 +26,17 @@ import {projectRootOf} from '../../foundation/release/choose.mjs';
|
|
|
26
26
|
import {readReleaseFacts} from '../../foundation/release/project.mjs';
|
|
27
27
|
import {buildManifest} from './lib/manifest.mjs';
|
|
28
28
|
import {cliError} from './lib/cli-error.mjs';
|
|
29
|
-
import {
|
|
29
|
+
import {section, text, records} from './formatters/index.mjs';
|
|
30
30
|
import {ERROR_CODES} from '../../foundation/response/error-codes.mjs';
|
|
31
31
|
import {levenshteinDistance} from '../../foundation/text/string-utils.mjs';
|
|
32
32
|
import {installJsonShim} from './lib/json-shim.mjs';
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
|
|
33
|
+
import {markReportsResult} from './lib/define-command.mjs';
|
|
34
|
+
import {
|
|
35
|
+
agentDocsTargetDir,
|
|
36
|
+
assertAgentDocsTarget,
|
|
37
|
+
isAstryxInitialized,
|
|
38
|
+
isAstryxPromptInReach,
|
|
39
|
+
} from '../../foundation/agent-docs/agent-docs.mjs';
|
|
36
40
|
import {CLI_ROOT} from '../../foundation/fs/paths.mjs';
|
|
37
41
|
import {setupNudge} from '../../foundation/agent-docs/agent-doc-state.mjs';
|
|
38
42
|
import * as debug from '../../foundation/debug/index.mjs';
|
|
@@ -292,7 +296,7 @@ function captureInvocation(actionCommand, root) {
|
|
|
292
296
|
*/
|
|
293
297
|
const commands = [
|
|
294
298
|
{name: 'init', path: './commands/init.mjs', register: 'registerInit'},
|
|
295
|
-
{name: 'component', path: './commands/component
|
|
299
|
+
{name: 'component', path: './commands/component.mjs', register: 'registerComponent'},
|
|
296
300
|
{name: 'docs', path: './commands/docs.mjs', register: 'registerDocs'},
|
|
297
301
|
{name: 'blog', path: './commands/blog.mjs', register: 'registerBlog'},
|
|
298
302
|
{name: 'swizzle', path: './commands/swizzle.mjs', register: 'registerSwizzle'},
|
|
@@ -300,13 +304,17 @@ const commands = [
|
|
|
300
304
|
// agent-docs folded into init — functions still importable from agent-docs.mjs
|
|
301
305
|
{name: 'template', path: './commands/template.mjs', register: 'registerTemplate'},
|
|
302
306
|
{name: 'upgrade', path: './commands/upgrade.mjs', register: 'registerUpgrade'},
|
|
303
|
-
{name: 'theme', path: './commands/
|
|
307
|
+
{name: 'theme', path: './commands/theme.mjs', register: 'registerTheme'},
|
|
304
308
|
{name: 'integration', path: './commands/integration.mjs', register: 'registerIntegration'},
|
|
305
|
-
{name: 'hook', path: './commands/hook
|
|
309
|
+
{name: 'hook', path: './commands/hook.mjs', register: 'registerHook'},
|
|
306
310
|
{name: 'discover', path: './commands/discover.mjs', register: 'registerDiscover'},
|
|
307
311
|
{name: 'search', path: './commands/search.mjs', register: 'registerSearch'},
|
|
308
312
|
{name: 'build', path: './commands/build.mjs', register: 'registerBuild'},
|
|
309
313
|
{name: 'doctor', path: './commands/doctor.mjs', register: 'registerDoctor'},
|
|
314
|
+
// Registered after every other command: the manifest lists the commands in
|
|
315
|
+
// registration order.
|
|
316
|
+
{name: 'manifest', path: './commands/manifest.mjs', register: 'registerManifest'},
|
|
317
|
+
{name: 'postinstall', path: './commands/postinstall.mjs', register: 'registerPostinstall'},
|
|
310
318
|
];
|
|
311
319
|
|
|
312
320
|
const SETUP_NUDGE_EXEMPT = new Set(['init', 'agent-docs']);
|
|
@@ -635,6 +643,19 @@ export async function createProgram() {
|
|
|
635
643
|
if (INTEGRATION_MANIFEST_FILES.some(file => fs.existsSync(path.join(cwd, file)))) return;
|
|
636
644
|
if (inOwnSourceCheckout(cwd)) return; // developing Astryx itself, not an app
|
|
637
645
|
if (isAstryxPromptInReach(cwd)) return; // already set up — stay quiet
|
|
646
|
+
// Where init writes the docs, by init's own rule: the project root, which
|
|
647
|
+
// can sit above a nested package such as functions/. Inside a git
|
|
648
|
+
// repository the walk above already reaches it (the root never lies
|
|
649
|
+
// above the repository root), so this changes nothing there; outside a
|
|
650
|
+
// repository the walk checks only cwd, and this finds the root.
|
|
651
|
+
if (isAstryxInitialized(agentDocsTargetDir(cwd))) return;
|
|
652
|
+
// In the home folder, or at the top of a settings folder in it, init
|
|
653
|
+
// writes no agent docs, so naming it would repeat on every command.
|
|
654
|
+
try {
|
|
655
|
+
assertAgentDocsTarget(agentDocsTargetDir(cwd));
|
|
656
|
+
} catch {
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
638
659
|
// Same wording as the core/cli postinstall nudges. getCliInvocation()
|
|
639
660
|
// renders the correct form for THIS project — an integration's cliCommand,
|
|
640
661
|
// scoped `npx @astryxdesign/cli` one-off, or `<pm> astryx` when installed —
|
|
@@ -659,7 +680,7 @@ export async function createProgram() {
|
|
|
659
680
|
for (const cmd of commands) {
|
|
660
681
|
try {
|
|
661
682
|
const mod = await import(cmd.path);
|
|
662
|
-
mod[cmd.register](program);
|
|
683
|
+
mod[cmd.register](program, {jsonSupported: JSON_SUPPORTED, version: pkg.version});
|
|
663
684
|
} catch (e) {
|
|
664
685
|
// Command fails to load but CLI still works
|
|
665
686
|
const reason = /** @type {any} */ (e).message;
|
|
@@ -679,84 +700,6 @@ export async function createProgram() {
|
|
|
679
700
|
}
|
|
680
701
|
}
|
|
681
702
|
|
|
682
|
-
// Capability manifest — a single, self-describing view of the whole CLI so
|
|
683
|
-
// agents can discover every command, argument, flag, and response type without
|
|
684
|
-
// scraping `--help`. `astryx manifest --json` is the dedicated surface; the bare
|
|
685
|
-
// `xds --json` embeds the same payload under data.manifest for convenience.
|
|
686
|
-
// Intentionally CLI-special — no `api/manifest`. It introspects the live
|
|
687
|
-
// Commander `program`, so extracting it to `api/` would create the `api → cli`
|
|
688
|
-
// cycle from #4302. `buildManifest(program)` lives in lib/; see its header.
|
|
689
|
-
const manifestCommand = program
|
|
690
|
-
.command('manifest')
|
|
691
|
-
.description('Print the full CLI capability manifest (use with --json)')
|
|
692
|
-
.action(() => {
|
|
693
|
-
const manifest = buildManifest(program, {
|
|
694
|
-
jsonSupported: JSON_SUPPORTED,
|
|
695
|
-
version: pkg.version,
|
|
696
|
-
});
|
|
697
|
-
// The manifest IS a result set: one entry per command the CLI ships.
|
|
698
|
-
debug.recordCommandResult(
|
|
699
|
-
debug.resultSet({
|
|
700
|
-
count: manifest.commands.length,
|
|
701
|
-
resultKind: 'command',
|
|
702
|
-
}),
|
|
703
|
-
);
|
|
704
|
-
if (program.opts().json) {
|
|
705
|
-
process.__xdsJsonHandled = true;
|
|
706
|
-
console.log(JSON.stringify({apiVersion: API_VERSION, type: 'manifest', data: manifest, meta: {answeredBy: answeredBy()}}, null, 2));
|
|
707
|
-
return;
|
|
708
|
-
}
|
|
709
|
-
// Human-readable summary as greppable records (agents should use --json).
|
|
710
|
-
// One record per command: name, whether it supports --json, and the
|
|
711
|
-
// description. Field names are the manifest entry's own keys.
|
|
712
|
-
emit(
|
|
713
|
-
section(`${manifest.name} v${manifest.version} (${manifest.commands.length} commands)`),
|
|
714
|
-
records(
|
|
715
|
-
manifest.commands.map(c => ({
|
|
716
|
-
name: c.name,
|
|
717
|
-
json: c.json ? 'yes' : '',
|
|
718
|
-
description: c.description || '',
|
|
719
|
-
})),
|
|
720
|
-
{fields: ['name', 'json', 'description']},
|
|
721
|
-
),
|
|
722
|
-
text(`Run \`${getCliInvocation()} manifest --json\` for the full structured manifest.`),
|
|
723
|
-
);
|
|
724
|
-
});
|
|
725
|
-
addDocHelp(manifestCommand, manifestDoc);
|
|
726
|
-
markReportsResult(manifestCommand);
|
|
727
|
-
|
|
728
|
-
// Hidden command used by package.json postinstall scripts
|
|
729
|
-
const postinstallCommand = program
|
|
730
|
-
.command('postinstall', {hidden: true})
|
|
731
|
-
.action(() => {
|
|
732
|
-
// Prints the welcome box. Nothing is looked up.
|
|
733
|
-
debug.recordCommandResult(debug.NO_RESULT_SET);
|
|
734
|
-
const r = getCliInvocation();
|
|
735
|
-
const pad = (/** @type {string} */ s, /** @type {number} */ len) => s + ' '.repeat(Math.max(0, len - s.length));
|
|
736
|
-
const W = 49; // inner width of the box
|
|
737
|
-
const line = (/** @type {string} */ s) => ` │ ${pad(s, W)}│`;
|
|
738
|
-
console.log(`
|
|
739
|
-
╭${'─'.repeat(W + 2)}╮
|
|
740
|
-
${line('')}
|
|
741
|
-
${line(' Design system installed!')}
|
|
742
|
-
${line('')}
|
|
743
|
-
${line(' Get started:')}
|
|
744
|
-
${line(` ${r} init Setup + AI agent docs`)}
|
|
745
|
-
${line(` ${r} --help See all commands`)}
|
|
746
|
-
${line('')}
|
|
747
|
-
${line(' Or run directly:')}
|
|
748
|
-
${line(` ${r} init Setup + AI agent docs`)}
|
|
749
|
-
${line(` ${r} component Browse component docs`)}
|
|
750
|
-
${line(` ${r} hook Browse hook docs`)}
|
|
751
|
-
${line(` ${r} docs Design system reference`)}
|
|
752
|
-
${line(` ${r} swizzle Customize a component`)}
|
|
753
|
-
${line(` ${r} template Add a page template`)}
|
|
754
|
-
${line('')}
|
|
755
|
-
╰${'─'.repeat(W + 2)}╯
|
|
756
|
-
`);
|
|
757
|
-
});
|
|
758
|
-
markReportsResult(postinstallCommand);
|
|
759
|
-
|
|
760
703
|
// Install the JSON shim AFTER all commands are registered so we can
|
|
761
704
|
// patch outputHelp on every command (root + subcommands). The shim
|
|
762
705
|
// extends the --json contract to cover Commander's parse-time short
|
|
@@ -21,7 +21,7 @@ import {getCliInvocation} from '../../../foundation/env/package-manager.mjs';
|
|
|
21
21
|
* (→ `.astryx-table-cell`), and `astryx-button` → key `button`.
|
|
22
22
|
*
|
|
23
23
|
* Keep the `astryx-` literal in sync with packages/core/src/naming.ts
|
|
24
|
-
* (NAMESPACE / classPrefix), the same way
|
|
24
|
+
* (NAMESPACE / classPrefix), the same way commands/theme.mjs mirrors it.
|
|
25
25
|
* <!-- SYNC: packages/core/src/naming.ts (namespace prefix source of truth) -->
|
|
26
26
|
* @param {import('@astryxdesign/cli/authoring').ComponentThemingTarget} target
|
|
27
27
|
* @returns {string}
|
|
@@ -63,10 +63,10 @@ export function reportsResultVia(cmd) {
|
|
|
63
63
|
/**
|
|
64
64
|
* Mark a hand-registered command as reporting its result.
|
|
65
65
|
*
|
|
66
|
-
* For
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
66
|
+
* For what does not come from a CommandDoc: the root program, and the stub
|
|
67
|
+
* left behind when a command module fails to load. Every command, `manifest`
|
|
68
|
+
* and the hidden `postinstall` hook included, registers through
|
|
69
|
+
* {@link defineCommand}. These call {@link recordCommandResult} themselves; this
|
|
70
70
|
* says so, and the coverage test pins the set of commands allowed to, so the
|
|
71
71
|
* mark cannot become a quiet way around the contract.
|
|
72
72
|
*
|
|
@@ -105,10 +105,12 @@ export function commandDocsOf(cmd) {
|
|
|
105
105
|
* fn?: import('@astryxdesign/cli/authoring').FunctionDoc,
|
|
106
106
|
* action?: (...args: any[]) => import('../../../foundation/debug/command-result.mjs').CommandResult
|
|
107
107
|
* | Promise<import('../../../foundation/debug/command-result.mjs').CommandResult>,
|
|
108
|
-
*
|
|
108
|
+
* hidden?: boolean,
|
|
109
|
+
* }} [impl] `hidden` keeps the command out of help and the manifest (a
|
|
110
|
+
* package-script hook, not a command for people or agents).
|
|
109
111
|
* @returns {import('commander').Command} the created command.
|
|
110
112
|
*/
|
|
111
|
-
export function defineCommand(parent, doc, {fn, action} = {}) {
|
|
113
|
+
export function defineCommand(parent, doc, {fn, action, hidden} = {}) {
|
|
112
114
|
// The command token is the last path segment ("theme build" -> "build"),
|
|
113
115
|
// since subcommands are added to their group command, not the program.
|
|
114
116
|
const token = doc.name.split(' ').pop() ?? doc.name;
|
|
@@ -119,7 +121,10 @@ export function defineCommand(parent, doc, {fn, action} = {}) {
|
|
|
119
121
|
})
|
|
120
122
|
.join(' ');
|
|
121
123
|
|
|
122
|
-
const cmd = parent.command(
|
|
124
|
+
const cmd = parent.command(
|
|
125
|
+
argSpec ? `${token} ${argSpec}` : token,
|
|
126
|
+
hidden ? {hidden: true} : {},
|
|
127
|
+
);
|
|
123
128
|
Object.defineProperty(cmd, COMMAND_DOCS, {value: {doc, fn}, configurable: true});
|
|
124
129
|
if (doc.summary) cmd.description(doc.summary);
|
|
125
130
|
if (doc.deprecated) {
|
|
@@ -24,6 +24,10 @@ for (const file of fs.readdirSync(COMMANDS).sort()) {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
const manifest = buildManifest(program, {jsonSupported: JSON_SUPPORTED, version: '0.0.0-test'});
|
|
27
|
+
/** Hidden commands (a package-script hook): documented, never in the manifest. */
|
|
28
|
+
const HIDDEN = new Set(
|
|
29
|
+
program.commands.filter((c) => /** @type {any} */ (c)._hidden).map((c) => c.name()),
|
|
30
|
+
);
|
|
27
31
|
/** @type {Map<string, any>} */
|
|
28
32
|
const entries = new Map();
|
|
29
33
|
const walk = (/** @type {any} */ c) => {
|
|
@@ -98,6 +102,7 @@ describe('command exit codes', () => {
|
|
|
98
102
|
|
|
99
103
|
it('the manifest carries every command exit code', () => {
|
|
100
104
|
for (const doc of commandDocs) {
|
|
105
|
+
if (HIDDEN.has(doc.name)) continue;
|
|
101
106
|
expect(entries.get(doc.name)?.exitCodes, doc.name).toEqual(
|
|
102
107
|
doc.exitCodes.map(({code, when}) => ({code, when})),
|
|
103
108
|
);
|
|
@@ -55,6 +55,10 @@ const CLI_LAYER_TYPES = {
|
|
|
55
55
|
};
|
|
56
56
|
|
|
57
57
|
const manifest = buildManifest(program, {jsonSupported: JSON_SUPPORTED, version: '0.0.0-test'});
|
|
58
|
+
/** Hidden commands (a package-script hook): documented, never in the manifest. */
|
|
59
|
+
const HIDDEN = new Set(
|
|
60
|
+
program.commands.filter((c) => /** @type {any} */ (c)._hidden).map((c) => c.name()),
|
|
61
|
+
);
|
|
58
62
|
|
|
59
63
|
/** Flatten the manifest command tree into fully-qualified names. */
|
|
60
64
|
function flatten(cmds, out = []) {
|
|
@@ -116,12 +120,19 @@ describe('manifest: drift guards', () => {
|
|
|
116
120
|
|
|
117
121
|
it('takes every command example from its CommandDoc', () => {
|
|
118
122
|
for (const [name, doc] of commandDocs) {
|
|
123
|
+
if (HIDDEN.has(name)) continue;
|
|
119
124
|
const entry = allEntries.find((c) => c.name === name);
|
|
120
125
|
expect(entry, `CommandDoc "${name}" has no manifest entry`).toBeDefined();
|
|
121
126
|
expect(entry.examples ?? [], name).toEqual((doc.examples ?? []).map((e) => e.cli));
|
|
122
127
|
}
|
|
123
128
|
});
|
|
124
129
|
|
|
130
|
+
it('documents the hidden postinstall hook and keeps it out of the manifest', () => {
|
|
131
|
+
expect([...HIDDEN]).toEqual(['postinstall']);
|
|
132
|
+
expect(commandDocs.has('postinstall')).toBe(true);
|
|
133
|
+
expect(allNames.has('postinstall')).toBe(false);
|
|
134
|
+
});
|
|
135
|
+
|
|
125
136
|
it('lists every response type the wrapped API function returns', () => {
|
|
126
137
|
for (const [name, doc] of commandDocs) {
|
|
127
138
|
if (!doc.fn) continue;
|
|
@@ -152,6 +163,7 @@ describe('manifest: drift guards', () => {
|
|
|
152
163
|
|
|
153
164
|
it('takes response types from the wrapped FunctionDoc, plus CLI-layer envelopes', () => {
|
|
154
165
|
for (const [name, doc] of commandDocs) {
|
|
166
|
+
if (HIDDEN.has(name)) continue;
|
|
155
167
|
const entry = allEntries.find((c) => c.name === name);
|
|
156
168
|
const returns = doc.fn ? functionDocs.get(doc.fn).returns.map((r) => r.type) : [];
|
|
157
169
|
const expected = [...returns, ...(CLI_LAYER_TYPES[name] ?? [])];
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file The welcome box `astryx postinstall` prints after the package installs.
|
|
5
|
+
*
|
|
6
|
+
* A fixed banner, not tabular output, so it is drawn here rather than with the
|
|
7
|
+
* formatter kit; the command prints it verbatim through `emit(code(...))`.
|
|
8
|
+
* @input The CLI invocation for this project (e.g. `pnpm exec astryx`).
|
|
9
|
+
* @output {@link welcomeBox}
|
|
10
|
+
* @position clients/cli/lib — presentation helper for commands/postinstall.mjs
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** Inner width of the box. */
|
|
14
|
+
const W = 49;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {string} s
|
|
18
|
+
* @param {number} len
|
|
19
|
+
*/
|
|
20
|
+
const pad = (s, len) => s + ' '.repeat(Math.max(0, len - s.length));
|
|
21
|
+
|
|
22
|
+
/** @param {string} s */
|
|
23
|
+
const line = s => ` │ ${pad(s, W)}│`;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The welcome box, with a blank line before and after it.
|
|
27
|
+
* @param {string} r the CLI invocation, e.g. `pnpm exec astryx`
|
|
28
|
+
* @returns {string}
|
|
29
|
+
*/
|
|
30
|
+
export function welcomeBox(r) {
|
|
31
|
+
return `
|
|
32
|
+
╭${'─'.repeat(W + 2)}╮
|
|
33
|
+
${line('')}
|
|
34
|
+
${line(' Design system installed!')}
|
|
35
|
+
${line('')}
|
|
36
|
+
${line(' Get started:')}
|
|
37
|
+
${line(` ${r} init Setup + AI agent docs`)}
|
|
38
|
+
${line(` ${r} --help See all commands`)}
|
|
39
|
+
${line('')}
|
|
40
|
+
${line(' Or run directly:')}
|
|
41
|
+
${line(` ${r} init Setup + AI agent docs`)}
|
|
42
|
+
${line(` ${r} component Browse component docs`)}
|
|
43
|
+
${line(` ${r} hook Browse hook docs`)}
|
|
44
|
+
${line(` ${r} docs Design system reference`)}
|
|
45
|
+
${line(` ${r} swizzle Customize a component`)}
|
|
46
|
+
${line(` ${r} template Add a page template`)}
|
|
47
|
+
${line('')}
|
|
48
|
+
╰${'─'.repeat(W + 2)}╯
|
|
49
|
+
`;
|
|
50
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file One run of the CLI, after the Node version gate: choose who answers
|
|
5
|
+
* the folder, hand the run off when that is another release (spec AST-081
|
|
6
|
+
* FR2, FR9), then dispatch the command.
|
|
7
|
+
*
|
|
8
|
+
* @input The arguments after `astryx`, read from `process.argv`; the CLI
|
|
9
|
+
* package root; and, for a run a programmatic host started, the reason the
|
|
10
|
+
* host declined the project's own CLI.
|
|
11
|
+
* @output The command's effects. The run owns the process: its exit status is
|
|
12
|
+
* `process.exitCode`, unless a hand-off or a failure exits the process.
|
|
13
|
+
* @position clients/cli — called by `bin/astryx.mjs` and by the host entry
|
|
14
|
+
* (`host/index.mjs`).
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Run the CLI once in this process.
|
|
19
|
+
*
|
|
20
|
+
* Every import here is dynamic: modules that load `styleText` must load only
|
|
21
|
+
* after the bin's Node version gate, and the release choice must run before
|
|
22
|
+
* the command modules load, so a run handed to another release loads none of
|
|
23
|
+
* them.
|
|
24
|
+
*
|
|
25
|
+
* @param {{cliRoot: string, argv: string[], declinedProjectCli?: string}} input
|
|
26
|
+
* @returns {Promise<import('../../host/index.js').HostedCliResult | undefined>}
|
|
27
|
+
* resolves when the command has finished; with another release's result
|
|
28
|
+
* when, in a hosted run, that release's host entry answered
|
|
29
|
+
*/
|
|
30
|
+
export async function runCli({cliRoot, argv, declinedProjectCli}) {
|
|
31
|
+
const {startRun} = await import('../../foundation/release/handoff.mjs');
|
|
32
|
+
const answered = await startRun({cliRoot, argv, declinedProjectCli});
|
|
33
|
+
if (answered) return answered;
|
|
34
|
+
|
|
35
|
+
const {
|
|
36
|
+
program,
|
|
37
|
+
loadProjectDebugHandler,
|
|
38
|
+
loadProjectForHelp,
|
|
39
|
+
handleVersionJsonPreflight,
|
|
40
|
+
} = await import('./index.mjs');
|
|
41
|
+
const {isJsonMode, toErrorEnvelope} =
|
|
42
|
+
await import('../../foundation/response/json.mjs');
|
|
43
|
+
const {handleCommanderError} = await import('./lib/json-shim.mjs');
|
|
44
|
+
const {setOutcome} = await import('../../foundation/debug/index.mjs');
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Top-level error boundary (contract guarantee #4): an uncaught throw must
|
|
48
|
+
* never reach a --json consumer as a raw stack trace. If we're in JSON mode,
|
|
49
|
+
* convert it to the contract's error envelope on stdout and exit 1;
|
|
50
|
+
* otherwise preserve the normal human-facing behavior.
|
|
51
|
+
*
|
|
52
|
+
* We detect JSON mode two ways: the global flag (set once root options are
|
|
53
|
+
* parsed) and a raw argv check, since a throw can occur during
|
|
54
|
+
* parsing/command load — before the preAction hook engages the flag.
|
|
55
|
+
*/
|
|
56
|
+
function inJsonMode() {
|
|
57
|
+
return isJsonMode() || process.argv.slice(2).includes('--json');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** @param {unknown} err */
|
|
61
|
+
function handleFatal(err) {
|
|
62
|
+
// CommanderError (parse errors, --help, unknown command) routes
|
|
63
|
+
// through the JSON shim so that a --json consumer always gets a
|
|
64
|
+
// valid envelope and the right exit code. handleCommanderError
|
|
65
|
+
// calls process.exit when it owns the error.
|
|
66
|
+
if (handleCommanderError(err)) return;
|
|
67
|
+
|
|
68
|
+
// Anything still here is an uncaught throw or an unhandled rejection —
|
|
69
|
+
// a bug rather than a user error, and the class of failure most worth
|
|
70
|
+
// having a record of.
|
|
71
|
+
setOutcome('fatal', {exitCode: 1, error: err});
|
|
72
|
+
|
|
73
|
+
if (inJsonMode()) {
|
|
74
|
+
// Only emit if a command didn't already produce an envelope.
|
|
75
|
+
if (!process.__xdsJsonHandled) {
|
|
76
|
+
process.__xdsJsonHandled = true;
|
|
77
|
+
console.log(JSON.stringify(toErrorEnvelope(err), null, 2));
|
|
78
|
+
}
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
// Human mode: preserve Commander/Node default-ish behavior.
|
|
82
|
+
console.error(
|
|
83
|
+
err instanceof Error ? err.stack || err.message : String(err),
|
|
84
|
+
);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
process.on('unhandledRejection', handleFatal);
|
|
89
|
+
process.on('uncaughtException', handleFatal);
|
|
90
|
+
|
|
91
|
+
// Pick up the project's `debug` function before parsing, so parse errors
|
|
92
|
+
// and `--help` — which short-circuit before any hook runs — are reported
|
|
93
|
+
// too.
|
|
94
|
+
await loadProjectDebugHandler();
|
|
95
|
+
// Help prints its commands while Commander parses, so a help run reads the
|
|
96
|
+
// project's declared `cliCommand` here.
|
|
97
|
+
await loadProjectForHelp();
|
|
98
|
+
|
|
99
|
+
// `--version --json` answers and exits without Commander, so it runs here —
|
|
100
|
+
// after the handler exists, or the run would go unrecorded.
|
|
101
|
+
handleVersionJsonPreflight();
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
await program.parseAsync(process.argv);
|
|
105
|
+
} catch (err) {
|
|
106
|
+
handleFatal(err);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -4,15 +4,25 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* Find all existing agent doc files in a directory, across EVERY location any
|
|
6
6
|
* preset can write (see {@link AGENT_DOC_PATHS}: AGENTS.md, CLAUDE.md,
|
|
7
|
-
* .claude/CLAUDE.md, .cursorrules, .hermes.md, HERMES.md).
|
|
7
|
+
* .claude/CLAUDE.md, GEMINI.md, .cursorrules, .hermes.md, HERMES.md).
|
|
8
8
|
* @param {string} targetDir
|
|
9
9
|
* @returns {string[]} Relative paths of existing agent doc files
|
|
10
10
|
*/
|
|
11
11
|
export function discoverAgentDocs(targetDir: string): string[];
|
|
12
|
+
/**
|
|
13
|
+
* Whether `content` holds an Astryx block. A managed block that only imports
|
|
14
|
+
* another file (the one-line `@./AGENTS.md` that init writes to GEMINI.md) does
|
|
15
|
+
* not count: it holds nothing once that file has lost its block. A malformed
|
|
16
|
+
* block still counts, so a half-written file reads as set up.
|
|
17
|
+
*
|
|
18
|
+
* @param {string} content
|
|
19
|
+
* @returns {boolean}
|
|
20
|
+
*/
|
|
21
|
+
export function holdsAstryxBlock(content: string): boolean;
|
|
12
22
|
/**
|
|
13
23
|
* Single source of truth for "is Astryx set up in this project?" — true when any
|
|
14
|
-
* agent-doc file already
|
|
15
|
-
*
|
|
24
|
+
* agent-doc file already holds an Astryx block, i.e. `init` / `agent-docs` has
|
|
25
|
+
* run. Reused by the init & upgrade commands, the per-command setup nudge
|
|
16
26
|
* (enforcement layer 3), and the cli postinstall nudge (layer 2). Core's
|
|
17
27
|
* postinstall (separate package, layer 1) mirrors the same marker contract.
|
|
18
28
|
*
|
|
@@ -68,6 +78,7 @@ export function shouldNudge({ scriptPath, npmCommand, isSetUp }?: {
|
|
|
68
78
|
export const AGENTS_MD: "AGENTS.md";
|
|
69
79
|
export const CLAUDE_MD: "CLAUDE.md";
|
|
70
80
|
export const CLAUDE_DIR_MD: ".claude/CLAUDE.md";
|
|
81
|
+
export const GEMINI_MD: "GEMINI.md";
|
|
71
82
|
export const CURSOR_RULES: ".cursorrules";
|
|
72
83
|
export const HERMES_DOT_MD: ".hermes.md";
|
|
73
84
|
export const HERMES_MD: "HERMES.md";
|
|
@@ -77,10 +88,12 @@ export const LEGACY_MARKER_START: "<!-- XDS:START -->";
|
|
|
77
88
|
export const LEGACY_MARKER_END: "<!-- XDS:END -->";
|
|
78
89
|
/**
|
|
79
90
|
* The canonical set of EVERY location an --agent preset (or the default) can
|
|
80
|
-
* write
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
91
|
+
* write a managed Astryx block — the full block, or the one-line import of
|
|
92
|
+
* AGENTS.md that the default writes to GEMINI.md. SINGLE
|
|
93
|
+
* SOURCE OF TRUTH: discovery, removal, and the `isAstryxInitialized` predicate
|
|
94
|
+
* all derive from this list, so "where init writes" and "where we look" can
|
|
95
|
+
* never drift. (Explicit --agent-docs-path targets are user-chosen and not
|
|
96
|
+
* enumerable here.)
|
|
84
97
|
*/
|
|
85
98
|
export const AGENT_DOC_PATHS: string[];
|
|
86
99
|
/**
|
|
@@ -29,6 +29,7 @@ import * as path from 'node:path';
|
|
|
29
29
|
export const AGENTS_MD = 'AGENTS.md';
|
|
30
30
|
export const CLAUDE_MD = 'CLAUDE.md';
|
|
31
31
|
export const CLAUDE_DIR_MD = '.claude/CLAUDE.md'; // cross-platform literal
|
|
32
|
+
export const GEMINI_MD = 'GEMINI.md';
|
|
32
33
|
export const CURSOR_RULES = '.cursorrules';
|
|
33
34
|
export const HERMES_DOT_MD = '.hermes.md';
|
|
34
35
|
export const HERMES_MD = 'HERMES.md';
|
|
@@ -41,15 +42,18 @@ export const LEGACY_MARKER_END = '<!-- XDS:END -->';
|
|
|
41
42
|
|
|
42
43
|
/**
|
|
43
44
|
* The canonical set of EVERY location an --agent preset (or the default) can
|
|
44
|
-
* write
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
45
|
+
* write a managed Astryx block — the full block, or the one-line import of
|
|
46
|
+
* AGENTS.md that the default writes to GEMINI.md. SINGLE
|
|
47
|
+
* SOURCE OF TRUTH: discovery, removal, and the `isAstryxInitialized` predicate
|
|
48
|
+
* all derive from this list, so "where init writes" and "where we look" can
|
|
49
|
+
* never drift. (Explicit --agent-docs-path targets are user-chosen and not
|
|
50
|
+
* enumerable here.)
|
|
48
51
|
*/
|
|
49
52
|
export const AGENT_DOC_PATHS = [
|
|
50
53
|
AGENTS_MD, // Codex / ChatGPT / Muse / generic
|
|
51
54
|
CLAUDE_MD, // Claude Code (root)
|
|
52
55
|
CLAUDE_DIR_MD, // Claude Code (.claude/CLAUDE.md)
|
|
56
|
+
GEMINI_MD, // Gemini CLI
|
|
53
57
|
CURSOR_RULES, // Cursor
|
|
54
58
|
HERMES_DOT_MD, // Hermes
|
|
55
59
|
HERMES_MD, // Hermes
|
|
@@ -64,7 +68,7 @@ export const INIT_MARKERS = [MARKER_START, LEGACY_MARKER_START];
|
|
|
64
68
|
/**
|
|
65
69
|
* Find all existing agent doc files in a directory, across EVERY location any
|
|
66
70
|
* preset can write (see {@link AGENT_DOC_PATHS}: AGENTS.md, CLAUDE.md,
|
|
67
|
-
* .claude/CLAUDE.md, .cursorrules, .hermes.md, HERMES.md).
|
|
71
|
+
* .claude/CLAUDE.md, GEMINI.md, .cursorrules, .hermes.md, HERMES.md).
|
|
68
72
|
* @param {string} targetDir
|
|
69
73
|
* @returns {string[]} Relative paths of existing agent doc files
|
|
70
74
|
*/
|
|
@@ -72,10 +76,33 @@ export function discoverAgentDocs(targetDir) {
|
|
|
72
76
|
return AGENT_DOC_PATHS.filter(p => fs.existsSync(path.join(targetDir, p)));
|
|
73
77
|
}
|
|
74
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Whether `content` holds an Astryx block. A managed block that only imports
|
|
81
|
+
* another file (the one-line `@./AGENTS.md` that init writes to GEMINI.md) does
|
|
82
|
+
* not count: it holds nothing once that file has lost its block. A malformed
|
|
83
|
+
* block still counts, so a half-written file reads as set up.
|
|
84
|
+
*
|
|
85
|
+
* @param {string} content
|
|
86
|
+
* @returns {boolean}
|
|
87
|
+
*/
|
|
88
|
+
export function holdsAstryxBlock(content) {
|
|
89
|
+
for (const marker of INIT_MARKERS) {
|
|
90
|
+
let at = content.indexOf(marker);
|
|
91
|
+
while (at !== -1) {
|
|
92
|
+
const from = at + marker.length;
|
|
93
|
+
const end = content.indexOf('<!--', from);
|
|
94
|
+
const inner = (end === -1 ? content.slice(from) : content.slice(from, end)).trim();
|
|
95
|
+
if (!/^@\S+$/.test(inner)) return true;
|
|
96
|
+
at = content.indexOf(marker, from);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
|
|
75
102
|
/**
|
|
76
103
|
* Single source of truth for "is Astryx set up in this project?" — true when any
|
|
77
|
-
* agent-doc file already
|
|
78
|
-
*
|
|
104
|
+
* agent-doc file already holds an Astryx block, i.e. `init` / `agent-docs` has
|
|
105
|
+
* run. Reused by the init & upgrade commands, the per-command setup nudge
|
|
79
106
|
* (enforcement layer 3), and the cli postinstall nudge (layer 2). Core's
|
|
80
107
|
* postinstall (separate package, layer 1) mirrors the same marker contract.
|
|
81
108
|
*
|
|
@@ -86,7 +113,7 @@ export function isAstryxInitialized(targetDir = process.cwd()) {
|
|
|
86
113
|
for (const rel of discoverAgentDocs(targetDir)) {
|
|
87
114
|
try {
|
|
88
115
|
const content = fs.readFileSync(path.join(targetDir, rel), 'utf-8');
|
|
89
|
-
if (
|
|
116
|
+
if (holdsAstryxBlock(content)) {
|
|
90
117
|
return true;
|
|
91
118
|
}
|
|
92
119
|
} catch {
|