@astryxdesign/cli 0.1.0-canary.f94dd07 → 0.1.1-canary.a514b99
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 +68 -0
- package/README.md +117 -75
- package/bin/astryx.mjs +22 -7
- package/docs/icons.doc.mjs +1 -1
- package/docs/migration.doc.mjs +2 -2
- package/docs/shape.doc.mjs +1 -1
- package/docs/styling.doc.mjs +2 -2
- package/docs/theme.doc.dense.mjs +2 -2
- package/docs/theme.doc.mjs +14 -0
- package/docs/theme.doc.zh.mjs +2 -2
- package/docs/working-with-ai.doc.mjs +4 -4
- package/package.json +8 -8
- package/src/api/search.mjs +207 -13
- package/src/api/template.mjs +2 -1
- package/src/codemods/__tests__/registry.test.mjs +1 -0
- package/src/codemods/registry.mjs +1 -0
- package/src/codemods/runner.mjs +105 -51
- package/src/codemods/transforms/v0.1.0/__tests__/migrate-xds-config-surfaces.test.mjs +116 -0
- package/src/codemods/transforms/v0.1.0/__tests__/migrate-xds-module-specifiers.test.mjs +51 -0
- package/src/codemods/transforms/v0.1.0/index.mjs +28 -0
- package/src/codemods/transforms/v0.1.0/migrate-xds-config-surfaces.mjs +230 -0
- package/src/codemods/transforms/v0.1.0/migrate-xds-module-specifiers.mjs +84 -0
- package/src/commands/agent-docs.mjs +92 -56
- package/src/commands/agent-docs.path-safety.test.mjs +1 -1
- package/src/commands/agent-docs.test.mjs +66 -10
- package/src/commands/build-theme.import-path.test.mjs +1 -1
- package/src/commands/build-theme.path-safety.test.mjs +1 -1
- package/src/commands/build-theme.prose.test.mjs +1 -1
- package/src/commands/build.mjs +196 -0
- package/src/commands/component-package.test.mjs +1 -1
- package/src/commands/component.test.mjs +1 -1
- package/src/commands/docs.test.mjs +1 -1
- package/src/commands/doctor.test.mjs +1 -1
- package/src/commands/external-showcase.test.mjs +1 -1
- package/src/commands/init.mjs +9 -1
- package/src/commands/interactive-guard.test.mjs +1 -1
- package/src/commands/json-contract.test.mjs +10 -3
- package/src/commands/swizzle-gap-safety.test.mjs +1 -1
- package/src/commands/swizzle.path-safety.test.mjs +1 -1
- package/src/commands/template.path-safety.test.mjs +1 -1
- package/src/commands/template.test.mjs +1 -1
- package/src/commands/upgrade.mjs +353 -169
- package/src/commands/upgrade.test.mjs +41 -27
- package/src/index.mjs +1 -0
- package/src/lib/config.mjs +12 -0
- package/src/lib/config.test.mjs +42 -0
- package/src/lib/error-codes.mjs +3 -0
- package/src/types/error-codes.d.ts +1 -0
- package/src/utils/interactive.mjs +1 -1
- package/src/utils/interactive.test.mjs +2 -0
- package/src/utils/package-manager.test.mjs +1 -1
- package/src/utils/path-safety.test.mjs +1 -1
- package/src/utils/paths.test.mjs +8 -8
- package/src/utils/update-check.mjs +4 -26
- package/src/utils/update-check.test.mjs +2 -64
- package/templates/blocks/components/AppShell/AppShellContentOnly.tsx +1 -9
- package/templates/blocks/components/AppShell/AppShellShowcase.tsx +1 -10
- package/templates/blocks/components/AppShell/AppShellSideNavOnly.tsx +1 -9
- package/templates/blocks/components/AppShell/AppShellTopNavOnly.tsx +1 -9
- package/templates/blocks/components/AppShell/AppShellTopNavWithSideNav.tsx +1 -9
- package/templates/blocks/components/AppShell/AppShellWithBanner.tsx +1 -9
- package/templates/blocks/components/AspectRatio/AspectRatioShowcase.tsx +12 -19
- package/templates/blocks/components/Banner/BannerShowcase.tsx +1 -8
- package/templates/blocks/components/Blockquote/BlockquoteShowcase.tsx +1 -8
- package/templates/blocks/components/Carousel/CarouselShowcase.tsx +2 -12
- package/templates/blocks/components/ChatComposerDrawer/ChatComposerDrawerShowcase.tsx +6 -9
- package/templates/blocks/components/ChatLayout/ChatLayoutPanelChat.tsx +10 -12
- package/templates/blocks/components/ChatMessageList/ChatMessageListDensity.tsx +1 -9
- package/templates/blocks/components/ChatMessageList/ChatMessageListFullFeatured.tsx +1 -9
- package/templates/blocks/components/ChatMessageList/ChatMessageListShowcase.tsx +1 -9
- package/templates/blocks/components/ChatMessageMetadata/ChatMessageMetadataShowcase.tsx +1 -8
- package/templates/blocks/components/ChatSendButton/ChatSendButtonInComposer.tsx +1 -8
- package/templates/blocks/components/Citation/CitationInlineText.tsx +4 -4
- package/templates/blocks/components/Code/CodeInlineInParagraph.tsx +1 -8
- package/templates/blocks/components/CodeBlock/CodeBlockBashCommand.tsx +1 -1
- package/templates/blocks/components/CodeBlock/CodeBlockJSONConfig.tsx +1 -1
- package/templates/blocks/components/CommandPaletteItem/CommandPaletteItemShowcase.tsx +9 -12
- package/templates/blocks/components/ContextMenu/ContextMenuShowcase.tsx +13 -15
- package/templates/blocks/components/Divider/DividerShowcase.tsx +1 -8
- package/templates/blocks/components/Divider/DividerVertical.tsx +7 -9
- package/templates/blocks/components/Field/FieldShowcase.tsx +1 -8
- package/templates/blocks/components/FormLayout/FormLayoutHorizontal.tsx +1 -6
- package/templates/blocks/components/Grid/GridResponsiveAutoFit.tsx +1 -9
- package/templates/blocks/components/HoverCard/HoverCardInlineTextHoverCard.tsx +4 -6
- package/templates/blocks/components/HoverCard/HoverCardInteractiveContent.tsx +1 -6
- package/templates/blocks/components/HoverCard/HoverCardProfileHoverCard.tsx +2 -8
- package/templates/blocks/components/HoverCard/HoverCardShowcase.tsx +1 -8
- package/templates/blocks/components/MoreMenu/MoreMenuInToolbar.tsx +2 -12
- package/templates/blocks/components/OverflowList/OverflowListOverflowBadges.tsx +8 -11
- package/templates/blocks/components/OverflowList/OverflowListOverflowDropdownActions.tsx +9 -12
- package/templates/blocks/components/Overlay/OverlayBottomStrip.tsx +4 -17
- package/templates/blocks/components/Overlay/OverlayHoverReveal.tsx +15 -16
- package/templates/blocks/components/Overlay/OverlayShowcase.tsx +5 -21
- package/templates/blocks/components/Pagination/PaginationDotsCarousel.tsx +2 -14
- package/templates/blocks/components/Pagination/PaginationPageSize.tsx +12 -14
- package/templates/blocks/components/Pagination/PaginationVariants.tsx +1 -8
- package/templates/blocks/components/Pagination/PaginationWithTable.tsx +2 -14
- package/templates/blocks/components/Tokenizer/TokenizerClear.tsx +1 -6
- package/templates/blocks/components/Tokenizer/TokenizerCreatable.tsx +2 -7
- package/templates/blocks/components/Tokenizer/TokenizerEndContent.tsx +1 -6
- package/templates/blocks/components/Tokenizer/TokenizerIcon.tsx +1 -6
- package/templates/blocks/components/Tokenizer/TokenizerMaxEntries.tsx +1 -6
- package/templates/blocks/components/Tokenizer/TokenizerOverflow.tsx +2 -7
- package/templates/blocks/components/Tokenizer/TokenizerShowcase.tsx +1 -6
- package/templates/blocks/components/Tokenizer/TokenizerStates.tsx +4 -9
- package/templates/blocks/components/Toolbar/ToolbarCardHeader.tsx +1 -10
- package/templates/blocks/components/Toolbar/ToolbarSizes.tsx +1 -8
- package/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +1 -8
- package/templates/blocks/components/Toolbar/ToolbarThreeSlot.tsx +1 -10
- package/templates/blocks/components/Toolbar/ToolbarWithTabs.tsx +8 -11
- package/templates/pages/ai-chat/page.tsx +71 -64
- package/templates/pages/ai-chat-landing/page.tsx +8 -12
- package/templates/pages/centered-hero/page.tsx +13 -15
- package/templates/pages/classic-gallery/page.tsx +27 -34
- package/templates/pages/detail-page/page.tsx +18 -18
- package/templates/pages/documentation/page.tsx +11 -14
- package/templates/pages/documentation-design/page.tsx +10 -13
- package/templates/pages/documentation-technical/page.tsx +15 -16
- package/templates/pages/editor/page.tsx +42 -54
- package/templates/pages/file-explorer/page.tsx +13 -16
- package/templates/pages/form-two-column/page.tsx +13 -17
- package/templates/pages/gallery-hero/page.tsx +13 -15
- package/templates/pages/ide/page.tsx +32 -39
- package/templates/pages/library/page.tsx +16 -23
- package/templates/pages/login/page.tsx +14 -18
- package/templates/pages/login-card/page.tsx +14 -18
- package/templates/pages/login-split/page.tsx +50 -48
- package/templates/pages/login-sso/page.tsx +9 -13
- package/templates/pages/mixed-gallery/page.tsx +51 -45
- package/templates/pages/payment-form/page.tsx +56 -70
- package/templates/pages/product-detail/page.tsx +27 -33
- package/templates/pages/product-gallery/page.tsx +7 -13
- package/templates/pages/settings-dialog/page.tsx +35 -43
- package/templates/pages/settings-sidebar/page.tsx +39 -47
- package/templates/pages/side-gallery/page.tsx +6 -9
- package/templates/pages/table-grouped/page.tsx +11 -15
- package/templates/pages/theme-showcase/page.tsx +33 -37
|
@@ -54,7 +54,7 @@ function writeTheme(dir, name) {
|
|
|
54
54
|
|
|
55
55
|
let tmpDir;
|
|
56
56
|
beforeEach(() => {
|
|
57
|
-
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), '
|
|
57
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-build-theme-paths-'));
|
|
58
58
|
});
|
|
59
59
|
afterEach(() => {
|
|
60
60
|
fs.rmSync(tmpDir, {recursive: true, force: true});
|
|
@@ -82,7 +82,7 @@ beforeAll(() => {
|
|
|
82
82
|
|
|
83
83
|
let tmpDir;
|
|
84
84
|
beforeEach(() => {
|
|
85
|
-
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), '
|
|
85
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-build-theme-prose-'));
|
|
86
86
|
});
|
|
87
87
|
afterEach(() => {
|
|
88
88
|
fs.rmSync(tmpDir, {recursive: true, force: true});
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file build command — the page-building assistant.
|
|
5
|
+
*
|
|
6
|
+
* Two modes:
|
|
7
|
+
* astryx build → the PLAYBOOK: how to build a page with Astryx
|
|
8
|
+
* astryx build "<what>" → a COMPOSITION KIT for what you're building:
|
|
9
|
+
* the closest page template (scaffold or layout
|
|
10
|
+
* reference), the blocks that cover parts, and
|
|
11
|
+
* the components to fill gaps, plus a one-line
|
|
12
|
+
* "Compose:" suggestion.
|
|
13
|
+
*
|
|
14
|
+
* `build` is the opinionated "assemble a page" verb. For a neutral lookup across
|
|
15
|
+
* the whole CLI, use `astryx search <query>` instead.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import {getRunPrefix} from '../utils/package-manager.mjs';
|
|
19
|
+
import {jsonOut, humanLog} from '../lib/json.mjs';
|
|
20
|
+
import {cliError} from '../lib/cli-error.mjs';
|
|
21
|
+
import {search as searchApi} from '../api/search.mjs';
|
|
22
|
+
|
|
23
|
+
/** A page scoring at/above this is confident enough to call a direct match. */
|
|
24
|
+
const PAGE_DIRECT = 95;
|
|
25
|
+
/** Below this a page is too weak to even offer as a layout reference. */
|
|
26
|
+
const PAGE_FLOOR = 50;
|
|
27
|
+
/** Below this a block/domain-component match is incidental noise, not surfaced. */
|
|
28
|
+
const DOMAIN_FLOOR = 55;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Always-surfaced primitives. Every page needs a shell + layout/typography/
|
|
32
|
+
* action atoms, but these never keyword-match an idea ("dashboard" != "Stack"),
|
|
33
|
+
* so search alone never returns them. We list them unconditionally so an agent
|
|
34
|
+
* composing from scratch has the whole kit (esp. off-template).
|
|
35
|
+
*/
|
|
36
|
+
const FRAME = ['AppShell', 'TopNav', 'SideNav', 'Layout'];
|
|
37
|
+
const FOUNDATION = [
|
|
38
|
+
'VStack', 'HStack', 'Grid', 'StackItem', 'Card', 'Section',
|
|
39
|
+
'Text', 'Heading', 'Button', 'Icon', 'Badge', 'Divider',
|
|
40
|
+
];
|
|
41
|
+
const ALWAYS = new Set([...FRAME, ...FOUNDATION]);
|
|
42
|
+
|
|
43
|
+
/** Print the build playbook (shown when `build` is run with no query). */
|
|
44
|
+
function printPlaybook(run) {
|
|
45
|
+
const lines = [
|
|
46
|
+
'',
|
|
47
|
+
'How to build a page with Astryx',
|
|
48
|
+
'',
|
|
49
|
+
"1. Find a starting point for what you're building:",
|
|
50
|
+
` ${run} astryx build "<what you're building>"`,
|
|
51
|
+
' → returns the closest [page] template, the [block]s that cover parts,',
|
|
52
|
+
' and the [component]s to fill the gaps, with a "Compose:" suggestion.',
|
|
53
|
+
'',
|
|
54
|
+
'2. If a [page] template matches → scaffold it and adapt:',
|
|
55
|
+
` ${run} astryx template <name> [path]`,
|
|
56
|
+
'',
|
|
57
|
+
'3. If nothing matches exactly → compose:',
|
|
58
|
+
` ${run} astryx template <name> --skeleton # study a close page's layout`,
|
|
59
|
+
` ${run} astryx template <BlockName> # drop in each block from the kit`,
|
|
60
|
+
` ${run} astryx component <Name> # fill remaining gaps (read props)`,
|
|
61
|
+
'',
|
|
62
|
+
'4. Rules (keep it on-system):',
|
|
63
|
+
' - No <div>/raw HTML for layout — use VStack/HStack/Grid/Stack/Card etc.',
|
|
64
|
+
' - No style={{}} — use component props; design tokens via `astryx docs tokens`.',
|
|
65
|
+
' - Wrap the app in <Theme theme={...}> and import core reset.css + astryx.css.',
|
|
66
|
+
'',
|
|
67
|
+
`Tip: \`${run} astryx build "<idea>"\` is the fastest way in. For a neutral`,
|
|
68
|
+
`lookup of any component/doc/template, use \`${run} astryx search <query>\`.`,
|
|
69
|
+
'',
|
|
70
|
+
];
|
|
71
|
+
for (const l of lines) humanLog(l);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function registerBuild(program) {
|
|
75
|
+
program
|
|
76
|
+
.command('build [query]')
|
|
77
|
+
.description('Build a page: composition kit for an idea, or the workflow playbook (no args)')
|
|
78
|
+
.option('--type <domain>', 'Filter the kit to one domain (component|hook|template)')
|
|
79
|
+
.option('--limit <n>', 'Max candidates to draw from (default 60)')
|
|
80
|
+
.option('--detail', 'Verbose output (include import paths and match reason)')
|
|
81
|
+
.action(async (query, options) => {
|
|
82
|
+
const run = getRunPrefix();
|
|
83
|
+
const json = program.opts().json || false;
|
|
84
|
+
|
|
85
|
+
// No query → print the playbook (the "how to build" skill).
|
|
86
|
+
if (!query || !String(query).trim()) {
|
|
87
|
+
if (json) return jsonOut('build.help', {playbook: true});
|
|
88
|
+
printPlaybook(run);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Default to a deep pool so each role section has candidates after grouping.
|
|
93
|
+
let limit = 60;
|
|
94
|
+
if (options.limit != null) {
|
|
95
|
+
const parsed = Number.parseInt(options.limit, 10);
|
|
96
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
97
|
+
cliError(`Invalid --limit value "${options.limit}". Must be a positive integer.`);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
limit = parsed;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
let result;
|
|
104
|
+
try {
|
|
105
|
+
result = await searchApi(query, {cwd: process.cwd(), type: options.type, limit});
|
|
106
|
+
} catch (e) {
|
|
107
|
+
cliError(e.message, {suggestions: e.suggestions});
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (json) return jsonOut(result.type, result.data);
|
|
112
|
+
|
|
113
|
+
const {query: q, results} = result.data;
|
|
114
|
+
|
|
115
|
+
if (results.length === 0) {
|
|
116
|
+
humanLog('');
|
|
117
|
+
humanLog(`No matches for "${q}".`);
|
|
118
|
+
humanLog(`Try a broader term, or browse: ${run} astryx component --list`);
|
|
119
|
+
humanLog('');
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ── Group results by role (the build kit) ──────────────────────
|
|
124
|
+
const pages = results
|
|
125
|
+
.filter(r => r.domain === 'template' && r.kind !== 'block' && r.score >= PAGE_FLOOR)
|
|
126
|
+
.slice(0, 3);
|
|
127
|
+
const blocks = results
|
|
128
|
+
.filter(r => r.domain === 'template' && r.kind === 'block' && r.score >= DOMAIN_FLOOR)
|
|
129
|
+
.slice(0, 5);
|
|
130
|
+
// Idea-specific atoms = matched components/hooks MINUS the always-on kit.
|
|
131
|
+
const domain = results
|
|
132
|
+
.filter(r => (r.domain === 'component' || r.domain === 'hook') && r.score >= DOMAIN_FLOOR && !ALWAYS.has(r.name))
|
|
133
|
+
.slice(0, 6);
|
|
134
|
+
const directMatch = pages.length > 0 && pages[0].score >= PAGE_DIRECT;
|
|
135
|
+
|
|
136
|
+
const printItem = (r, label) => {
|
|
137
|
+
const display = r.domain === 'template' && r.displayName ? r.displayName : r.name;
|
|
138
|
+
humanLog('');
|
|
139
|
+
humanLog(` [${label}] ${display}`);
|
|
140
|
+
if (r.description) humanLog(` ${r.description}`);
|
|
141
|
+
humanLog(` → ${run} ${r.command}`);
|
|
142
|
+
if (options.detail) {
|
|
143
|
+
if (r.import) humanLog(` import: ${r.import}`);
|
|
144
|
+
humanLog(` match: ${r.reason} (score ${r.score})`);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
humanLog('');
|
|
149
|
+
humanLog(`Building "${q}":`);
|
|
150
|
+
|
|
151
|
+
// START — the single recommended path.
|
|
152
|
+
humanLog('');
|
|
153
|
+
if (directMatch) {
|
|
154
|
+
humanLog(`START → Scaffold the \`${pages[0].name}\` page template, then adapt: ${run} astryx template ${pages[0].name} ./src/App.tsx`);
|
|
155
|
+
} else if (pages.length) {
|
|
156
|
+
humanLog(`START → No exact page template. Use \`${pages[0].name}\` as a layout reference (${run} astryx template ${pages[0].name} --skeleton) and compose the pieces below.`);
|
|
157
|
+
} else {
|
|
158
|
+
humanLog(`START → No page template fits. Frame with AppShell and compose the blocks + components below.`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// PAGE
|
|
162
|
+
if (pages.length) {
|
|
163
|
+
humanLog('');
|
|
164
|
+
humanLog(directMatch ? 'PAGE TEMPLATE — direct match:' : 'CLOSEST PAGE TEMPLATES — layout reference:');
|
|
165
|
+
pages.forEach(p => printItem(p, directMatch ? 'page' : 'closest'));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// FRAME — always (the page shell).
|
|
169
|
+
humanLog('');
|
|
170
|
+
humanLog(`FRAME — page shell (always): ${FRAME.join(', ')}`);
|
|
171
|
+
humanLog(` full-page → AppShell; or Layout + SideNav/TopNav. ${run} astryx component AppShell`);
|
|
172
|
+
|
|
173
|
+
// BLOCKS — idea-specific composed patterns.
|
|
174
|
+
if (blocks.length) {
|
|
175
|
+
humanLog('');
|
|
176
|
+
humanLog('BLOCKS — drop-in patterns that cover parts of it:');
|
|
177
|
+
blocks.forEach(b => printItem(b, 'block'));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// DOMAIN COMPONENTS — idea-specific atoms.
|
|
181
|
+
if (domain.length) {
|
|
182
|
+
humanLog('');
|
|
183
|
+
humanLog('DOMAIN COMPONENTS — specific to this idea:');
|
|
184
|
+
domain.forEach(c => printItem(c, c.domain === 'hook' ? 'hook' : 'component'));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// FOUNDATION — always (layout/typography/actions).
|
|
188
|
+
humanLog('');
|
|
189
|
+
humanLog(`FOUNDATION — always available (layout/text/actions): ${FOUNDATION.join(' ')}`);
|
|
190
|
+
|
|
191
|
+
// SETUP — so it renders / stays on-system.
|
|
192
|
+
humanLog('');
|
|
193
|
+
humanLog('SETUP — import "@astryxdesign/core/reset.css" + "astryx.css". No <div>/style for layout — use Stack/Grid + tokens.');
|
|
194
|
+
humanLog('');
|
|
195
|
+
});
|
|
196
|
+
}
|
|
@@ -10,7 +10,7 @@ import {registerDocs} from './docs.mjs';
|
|
|
10
10
|
let tmpDir;
|
|
11
11
|
|
|
12
12
|
beforeEach(() => {
|
|
13
|
-
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), '
|
|
13
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-docs-test-'));
|
|
14
14
|
vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
15
15
|
vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
16
16
|
});
|
|
@@ -26,7 +26,7 @@ let logCalls;
|
|
|
26
26
|
let exitCode;
|
|
27
27
|
|
|
28
28
|
beforeEach(() => {
|
|
29
|
-
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), '
|
|
29
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-doctor-test-'));
|
|
30
30
|
logCalls = [];
|
|
31
31
|
exitCode = undefined;
|
|
32
32
|
vi.spyOn(console, 'log').mockImplementation((...args) => {
|
package/src/commands/init.mjs
CHANGED
|
@@ -100,7 +100,15 @@ async function runTemplate(targetDir, {interactive = true, templateName} = {}) {
|
|
|
100
100
|
|
|
101
101
|
if (!interactive) {
|
|
102
102
|
if (!templateName) {
|
|
103
|
-
|
|
103
|
+
// Point agents at the build workflow rather than dumping page-template
|
|
104
|
+
// names — `build` surfaces pages AND blocks AND components for an idea,
|
|
105
|
+
// and `build` with no args is the full how-to-build playbook.
|
|
106
|
+
humanLog('✓ To build UI, use these commands:');
|
|
107
|
+
humanLog('');
|
|
108
|
+
humanLog(` ${run} astryx build "<what you're building>" build a page — kit: closest template + blocks + components`);
|
|
109
|
+
humanLog(` ${run} astryx build the how-to-build workflow (read this first)`);
|
|
110
|
+
humanLog(` ${run} astryx search <query> find anything — components, docs, templates, blocks`);
|
|
111
|
+
humanLog('');
|
|
104
112
|
return;
|
|
105
113
|
}
|
|
106
114
|
|
|
@@ -53,7 +53,7 @@ function parseJson(stdout) {
|
|
|
53
53
|
let tmpDir;
|
|
54
54
|
|
|
55
55
|
beforeEach(() => {
|
|
56
|
-
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), '
|
|
56
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-json-contract-'));
|
|
57
57
|
});
|
|
58
58
|
|
|
59
59
|
afterEach(() => {
|
|
@@ -177,9 +177,16 @@ describe('--json contract: supported commands emit valid envelopes', () => {
|
|
|
177
177
|
});
|
|
178
178
|
|
|
179
179
|
it('astryx upgrade --json (already up to date) emits upgrade.status', () => {
|
|
180
|
-
// Force a no-op range: from >
|
|
180
|
+
// Force a no-op range: from > installed target.
|
|
181
|
+
const coreDir = path.join(tmpDir, 'node_modules', '@astryxdesign', 'core');
|
|
182
|
+
fs.mkdirSync(coreDir, {recursive: true});
|
|
183
|
+
fs.writeFileSync(
|
|
184
|
+
path.join(coreDir, 'package.json'),
|
|
185
|
+
JSON.stringify({name: '@astryxdesign/core', version: '0.0.1'}, null, 2),
|
|
186
|
+
);
|
|
187
|
+
|
|
181
188
|
const {status, stdout} = runCli(
|
|
182
|
-
['upgrade', '--json', '--from', '99.0.0'
|
|
189
|
+
['upgrade', '--json', '--from', '99.0.0'],
|
|
183
190
|
{cwd: tmpDir},
|
|
184
191
|
);
|
|
185
192
|
expect(status).toBe(0);
|
|
@@ -36,7 +36,7 @@ let markerFile;
|
|
|
36
36
|
let baseEnv;
|
|
37
37
|
|
|
38
38
|
beforeAll(() => {
|
|
39
|
-
shimDir = fs.mkdtempSync(path.join(os.tmpdir(), '
|
|
39
|
+
shimDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-gh-shim-'));
|
|
40
40
|
markerFile = path.join(shimDir, 'gh-issue-create-was-called.marker');
|
|
41
41
|
|
|
42
42
|
// Sabotaged `gh` shim. Records ONLY `gh issue create` invocations to the
|
|
@@ -58,7 +58,7 @@ function runCli(args, cwd) {
|
|
|
58
58
|
|
|
59
59
|
let tmpDir;
|
|
60
60
|
beforeEach(() => {
|
|
61
|
-
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), '
|
|
61
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-swizzle-paths-'));
|
|
62
62
|
});
|
|
63
63
|
afterEach(() => {
|
|
64
64
|
fs.rmSync(tmpDir, {recursive: true, force: true});
|
|
@@ -17,7 +17,7 @@ let tmpDir;
|
|
|
17
17
|
let templateApi;
|
|
18
18
|
|
|
19
19
|
beforeEach(async () => {
|
|
20
|
-
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), '
|
|
20
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-template-paths-'));
|
|
21
21
|
templateApi = (await import('../api/template.mjs')).template;
|
|
22
22
|
});
|
|
23
23
|
afterEach(() => {
|