@astryxdesign/cli 0.1.1 → 0.1.2-canary.043f3fd
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 +50 -0
- package/docs/theme.doc.mjs +2 -2
- package/docs/working-with-ai.doc.mjs +6 -6
- package/package.json +31 -8
- package/src/api/component.mjs +253 -12
- package/src/api/discover.mjs +87 -28
- package/src/api/doctor.mjs +7 -22
- package/src/api/index.mjs +1 -0
- package/src/api/layout.mjs +302 -0
- package/src/api/layout.test.mjs +241 -0
- package/src/api/template-integration.test.mjs +225 -0
- package/src/api/template.mjs +421 -122
- package/src/api/template.test.mjs +2 -0
- package/src/api/theme-add.mjs +182 -0
- package/src/api/validate-integration.mjs +370 -0
- package/src/api/validate-integration.test.mjs +222 -0
- package/src/codemod.mjs +93 -0
- package/src/codemod.test.mjs +134 -0
- package/src/codemods/__tests__/registry.test.mjs +2 -0
- package/src/codemods/__tests__/runner.test.mjs +103 -0
- package/src/codemods/integration-discovery.mjs +168 -0
- package/src/codemods/integration-discovery.test.mjs +234 -0
- package/src/codemods/integration-runner.mjs +109 -0
- package/src/codemods/registry.mjs +2 -0
- package/src/codemods/run-codemod.mjs +207 -0
- package/src/codemods/runner.mjs +73 -96
- package/src/codemods/transforms/v0.0.15/index.mjs +0 -13
- package/src/codemods/transforms/v0.1.0/__tests__/v0.1.0-ordering.test.mjs +81 -0
- package/src/codemods/transforms/{v0.0.15 → v0.1.0}/drop-xds-prefix-imports.mjs +15 -4
- package/src/codemods/transforms/v0.1.0/index.mjs +15 -6
- package/src/codemods/transforms/v0.1.2/__tests__/rename-text-color-active-to-accent.test.mjs +120 -0
- package/src/codemods/transforms/v0.1.2/index.mjs +19 -0
- package/src/codemods/transforms/v0.1.2/rename-text-color-active-to-accent.mjs +136 -0
- package/src/codemods/transforms/v0.1.3/__tests__/migrate-layout-components-to-experimental.test.mjs +360 -0
- package/src/codemods/transforms/v0.1.3/index.mjs +19 -0
- package/src/codemods/transforms/v0.1.3/migrate-layout-components-to-experimental.mjs +260 -0
- package/src/commands/build-theme.import-path.test.mjs +22 -2
- package/src/commands/build-theme.mjs +185 -16
- package/src/commands/component/index.mjs +44 -10
- package/src/commands/component-ownership.test.mjs +227 -0
- package/src/commands/discover.mjs +5 -16
- package/src/commands/doctor.test.mjs +3 -3
- package/src/commands/init.mjs +34 -8
- package/src/commands/init.next-steps.test.mjs +46 -0
- package/src/commands/json-contract.test.mjs +0 -32
- package/src/commands/layout.mjs +139 -0
- package/src/commands/swizzle.mjs +241 -224
- package/src/commands/swizzle.path-safety.test.mjs +3 -3
- package/src/commands/swizzle.routing.test.mjs +279 -0
- package/src/commands/template.mjs +33 -37
- package/src/commands/upgrade.config-ordering.test.mjs +273 -0
- package/src/commands/upgrade.integration-policy.test.mjs +204 -0
- package/src/commands/upgrade.mjs +349 -239
- package/src/commands/validate-integration.mjs +110 -0
- package/src/commands/validate-integration.test.mjs +124 -0
- package/src/config.mjs +18 -0
- package/src/config.test.mjs +100 -0
- package/src/index.mjs +13 -3
- package/src/integration.mjs +19 -0
- package/src/lib/component-discovery.mjs +177 -0
- package/src/lib/config-cache.mjs +91 -0
- package/src/lib/config-cache.test.mjs +83 -0
- package/src/lib/config-schema.mjs +105 -0
- package/src/lib/error-codes.mjs +18 -12
- package/src/lib/integration-warnings.mjs +62 -0
- package/src/lib/integration-warnings.test.mjs +102 -0
- package/src/lib/integrations.mjs +132 -0
- package/src/lib/integrations.test.mjs +135 -0
- package/src/lib/levenshtein.mjs +29 -0
- package/src/lib/manifest.mjs +15 -2
- package/src/lib/module-loader.mjs +80 -0
- package/src/lib/module-loader.test.mjs +106 -0
- package/src/lib/package-scanner.mjs +31 -7
- package/src/lib/project.mjs +502 -0
- package/src/lib/project.test.mjs +308 -0
- package/src/lib/string-utils.mjs +5 -14
- package/src/lib/xle/browser.d.ts +100 -0
- package/src/lib/xle/browser.mjs +120 -0
- package/src/lib/xle/expand.mjs +622 -0
- package/src/lib/xle/parse.mjs +581 -0
- package/src/lib/xle/print.mjs +174 -0
- package/src/lib/xle/registry-core.mjs +170 -0
- package/src/lib/xle/registry.mjs +237 -0
- package/src/lib/xle/splice.mjs +137 -0
- package/src/lib/xle/validate.mjs +356 -0
- package/src/lib/xle/xle.test.mjs +333 -0
- package/src/template.mjs +73 -0
- package/src/template.test.mjs +127 -0
- package/src/types/api.d.ts +2 -6
- package/src/types/base.d.ts +3 -9
- package/src/types/codemod.d.ts +81 -0
- package/src/types/component.d.ts +27 -2
- package/src/types/config.d.ts +70 -0
- package/src/types/error-codes.d.ts +5 -3
- package/src/types/index.d.ts +0 -1
- package/src/types/integration.d.ts +29 -0
- package/src/types/swizzle.d.ts +9 -2
- package/src/types/template-api.d.ts +54 -0
- package/src/types/template.d.ts +10 -7
- package/src/types/upgrade.d.ts +29 -0
- package/src/types/validate-integration.d.ts +24 -0
- package/src/utils/github.mjs +0 -252
- package/src/utils/interactive.mjs +2 -2
- package/templates/blocks/components/Card/ClickableCardWithNestedButton.doc.mjs +1 -1
- package/templates/blocks/components/Card/SelectableCardMulti.doc.mjs +1 -1
- package/templates/blocks/components/ChatComposerDrawer/ChatComposerDrawerWithProgress.tsx +1 -1
- package/templates/blocks/components/ChatDictationButton/ChatDictationButtonShowcase.tsx +3 -3
- package/templates/blocks/components/CommandPaletteEmpty/CommandPaletteEmptyShowcase.doc.mjs +15 -0
- package/templates/blocks/components/CommandPaletteEmpty/CommandPaletteEmptyShowcase.tsx +26 -0
- package/templates/blocks/components/DateInput/DateInputDateRange.doc.mjs +2 -2
- package/templates/blocks/components/DateRangeInput/DateRangeInputWithPresets.doc.mjs +14 -0
- package/templates/blocks/components/DateRangeInput/DateRangeInputWithPresets.tsx +46 -0
- package/templates/blocks/components/DateRangeInput/DateRangeInputWithValidation.doc.mjs +14 -0
- package/templates/blocks/components/DateRangeInput/DateRangeInputWithValidation.tsx +52 -0
- package/templates/blocks/components/DateTimeInput/DateTimeInputWithValidation.doc.mjs +14 -0
- package/templates/blocks/components/DateTimeInput/DateTimeInputWithValidation.tsx +43 -0
- package/templates/blocks/components/FileInput/FileInputShowcase.tsx +4 -2
- package/templates/blocks/components/HoverCard/HoverCardInteractiveContent.doc.mjs +1 -1
- package/templates/blocks/components/HoverCard/HoverCardInteractiveContent.tsx +9 -4
- package/templates/blocks/components/LinkProvider/LinkProviderCustomLink.doc.mjs +14 -0
- package/templates/blocks/components/LinkProvider/LinkProviderCustomLink.tsx +43 -0
- package/templates/blocks/components/MultiSelector/MultiSelectorShowcase.tsx +6 -2
- package/templates/blocks/components/NumberInput/NumberInputShowcase.tsx +6 -2
- package/templates/blocks/components/Outline/OutlineShowcase.doc.mjs +15 -0
- package/templates/blocks/components/Outline/OutlineShowcase.tsx +22 -0
- package/templates/blocks/components/RadioList/RadioListShowcase.tsx +8 -1
- package/templates/blocks/components/SegmentedControl/SegmentedControlShowcase.tsx +3 -1
- package/templates/blocks/components/Selector/SelectorShowcase.tsx +4 -1
- package/templates/blocks/components/Slider/SliderShowcase.tsx +10 -1
- package/templates/blocks/components/Tab/TabShowcase.tsx +3 -1
- package/templates/blocks/components/Tab/TabWithSelectedIcon.doc.mjs +13 -0
- package/templates/blocks/components/Tab/TabWithSelectedIcon.tsx +39 -0
- package/templates/blocks/components/TabList/TabListShowcase.tsx +3 -1
- package/templates/blocks/components/TabMenu/TabMenuShowcase.tsx +3 -1
- package/templates/blocks/components/Table/ColumnResizeHookUsage.doc.mjs +14 -0
- package/templates/blocks/components/Table/ColumnResizeHookUsage.tsx +59 -0
- package/templates/blocks/components/Table/StickyColumnsHookUsage.doc.mjs +14 -0
- package/templates/blocks/components/Table/StickyColumnsHookUsage.tsx +104 -0
- package/templates/blocks/components/Text/TextColors.tsx +20 -5
- package/templates/blocks/components/TextArea/TextAreaShowcase.tsx +4 -2
- package/templates/blocks/components/TextInput/TextInputShowcase.tsx +4 -2
- package/templates/blocks/components/Thumbnail/ThumbnailDisabled.tsx +11 -6
- package/templates/blocks/components/Thumbnail/ThumbnailGallery.tsx +43 -7
- package/templates/blocks/components/Thumbnail/ThumbnailRemovable.tsx +40 -3
- package/templates/blocks/components/Thumbnail/ThumbnailShowcase.tsx +6 -5
- package/templates/blocks/components/Thumbnail/ThumbnailStates.tsx +11 -6
- package/templates/blocks/components/Timestamp/TimestampColors.tsx +2 -2
- package/templates/blocks/components/ToggleButton/ToggleButtonGroup.doc.mjs +1 -1
- package/templates/blocks/components/Tokenizer/TokenizerShowcase.tsx +8 -6
- package/templates/blocks/components/Toolbar/ToolbarTableFilter.doc.mjs +2 -2
- package/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +23 -14
- package/templates/blocks/components/Typeahead/TypeaheadShowcase.tsx +6 -2
- package/templates/pages/shell-nav/page.tsx +321 -0
- package/templates/pages/shell-nav/template.doc.mjs +12 -0
- package/templates/pages/shell-side-nav/page.tsx +242 -0
- package/templates/pages/shell-side-nav/template.doc.mjs +12 -0
- package/templates/pages/shell-top-nav/page.tsx +224 -0
- package/templates/pages/shell-top-nav/template.doc.mjs +12 -0
- package/templates/pages/theme-showcase/page.tsx +8 -19
- package/templates/themes/butter/butterTheme.ts +916 -0
- package/templates/themes/butter/icons.tsx +77 -0
- package/templates/themes/chocolate/chocolateTheme.ts +230 -0
- package/templates/themes/chocolate/icons.tsx +77 -0
- package/templates/themes/gothic/gothicTheme.ts +657 -0
- package/templates/themes/gothic/icons.tsx +77 -0
- package/templates/themes/manifest.json +90 -0
- package/templates/themes/matcha/icons.tsx +67 -0
- package/templates/themes/matcha/matchaTheme.ts +247 -0
- package/templates/themes/neutral/icons.tsx +77 -0
- package/templates/themes/neutral/neutralTheme.ts +603 -0
- package/templates/themes/stone/icons.tsx +77 -0
- package/templates/themes/stone/stoneTheme.ts +652 -0
- package/templates/themes/y2k/icons.tsx +67 -0
- package/templates/themes/y2k/y2kTheme.ts +617 -0
- package/src/codemods/transforms/v0.1.0/__tests__/migrate-xds-config-surfaces.test.mjs +0 -116
- package/src/codemods/transforms/v0.1.0/migrate-xds-config-surfaces.mjs +0 -230
- package/src/commands/gap-report.mjs +0 -456
- package/src/commands/gap-report.test.mjs +0 -163
- package/src/commands/swizzle-gap-safety.test.mjs +0 -273
- package/src/lib/config.mjs +0 -86
- package/src/lib/config.test.mjs +0 -42
- package/src/types/gap-report.d.ts +0 -29
- package/templates/blocks/components/MoreMenu/MoreMenuInToolbar.doc.mjs +0 -14
- package/templates/blocks/components/MoreMenu/MoreMenuInToolbar.tsx +0 -57
- /package/src/codemods/transforms/{v0.0.15 → v0.1.0}/__tests__/drop-xds-prefix-imports.test.mjs +0 -0
package/src/types/component.d.ts
CHANGED
|
@@ -28,7 +28,18 @@ import type {ComponentDoc, PropDoc} from '../../../core/src/docs-types';
|
|
|
28
28
|
/** xds --json component [--list] [--category X] [--detail brief] */
|
|
29
29
|
export interface ComponentListResponse {
|
|
30
30
|
type: 'component.list';
|
|
31
|
-
data: Record<string,
|
|
31
|
+
data: Record<string, ComponentListEntry[]>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A single entry in a `component.list` group. Pre-1.0 the list moved from bare
|
|
36
|
+
* strings to package-qualified objects so consumers can disambiguate ownership
|
|
37
|
+
* (core vs. an integration package).
|
|
38
|
+
*/
|
|
39
|
+
export interface ComponentListEntry {
|
|
40
|
+
name: string;
|
|
41
|
+
/** Owner package, e.g. '@astryxdesign/core' or '@acme/astryx-meta'. */
|
|
42
|
+
package: string;
|
|
32
43
|
}
|
|
33
44
|
|
|
34
45
|
/** xds --json component --list --detail compact */
|
|
@@ -52,7 +63,21 @@ export interface ComponentFullResponse {
|
|
|
52
63
|
/** xds --json component <name> */
|
|
53
64
|
export interface ComponentDetailResponse {
|
|
54
65
|
type: 'component.detail';
|
|
55
|
-
data: ComponentDoc;
|
|
66
|
+
data: ComponentDoc & ComponentOwnership;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Ownership metadata attached to every `component.detail` payload. Exposes the
|
|
71
|
+
* owner package, the import specifier, and whether a swizzleable source file is
|
|
72
|
+
* available — the inputs the integration-component swizzle (a later PR) needs.
|
|
73
|
+
*/
|
|
74
|
+
export interface ComponentOwnership {
|
|
75
|
+
/** Owner package, e.g. '@astryxdesign/core' or an integration package name. */
|
|
76
|
+
package: string;
|
|
77
|
+
/** Import specifier for the component (e.g. '@astryxdesign/core/Button'). */
|
|
78
|
+
import: string;
|
|
79
|
+
/** Whether a component source file exists for `--source` / swizzle. */
|
|
80
|
+
sourceAvailable: boolean;
|
|
56
81
|
}
|
|
57
82
|
|
|
58
83
|
/** xds --json component <name> --props */
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A command to run as part of a post-codemod hook. Returned by a hook's
|
|
5
|
+
* `buildCommand` and executed via `execFile` after codemods write files.
|
|
6
|
+
*/
|
|
7
|
+
export interface PostCodemodCommand {
|
|
8
|
+
command: string;
|
|
9
|
+
args?: string[];
|
|
10
|
+
options?: {
|
|
11
|
+
cwd?: string;
|
|
12
|
+
env?: NodeJS.ProcessEnv;
|
|
13
|
+
timeout?: number;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A post-codemod hook. `buildCommand` receives the package directory and the
|
|
19
|
+
* list of files changed by codemods, and returns the command to run (or a
|
|
20
|
+
* nullish value to skip).
|
|
21
|
+
*/
|
|
22
|
+
export type PostCodemodHook = {
|
|
23
|
+
name?: string;
|
|
24
|
+
buildCommand: (ctx: {
|
|
25
|
+
packageDir: string;
|
|
26
|
+
files: string[];
|
|
27
|
+
}) =>
|
|
28
|
+
| PostCodemodCommand
|
|
29
|
+
| null
|
|
30
|
+
| undefined
|
|
31
|
+
| Promise<PostCodemodCommand | null | undefined>;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/** A component XLE layout expressions can reference by name via `{hint}`. */
|
|
35
|
+
export interface XleComponent {
|
|
36
|
+
/** Import specifier the component is imported from, e.g. '@/components/KpiCard'. */
|
|
37
|
+
from: string;
|
|
38
|
+
/** Optional human description shown in tooling. */
|
|
39
|
+
description?: string;
|
|
40
|
+
/** Import as the module's default export instead of a named export. Defaults to false. */
|
|
41
|
+
default?: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** User config exported from astryx.config.{ts,mjs,js}. */
|
|
45
|
+
export interface AstryxConfig {
|
|
46
|
+
/** Integration package names to load. */
|
|
47
|
+
integrations?: string[];
|
|
48
|
+
/** Where to file issues/feedback for this project. */
|
|
49
|
+
issuesUrl?: string;
|
|
50
|
+
/** Lifecycle hooks. */
|
|
51
|
+
hooks?: {
|
|
52
|
+
postCodemod?: PostCodemodHook[];
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* EXPERIMENTAL — shape may change and is not part of the stable config
|
|
56
|
+
* contract. Provisional home for features still being proven out.
|
|
57
|
+
*/
|
|
58
|
+
experimental?: {
|
|
59
|
+
/** Experimental XLE (layout expression) configuration. */
|
|
60
|
+
xle?: {
|
|
61
|
+
/**
|
|
62
|
+
* Register app-local components so XLE layout expressions can
|
|
63
|
+
* reference them by name via {hint}. Keyed by component name.
|
|
64
|
+
*/
|
|
65
|
+
components?: Record<string, XleComponent>;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export declare function createConfig<T extends AstryxConfig>(config: T): T;
|
|
@@ -25,6 +25,9 @@ export type ErrorCode =
|
|
|
25
25
|
| 'ERR_UNKNOWN_SECTION'
|
|
26
26
|
| 'ERR_UNKNOWN_CATEGORY'
|
|
27
27
|
| 'ERR_UNKNOWN_TEMPLATE'
|
|
28
|
+
| 'ERR_AMBIGUOUS_TEMPLATE'
|
|
29
|
+
| 'ERR_AMBIGUOUS_COMPONENT'
|
|
30
|
+
| 'ERR_UNKNOWN_THEME'
|
|
28
31
|
| 'ERR_UNKNOWN_PACKAGE'
|
|
29
32
|
| 'ERR_UNKNOWN_AGENT'
|
|
30
33
|
| 'ERR_UNKNOWN_FEATURE'
|
|
@@ -41,13 +44,12 @@ export type ErrorCode =
|
|
|
41
44
|
| 'ERR_WRITE_FAILED'
|
|
42
45
|
| 'ERR_THEME_INVALID'
|
|
43
46
|
| 'ERR_THEME_LOAD'
|
|
44
|
-
| 'ERR_TEMPLATE_CONFIG'
|
|
45
|
-
| 'ERR_TEMPLATE_GET'
|
|
46
47
|
| 'ERR_VERSION_DETECT'
|
|
47
48
|
| 'ERR_INVALID_VERSION'
|
|
48
49
|
| 'ERR_DEP_MISSING'
|
|
49
50
|
| 'ERR_GH_CLI'
|
|
50
|
-
| '
|
|
51
|
+
| 'ERR_LAYOUT_PARSE'
|
|
52
|
+
| 'ERR_LAYOUT_INVALID';
|
|
51
53
|
|
|
52
54
|
/** The frozen runtime map of all error codes (keys === values). */
|
|
53
55
|
export declare const ERROR_CODES: Readonly<Record<ErrorCode, ErrorCode>>;
|
package/src/types/index.d.ts
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Integration manifest exported from a conventional root manifest file
|
|
5
|
+
* (astryx.integration.{ts,mjs,js}) sibling to the integration package's
|
|
6
|
+
* package.json. Identity (name/version) comes from the package's
|
|
7
|
+
* package.json, not from the manifest.
|
|
8
|
+
*/
|
|
9
|
+
export interface AstryxIntegration {
|
|
10
|
+
/** Relative path to the components/docs root (resolved to absolute). */
|
|
11
|
+
components?: string;
|
|
12
|
+
/** Relative path to the templates root (resolved to absolute). */
|
|
13
|
+
templates?: string;
|
|
14
|
+
/** Relative path to the codemods root (resolved to absolute). */
|
|
15
|
+
codemods?: string;
|
|
16
|
+
/** Where to file issues/feedback for this integration. */
|
|
17
|
+
issuesUrl?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** An issue surfaced by an integration. */
|
|
21
|
+
export interface AstryxIntegrationIssue {
|
|
22
|
+
code: string;
|
|
23
|
+
severity: 'warning' | 'error';
|
|
24
|
+
message: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export declare function createIntegration<T extends AstryxIntegration>(
|
|
28
|
+
integration: T,
|
|
29
|
+
): T;
|
package/src/types/swizzle.d.ts
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
* ------------------------------------------------------------------
|
|
8
8
|
* xds --json swizzle [--list] -> swizzle.list
|
|
9
9
|
* xds --json swizzle <component> -> swizzle.copy
|
|
10
|
-
* xds --json swizzle <component> --gap "x" -> swizzle.copy (with gapReport)
|
|
11
10
|
* (not found) -> CLIError
|
|
12
11
|
*/
|
|
13
12
|
|
|
@@ -17,6 +16,14 @@ export interface SwizzleListResponse {
|
|
|
17
16
|
data: string[];
|
|
18
17
|
}
|
|
19
18
|
|
|
19
|
+
/** Maintainer feedback note emitted after a successful swizzle. */
|
|
20
|
+
export interface SwizzleFeedback {
|
|
21
|
+
/** Where to report the gap that led to swizzling. */
|
|
22
|
+
issuesUrl: string;
|
|
23
|
+
/** Ready-to-run `gh issue create` command, when `gh` is available. */
|
|
24
|
+
ghCommand?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
20
27
|
/** xds --json swizzle <component> */
|
|
21
28
|
export interface SwizzleCopyResponse {
|
|
22
29
|
type: 'swizzle.copy';
|
|
@@ -25,6 +32,6 @@ export interface SwizzleCopyResponse {
|
|
|
25
32
|
outputDir: string;
|
|
26
33
|
filesCopied: number;
|
|
27
34
|
files: string[];
|
|
28
|
-
|
|
35
|
+
feedback?: SwizzleFeedback;
|
|
29
36
|
};
|
|
30
37
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Authoring surface for Astryx static templates, exported from
|
|
5
|
+
* `@astryxdesign/cli/template`.
|
|
6
|
+
*
|
|
7
|
+
* A template doc lives in a `<id>.doc.{ts,mjs,js}` file with a required
|
|
8
|
+
* same-stem sibling source file (`<id>.tsx`). The doc's `type` (page or
|
|
9
|
+
* block) — injected by the create* helpers — decides how the template is
|
|
10
|
+
* scaffolded; there is no `/pages` vs `/blocks` directory requirement.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** Optional preview metadata for a template (used by docs surfaces). */
|
|
14
|
+
export interface AstryxTemplatePreview {
|
|
15
|
+
/** Path or URL to a preview image. */
|
|
16
|
+
image?: string;
|
|
17
|
+
/** CSS aspect-ratio hint for the preview, e.g. "16 / 9". */
|
|
18
|
+
aspectRatio?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Fields common to page and block template docs (without the `type` tag). */
|
|
22
|
+
export interface AstryxTemplateInput {
|
|
23
|
+
/** Human-readable template name. Required. */
|
|
24
|
+
name: string;
|
|
25
|
+
/** One-line description of what the template provides. Required. */
|
|
26
|
+
description: string;
|
|
27
|
+
/** Optional grouping/category label. */
|
|
28
|
+
category?: string;
|
|
29
|
+
/** Component display names the template composes. */
|
|
30
|
+
componentsUsed?: string[];
|
|
31
|
+
/** Optional preview metadata. */
|
|
32
|
+
preview?: AstryxTemplatePreview;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Input accepted by {@link createPageTemplate} (no `type` field). */
|
|
36
|
+
export type AstryxPageTemplateInput = AstryxTemplateInput;
|
|
37
|
+
/** Input accepted by {@link createBlockTemplate} (no `type` field). */
|
|
38
|
+
export type AstryxBlockTemplateInput = AstryxTemplateInput;
|
|
39
|
+
|
|
40
|
+
/** A validated page template doc. */
|
|
41
|
+
export type AstryxPageTemplate = AstryxTemplateInput & {type: 'page'};
|
|
42
|
+
/** A validated block template doc. */
|
|
43
|
+
export type AstryxBlockTemplate = AstryxTemplateInput & {type: 'block'};
|
|
44
|
+
|
|
45
|
+
/** A validated template doc (page or block). */
|
|
46
|
+
export type AstryxTemplate = AstryxPageTemplate | AstryxBlockTemplate;
|
|
47
|
+
|
|
48
|
+
export declare function createPageTemplate<T extends AstryxPageTemplateInput>(
|
|
49
|
+
def: T,
|
|
50
|
+
): T & {type: 'page'};
|
|
51
|
+
|
|
52
|
+
export declare function createBlockTemplate<T extends AstryxBlockTemplateInput>(
|
|
53
|
+
def: T,
|
|
54
|
+
): T & {type: 'block'};
|
package/src/types/template.d.ts
CHANGED
|
@@ -21,12 +21,21 @@ export interface TemplateListResponse {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export interface TemplateListEntry {
|
|
24
|
+
/** Stable template id (relative path under the templates root, minus the .doc.* suffix). */
|
|
25
|
+
id: string;
|
|
24
26
|
name: string;
|
|
27
|
+
/** @deprecated Alias of `name`, retained for back-compat. */
|
|
25
28
|
displayName: string;
|
|
26
29
|
description: string;
|
|
30
|
+
type: 'page' | 'block';
|
|
31
|
+
/** Owning package; core (built-in) templates report '@astryxdesign/core'. */
|
|
32
|
+
package: string;
|
|
33
|
+
/** Optional grouping/category label. */
|
|
34
|
+
category?: string;
|
|
35
|
+
/** Component display names the template composes. */
|
|
36
|
+
componentsUsed?: string[];
|
|
27
37
|
isReady: boolean;
|
|
28
38
|
scaffold?: boolean;
|
|
29
|
-
type: 'page' | 'block';
|
|
30
39
|
}
|
|
31
40
|
|
|
32
41
|
/** xds --json template <name> */
|
|
@@ -62,9 +71,3 @@ export interface TemplateCopyResponse {
|
|
|
62
71
|
filesCopied: number;
|
|
63
72
|
};
|
|
64
73
|
}
|
|
65
|
-
|
|
66
|
-
/** xds --json template get --id <id> */
|
|
67
|
-
export interface TemplateGetResponse {
|
|
68
|
-
type: 'template.get';
|
|
69
|
-
data: {id: string; source: string};
|
|
70
|
-
}
|
package/src/types/upgrade.d.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* ------------------------------------------------------------------
|
|
8
8
|
* xds --json upgrade --list -> upgrade.list
|
|
9
9
|
* xds --json upgrade [--apply] -> upgrade.run
|
|
10
|
+
* xds --json upgrade (status short-circuit) -> upgrade.status
|
|
10
11
|
* (version detection failure) -> CLIError
|
|
11
12
|
*/
|
|
12
13
|
|
|
@@ -33,3 +34,31 @@ export interface UpgradeRunResponse {
|
|
|
33
34
|
agentDocsRefreshed: boolean;
|
|
34
35
|
};
|
|
35
36
|
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* xds --json upgrade — short-circuit status results.
|
|
40
|
+
*
|
|
41
|
+
* - `up_to_date`: `--from` is >= installed target and `--force` was not passed.
|
|
42
|
+
* - `no_codemods`: no codemods (core or integration) apply to the range.
|
|
43
|
+
* - `config_fixable`: DRY-RUN ONLY. The consumer's astryx.config currently
|
|
44
|
+
* fails strict validation, but a pending core CONFIG codemod (in the selected
|
|
45
|
+
* range) would repair it. The dry run previews the fix without writing and
|
|
46
|
+
* reports the exact command to apply it; integrations are skipped for the
|
|
47
|
+
* preview (they will be processed on the `--apply` run).
|
|
48
|
+
*/
|
|
49
|
+
export interface UpgradeStatusResponse {
|
|
50
|
+
type: 'upgrade.status';
|
|
51
|
+
data:
|
|
52
|
+
| {status: 'up_to_date'; from: string; to: string}
|
|
53
|
+
| {status: 'no_codemods'; from: string; to: string}
|
|
54
|
+
| {
|
|
55
|
+
status: 'config_fixable';
|
|
56
|
+
from: string;
|
|
57
|
+
to: string;
|
|
58
|
+
configError: string;
|
|
59
|
+
configCodemods: string[];
|
|
60
|
+
suggestedCommand: string;
|
|
61
|
+
message: string;
|
|
62
|
+
note: string;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* validate-integration command JSON responses.
|
|
5
|
+
*
|
|
6
|
+
* Invocation -> type discriminator
|
|
7
|
+
* ------------------------------------------------------------
|
|
8
|
+
* astryx --json validate-integration -> integration.validate
|
|
9
|
+
* astryx --json validate-integration <pkg> -> integration.validate
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type {AstryxIntegrationIssue} from './integration';
|
|
13
|
+
|
|
14
|
+
/** astryx --json validate-integration [package] */
|
|
15
|
+
export interface ValidateIntegrationResponse {
|
|
16
|
+
type: 'integration.validate';
|
|
17
|
+
data: {
|
|
18
|
+
/** Integration package name, or null when no manifest was located. */
|
|
19
|
+
name: string | null;
|
|
20
|
+
/** Integration package version, or null when unavailable. */
|
|
21
|
+
version: string | null;
|
|
22
|
+
issues: AstryxIntegrationIssue[];
|
|
23
|
+
};
|
|
24
|
+
}
|
package/src/utils/github.mjs
CHANGED
|
@@ -4,84 +4,9 @@
|
|
|
4
4
|
* @file GitHub utilities for Astryx CLI
|
|
5
5
|
*
|
|
6
6
|
* Shared helpers for interacting with the GitHub CLI (`gh`).
|
|
7
|
-
* Used by gap-report and swizzle commands.
|
|
8
|
-
*
|
|
9
|
-
* Gap reporting can be configured via astryx.config.mjs:
|
|
10
|
-
* gapReport: false — disable entirely
|
|
11
|
-
* gapReport: { command: './scripts/report-gap.sh' } — run custom script (receives JSON on stdin)
|
|
12
|
-
*
|
|
13
|
-
* Or via environment variable:
|
|
14
|
-
* ASTRYX_GAP_REPORT=off — disable entirely
|
|
15
|
-
* ASTRYX_GAP_REPORT=./scripts/report-gap.sh — run custom script
|
|
16
7
|
*/
|
|
17
8
|
|
|
18
9
|
import {execFileSync} from 'node:child_process';
|
|
19
|
-
import * as fs from 'node:fs';
|
|
20
|
-
import * as path from 'node:path';
|
|
21
|
-
|
|
22
|
-
/** Default target repository for gap report issues. */
|
|
23
|
-
const DEFAULT_REPO = 'facebookexperimental/xds';
|
|
24
|
-
|
|
25
|
-
/** Gap report category options. */
|
|
26
|
-
export const GAP_CATEGORIES = [
|
|
27
|
-
{value: 'missing_component', label: 'Missing component'},
|
|
28
|
-
{value: 'missing_variant', label: 'Missing variant or prop'},
|
|
29
|
-
{value: 'layout_gap', label: 'Layout gap'},
|
|
30
|
-
{value: 'styling_gap', label: 'Styling gap'},
|
|
31
|
-
{value: 'a11y_gap', label: 'Accessibility gap'},
|
|
32
|
-
{value: 'api_friction', label: 'API friction'},
|
|
33
|
-
{value: 'docs_gap', label: 'Documentation gap'},
|
|
34
|
-
{value: 'other', label: 'Other'},
|
|
35
|
-
];
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Load gap report configuration.
|
|
39
|
-
*
|
|
40
|
-
* Priority: env var > astryx.config.mjs > default (GitHub issue)
|
|
41
|
-
*
|
|
42
|
-
* Returns { enabled: boolean, command?: string }
|
|
43
|
-
* - enabled: false → gap reporting disabled
|
|
44
|
-
* - command: string → run this script instead of creating a GitHub issue
|
|
45
|
-
* - neither → default behavior (GitHub issue to facebookexperimental/xds)
|
|
46
|
-
*/
|
|
47
|
-
export function loadGapReportConfig() {
|
|
48
|
-
// 1. Check environment variable
|
|
49
|
-
const envVar = process.env.ASTRYX_GAP_REPORT;
|
|
50
|
-
if (envVar) {
|
|
51
|
-
if (envVar === 'off' || envVar === 'false' || envVar === '0') {
|
|
52
|
-
return {enabled: false};
|
|
53
|
-
}
|
|
54
|
-
// Treat as custom command
|
|
55
|
-
return {enabled: true, command: envVar};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// 2. Check astryx.config.mjs
|
|
59
|
-
const configPath = path.join(process.cwd(), 'astryx.config.mjs');
|
|
60
|
-
if (fs.existsSync(configPath)) {
|
|
61
|
-
try {
|
|
62
|
-
const content = fs.readFileSync(configPath, 'utf-8');
|
|
63
|
-
const match = content.match(/gapReport\s*:\s*(.+?)[\s,}]/s);
|
|
64
|
-
if (match) {
|
|
65
|
-
const value = match[1].trim();
|
|
66
|
-
if (value === 'false') {
|
|
67
|
-
return {enabled: false};
|
|
68
|
-
}
|
|
69
|
-
// Look for command property in object literal
|
|
70
|
-
const cmdMatch = content.match(
|
|
71
|
-
/gapReport\s*:\s*\{[^}]*command\s*:\s*['"](.+?)['"]/s,
|
|
72
|
-
);
|
|
73
|
-
if (cmdMatch) {
|
|
74
|
-
return {enabled: true, command: cmdMatch[1]};
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
} catch {
|
|
78
|
-
// Config parse error — fall through to defaults
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// 3. Default
|
|
83
|
-
return {enabled: true};
|
|
84
|
-
}
|
|
85
10
|
|
|
86
11
|
/**
|
|
87
12
|
* Check if `gh` CLI is installed and authenticated.
|
|
@@ -95,180 +20,3 @@ export function checkGhCli() {
|
|
|
95
20
|
return false;
|
|
96
21
|
}
|
|
97
22
|
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Idempotently create the `gap-report` and `gap-analysis` labels.
|
|
101
|
-
* Uses `--force` to avoid errors if labels already exist.
|
|
102
|
-
*/
|
|
103
|
-
function ensureGapReportLabel() {
|
|
104
|
-
try {
|
|
105
|
-
execFileSync(
|
|
106
|
-
'gh',
|
|
107
|
-
[
|
|
108
|
-
'label',
|
|
109
|
-
'create',
|
|
110
|
-
'gap-report',
|
|
111
|
-
'--repo',
|
|
112
|
-
DEFAULT_REPO,
|
|
113
|
-
'--color',
|
|
114
|
-
'D4C5F9',
|
|
115
|
-
'--description',
|
|
116
|
-
'Auto-filed gap report from swizzle/gap-report CLI',
|
|
117
|
-
'--force',
|
|
118
|
-
],
|
|
119
|
-
{stdio: 'ignore'},
|
|
120
|
-
);
|
|
121
|
-
execFileSync(
|
|
122
|
-
'gh',
|
|
123
|
-
[
|
|
124
|
-
'label',
|
|
125
|
-
'create',
|
|
126
|
-
'gap-analysis',
|
|
127
|
-
'--repo',
|
|
128
|
-
DEFAULT_REPO,
|
|
129
|
-
'--color',
|
|
130
|
-
'0E8A16',
|
|
131
|
-
'--description',
|
|
132
|
-
'Curated gap analysis summary',
|
|
133
|
-
'--force',
|
|
134
|
-
],
|
|
135
|
-
{stdio: 'ignore'},
|
|
136
|
-
);
|
|
137
|
-
} catch {
|
|
138
|
-
// Best-effort — labels may already exist or user may lack permissions
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Run a custom gap report command, piping report data as JSON to stdin.
|
|
144
|
-
*
|
|
145
|
-
* @param {string} command Script path to execute
|
|
146
|
-
* @param {object} report Report data (component, category, intention, detail, source)
|
|
147
|
-
* @returns {string} stdout from the command
|
|
148
|
-
*/
|
|
149
|
-
function runCustomCommand(command, report) {
|
|
150
|
-
const resolved = path.resolve(process.cwd(), command);
|
|
151
|
-
const json = JSON.stringify(report, null, 2);
|
|
152
|
-
|
|
153
|
-
const result = execFileSync(resolved, [], {
|
|
154
|
-
input: json,
|
|
155
|
-
encoding: 'utf-8',
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
return result.trim();
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Build the report payload + rendered title/body for a gap report.
|
|
163
|
-
* Pure function — no side effects, never calls `gh` or external scripts.
|
|
164
|
-
*
|
|
165
|
-
* @returns {{
|
|
166
|
-
* enabled: boolean,
|
|
167
|
-
* mode: 'disabled' | 'custom' | 'github',
|
|
168
|
-
* command?: string,
|
|
169
|
-
* report: object,
|
|
170
|
-
* title: string,
|
|
171
|
-
* body: string,
|
|
172
|
-
* repo: string,
|
|
173
|
-
* }}
|
|
174
|
-
*/
|
|
175
|
-
export function buildGapReportPreview({
|
|
176
|
-
component,
|
|
177
|
-
category,
|
|
178
|
-
intention,
|
|
179
|
-
detail,
|
|
180
|
-
source = 'cli',
|
|
181
|
-
}) {
|
|
182
|
-
const config = loadGapReportConfig();
|
|
183
|
-
const categoryLabel =
|
|
184
|
-
GAP_CATEGORIES.find(c => c.value === category)?.label ?? category;
|
|
185
|
-
|
|
186
|
-
const report = {
|
|
187
|
-
component,
|
|
188
|
-
category,
|
|
189
|
-
categoryLabel,
|
|
190
|
-
intention,
|
|
191
|
-
detail: detail || null,
|
|
192
|
-
source,
|
|
193
|
-
timestamp: new Date().toISOString(),
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
const title = `[gap] ${component}: ${intention.slice(0, 70)}`;
|
|
197
|
-
const body = [
|
|
198
|
-
'| Field | Value |',
|
|
199
|
-
'|-------|-------|',
|
|
200
|
-
`| **Component** | ${component} |`,
|
|
201
|
-
`| **Category** | ${categoryLabel} |`,
|
|
202
|
-
`| **Source** | ${source} |`,
|
|
203
|
-
`| **Timestamp** | ${report.timestamp} |`,
|
|
204
|
-
'',
|
|
205
|
-
'## User Intention',
|
|
206
|
-
'',
|
|
207
|
-
intention,
|
|
208
|
-
...(detail ? ['', '## Additional Context', '', detail] : []),
|
|
209
|
-
].join('\n');
|
|
210
|
-
|
|
211
|
-
let mode = 'github';
|
|
212
|
-
if (!config.enabled) mode = 'disabled';
|
|
213
|
-
else if (config.command) mode = 'custom';
|
|
214
|
-
|
|
215
|
-
return {
|
|
216
|
-
enabled: config.enabled,
|
|
217
|
-
mode,
|
|
218
|
-
command: config.command,
|
|
219
|
-
report,
|
|
220
|
-
title,
|
|
221
|
-
body,
|
|
222
|
-
repo: DEFAULT_REPO,
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Create a gap report — either via GitHub issue or custom command.
|
|
228
|
-
*
|
|
229
|
-
* SAFETY: This actually invokes `gh issue create` (or runs the custom command).
|
|
230
|
-
* Callers MUST gate this behind explicit user confirmation or a `--commit`-style
|
|
231
|
-
* flag in non-interactive contexts. Use `buildGapReportPreview` for dry-run.
|
|
232
|
-
*
|
|
233
|
-
* @param {object} opts
|
|
234
|
-
* @param {string} opts.component Component name (e.g. "Button")
|
|
235
|
-
* @param {string} opts.category One of GAP_CATEGORIES values
|
|
236
|
-
* @param {string} opts.intention What the user was trying to achieve
|
|
237
|
-
* @param {string} [opts.detail] Additional context
|
|
238
|
-
* @param {string} [opts.source] Who filed it: "interactive", "llm-auto", "cli"
|
|
239
|
-
* @returns {string|null} URL of the created issue (or custom command output), null if disabled
|
|
240
|
-
*/
|
|
241
|
-
export function createGapReport(opts) {
|
|
242
|
-
const preview = buildGapReportPreview(opts);
|
|
243
|
-
|
|
244
|
-
if (!preview.enabled) {
|
|
245
|
-
return null;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// Custom command mode — pipe JSON to the script
|
|
249
|
-
if (preview.mode === 'custom') {
|
|
250
|
-
return runCustomCommand(preview.command, preview.report);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Default mode — create GitHub issue
|
|
254
|
-
ensureGapReportLabel();
|
|
255
|
-
|
|
256
|
-
const result = execFileSync(
|
|
257
|
-
'gh',
|
|
258
|
-
[
|
|
259
|
-
'issue',
|
|
260
|
-
'create',
|
|
261
|
-
'--repo',
|
|
262
|
-
preview.repo,
|
|
263
|
-
'--title',
|
|
264
|
-
preview.title,
|
|
265
|
-
'--body',
|
|
266
|
-
preview.body,
|
|
267
|
-
'--label',
|
|
268
|
-
'gap-report',
|
|
269
|
-
],
|
|
270
|
-
{encoding: 'utf-8'},
|
|
271
|
-
);
|
|
272
|
-
|
|
273
|
-
return result.trim();
|
|
274
|
-
}
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
* fail fast (exit 1) with actionable, non-interactive guidance.
|
|
19
19
|
*
|
|
20
20
|
* - `isInteractive()` — for commands with an OPTIONAL secondary prompt
|
|
21
|
-
*
|
|
22
|
-
*
|
|
21
|
+
* that runs after the primary work has already succeeded; callers use
|
|
22
|
+
* this to skip the prompt gracefully in non-interactive contexts.
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
25
|
/**
|
|
@@ -5,7 +5,7 @@ export const doc = {
|
|
|
5
5
|
type: 'block',
|
|
6
6
|
exampleFor: 'ClickableCard',
|
|
7
7
|
name: 'ClickableCardWithNestedButton',
|
|
8
|
-
displayName: 'Clickable Card
|
|
8
|
+
displayName: 'Clickable Card — Nested Button',
|
|
9
9
|
description:
|
|
10
10
|
'A product card that navigates on click but has an independent "Add to cart" button inside.',
|
|
11
11
|
isReady: true,
|
|
@@ -5,7 +5,7 @@ export const doc = {
|
|
|
5
5
|
type: 'block',
|
|
6
6
|
exampleFor: 'SelectableCard',
|
|
7
7
|
name: 'SelectableCardMulti',
|
|
8
|
-
displayName: 'Selectable Card Multi',
|
|
8
|
+
displayName: 'Selectable Card — Multi-select',
|
|
9
9
|
description:
|
|
10
10
|
'Multi-select tag picker using color variant selectable cards with color-matched selection borders.',
|
|
11
11
|
isReady: true,
|
|
@@ -44,7 +44,7 @@ export default function ChatComposerDrawerWithProgress() {
|
|
|
44
44
|
}
|
|
45
45
|
headerContext={
|
|
46
46
|
<Stack direction="horizontal" gap={2} vAlign="center">
|
|
47
|
-
<ProgressBar value={42} label="Context usage" isLabelHidden
|
|
47
|
+
<ProgressBar value={42} label="Context usage" isLabelHidden />
|
|
48
48
|
</Stack>
|
|
49
49
|
}
|
|
50
50
|
/>
|