@astryxdesign/cli 0.3.0-canary.c857354 → 0.3.0-canary.d52d2cb

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.
Files changed (129) hide show
  1. package/api/component/_adapter.mjs +3 -0
  2. package/api/integration/validate-integration.d.mts +2 -18
  3. package/api/integration/validate-integration.mjs +16 -141
  4. package/api/template/copy/copy.d.mts +2 -2
  5. package/api/template/copy/copy.mjs +2 -2
  6. package/api/template/list/list.d.mts +2 -2
  7. package/api/template/list/list.mjs +2 -2
  8. package/api/template/show/show.d.mts +2 -2
  9. package/api/template/show/show.mjs +2 -2
  10. package/api/template/skeleton/skeleton.d.mts +3 -3
  11. package/api/template/skeleton/skeleton.mjs +3 -3
  12. package/api/template/template.d.mts +7 -7
  13. package/api/template/template.mjs +7 -7
  14. package/api/template/template.test.mjs +12 -13
  15. package/assets/codemods/transforms/v0.3.0/__tests__/migrate-grid-minchildwidth-to-columns.test.mjs +82 -0
  16. package/assets/codemods/transforms/v0.3.0/migrate-grid-minchildwidth-to-columns.mjs +38 -2
  17. package/assets/docs/layout.doc.dense.mjs +1 -1
  18. package/assets/templates/blocks/components/AspectRatio/AspectRatioCircleImage.tsx +1 -1
  19. package/assets/templates/blocks/components/AspectRatio/AspectRatioImageGallery.tsx +1 -1
  20. package/assets/templates/blocks/components/AspectRatio/AspectRatioShowcase.tsx +3 -3
  21. package/assets/templates/blocks/components/AspectRatio/AspectRatioSquareImage.tsx +1 -1
  22. package/assets/templates/blocks/components/AspectRatio/AspectRatioWidescreen.tsx +1 -1
  23. package/assets/templates/blocks/components/Avatar/AvatarFallbackChain.tsx +6 -6
  24. package/assets/templates/blocks/components/Avatar/AvatarGroup.tsx +5 -5
  25. package/assets/templates/blocks/components/Avatar/AvatarInteractive.tsx +2 -2
  26. package/assets/templates/blocks/components/Avatar/AvatarShowcase.tsx +4 -4
  27. package/assets/templates/blocks/components/Avatar/AvatarTooltip.tsx +4 -4
  28. package/assets/templates/blocks/components/Avatar/AvatarUserCard.tsx +3 -3
  29. package/assets/templates/blocks/components/Avatar/AvatarWithImage.tsx +4 -4
  30. package/assets/templates/blocks/components/Avatar/AvatarWithStatus.tsx +3 -3
  31. package/assets/templates/blocks/components/ChatComposerDrawer/ChatComposerDrawerAttachments.tsx +5 -5
  32. package/assets/templates/blocks/components/Lightbox/LightboxGallery.tsx +4 -4
  33. package/assets/templates/blocks/components/Lightbox/LightboxShowcase.tsx +1 -1
  34. package/assets/templates/blocks/components/Lightbox/LightboxVideo.tsx +1 -1
  35. package/assets/templates/blocks/components/Lightbox/LightboxZoom.tsx +2 -2
  36. package/assets/templates/blocks/components/MediaTheme/MediaThemeImageOverlay.tsx +1 -1
  37. package/assets/templates/blocks/components/MediaTheme/MediaThemeLightScrim.tsx +1 -1
  38. package/assets/templates/blocks/components/MediaTheme/MediaThemeShowcase.tsx +1 -1
  39. package/assets/templates/blocks/components/Overlay/OverlayBottomStrip.tsx +1 -1
  40. package/assets/templates/blocks/components/Overlay/OverlayHoverReveal.tsx +1 -1
  41. package/assets/templates/blocks/components/Overlay/OverlayShowcase.tsx +1 -1
  42. package/assets/templates/blocks/components/TopNav/TopNavMegaMenu.tsx +1 -1
  43. package/assets/templates/pages/centered-hero/page.tsx +1 -1
  44. package/assets/templates/pages/classic-gallery/page.tsx +10 -10
  45. package/assets/templates/pages/detail-page/page.tsx +5 -5
  46. package/assets/templates/pages/form-two-column/page.tsx +1 -1
  47. package/assets/templates/pages/gallery-hero/page.tsx +3 -3
  48. package/assets/templates/pages/library/page.tsx +30 -30
  49. package/assets/templates/pages/login/page.tsx +1 -2
  50. package/assets/templates/pages/login-card/page.tsx +1 -2
  51. package/assets/templates/pages/login-split/page.tsx +5 -6
  52. package/assets/templates/pages/login-sso/page.tsx +2 -3
  53. package/assets/templates/pages/mixed-gallery/page.tsx +5 -5
  54. package/assets/templates/pages/payment-form/page.tsx +3 -3
  55. package/assets/templates/pages/product-detail/page.tsx +7 -7
  56. package/assets/templates/pages/product-gallery/page.tsx +6 -6
  57. package/assets/templates/pages/shell-top-nav/page.tsx +2 -2
  58. package/assets/templates/pages/side-gallery/page.tsx +9 -9
  59. package/assets/templates/pages/table-page-chart/page.tsx +6 -6
  60. package/assets/templates/pages/theme-showcase/page.tsx +6 -6
  61. package/authoring/_shared/errors.d.mts +21 -0
  62. package/authoring/codemod/codemod.doc.d.mts +11 -0
  63. package/authoring/codemod/parse.d.mts +48 -2
  64. package/authoring/config/config.doc.d.mts +10 -0
  65. package/authoring/config/parse.d.mts +54 -2
  66. package/authoring/doctypes/_schema.d.mts +248 -0
  67. package/authoring/doctypes/base/type.ts +6 -0
  68. package/authoring/doctypes/command/command.doc.d.mts +12 -0
  69. package/authoring/doctypes/command/parse.d.mts +11 -2
  70. package/authoring/doctypes/component/component.doc.d.mts +11 -0
  71. package/authoring/doctypes/component/parse.d.mts +11 -2
  72. package/authoring/doctypes/enum/enum.doc.d.mts +11 -0
  73. package/authoring/doctypes/enum/parse.d.mts +11 -2
  74. package/authoring/doctypes/function/function.doc.d.mts +11 -0
  75. package/authoring/doctypes/function/parse.d.mts +11 -2
  76. package/authoring/doctypes/function/parse.mjs +24 -4
  77. package/authoring/doctypes/hook/hook.doc.d.mts +10 -0
  78. package/authoring/doctypes/hook/parse.d.mts +11 -2
  79. package/authoring/doctypes/legacy.d.mts +13 -2
  80. package/authoring/doctypes/parse.d.mts +29 -20
  81. package/authoring/doctypes/reference/parse.d.mts +11 -2
  82. package/authoring/doctypes/reference/reference.doc.d.mts +11 -0
  83. package/authoring/doctypes/schema/parse.d.mts +11 -2
  84. package/authoring/doctypes/schema/schema.doc.d.mts +11 -0
  85. package/authoring/doctypes/template/parse.d.mts +12 -2
  86. package/authoring/doctypes/template/template.doc.d.mts +11 -0
  87. package/authoring/index.d.mts +16 -0
  88. package/authoring/integration/integration.doc.d.mts +10 -0
  89. package/authoring/integration/parse.d.mts +30 -2
  90. package/clients/cli/commands/hook.doc.mjs +1 -1
  91. package/clients/cli/lib/manifest.mjs +1 -1
  92. package/foundation/agent-docs/agent-docs.d.mts +197 -0
  93. package/foundation/agent-docs/agent-docs.mjs +3 -4
  94. package/foundation/agent-docs/agent-docs.test.mjs +8 -0
  95. package/foundation/config/config-cache.d.mts +53 -0
  96. package/foundation/config/project.d.mts +154 -0
  97. package/foundation/config/project.mjs +3 -3
  98. package/foundation/discovery/component-discovery.d.mts +140 -0
  99. package/foundation/discovery/component-loader.d.mts +50 -0
  100. package/foundation/discovery/hook-discovery.d.mts +28 -0
  101. package/{api/template/_adapter.d.mts → foundation/discovery/template-adapter.d.mts} +1 -1
  102. package/{api/template/_adapter.mjs → foundation/discovery/template-adapter.mjs} +28 -19
  103. package/foundation/env/node-version.d.mts +52 -0
  104. package/foundation/env/package-manager.d.mts +84 -0
  105. package/foundation/env/semver.d.mts +56 -0
  106. package/foundation/fs/module-loader.d.mts +36 -0
  107. package/foundation/fs/path-safety.d.mts +74 -0
  108. package/foundation/fs/paths.d.mts +35 -0
  109. package/foundation/integrations/integration-warnings.d.mts +17 -0
  110. package/foundation/integrations/integration-warnings.mjs +1 -1
  111. package/foundation/integrations/integrations.d.mts +80 -0
  112. package/foundation/integrations/validate-contributions.d.mts +22 -0
  113. package/foundation/integrations/validate-contributions.mjs +162 -0
  114. package/foundation/response/error-codes.d.mts +103 -0
  115. package/foundation/response/error-codes.doc.d.mts +11 -0
  116. package/foundation/response/json.d.mts +75 -0
  117. package/foundation/response/response-types.doc.d.mts +12 -0
  118. package/foundation/response/response.doc.d.mts +11 -0
  119. package/foundation/text/levenshtein.d.mts +21 -0
  120. package/foundation/text/string-utils.d.mts +43 -0
  121. package/foundation/xle/browser.d.mts +89 -0
  122. package/foundation/xle/expand.d.mts +23 -0
  123. package/foundation/xle/parse.d.mts +72 -0
  124. package/foundation/xle/print.d.mts +7 -0
  125. package/foundation/xle/registry-core.d.mts +168 -0
  126. package/foundation/xle/registry.d.mts +19 -0
  127. package/foundation/xle/splice.d.mts +42 -0
  128. package/foundation/xle/validate.d.mts +94 -0
  129. package/package.json +9 -9
@@ -19,7 +19,7 @@
19
19
  * ADDS a one-line nudge.
20
20
  */
21
21
 
22
- import {validateLoadedIntegration} from '../../api/integration/validate-integration.mjs';
22
+ import {validateLoadedIntegration} from './validate-contributions.mjs';
23
23
 
24
24
  /**
25
25
  * For each configured (already-loaded) integration, compute its issues using
@@ -0,0 +1,80 @@
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
+ * Return the conventional root manifest paths present in `dir`, in
6
+ * load-precedence order. Unlike {@link resolveManifestPath} this never throws —
7
+ * callers (e.g. validate-integration) decide how to treat zero / multiple.
8
+ * @param {string} dir
9
+ * @returns {string[]} absolute manifest paths
10
+ */
11
+ export function findManifestPaths(dir: string): string[];
12
+ /**
13
+ * Load and validate a manifest module's default export against the integration
14
+ * schema. Default export only — `.ts` is loaded via jiti; `.mjs`/`.js` via
15
+ * dynamic import. Throws if the default export is missing or invalid. Exposed
16
+ * for validate-integration.
17
+ * @param {string} file absolute manifest path
18
+ * @param {string} [label] used in error messages
19
+ * @returns {Promise<import('../../authoring/integration/type').AstryxIntegration>}
20
+ */
21
+ export function loadManifestObject(file: string, label?: string): Promise<import("../../authoring/integration/type").AstryxIntegration>;
22
+ /**
23
+ * Resolve the directory of an installed integration package from the consumer's
24
+ * node_modules.
25
+ * @param {string} packageName
26
+ * @param {string} [cwd]
27
+ */
28
+ export function resolvePackageDir(packageName: string, cwd?: string): string;
29
+ /**
30
+ * Load configured integrations.
31
+ *
32
+ * @param {string[]} [specs] package names
33
+ * @param {{cwd?: string}} [options]
34
+ * @returns {Promise<LoadedIntegration[]>}
35
+ */
36
+ export function loadIntegrations(specs?: string[], { cwd }?: {
37
+ cwd?: string;
38
+ }): Promise<LoadedIntegration[]>;
39
+ /**
40
+ * A fully-resolved, loaded integration. Identity (`name`, `version`) comes from
41
+ * the package's package.json; the `components`/`templates`/`codemods` roots are
42
+ * absolute paths resolved from the manifest. The `__`-prefixed fields are
43
+ * internal bookkeeping used by validate-integration and Project.
44
+ * @typedef {object} LoadedIntegration
45
+ * @property {string} name
46
+ * @property {string} [version]
47
+ * @property {string} [components]
48
+ * @property {string} [templates]
49
+ * @property {string} [codemods]
50
+ * @property {string} [issuesUrl]
51
+ * @property {string} __spec
52
+ * @property {string} __packageDir
53
+ * @property {string} __manifestFile
54
+ * @property {string} [__loadError] set when the manifest failed to load/validate;
55
+ * such an integration contributes nothing and is surfaced via Project.issues()
56
+ */
57
+ /** Conventional manifest basenames, in load-precedence order. */
58
+ export const MANIFEST_BASENAMES: string[];
59
+ /**
60
+ * A fully-resolved, loaded integration. Identity (`name`, `version`) comes from
61
+ * the package's package.json; the `components`/`templates`/`codemods` roots are
62
+ * absolute paths resolved from the manifest. The `__`-prefixed fields are
63
+ * internal bookkeeping used by validate-integration and Project.
64
+ */
65
+ export type LoadedIntegration = {
66
+ name: string;
67
+ version?: string | undefined;
68
+ components?: string | undefined;
69
+ templates?: string | undefined;
70
+ codemods?: string | undefined;
71
+ issuesUrl?: string | undefined;
72
+ __spec: string;
73
+ __packageDir: string;
74
+ __manifestFile: string;
75
+ /**
76
+ * set when the manifest failed to load/validate;
77
+ * such an integration contributes nothing and is surfaced via Project.issues()
78
+ */
79
+ __loadError?: string | undefined;
80
+ };
@@ -0,0 +1,22 @@
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
+ * @typedef {import('./issue').AstryxIntegrationIssue} Issue
6
+ * @typedef {import('./integrations.mjs').LoadedIntegration} LoadedIntegration
7
+ */
8
+ /** @param {string} code @param {string} message @returns {Issue} */
9
+ export function issueError(code: string, message: string): Issue;
10
+ /**
11
+ * Validate an already-LOADED integration (as produced by `loadIntegrations` —
12
+ * absolute contribution roots plus identity) and return its issues. This is the
13
+ * reuse seam for everyday commands that have already loaded the configured
14
+ * integrations and want the SAME validators that `validate-integration` runs,
15
+ * without re-resolving the manifest from disk.
16
+ *
17
+ * @param {LoadedIntegration} loaded loaded-integration-shaped object
18
+ * @returns {Promise<Issue[]>}
19
+ */
20
+ export function validateLoadedIntegration(loaded: LoadedIntegration): Promise<Issue[]>;
21
+ export type Issue = import("./issue").AstryxIntegrationIssue;
22
+ export type LoadedIntegration = import("./integrations.mjs").LoadedIntegration;
@@ -0,0 +1,162 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file On-disk contribution checks for a LOADED integration.
5
+ *
6
+ * These validators live in foundation rather than beside the
7
+ * `validate-integration` command because foundation itself needs them:
8
+ * `Project` collects integration issues while assembling components/templates,
9
+ * and `integration-warnings` nudges about them on ordinary commands. Keeping
10
+ * them here means those callers no longer reach up into `api/`.
11
+ *
12
+ * The manifest schema is NOT re-validated here — `loadIntegrations` already did
13
+ * that and throws otherwise. What is re-checked is the on-disk contributions
14
+ * (roots + codemods/templates/components), because those regress independently
15
+ * of the manifest: a deleted directory, a template that lost its source file.
16
+ *
17
+ * @input a loaded-integration-shaped object (absolute contribution roots + identity)
18
+ * @output AstryxIntegrationIssue[]
19
+ * @position packages/cli/foundation/integrations — shared contribution validators
20
+ */
21
+
22
+ import * as fs from 'node:fs';
23
+ import {discoverIntegrationCodemods} from '../../assets/codemods/integration-discovery.mjs';
24
+ import {discoverIntegrationTemplatesForOne} from '../discovery/template-adapter.mjs';
25
+ import * as componentDiscovery from '../discovery/component-discovery.mjs';
26
+
27
+ /**
28
+ * @typedef {import('./issue').AstryxIntegrationIssue} Issue
29
+ * @typedef {import('./integrations.mjs').LoadedIntegration} LoadedIntegration
30
+ */
31
+
32
+ /** @param {string} code @param {string} message @returns {Issue} */
33
+ export function issueError(code, message) {
34
+ return {code, severity: 'error', message};
35
+ }
36
+
37
+ /**
38
+ * Verify each declared contribution root exists on disk. A declared-but-missing
39
+ * root is a `missing_root` error.
40
+ * @param {{components?: string, templates?: string, codemods?: string}} resolved
41
+ * absolute resolved roots (undefined when not declared)
42
+ * @param {Issue[]} issues
43
+ */
44
+ function checkRoots(resolved, issues) {
45
+ const kinds = /** @type {const} */ (['components', 'templates', 'codemods']);
46
+ for (const kind of kinds) {
47
+ const root = resolved[kind];
48
+ if (root == null) continue;
49
+ if (!fs.existsSync(root)) {
50
+ issues.push(
51
+ issueError(
52
+ 'missing_root',
53
+ `Declared ${kind} root does not exist on disk: ${root}`,
54
+ ),
55
+ );
56
+ }
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Validate the integration's codemods via the landed discovery. Discovery is
62
+ * strict (throws on bad export / duplicate id); we convert any throw into an
63
+ * `invalid_codemod` error.
64
+ * @param {LoadedIntegration} integration loaded-integration-shaped object
65
+ * @param {Issue[]} issues
66
+ */
67
+ async function checkCodemods(integration, issues) {
68
+ if (!integration.codemods || !fs.existsSync(integration.codemods)) return;
69
+ try {
70
+ await discoverIntegrationCodemods([integration]);
71
+ } catch (err) {
72
+ issues.push(issueError('invalid_codemod', /** @type {any} */ (err).message));
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Validate the integration's templates via the landed discovery. Per-template
78
+ * problems are reported as `invalid_template` errors.
79
+ * @param {LoadedIntegration} integration loaded-integration-shaped object
80
+ * @param {Issue[]} issues
81
+ */
82
+ async function checkTemplates(integration, issues) {
83
+ if (!integration.templates || !fs.existsSync(integration.templates)) return;
84
+ try {
85
+ const {errors} = await discoverIntegrationTemplatesForOne(integration);
86
+ for (const e of errors) {
87
+ issues.push(issueError('invalid_template', e.message));
88
+ }
89
+ } catch (err) {
90
+ issues.push(issueError('invalid_template', /** @type {any} */ (err).message));
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Validate the integration's components via the landed ownership discovery.
96
+ * Feature-detected: if the component-ownership export isn't present in this
97
+ * build (sibling PR not yet merged), component validation is skipped rather
98
+ * than hard-failing.
99
+ *
100
+ * `discoverIntegrationComponents` returns ownership records and does not throw
101
+ * on a missing same-stem source — it records `sourcePath: null`. We surface
102
+ * each such record as an `invalid_component` error.
103
+ * @param {LoadedIntegration} integration loaded-integration-shaped object
104
+ * @param {Issue[]} issues
105
+ */
106
+ async function checkComponents(integration, issues) {
107
+ if (!integration.components || !fs.existsSync(integration.components)) return;
108
+ const discover = componentDiscovery.discoverIntegrationComponents;
109
+ if (typeof discover !== 'function') return; // feature not present yet
110
+ try {
111
+ const records = (await discover(integration)) ?? [];
112
+ for (const record of records) {
113
+ if (record?.sourcePath == null) {
114
+ issues.push(
115
+ issueError(
116
+ 'invalid_component',
117
+ `Component "${record?.name}" is missing its same-stem source file ${record?.name}.tsx.`,
118
+ ),
119
+ );
120
+ }
121
+ }
122
+ } catch (err) {
123
+ issues.push(issueError('invalid_component', /** @type {any} */ (err).message));
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Run every contribution validator against a loaded-integration-shaped object.
129
+ * @param {LoadedIntegration} integration
130
+ * @param {Issue[]} issues
131
+ */
132
+ async function runContributionChecks(integration, issues) {
133
+ await checkCodemods(integration, issues);
134
+ await checkTemplates(integration, issues);
135
+ await checkComponents(integration, issues);
136
+ }
137
+
138
+ /**
139
+ * Validate an already-LOADED integration (as produced by `loadIntegrations` —
140
+ * absolute contribution roots plus identity) and return its issues. This is the
141
+ * reuse seam for everyday commands that have already loaded the configured
142
+ * integrations and want the SAME validators that `validate-integration` runs,
143
+ * without re-resolving the manifest from disk.
144
+ *
145
+ * @param {LoadedIntegration} loaded loaded-integration-shaped object
146
+ * @returns {Promise<Issue[]>}
147
+ */
148
+ export async function validateLoadedIntegration(loaded) {
149
+ /** @type {Issue[]} */
150
+ const issues = [];
151
+ if (!loaded || typeof loaded !== 'object') return issues;
152
+ checkRoots(
153
+ {
154
+ components: loaded.components,
155
+ templates: loaded.templates,
156
+ codemods: loaded.codemods,
157
+ },
158
+ issues,
159
+ );
160
+ await runContributionChecks(loaded, issues);
161
+ return issues;
162
+ }
@@ -0,0 +1,103 @@
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
+ * Type guard: is `value` one of the known error codes?
6
+ * @param {unknown} value
7
+ * @returns {value is ErrorCode}
8
+ */
9
+ export function isErrorCode(value: unknown): value is ErrorCode;
10
+ /**
11
+ * All error code string values, sorted. Handy for tests and tooling.
12
+ * @returns {string[]}
13
+ */
14
+ export function allErrorCodes(): string[];
15
+ /**
16
+ * @file Astryx CLI — stable machine-readable error codes.
17
+ *
18
+ * ## Why codes exist
19
+ *
20
+ * The JSON error envelope (see json.mjs) carries a human-readable `error`
21
+ * string. That string is for people. It changes whenever we improve the
22
+ * wording, add detail, or localize. AI agents and CI scripts that consume
23
+ * `xds --json` must NOT branch on prose — string-matching "No component
24
+ * named X" is brittle and silently breaks the moment we reword it.
25
+ *
26
+ * The `code` field is the stable contract. Every error — whether raised by a
27
+ * command, the API layer (`AstryxError`), or Commander's own parse machinery —
28
+ * carries one of the identifiers below. Codes are append-only: once shipped,
29
+ * a code's meaning never changes and the code is never removed. The message
30
+ * may change freely; the code never does.
31
+ *
32
+ * ## Naming
33
+ *
34
+ * `ERR_<SUBJECT>[_<QUALIFIER>]`, SCREAMING_SNAKE_CASE, always prefixed
35
+ * `ERR_`. Group by subject (component, hook, docs, template, theme, …).
36
+ *
37
+ * ## Usage
38
+ *
39
+ * import {ERROR_CODES} from './error-codes.mjs';
40
+ * cliError('No component named "Buton"', {code: ERROR_CODES.ERR_UNKNOWN_COMPONENT});
41
+ * throw new AstryxError('No component named "Buton"', suggestions, ERROR_CODES.ERR_UNKNOWN_COMPONENT);
42
+ *
43
+ * Consumers read `envelope.code` and compare against the published list in
44
+ * packages/cli/README.md.
45
+ */
46
+ /**
47
+ * Stable error-code string union. Append-only.
48
+ *
49
+ * @typedef {(
50
+ * | 'ERR_UNKNOWN'
51
+ * | 'ERR_UNKNOWN_COMMAND'
52
+ * | 'ERR_UNKNOWN_SUBCOMMAND'
53
+ * | 'ERR_INVALID_OPTION'
54
+ * | 'ERR_INVALID_ARGUMENT'
55
+ * | 'ERR_MISSING_ARGUMENT'
56
+ * | 'ERR_INVALID_LANG'
57
+ * | 'ERR_INVALID_DETAIL'
58
+ * | 'ERR_NODE_VERSION'
59
+ * | 'ERR_CORE_NOT_FOUND'
60
+ * | 'ERR_UNKNOWN_COMPONENT'
61
+ * | 'ERR_UNKNOWN_HOOK'
62
+ * | 'ERR_UNKNOWN_TOPIC'
63
+ * | 'ERR_UNKNOWN_SECTION'
64
+ * | 'ERR_UNKNOWN_CATEGORY'
65
+ * | 'ERR_UNKNOWN_TEMPLATE'
66
+ * | 'ERR_AMBIGUOUS_TEMPLATE'
67
+ * | 'ERR_AMBIGUOUS_COMPONENT'
68
+ * | 'ERR_UNKNOWN_THEME'
69
+ * | 'ERR_UNKNOWN_PACKAGE'
70
+ * | 'ERR_UNKNOWN_AGENT'
71
+ * | 'ERR_UNKNOWN_FEATURE'
72
+ * | 'ERR_UNKNOWN_CODEMOD'
73
+ | 'ERR_CODEMOD_FAILED'
74
+ * | 'ERR_NOT_FOUND'
75
+ * | 'ERR_NO_DOC'
76
+ * | 'ERR_NO_SHOWCASE'
77
+ * | 'ERR_NO_SOURCE'
78
+ * | 'ERR_INVALID_DOC'
79
+ * | 'ERR_FILE_NOT_FOUND'
80
+ * | 'ERR_FILE_EXISTS'
81
+ * | 'ERR_PATH_TRAVERSAL'
82
+ * | 'ERR_WRITE_FAILED'
83
+ * | 'ERR_THEME_INVALID'
84
+ * | 'ERR_THEME_LOAD'
85
+ * | 'ERR_VERSION_DETECT'
86
+ * | 'ERR_INVALID_VERSION'
87
+ * | 'ERR_DEP_MISSING'
88
+ * | 'ERR_GH_CLI'
89
+ * | 'ERR_UNKNOWN_POST'
90
+ * | 'ERR_FETCH_FAILED'
91
+ * | 'ERR_LAYOUT_PARSE'
92
+ * | 'ERR_LAYOUT_INVALID'
93
+ * )} ErrorCode
94
+ */
95
+ /**
96
+ * The complete, frozen set of Astryx CLI error codes. Append-only.
97
+ * @type {Readonly<Record<ErrorCode, ErrorCode>>}
98
+ */
99
+ export const ERROR_CODES: Readonly<Record<ErrorCode, ErrorCode>>;
100
+ /**
101
+ * Stable error-code string union. Append-only.
102
+ */
103
+ export type ErrorCode = ("ERR_UNKNOWN" | "ERR_UNKNOWN_COMMAND" | "ERR_UNKNOWN_SUBCOMMAND" | "ERR_INVALID_OPTION" | "ERR_INVALID_ARGUMENT" | "ERR_MISSING_ARGUMENT" | "ERR_INVALID_LANG" | "ERR_INVALID_DETAIL" | "ERR_NODE_VERSION" | "ERR_CORE_NOT_FOUND" | "ERR_UNKNOWN_COMPONENT" | "ERR_UNKNOWN_HOOK" | "ERR_UNKNOWN_TOPIC" | "ERR_UNKNOWN_SECTION" | "ERR_UNKNOWN_CATEGORY" | "ERR_UNKNOWN_TEMPLATE" | "ERR_AMBIGUOUS_TEMPLATE" | "ERR_AMBIGUOUS_COMPONENT" | "ERR_UNKNOWN_THEME" | "ERR_UNKNOWN_PACKAGE" | "ERR_UNKNOWN_AGENT" | "ERR_UNKNOWN_FEATURE" | "ERR_UNKNOWN_CODEMOD" | "ERR_CODEMOD_FAILED" | "ERR_NOT_FOUND" | "ERR_NO_DOC" | "ERR_NO_SHOWCASE" | "ERR_NO_SOURCE" | "ERR_INVALID_DOC" | "ERR_FILE_NOT_FOUND" | "ERR_FILE_EXISTS" | "ERR_PATH_TRAVERSAL" | "ERR_WRITE_FAILED" | "ERR_THEME_INVALID" | "ERR_THEME_LOAD" | "ERR_VERSION_DETECT" | "ERR_INVALID_VERSION" | "ERR_DEP_MISSING" | "ERR_GH_CLI" | "ERR_UNKNOWN_POST" | "ERR_FETCH_FAILED" | "ERR_LAYOUT_PARSE" | "ERR_LAYOUT_INVALID");
@@ -0,0 +1,11 @@
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
+ * @file EnumDoc for the CLI's stable error-code taxonomy. Colocated with the
6
+ * source of truth it documents (`error-codes.mjs`); the member set must stay in
7
+ * lockstep with ERROR_CODES — a drift test enforces that the two match exactly.
8
+ * @position packages/cli/foundation/response — enum documentation
9
+ */
10
+ /** @type {import('@astryxdesign/cli/authoring').EnumDoc} */
11
+ export const doc: import("@astryxdesign/cli/authoring").EnumDoc;
@@ -0,0 +1,75 @@
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
+ * Enable/disable JSON mode globally. Called once from index.mjs as soon as
6
+ * the root options are known (preAction), before any command body runs.
7
+ * @param {boolean} on
8
+ */
9
+ export function setJsonMode(on: boolean): void;
10
+ /** @returns {boolean} */
11
+ export function isJsonMode(): boolean;
12
+ /**
13
+ * Human-facing output that is automatically suppressed in --json mode.
14
+ *
15
+ * This is the stdout-discipline primitive: instead of scattering
16
+ * `if (!json) console.log(...)` across commands (easy to forget, and one
17
+ * miss corrupts the JSON), route all human chatter through humanLog. In JSON
18
+ * mode it is a no-op, guaranteeing stdout carries only the JSON envelope.
19
+ *
20
+ * @param {...unknown} args
21
+ */
22
+ export function humanLog(...args: unknown[]): void;
23
+ /**
24
+ * Human-facing stderr (warnings, hints). Also suppressed in JSON mode so a
25
+ * stray warning can't interleave with piped output. Use jsonError for real
26
+ * errors that must reach a JSON consumer.
27
+ * @param {...unknown} args
28
+ */
29
+ export function humanWarn(...args: unknown[]): void;
30
+ /**
31
+ * Output a JSON response envelope and mark it handled.
32
+ *
33
+ * Structural serializer: pass a command/API result straight through as
34
+ * `{type, data, meta?}`. There is no central response union — the correctness
35
+ * of the `type` discriminator is guaranteed at each API function's `@returns`
36
+ * (that's the fractal source-of-truth point), not by a map in this file.
37
+ *
38
+ * @param {{type: string, data: unknown, meta?: Record<string, unknown>}} response
39
+ * @returns {void}
40
+ */
41
+ export function jsonOut(response: {
42
+ type: string;
43
+ data: unknown;
44
+ meta?: Record<string, unknown>;
45
+ }): void;
46
+ /**
47
+ * Build a structured error envelope without emitting it. Used by the bin
48
+ * error boundary to convert an uncaught throw into the contract's error
49
+ * shape.
50
+ *
51
+ * The `code` is resolved in priority order: an explicit `code` argument,
52
+ * then a `code` property carried on a thrown Error/AstryxError, then the
53
+ * generic `ERR_UNKNOWN` fallback. It always appears on the envelope so
54
+ * consumers can branch on it unconditionally.
55
+ *
56
+ * @param {unknown} err
57
+ * @param {import('./base').Suggestion[]} [suggestions]
58
+ * @param {string} [code] - Explicit stable error code. Overrides any code
59
+ * carried on a thrown Error.
60
+ * @returns {{apiVersion: number, error: string, code: string, suggestions?: import('./base').Suggestion[]}}
61
+ */
62
+ export function toErrorEnvelope(err: unknown, suggestions?: import("./base").Suggestion[], code?: string): {
63
+ apiVersion: number;
64
+ error: string;
65
+ code: string;
66
+ suggestions?: import("./base").Suggestion[];
67
+ };
68
+ /**
69
+ * Output a structured JSON error and exit.
70
+ * @param {string} message
71
+ * @param {import('./base').Suggestion[]} [suggestions]
72
+ * @param {string} [code] - Stable machine-readable error code (error-codes.mjs).
73
+ */
74
+ export function jsonError(message: string, suggestions?: import("./base").Suggestion[], code?: string): void;
75
+ export const API_VERSION: 1;
@@ -0,0 +1,12 @@
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
+ * @file EnumDoc for the `type` discriminant carried on every --json success
6
+ * envelope. The vocabulary mirrors the RESPONSE_TYPES map (each command's
7
+ * `jsonOut(...)` call sites) in `clients/cli/lib/manifest.mjs`; a consumer
8
+ * switches on `type` to narrow the `data` payload.
9
+ * @position packages/cli/foundation/response — enum documentation
10
+ */
11
+ /** @type {import('@astryxdesign/cli/authoring').EnumDoc} */
12
+ export const doc: import("@astryxdesign/cli/authoring").EnumDoc;
@@ -0,0 +1,11 @@
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
+ * @file SchemaDoc for the Astryx CLI JSON output envelope (the `astryx --json`
6
+ * contract). Colocated with the serializer (`json.mjs`) and shared types
7
+ * (`base.d.ts`) it documents.
8
+ * @position packages/cli/foundation/response — schema documentation
9
+ */
10
+ /** @type {import('@astryxdesign/cli/authoring').SchemaDoc} */
11
+ export const doc: import("@astryxdesign/cli/authoring").SchemaDoc;
@@ -0,0 +1,21 @@
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
+ * @file Levenshtein edit distance — pure, dependency-free.
6
+ *
7
+ * Lives apart from string-utils.mjs (which dynamically imports node:fs/path
8
+ * for component search) so browser-bundled code — the XLE/XLO layout
9
+ * language — can use fuzzy matching without dragging node: schemes into the
10
+ * webpack graph.
11
+ *
12
+ * @input two strings
13
+ * @output edit distance (number)
14
+ * @position lib — shared by string-utils.mjs and lib/xle/validate.mjs
15
+ */
16
+ /**
17
+ * @param {string} a
18
+ * @param {string} b
19
+ * @returns {number}
20
+ */
21
+ export function levenshteinDistance(a: string, b: string): number;
@@ -0,0 +1,43 @@
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
+ * Find the closest component names to a given (possibly misspelled) name.
6
+ * Returns matches sorted by distance, filtered to maxDistance.
7
+ * @param {string} name
8
+ * @param {Record<string, string[]>} components
9
+ * @param {number} [maxDistance]
10
+ * @returns {{name: string, distance: number}[]}
11
+ */
12
+ export function findClosestComponents(name: string, components: Record<string, string[]>, maxDistance?: number): {
13
+ name: string;
14
+ distance: number;
15
+ }[];
16
+ /**
17
+ * Unified component search that scores matches across multiple signals:
18
+ * name similarity, keyword matches, and description/feature text search.
19
+ *
20
+ * Always returns results (top 5 minimum). Scores determine confidence:
21
+ * 100 exact name match
22
+ * 90 exact keyword match
23
+ * 80 name Levenshtein distance 1
24
+ * 70 keyword substring or Levenshtein distance 1
25
+ * 60 substring match on component name (min 4 chars, 50%+ coverage)
26
+ * 50 description or feature text contains the search term
27
+ * 40 name Levenshtein distance 2
28
+ * 30 keyword Levenshtein distance 2
29
+ * 20 name Levenshtein distance 3
30
+ *
31
+ * Each result: { name, score, reason }
32
+ *
33
+ * @param {string} needle
34
+ * @param {string} coreDir
35
+ * @param {Record<string, string[]>} components
36
+ * @returns {Promise<{name: string, score: number, reason: string}[]>}
37
+ */
38
+ export function searchComponents(needle: string, coreDir: string, components: Record<string, string[]>): Promise<{
39
+ name: string;
40
+ score: number;
41
+ reason: string;
42
+ }[]>;
43
+ export { levenshteinDistance } from "./levenshtein.mjs";
@@ -0,0 +1,89 @@
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
+ * Validate an expression and return both canonical surfaces — the browser
6
+ * twin of `layout check`. Never throws on invalid input; returns the errors.
7
+ *
8
+ * @param {string} expression
9
+ * @param {import('./xle-ast').Registry | import('./browser').SerializedRegistry | object} registry - serialized or hydrated
10
+ * @param {object} [opts]
11
+ * @param {import('./browser').XLEBlock[]} [opts.blocks] - block list for {hint} resolution (default [])
12
+ * @param {'compact'|'outline'|'auto'} [opts.form]
13
+ * @param {boolean} [opts.loose]
14
+ * @returns {import('./browser').CheckResult}
15
+ */
16
+ export function checkExpression(expression: string, registry: import("./xle-ast").Registry | import("./browser").SerializedRegistry | object, opts?: {
17
+ blocks?: import("./browser").XLEBlock[] | undefined;
18
+ form?: "compact" | "outline" | "auto" | undefined;
19
+ loose?: boolean | undefined;
20
+ }): import("./browser").CheckResult;
21
+ /**
22
+ * Validate + expand to TSX — the browser twin of `layout expand`.
23
+ * Returns either {code, ...} or {errors} (never writes files).
24
+ *
25
+ * @param {string} expression
26
+ * @param {import('./xle-ast').Registry | import('./browser').SerializedRegistry | object} registry
27
+ * @param {object} [opts]
28
+ * @param {import('./browser').XLEBlock[]} [opts.blocks]
29
+ * @param {'compact'|'outline'|'auto'} [opts.form]
30
+ * @param {boolean} [opts.loose]
31
+ * @param {string} [opts.name] - generated component name (PascalCase)
32
+ * @param {Map<string, import('./xle-ast').BlockModule>} [opts.blockModules] - prepared block sources/imports for splicing;
33
+ * omit in the browser (hints stay as TODO markers without sources)
34
+ */
35
+ export function expandExpression(expression: string, registry: import("./xle-ast").Registry | import("./browser").SerializedRegistry | object, opts?: {
36
+ blocks?: import("./browser").XLEBlock[] | undefined;
37
+ form?: "compact" | "outline" | "auto" | undefined;
38
+ loose?: boolean | undefined;
39
+ name?: string | undefined;
40
+ blockModules?: Map<string, import("./xle-ast").BlockModule> | undefined;
41
+ }): {
42
+ ok: boolean;
43
+ errors: {
44
+ message: string;
45
+ line: number;
46
+ col: number;
47
+ formatted: string;
48
+ kind: string;
49
+ }[];
50
+ form?: undefined;
51
+ code?: undefined;
52
+ componentsUsed?: undefined;
53
+ states?: undefined;
54
+ todos?: undefined;
55
+ warnings?: undefined;
56
+ } | {
57
+ ok: boolean;
58
+ errors: {
59
+ formatted: string;
60
+ message: string;
61
+ line?: number;
62
+ col?: number;
63
+ suggestions?: string[];
64
+ }[];
65
+ form?: undefined;
66
+ code?: undefined;
67
+ componentsUsed?: undefined;
68
+ states?: undefined;
69
+ todos?: undefined;
70
+ warnings?: undefined;
71
+ } | {
72
+ ok: boolean;
73
+ form: "compact" | "outline";
74
+ code: string;
75
+ componentsUsed: string[];
76
+ states: number;
77
+ todos: string[];
78
+ warnings: string[];
79
+ errors?: undefined;
80
+ };
81
+ import { parse } from './parse.mjs';
82
+ import { detectForm } from './parse.mjs';
83
+ import { XLEParseError } from './parse.mjs';
84
+ import { validate } from './validate.mjs';
85
+ import { expand } from './expand.mjs';
86
+ import { toCompact } from './print.mjs';
87
+ import { toOutline } from './print.mjs';
88
+ export { parse, detectForm, XLEParseError, validate, expand, toCompact, toOutline };
89
+ export { hydrateRegistry, serializeRegistry, ALIAS_TABLE, resolveComponent, SPACING_STEPS } from "./registry-core.mjs";
@@ -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
+ * Expand a validated document into a complete TSX module.
6
+ *
7
+ * @param {{roots: import('./xle-ast').XLEItem[], overlays: import('./xle-ast').XLEItem[]}} doc
8
+ * @param {import('./xle-ast').Registry} registry
9
+ * @param {{componentName?: string, blockModules?: Map<string, import('./xle-ast').BlockModule>}} [options]
10
+ * @returns {{code: string, componentsUsed: string[], states: number, todos: string[]}}
11
+ */
12
+ export function expand(doc: {
13
+ roots: import("./xle-ast").XLEItem[];
14
+ overlays: import("./xle-ast").XLEItem[];
15
+ }, registry: import("./xle-ast").Registry, options?: {
16
+ componentName?: string;
17
+ blockModules?: Map<string, import("./xle-ast").BlockModule>;
18
+ }): {
19
+ code: string;
20
+ componentsUsed: string[];
21
+ states: number;
22
+ todos: string[];
23
+ };