@ikas/component-cli 0.82.0 → 0.85.0

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 (39) hide show
  1. package/dist/commands/create.d.ts.map +1 -1
  2. package/dist/commands/create.js +36 -791
  3. package/dist/commands/create.js.map +1 -1
  4. package/dist/utils/component-helpers.d.ts +1 -1
  5. package/dist/utils/component-helpers.d.ts.map +1 -1
  6. package/dist/utils/component-helpers.js +13 -65
  7. package/dist/utils/component-helpers.js.map +1 -1
  8. package/dist/utils/observer-runtime.d.ts.map +1 -1
  9. package/dist/utils/observer-runtime.js +2 -37
  10. package/dist/utils/observer-runtime.js.map +1 -1
  11. package/dist/utils/template.d.ts +8 -0
  12. package/dist/utils/template.d.ts.map +1 -0
  13. package/dist/utils/template.js +24 -0
  14. package/dist/utils/template.js.map +1 -0
  15. package/package.json +3 -2
  16. package/templates/add/component.css +13 -0
  17. package/templates/add/component.tsx +12 -0
  18. package/templates/add/section.css +17 -0
  19. package/templates/add/section.tsx +14 -0
  20. package/templates/create/CLAUDE.md +258 -0
  21. package/templates/create/README.md +50 -0
  22. package/templates/create/cursorrules +108 -0
  23. package/templates/create/gitignore +5 -0
  24. package/templates/create/ikas.config.json +95 -0
  25. package/templates/create/mcp.json +10 -0
  26. package/templates/create/package.json +21 -0
  27. package/templates/create/src/components/ExampleComponent/index.tsx +22 -0
  28. package/templates/create/src/components/ExampleComponent/styles.css +36 -0
  29. package/templates/create/src/components/ExampleComponent/types.ts +7 -0
  30. package/templates/create/src/components/ExampleSection/index.tsx +14 -0
  31. package/templates/create/src/components/ExampleSection/styles.css +29 -0
  32. package/templates/create/src/components/ExampleSection/types.ts +6 -0
  33. package/templates/create/src/components/index.ts +2 -0
  34. package/templates/create/src/global-types.ts +5 -0
  35. package/templates/create/src/global.css +12 -0
  36. package/templates/create/src/ikas-component-utils.d.ts +3 -0
  37. package/templates/create/tsconfig.json +30 -0
  38. package/templates/create/vite.config.ts +15 -0
  39. package/templates/observer-runtime.js +34 -0
@@ -5,6 +5,7 @@ import inquirer from "inquirer";
5
5
  import ora from "ora";
6
6
  import * as path from "path";
7
7
  import { generateComponentId, generateProjectId } from "../utils/component-helpers.js";
8
+ import { readTemplate } from "../utils/template.js";
8
9
  const PROP_TYPES = [
9
10
  "TEXT",
10
11
  "NUMBER",
@@ -21,6 +22,8 @@ const PROP_TYPES = [
21
22
  "BRAND_LIST",
22
23
  "BLOG",
23
24
  "BLOG_LIST",
25
+ "BLOG_CATEGORY",
26
+ "BLOG_CATEGORY_LIST",
24
27
  "TYPE",
25
28
  "ENUM",
26
29
  "COMPONENT",
@@ -39,799 +42,41 @@ async function createProject(projectName) {
39
42
  fs.mkdirSync(projectPath, { recursive: true });
40
43
  fs.mkdirSync(path.join(projectPath, "src/components/ExampleComponent"), { recursive: true });
41
44
  fs.mkdirSync(path.join(projectPath, "src/components/ExampleSection"), { recursive: true });
42
- // Create package.json
43
- const packageJson = {
44
- name: projectName,
45
- version: "1.0.0",
46
- type: "module",
47
- scripts: {
48
- dev: "ikas-component dev",
49
- build: "ikas-component build",
50
- add: "ikas-component add",
51
- publish: "ikas-component publish"
52
- },
53
- dependencies: {
54
- preact: "^10.19.3"
55
- },
56
- devDependencies: {
57
- "@ikas/component-cli": "*",
58
- "@ikas/bp-storefront": "*",
59
- "@ikas/code-components-mcp": "*",
60
- typescript: "^5.3.0",
61
- vite: "^5.0.0"
62
- }
63
- };
64
- fs.writeFileSync(path.join(projectPath, "package.json"), JSON.stringify(packageJson, null, 2));
65
- // Create tsconfig.json
66
- const tsConfig = {
67
- compilerOptions: {
68
- target: "ES2022",
69
- lib: ["DOM", "DOM.Iterable", "ES2022"],
70
- module: "ESNext",
71
- moduleResolution: "bundler",
72
- jsx: "react-jsx",
73
- jsxImportSource: "preact",
74
- strict: true,
75
- esModuleInterop: true,
76
- skipLibCheck: true,
77
- forceConsistentCasingInFileNames: true,
78
- resolveJsonModule: true,
79
- declaration: true,
80
- declarationMap: true,
81
- outDir: "./dist",
82
- rootDir: "./src"
83
- },
84
- include: ["src/**/*"],
85
- exclude: ["node_modules", "dist"]
86
- };
87
- fs.writeFileSync(path.join(projectPath, "tsconfig.json"), JSON.stringify(tsConfig, null, 2));
88
- // Create vite.config.ts
89
- const viteConfig = `import { defineConfig } from "vite";
90
- import preact from "@preact/preset-vite";
91
-
92
- export default defineConfig({
93
- plugins: [preact()],
94
- build: {
95
- lib: {
96
- entry: "./src/components/index.ts",
97
- formats: ["es"]
98
- },
99
- rollupOptions: {
100
- external: ["preact", "preact/hooks", "@ikas/component-utils"]
101
- }
102
- }
103
- });
104
- `;
105
- fs.writeFileSync(path.join(projectPath, "vite.config.ts"), viteConfig);
106
- // Create ikas.config.json
45
+ // Generate IDs for the example config
107
46
  const projectId = generateProjectId();
108
- const ikasConfig = {
109
- name: projectName,
110
- version: "1.0.0",
111
- projectId,
112
- globalStyles: "./src/global.css",
113
- components: [
114
- {
115
- id: generateComponentId(projectId, "example-component"),
116
- name: "Example Component",
117
- entry: "./src/components/ExampleComponent/index.tsx",
118
- styles: "./src/components/ExampleComponent/styles.css",
119
- props: [
120
- {
121
- name: "title",
122
- displayName: "Title",
123
- type: "TEXT",
124
- required: true,
125
- defaultValue: "Hello World",
126
- description: "The main title text"
127
- },
128
- {
129
- name: "description",
130
- displayName: "Description",
131
- type: "TEXT",
132
- required: false,
133
- defaultValue: "This is an example ikas code component built with Preact.",
134
- description: "The description text below the title"
135
- },
136
- {
137
- name: "showButton",
138
- displayName: "Show Button",
139
- type: "BOOLEAN",
140
- required: false,
141
- defaultValue: true,
142
- description: "Whether to show the action button"
143
- },
144
- {
145
- name: "buttonText",
146
- displayName: "Button Text",
147
- type: "TEXT",
148
- required: false,
149
- defaultValue: "Click Me",
150
- description: "The text displayed on the button"
151
- }
152
- ]
153
- },
154
- {
155
- id: generateComponentId(projectId, "example-section"),
156
- name: "Example Section",
157
- entry: "./src/components/ExampleSection/index.tsx",
158
- styles: "./src/components/ExampleSection/styles.css",
159
- type: "section",
160
- props: [
161
- {
162
- name: "heading",
163
- displayName: "Heading",
164
- type: "TEXT",
165
- required: true,
166
- defaultValue: "Welcome to Our Store",
167
- description: "The section heading text",
168
- groupId: "content"
169
- },
170
- {
171
- name: "subtitle",
172
- displayName: "Subtitle",
173
- type: "TEXT",
174
- required: false,
175
- defaultValue: "Discover our latest products and collections.",
176
- description: "The subtitle text below the heading",
177
- groupId: "content"
178
- },
179
- {
180
- name: "backgroundColor",
181
- displayName: "Background Color",
182
- type: "COLOR",
183
- required: false,
184
- description: "The section background color",
185
- groupId: "appearance"
186
- }
187
- ],
188
- propGroups: [
189
- { id: "content", name: "Content", description: "Text and copy settings" },
190
- { id: "appearance", name: "Appearance", description: "Colors and visual style" }
191
- ]
192
- }
193
- ]
47
+ const exampleComponentId = generateComponentId(projectId, "example-component");
48
+ const exampleSectionId = generateComponentId(projectId, "example-section");
49
+ const vars = {
50
+ PROJECT_NAME: projectName,
51
+ PROJECT_ID: projectId,
52
+ EXAMPLE_COMPONENT_ID: exampleComponentId,
53
+ EXAMPLE_SECTION_ID: exampleSectionId,
194
54
  };
195
- fs.writeFileSync(path.join(projectPath, "ikas.config.json"), JSON.stringify(ikasConfig, null, 2));
196
- // Create ExampleComponent
197
- const exampleComponentTsx = `import { Props } from "./types";
198
-
199
- export function ExampleComponent({
200
- title,
201
- description = "This is an example ikas code component built with Preact.",
202
- showButton,
203
- buttonText = "Click Me",
204
- }: Props) {
205
- return (
206
- <div className="example-component">
207
- <h1 className="example-title">{title}</h1>
208
- <p className="example-description">{description}</p>
209
- {showButton && (
210
- <button className="example-button">
211
- {buttonText}
212
- </button>
213
- )}
214
- </div>
215
- );
216
- }
217
-
218
- export default ExampleComponent;
219
- `;
220
- fs.writeFileSync(path.join(projectPath, "src/components/ExampleComponent/index.tsx"), exampleComponentTsx);
221
- // Create component types
222
- const componentTypes = `// Auto-generated types based on ikas.config.json props
223
- export interface Props {
224
- title: string;
225
- description?: string;
226
- showButton?: boolean;
227
- buttonText?: string;
228
- }
229
- `;
230
- fs.writeFileSync(path.join(projectPath, "src/components/ExampleComponent/types.ts"), componentTypes);
231
- // Create component styles
232
- const componentStyles = `.example-component {
233
- padding: 24px;
234
- border-radius: 8px;
235
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
236
- color: white;
237
- font-family: system-ui, -apple-system, sans-serif;
238
- }
239
-
240
- .example-title {
241
- margin: 0 0 12px 0;
242
- font-size: 28px;
243
- font-weight: 700;
244
- }
245
-
246
- .example-description {
247
- margin: 0 0 20px 0;
248
- font-size: 16px;
249
- opacity: 0.9;
250
- }
251
-
252
- .example-button {
253
- padding: 12px 24px;
254
- border: none;
255
- border-radius: 6px;
256
- background: white;
257
- color: #667eea;
258
- font-size: 16px;
259
- font-weight: 600;
260
- cursor: pointer;
261
- transition: transform 0.2s, box-shadow 0.2s;
262
- }
263
-
264
- .example-button:hover {
265
- transform: translateY(-2px);
266
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
267
- }
268
- `;
269
- fs.writeFileSync(path.join(projectPath, "src/components/ExampleComponent/styles.css"), componentStyles);
270
- // Create ExampleSection
271
- const exampleSectionTsx = `import { Props } from "./types";
272
-
273
- export function ExampleSection({ heading, subtitle, backgroundColor }: Props) {
274
- return (
275
- <section className="example-section" style={backgroundColor ? { backgroundColor } : undefined}>
276
- <div className="example-section-inner">
277
- <h2 className="example-section-heading">{heading}</h2>
278
- {subtitle && <p className="example-section-subtitle">{subtitle}</p>}
279
- </div>
280
- </section>
281
- );
282
- }
283
-
284
- export default ExampleSection;
285
- `;
286
- fs.writeFileSync(path.join(projectPath, "src/components/ExampleSection/index.tsx"), exampleSectionTsx);
287
- // Create section types
288
- const sectionTypes = `// Auto-generated types based on ikas.config.json props
289
- export interface Props {
290
- heading: string;
291
- subtitle?: string;
292
- backgroundColor?: string;
293
- }
294
- `;
295
- fs.writeFileSync(path.join(projectPath, "src/components/ExampleSection/types.ts"), sectionTypes);
296
- // Create section styles
297
- const sectionStyles = `.example-section {
298
- width: 100%;
299
- padding: 64px 24px;
300
- background: #f8f9fa;
301
- }
302
-
303
- .example-section-inner {
304
- max-width: 1200px;
305
- margin: 0 auto;
306
- text-align: center;
307
- }
308
-
309
- .example-section-heading {
310
- margin: 0 0 16px 0;
311
- font-size: 36px;
312
- font-weight: 700;
313
- color: #1a1a2e;
314
- font-family: system-ui, -apple-system, sans-serif;
315
- }
316
-
317
- .example-section-subtitle {
318
- margin: 0;
319
- font-size: 18px;
320
- color: #6b7280;
321
- font-family: system-ui, -apple-system, sans-serif;
322
- max-width: 600px;
323
- margin-left: auto;
324
- margin-right: auto;
325
- }
326
- `;
327
- fs.writeFileSync(path.join(projectPath, "src/components/ExampleSection/styles.css"), sectionStyles);
328
- // Create global CSS file
329
- const globalCss = `/*
330
- * Global styles for your ikas code components project.
331
- * These styles are NOT scoped — they apply across all components.
332
- * Use this for CSS resets, base typography, utility classes, or CSS variables.
333
- *
334
- * Loading order:
335
- * 1. Global CSS (this file) — lowest specificity
336
- * 2. Shared chunk CSS — multi-scope (.cc_a .sel, .cc_b .sel)
337
- * 3. Component CSS — single scope (.cc_id .sel) — highest specificity
338
- *
339
- * Component-scoped styles naturally override these globals.
340
- */
341
- `;
342
- fs.writeFileSync(path.join(projectPath, "src/global.css"), globalCss);
343
- // Create empty global types file
344
- const globalTypes = `// Auto-generated global type definitions for ikas code components.
345
- // Custom enum types from the editor will appear here.
346
- // This file is regenerated automatically — do not edit manually.
347
-
348
- export {};
349
- `;
350
- fs.writeFileSync(path.join(projectPath, "src/global-types.ts"), globalTypes);
351
- // Create components index
352
- const componentsIndex = `export { ExampleComponent } from "./ExampleComponent/index";
353
- export { ExampleSection } from "./ExampleSection/index";
354
- `;
355
- fs.writeFileSync(path.join(projectPath, "src/components/index.ts"), componentsIndex);
356
- // Create README
357
- const readme = `# ${projectName}
358
-
359
- An ikas code components project.
360
-
361
- ## Getting Started
362
-
363
- 1. Install dependencies:
364
- \`\`\`bash
365
- npm install
366
- \`\`\`
367
-
368
- 2. Start the development server:
369
- \`\`\`bash
370
- npm run dev
371
- \`\`\`
372
-
373
- 3. Open the ikas editor and connect to the dev server from the Dev Components panel.
374
-
375
- ## Commands
376
-
377
- - \`npm run dev\` - Start development server with live editor updates
378
- - \`npm run build\` - Build components for production
379
- - \`npm run add\` - Add a new component to the project
380
-
381
- ## Project Structure
382
-
383
- \`\`\`
384
- ${projectName}/
385
- ├── src/
386
- │ ├── components/
387
- │ │ ├── ExampleComponent/ # A child component (type: "component")
388
- │ │ │ ├── index.tsx
389
- │ │ │ ├── styles.css
390
- │ │ │ └── types.ts
391
- │ │ ├── ExampleSection/ # A page-level section (type: "section")
392
- │ │ │ ├── index.tsx
393
- │ │ │ ├── styles.css
394
- │ │ │ └── types.ts
395
- │ │ └── index.ts
396
- │ ├── global.css # Unscoped global styles
397
- │ └── global-types.ts # Auto-generated shared enum types
398
- ├── ikas.config.json
399
- ├── package.json
400
- ├── tsconfig.json
401
- └── vite.config.ts
402
- \`\`\`
403
-
404
- ## Sections vs Components
405
-
406
- There are two types of code components:
407
-
408
- - **Sections** are page-level, full-width containers (e.g. Header, Hero Banner, Footer).
409
- Set \`"type": "section"\` on the component entry in \`ikas.config.json\`.
410
- - **Components** are child elements placed inside sections (e.g. buttons, cards, badges).
411
- No \`type\` field needed — it defaults to \`"component"\`.
412
-
413
- ## Adding Props
414
-
415
- Edit \`ikas.config.json\` to add props to your components. Available prop types:
416
-
417
- - \`TEXT\` - String input
418
- - \`NUMBER\` - Number input
419
- - \`BOOLEAN\` - Checkbox toggle
420
- - \`IMAGE\` - Image picker
421
- - \`LINK\` - Link/URL input
422
- - \`LIST_OF_LINK\` - List of navigation links
423
- - \`COLOR\` - Color picker
424
- - \`PRODUCT\` - Single product selector
425
- - \`PRODUCT_LIST\` - Multiple products selector
426
- - \`CATEGORY\` - Single category selector
427
- - \`CATEGORY_LIST\` - Multiple categories selector
428
- - \`BRAND\` - Single brand selector
429
- - \`BRAND_LIST\` - Multiple brands selector
430
- - \`BLOG\` - Single blog post selector
431
- - \`BLOG_LIST\` - Multiple blog posts selector
432
-
433
- ## Building for Production
434
-
435
- Run \`npm run build\` to compile your components. The output will be ready to upload to the ikas editor.
436
- `;
437
- fs.writeFileSync(path.join(projectPath, "README.md"), readme);
438
- // Create .gitignore
439
- const gitignore = `node_modules/
440
- dist/
441
- .DS_Store
442
- *.log
443
- `;
444
- fs.writeFileSync(path.join(projectPath, ".gitignore"), gitignore);
445
- // Create type declarations for virtual modules
446
- const componentUtilsTypes = `declare module "@ikas/component-utils" {
447
- export function observer<T extends (props: any) => any>(component: T): T;
448
- }
449
- `;
450
- fs.writeFileSync(path.join(projectPath, "src/ikas-component-utils.d.ts"), componentUtilsTypes);
451
- // Create CLAUDE.md for Claude Code AI assistant
452
- const claudeMd = `# ikas Code Components Project
453
-
454
- You are building **Preact + TypeScript components for an e-commerce storefront**.
455
- This project uses the ikas Code Components framework with an MCP server for API documentation.
456
-
457
- **ALWAYS query MCP tools before writing code that uses storefront APIs.**
458
- Never guess function signatures or type shapes — the MCP server is the source of truth.
459
-
460
- ## CRITICAL: Auto-Generated Files
461
-
462
- **NEVER manually create or edit \`types.ts\` or \`global-types.ts\`** — they are auto-generated by CLI commands.
463
- Use \`npx ikas-component config add-component --props '[...]'\` or \`npx ikas-component config add-prop\` to manage props.
464
- These commands update \`ikas.config.json\`, \`types.ts\`, and \`global-types.ts\` automatically.
465
-
466
- ## MCP Tools (12 tools)
467
-
468
- ### Starting a New Section
469
- | Tool | Purpose |
470
- |------|---------|
471
- | \`get_section_template(sectionType)\` | **Start here** — production-ready starter template (index.tsx + types.ts + styles.css + config) for common sections: header, footer, product-detail, product-list, cart, login, register, hero-banner, blog-post, faq, etc. |
472
- | \`get_framework_guide(topic)\` | Framework docs — "ai-workflow", "common-pitfalls", "prop-types", "css-scoping", "form-handling", "imports", "sections-vs-components" |
473
- | \`get_code_example(task)\` | Code examples — "add to cart", "variant selection", "image-handling", "product-detail-section", "cart-section" |
474
-
475
- ### Looking Up APIs
476
- | Tool | Purpose |
477
- |------|---------|
478
- | \`search_docs(query)\` | Search across all storefront API docs and framework guides |
479
- | \`get_function_doc(name)\` | Full docs for a specific function (e.g. "addItemToCart", "Router.navigate") |
480
- | \`list_functions(category?)\` | List functions by category: ProductDetail, Cart, ProductList, Navigation, Customer, Order, Image, Blog, Brand, Category, Pricing, Form, Validation, Pagination, Filtering |
481
- | \`get_prop_types()\` | All available ikas.config.json prop types with TS types and examples |
482
-
483
- ### Exploring Types
484
- | Tool | Purpose |
485
- |------|---------|
486
- | \`get_model_guide(model)\` | **One-stop-shop** — type definition + all utility functions + examples + related types for a model (e.g. "IkasProduct", "IkasOrder") |
487
- | \`get_type_definition(name)\` | Full definition of a type or enum (e.g. "IkasProduct", "IkasOrderStatus") |
488
- | \`get_functions_for_type(typeName)\` | All utility functions for a type (e.g. "IkasImage") |
489
- | \`search_types(query)\` | Search types/enums by keyword (e.g. "price", "address", "status") |
490
- | \`list_types(domain?, kind?)\` | List all types, optionally filtered by domain ("product", "cart", "order") or kind ("type", "enum") |
491
-
492
- ## CLI Commands
493
-
494
- **Never edit ikas.config.json or types.ts manually** — use the CLI commands:
495
-
496
- | Command | Purpose |
497
- |---------|---------|
498
- | \`npx ikas-component config add-component --name "Name" --type section --props '[...]'\` | **Primary** — create component with all props in one command |
499
- | \`npx ikas-component config add-component --name "Name" --type section\` | Create component with no props (add later) |
500
- | \`npx ikas-component config add-prop --component "Name" --name title --displayName "Title" --type TEXT --required [--group content]\` | Add a single prop incrementally |
501
- | \`npx ikas-component config update-prop --component "Name" --prop title --type RICH_TEXT [--group colors]\` | Update a prop's type or group |
502
- | \`npx ikas-component config remove-prop --component "Name" --prop title\` | Remove a prop |
503
- | \`npx ikas-component config remove-component --name "Name"\` | Remove a component |
504
- | \`npx ikas-component config add-prop-group --component "Name" --id colors --name "Colors" [--description "..."] [--parent style]\` | Create a prop group |
505
- | \`npx ikas-component config update-prop-group --component "Name" --id colors [--name "..."] [--description "..."]\` | Update a prop group |
506
- | \`npx ikas-component config remove-prop-group --component "Name" --id colors\` | Remove a prop group |
507
- | \`npx ikas-component config list\` | List all components and their props |
508
- | \`npx ikas-component check --json\` | Type-check all components, output errors as JSON |
509
- | \`npx ikas-component build\` | Compile server.js + client.js + styles.css per component |
510
- | \`npx ikas-component dev\` | Start dev server (Vite 5200 + WebSocket 5201) |
511
-
512
- ## Workflow: Building a New Section
513
-
514
- 1. \`get_section_template("product-detail")\` → get starter files + CLI command with --props
515
- 2. Run the CLI command (creates component + props + types.ts in one step)
516
- 3. Write \`index.tsx\` and \`styles.css\` using the template (do NOT edit types.ts — it's already generated)
517
- 4. Look up APIs → \`get_model_guide("IkasProduct")\`, \`get_function_doc("addItemToCart")\`
518
- 5. \`npx ikas-component check --json\` → fix type errors
519
- 6. \`npx ikas-component build\` → verify clean build
520
-
521
- ## Sub-Component Structure
522
-
523
- **ALWAYS create sub-components in \`src/sub-components/\` with their own folder containing \`index.tsx\` and \`styles.css\`. NEVER create flat .tsx files inside a component folder.**
524
-
525
- \`\`\`
526
- src/
527
- ├── components/
528
- │ ├── ProductList/
529
- │ │ ├── index.tsx # imports from ../../sub-components/...
530
- │ │ ├── types.ts # auto-generated (CLI-managed)
531
- │ │ └── styles.css # @import "../../sub-components/.../styles.css"
532
- │ └── index.ts
533
- ├── sub-components/
534
- │ ├── ProductCard/
535
- │ │ ├── index.tsx # sub-component with inline Props
536
- │ │ └── styles.css
537
- │ └── FilterSidebar/
538
- │ ├── index.tsx
539
- │ └── styles.css
540
- ├── global.css # unscoped global styles
541
- └── global-types.ts # auto-generated shared enum types
542
- \`\`\`
543
-
544
- **Key rules:**
545
- - \`src/components/\` = registered in ikas.config.json. \`src/sub-components/\` = internal helpers (NOT in ikas.config.json)
546
- - Sub-components do NOT have \`types.ts\` — define \`Props\` inline in \`index.tsx\`
547
- - Custom enum types are exported from \`src/global-types.ts\` (auto-generated). Sub-components can import them: \`import type { MyEnum } from "../../global-types";\`
548
- - CSS: use \`@import "../../sub-components/ProductCard/styles.css";\` in parent styles.css
549
- - TSX: use \`import ProductCard from "../../sub-components/ProductCard";\`
550
- - Sub-components that read MobX stores need \`observer()\`, others don't
551
- - Sub-components can be shared across multiple parent sections
552
-
553
- \`\`\`tsx
554
- // src/sub-components/ProductCard/index.tsx — inline Props, no types.ts
555
- import { IkasProduct, getSelectedProductVariant } from "@ikas/bp-storefront";
556
-
557
- interface Props { product: IkasProduct; }
558
-
559
- export default function ProductCard({ product }: Props) { ... }
560
- \`\`\`
561
-
562
- ## Key Patterns
563
-
564
- ### Component Exports & Reactivity
565
- \`\`\`tsx
566
- // Root components are automatically reactive — the ikas runtime wraps them in autorun().
567
- // Do NOT import or use observer() on root exports.
568
- import { Props } from "./types";
569
-
570
- export function MySection({ product }: Props) { ... }
571
- export default MySection;
572
- \`\`\`
573
-
574
- \`\`\`tsx
575
- // Only use observer() on extracted SUB-COMPONENTS that independently read MobX stores:
576
- import { observer } from "@ikas/component-utils";
577
-
578
- const CartBadge = observer(function CartBadge() {
579
- const count = cartStore.order?.orderLineItems?.length ?? 0;
580
- return <span>{count}</span>;
581
- });
582
- \`\`\`
583
-
584
- ### Null Safety
585
- \`\`\`tsx
586
- // Storefront models can be null — always check before accessing
587
- if (!product) return null;
588
- const price = product.selectedVariant?.price?.formattedPrice ?? "";
589
- \`\`\`
590
-
591
- ### Mutations
592
- \`\`\`tsx
593
- // Functions like addItemToCart() mutate the model in-place (MobX observable)
594
- // No need to capture return value — root components re-render automatically via autorun()
595
- await addItemToCart({ product });
596
- \`\`\`
597
-
598
- ### COMPONENT & COMPONENT_LIST Props
599
- These props let you create **slot-based** architectures where store owners can drag child components into your section/component from the editor.
600
-
601
- - \`COMPONENT\` — a single child component slot (TS type: \`any\`)
602
- - \`COMPONENT_LIST\` — a list of child components (TS type: \`any\`)
603
-
604
- **Rendering:** Use the \`<IkasComponentRenderer>\` wrapper to render child components:
605
- \`\`\`tsx
606
- import { IkasComponentRenderer } from "@ikas/bp-storefront";
607
- import { Props } from "./types";
608
-
609
- export function MySection({ title, cardList, ...props }: Props) {
610
- return (
611
- <section>
612
- <h2>{title}</h2>
613
- <div className="cards">
614
- {/* COMPONENT_LIST — render a list of child components */}
615
- <IkasComponentRenderer
616
- components={cardList as any[]}
617
- parentProps={props}
618
- />
619
- </div>
620
- </section>
621
- );
622
- }
623
- export default MySection;
624
- \`\`\`
625
-
626
- **Key rules:**
627
- - Always pass \`parentProps={props}\` so child components can access parent data via dynamic values
628
- - Cast the prop value: \`components={myList as any[]}\` for COMPONENT_LIST, \`components={[myComp] as any[]}\` for COMPONENT
629
- - \`<IkasComponentRenderer>\` handles rendering, styling, and reactivity of child components automatically
630
-
631
- **Config example:**
632
- \`\`\`json
633
- {
634
- "name": "cardList",
635
- "displayName": "Card List",
636
- "type": "COMPONENT_LIST"
637
- }
638
- \`\`\`
639
-
640
- ### CSS Scoping
641
- All CSS is auto-scoped with \`.cc_{componentId}\` prefix. Write plain class names — they are scoped at build time.
642
-
643
- ### Preact Event Handling
644
- Use \`onInput\` instead of \`onChange\` for text inputs (Preact behavior).
645
-
646
- ### Import Source
647
- \`\`\`tsx
648
- import { addItemToCart, IkasProduct, IkasImage } from "@ikas/bp-storefront";
649
- \`\`\`
650
-
651
- ## No Static Text Rule
652
-
653
- **CRITICAL: Never hardcode user-visible text in JSX.** All text strings (headings, button labels,
654
- empty states, loading messages, form labels) MUST be TEXT props with defaultValues.
655
-
656
- Wrong: \`<h1>Sign In</h1>\`
657
- Correct: \`<h1>{title}</h1>\` with \`title\` as TEXT prop (defaultValue: "Sign In")
658
-
659
- For button loading states, use two separate props:
660
- - \`submitButtonText\` (default: "Sign In")
661
- - \`submittingButtonText\` (default: "Signing in...")
662
-
663
- Group text props under a "Texts" propGroup when the component has 5+ props.
664
-
665
- ## Sections vs Components
666
-
667
- - **Sections** = page-level, full-width containers (Header, Hero, Product Grid, Footer).
668
- Set \`"type": "section"\` via CLI. Use \`<section>\` root element. Props interface: \`Props\`.
669
- **Sections MUST always include a \`backgroundColor\` COLOR prop** (default: \`#ffffff\`).
670
- Apply via inline style: \`style={backgroundColor ? { backgroundColor } : undefined}\`
671
- Consider also adding \`textColor\` COLOR props for text elements directly on the section background.
672
- - **Components** = child elements placed inside sections (buttons, cards, badges).
673
- Defaults to \`"component"\`. Use \`<div>\` root element. Props interface: \`Props\`.
674
-
675
- ## Prop Groups
676
-
677
- Organize props into collapsible groups in the editor sidebar. Use prop groups when a component has 5+ props to improve UX.
678
-
679
- ### Config Format
680
- - Define groups in \`propGroups\` array on the component in \`ikas.config.json\`
681
- - Assign props to groups via \`groupId\` on each prop
682
- - Groups can nest 1 level deep via \`children\`
683
- - Props without \`groupId\` appear ungrouped at root level
684
- - Group IDs must be unique within a component
685
-
686
- ### CLI Commands
687
- - \`config add-prop-group --component "Name" --id content --name "Content"\` — create group
688
- - \`config add-prop-group --component "Name" --id colors --name "Colors" --parent style\` — create nested group
689
- - \`config add-prop --component "Name" --name title --displayName "Title" --type TEXT --group content\` — add prop to group
690
- - \`config update-prop --component "Name" --prop title --group colors\` — move prop to different group
691
- - \`config remove-prop-group --component "Name" --id content\` — remove group (props become ungrouped)
692
-
693
- ### When to Use
694
- - 5+ props → group related props
695
- - Sections with content + style props → separate "Content" and "Appearance" groups
696
- - Complex sections → use nested groups (e.g., "Style" → "Colors", "Typography")
697
-
698
- ## Workflow Addition
699
-
700
- When building a section with 5+ props, organize into prop groups after defining props:
701
- \`\`\`bash
702
- npx ikas-component config add-prop-group --component "Name" --id content --name "Content"
703
- npx ikas-component config update-prop --component "Name" --prop title --group content
704
- \`\`\`
705
-
706
- ## Build Verification
707
-
708
- IMPORTANT: After completing any task, always run \`npx ikas-component build\` (or \`npm run build\`) to check for
709
- TypeScript and build errors. Fix any errors before considering the task done.
710
- `;
711
- fs.writeFileSync(path.join(projectPath, "CLAUDE.md"), claudeMd);
712
- // Create .cursorrules for Cursor AI assistant
713
- const cursorrules = `# ikas Code Components
714
-
715
- You are building **Preact + TypeScript components for an e-commerce storefront**.
716
- **ALWAYS query MCP tools before writing code that uses storefront APIs.**
717
-
718
- ## CRITICAL: Auto-Generated Files
719
-
720
- **NEVER manually create or edit \`types.ts\` or \`global-types.ts\`** — they are auto-generated by CLI commands.
721
- Use \`npx ikas-component config add-component --props '[...]'\` or \`npx ikas-component config add-prop\` to manage props.
722
- These commands update \`ikas.config.json\`, \`types.ts\`, and \`global-types.ts\` automatically.
723
-
724
- ## MCP Tools (12 tools)
725
-
726
- ### Starting a New Section
727
- - get_section_template(sectionType) — **Start here** — production-ready starter template for common sections (header, footer, product-detail, product-list, cart, login, hero-banner, blog-post, faq, etc.)
728
- - get_framework_guide(topic) — Framework docs ("ai-workflow", "common-pitfalls", "prop-types", "css-scoping", "form-handling", "imports")
729
- - get_code_example(task) — Code examples ("add to cart", "variant selection", "image-handling")
730
-
731
- ### Looking Up APIs
732
- - search_docs(query) — Search all storefront API docs and framework guides
733
- - get_function_doc(name) — Full docs for a function (e.g. "addItemToCart", "Router.navigate")
734
- - list_functions(category?) — List functions by category (ProductDetail, Cart, ProductList, Navigation, Customer, Order, Image, Blog, Brand, Pricing, Form, Validation, Pagination, Filtering)
735
- - get_prop_types() — All available ikas.config.json prop types
736
-
737
- ### Exploring Types
738
- - get_model_guide(model) — **One-stop-shop** — type def + utility functions + examples for a model (e.g. "IkasProduct", "IkasOrder")
739
- - get_type_definition(name) — Full definition of a type or enum
740
- - get_functions_for_type(typeName) — All utility functions for a type
741
- - search_types(query) — Search types/enums by keyword ("price", "address", "status")
742
- - list_types(domain?, kind?) — List all types, filter by domain or kind ("type"/"enum")
743
-
744
- ## CLI Commands (never edit ikas.config.json or types.ts manually)
745
- - npx ikas-component config add-component --name "Name" --type section --props '[...]' — **Primary** — create with all props in one command
746
- - npx ikas-component config add-component --name "Name" --type section — Create component with no props
747
- - npx ikas-component config add-prop --component "Name" --name title --displayName "Title" --type TEXT --required [--group content] — Add a prop incrementally
748
- - npx ikas-component config update-prop --component "Name" --prop title --type RICH_TEXT [--group colors] — Update a prop or group
749
- - npx ikas-component config remove-prop --component "Name" --prop title — Remove a prop
750
- - npx ikas-component config remove-component --name "Name" — Remove a component
751
- - npx ikas-component config add-prop-group --component "Name" --id colors --name "Colors" [--parent style] — Create a prop group
752
- - npx ikas-component config update-prop-group --component "Name" --id colors [--name "..."] — Update a prop group
753
- - npx ikas-component config remove-prop-group --component "Name" --id colors — Remove a prop group
754
- - npx ikas-component config list — List all components and their props
755
- - npx ikas-component check --json — Type-check all components
756
- - npx ikas-component build — Compile server.js + client.js + styles.css per component
757
- - npx ikas-component dev — Start dev server (Vite 5200 + WebSocket 5201)
758
-
759
- ## Workflow: Building a New Section
760
- 1. get_section_template("product-detail") → get starter files + CLI command with --props
761
- 2. Run the CLI command (creates component + props + types.ts in one step)
762
- 3. Write index.tsx and styles.css using the template (do NOT edit types.ts — it's already generated)
763
- 4. Look up APIs: get_model_guide("IkasProduct"), get_function_doc("addItemToCart")
764
- 5. npx ikas-component check --json → fix type errors
765
- 6. npx ikas-component build → verify clean build
766
-
767
- ## Sub-Component Structure
768
- **ALWAYS create sub-components in \`src/sub-components/\` with their own folder containing \`index.tsx\` and \`styles.css\`.**
769
- - \`src/components/\` = registered in ikas.config.json. \`src/sub-components/\` = internal helpers (NOT in ikas.config.json)
770
- - Sub-components do NOT have \`types.ts\` — define \`Props\` inline in \`index.tsx\`
771
- - Custom enum types are exported from \`src/global-types.ts\` (auto-generated). Sub-components can import them: \`import type { MyEnum } from "../../global-types";\`
772
- - CSS: \`@import "../../sub-components/ProductCard/styles.css";\` in parent styles.css
773
- - TSX: \`import ProductCard from "../../sub-components/ProductCard";\`
774
- - Sub-components that read MobX stores need \`observer()\`, others don't
775
- - Sub-components can be shared across multiple parent sections
776
- - NEVER create flat .tsx files inside a component folder
777
-
778
- ## Key Patterns
779
- - Root components are automatically reactive (ikas runtime uses autorun). Do NOT use observer() on root exports.
780
- Pattern: \`export function MySection({ title }: Props) { ... }\` + \`export default MySection;\`
781
- Only use observer() on extracted sub-components that independently read MobX stores.
782
- - Null safety: storefront models can be null — always check before accessing
783
- - Mutations: addItemToCart() etc. mutate MobX observables in-place — no return capture needed
784
- - COMPONENT & COMPONENT_LIST props: slot-based child components rendered via \`<IkasComponentRenderer>\`
785
- \`import { IkasComponentRenderer } from "@ikas/bp-storefront"\`
786
- \`<IkasComponentRenderer components={myList as any[]} parentProps={props} />\`
787
- Always pass \`parentProps={props}\` so children can access parent data. Cast with \`as any[]\`.
788
- - CSS: write plain class names — auto-scoped with .cc_{componentId} at build time
789
- - Events: use onInput (not onChange) for text inputs (Preact behavior)
790
- - Imports: \`import { addItemToCart, IkasProduct } from "@ikas/bp-storefront"\`
791
-
792
- ## No Static Text Rule
793
- **CRITICAL: Never hardcode user-visible text in JSX.** All text strings (headings, button labels,
794
- empty states, loading messages, form labels) MUST be TEXT props with defaultValues.
795
- Wrong: \`<h1>Sign In</h1>\`
796
- Correct: \`<h1>{title}</h1>\` with \`title\` as TEXT prop (defaultValue: "Sign In")
797
- For button loading states, use two separate props (e.g., \`submitButtonText\` + \`submittingButtonText\`).
798
- Group text props under a "Texts" propGroup when the component has 5+ props.
799
-
800
- ## Sections vs Components
801
- - Sections = page-level containers (Header, Hero, Product Grid, Footer)
802
- Set "type": "section" via CLI. Use <section> root element. Props interface: Props.
803
- **Sections MUST always include a \`backgroundColor\` COLOR prop** (default: \`#ffffff\`).
804
- Apply via inline style: \`style={backgroundColor ? { backgroundColor } : undefined}\`
805
- Consider also adding \`textColor\` COLOR props for text elements directly on the section background.
806
- - Components = child elements inside sections (buttons, cards, badges)
807
- Defaults to "component". Use <div> root element. Props interface: Props.
808
-
809
- ## Prop Groups
810
- Organize 5+ props into collapsible groups in editor sidebar.
811
- - Define groups in \`propGroups\` on component in ikas.config.json
812
- - Assign props via \`groupId\` on each prop
813
- - Nest 1 level deep with \`children\`
814
- - Group IDs must be unique within a component
815
- - CLI: add-prop-group, update-prop-group, remove-prop-group
816
- - Add prop to group: add-prop --group <groupId> or update-prop --group <groupId>
817
-
818
- ## Build Verification
819
- IMPORTANT: After completing any task, always run \`npx ikas-component build\` (or \`npm run build\`)
820
- to check for TypeScript and build errors. Fix any errors before considering the task done.
821
- `;
822
- fs.writeFileSync(path.join(projectPath, ".cursorrules"), cursorrules);
823
- // Create .mcp.json for MCP server configuration
824
- // Uses npx which resolves the bin through node_modules hierarchy,
825
- // working both in standalone projects and monorepo workspaces.
826
- const mcpConfig = {
827
- mcpServers: {
828
- "ikas-code-components": {
829
- command: "npx",
830
- args: ["ikas-mcp"]
831
- }
832
- }
833
- };
834
- fs.writeFileSync(path.join(projectPath, ".mcp.json"), JSON.stringify(mcpConfig, null, 2));
55
+ // Write all template files
56
+ const files = [
57
+ { template: "create/package.json", dest: "package.json", vars },
58
+ { template: "create/tsconfig.json", dest: "tsconfig.json" },
59
+ { template: "create/vite.config.ts", dest: "vite.config.ts" },
60
+ { template: "create/ikas.config.json", dest: "ikas.config.json", vars },
61
+ { template: "create/gitignore", dest: ".gitignore" },
62
+ { template: "create/mcp.json", dest: ".mcp.json" },
63
+ { template: "create/README.md", dest: "README.md", vars },
64
+ { template: "create/CLAUDE.md", dest: "CLAUDE.md" },
65
+ { template: "create/cursorrules", dest: ".cursorrules" },
66
+ { template: "create/src/global.css", dest: "src/global.css" },
67
+ { template: "create/src/global-types.ts", dest: "src/global-types.ts" },
68
+ { template: "create/src/ikas-component-utils.d.ts", dest: "src/ikas-component-utils.d.ts" },
69
+ { template: "create/src/components/index.ts", dest: "src/components/index.ts" },
70
+ { template: "create/src/components/ExampleComponent/index.tsx", dest: "src/components/ExampleComponent/index.tsx" },
71
+ { template: "create/src/components/ExampleComponent/types.ts", dest: "src/components/ExampleComponent/types.ts" },
72
+ { template: "create/src/components/ExampleComponent/styles.css", dest: "src/components/ExampleComponent/styles.css" },
73
+ { template: "create/src/components/ExampleSection/index.tsx", dest: "src/components/ExampleSection/index.tsx" },
74
+ { template: "create/src/components/ExampleSection/types.ts", dest: "src/components/ExampleSection/types.ts" },
75
+ { template: "create/src/components/ExampleSection/styles.css", dest: "src/components/ExampleSection/styles.css" },
76
+ ];
77
+ for (const file of files) {
78
+ fs.writeFileSync(path.join(projectPath, file.dest), readTemplate(file.template, file.vars));
79
+ }
835
80
  // Create or merge .cursor/mcp.json for Cursor editor
836
81
  // Uses node + ${workspaceFolder} instead of npx because Cursor
837
82
  // doesn't reliably inherit the shell PATH.