@aiworkbench/vibe-cli 0.0.4 → 0.0.6
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/dist/index.js +843 -2
- package/package.json +6 -4
- package/templates/react/.env.example +21 -0
- package/templates/react/index.html +82 -0
- package/templates/react/manifest.json +7 -0
- package/templates/react/package.json +24 -0
- package/templates/react/src/App.tsx +15 -0
- package/templates/react/src/main.tsx +35 -0
- package/templates/react/tsconfig.json +13 -0
- package/templates/react/vite.config.ts +23 -0
- package/templates/vanilla/.env.example +21 -0
- package/templates/vanilla/index.html +82 -0
- package/templates/vanilla/manifest.json +7 -0
- package/templates/vanilla/package.json +19 -0
- package/templates/vanilla/src/main.ts +61 -0
- package/templates/vanilla/tsconfig.json +12 -0
- package/templates/vanilla/vite.config.ts +12 -0
- package/templates/vue/.env.example +21 -0
- package/templates/vue/index.html +82 -0
- package/templates/vue/manifest.json +7 -0
- package/templates/vue/package.json +21 -0
- package/templates/vue/src/App.vue +15 -0
- package/templates/vue/src/main.ts +10 -0
- package/templates/vue/tsconfig.json +12 -0
- package/templates/vue/vite.config.ts +22 -0
package/dist/index.js
CHANGED
|
@@ -2789,6 +2789,9 @@ function isKebabCase(name) {
|
|
|
2789
2789
|
function toKebabCase(name) {
|
|
2790
2790
|
return name.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").replace(/[^a-z0-9-]/gi, "").toLowerCase().replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
2791
2791
|
}
|
|
2792
|
+
function isValidCustomElementName(name) {
|
|
2793
|
+
return /^[a-z][a-z0-9]*-[a-z0-9-]*$/.test(name);
|
|
2794
|
+
}
|
|
2792
2795
|
function toPascalCase(kebab) {
|
|
2793
2796
|
return kebab.split("-").map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join("");
|
|
2794
2797
|
}
|
|
@@ -2806,6 +2809,7 @@ function buildTemplateContext(projectName, framework) {
|
|
|
2806
2809
|
var __dirname2 = dirname2(fileURLToPath(import.meta.url));
|
|
2807
2810
|
async function templateDir(framework) {
|
|
2808
2811
|
const candidates = [
|
|
2812
|
+
resolve(__dirname2, "..", "templates", framework),
|
|
2809
2813
|
resolve(__dirname2, "..", "..", "..", "..", "templates", framework),
|
|
2810
2814
|
resolve(__dirname2, "..", "..", "..", "templates", framework)
|
|
2811
2815
|
];
|
|
@@ -6300,6 +6304,793 @@ this._shadow.appendChild(img);
|
|
|
6300
6304
|
}
|
|
6301
6305
|
}
|
|
6302
6306
|
|
|
6307
|
+
// src/skills/host-design-system.ts
|
|
6308
|
+
function generateHostDesignSystem(config) {
|
|
6309
|
+
const { framework } = config;
|
|
6310
|
+
const stylingApproach = getStylingApproach(framework);
|
|
6311
|
+
return `# Host Design System — USECASE-EDITOR
|
|
6312
|
+
|
|
6313
|
+
Your mini-app renders inside the host's content area via \`<VibeHost>\`. The host provides
|
|
6314
|
+
the header, sidebar, and scroll container. Your job is to fill the content region with UI
|
|
6315
|
+
that looks native to the platform. This guide contains every design token and pattern you
|
|
6316
|
+
need.
|
|
6317
|
+
|
|
6318
|
+
## Important: Shadow DOM Isolation
|
|
6319
|
+
|
|
6320
|
+
Your mini-app lives inside a Shadow DOM boundary. This means:
|
|
6321
|
+
- Host Tailwind classes are **NOT available** inside your component
|
|
6322
|
+
- CSS custom properties (variables) **DO inherit** through Shadow DOM
|
|
6323
|
+
- You must write your own CSS using the values below, not Tailwind utility classes
|
|
6324
|
+
- Use \`adoptedStyleSheets\` or \`?inline\` CSS imports to inject styles into the shadow root
|
|
6325
|
+
|
|
6326
|
+
## Color System (OKLCH)
|
|
6327
|
+
|
|
6328
|
+
The host uses oklch color space exclusively. Use these hardcoded values in your CSS.
|
|
6329
|
+
CSS custom properties like \`var(--foreground)\` will inherit from the host through the
|
|
6330
|
+
shadow boundary, but having the literal values ensures correct rendering in dev sandbox.
|
|
6331
|
+
|
|
6332
|
+
### Light Mode
|
|
6333
|
+
|
|
6334
|
+
| Token | Value | Usage |
|
|
6335
|
+
|-------|-------|-------|
|
|
6336
|
+
| background | \`oklch(1 0 0)\` | Page background |
|
|
6337
|
+
| foreground | \`oklch(0.145 0 0)\` | Primary text |
|
|
6338
|
+
| card | \`oklch(1 0 0)\` | Card backgrounds |
|
|
6339
|
+
| card-foreground | \`oklch(0.145 0 0)\` | Card text |
|
|
6340
|
+
| primary | \`oklch(0.205 0 0)\` | Buttons, emphasis |
|
|
6341
|
+
| primary-foreground | \`oklch(0.985 0 0)\` | Text on primary |
|
|
6342
|
+
| secondary | \`oklch(0.97 0 0)\` | Secondary backgrounds |
|
|
6343
|
+
| secondary-foreground | \`oklch(0.205 0 0)\` | Text on secondary |
|
|
6344
|
+
| tertiary | \`oklch(0.8544 0.1746 90.88)\` | Accent highlight (yellow-green) |
|
|
6345
|
+
| tertiary-foreground | \`oklch(0.145 0 0)\` | Text on tertiary |
|
|
6346
|
+
| muted | \`oklch(0.97 0 0)\` | Subdued backgrounds |
|
|
6347
|
+
| muted-foreground | \`oklch(0.556 0 0)\` | Subdued text, descriptions |
|
|
6348
|
+
| destructive | \`oklch(0.577 0.245 27.325)\` | Error, danger |
|
|
6349
|
+
| border | \`oklch(0.922 0 0)\` | Borders, dividers |
|
|
6350
|
+
| input | \`oklch(0.922 0 0)\` | Input borders |
|
|
6351
|
+
| ring | \`oklch(0.708 0 0)\` | Focus rings |
|
|
6352
|
+
|
|
6353
|
+
### Dark Mode
|
|
6354
|
+
|
|
6355
|
+
| Token | Value | Usage |
|
|
6356
|
+
|-------|-------|-------|
|
|
6357
|
+
| background | \`oklch(0.145 0 0)\` | Page background |
|
|
6358
|
+
| foreground | \`oklch(0.985 0 0)\` | Primary text |
|
|
6359
|
+
| card | \`oklch(0.205 0 0)\` | Card backgrounds |
|
|
6360
|
+
| card-foreground | \`oklch(0.985 0 0)\` | Card text |
|
|
6361
|
+
| primary | \`oklch(0.922 0 0)\` | Buttons, emphasis |
|
|
6362
|
+
| primary-foreground | \`oklch(0.205 0 0)\` | Text on primary |
|
|
6363
|
+
| secondary | \`oklch(0.269 0 0)\` | Secondary backgrounds |
|
|
6364
|
+
| secondary-foreground | \`oklch(0.985 0 0)\` | Text on secondary |
|
|
6365
|
+
| tertiary | \`oklch(0.8544 0.1746 90.88)\` | Same accent (unchanged) |
|
|
6366
|
+
| tertiary-foreground | \`oklch(0.145 0 0)\` | Text on tertiary |
|
|
6367
|
+
| muted | \`oklch(0.269 0 0)\` | Subdued backgrounds |
|
|
6368
|
+
| muted-foreground | \`oklch(0.708 0 0)\` | Subdued text |
|
|
6369
|
+
| destructive | \`oklch(0.704 0.191 22.216)\` | Error (lighter in dark) |
|
|
6370
|
+
| border | \`oklch(1 0 0 / 10%)\` | Borders (semi-transparent) |
|
|
6371
|
+
| input | \`oklch(1 0 0 / 15%)\` | Input borders |
|
|
6372
|
+
| ring | \`oklch(0.556 0 0)\` | Focus rings |
|
|
6373
|
+
|
|
6374
|
+
### Using Host CSS Variables
|
|
6375
|
+
|
|
6376
|
+
CSS custom properties inherit through Shadow DOM. Prefer variables when possible:
|
|
6377
|
+
|
|
6378
|
+
\`\`\`css
|
|
6379
|
+
.my-card {
|
|
6380
|
+
background: var(--card, oklch(1 0 0));
|
|
6381
|
+
color: var(--card-foreground, oklch(0.145 0 0));
|
|
6382
|
+
border: 1px solid var(--border, oklch(0.922 0 0));
|
|
6383
|
+
}
|
|
6384
|
+
\`\`\`
|
|
6385
|
+
|
|
6386
|
+
The fallback values ensure correct rendering in the dev sandbox where host variables
|
|
6387
|
+
are not present.
|
|
6388
|
+
|
|
6389
|
+
## Typography
|
|
6390
|
+
|
|
6391
|
+
### Fonts
|
|
6392
|
+
|
|
6393
|
+
The host loads **Geist** (sans) and **Geist Mono** via Google Fonts, exposed as CSS variables:
|
|
6394
|
+
|
|
6395
|
+
\`\`\`css
|
|
6396
|
+
font-family: var(--font-geist-sans, system-ui, -apple-system, sans-serif);
|
|
6397
|
+
font-family: var(--font-geist-mono, ui-monospace, monospace);
|
|
6398
|
+
\`\`\`
|
|
6399
|
+
|
|
6400
|
+
These variables inherit through Shadow DOM. Always include system font fallbacks.
|
|
6401
|
+
|
|
6402
|
+
### Type Scale
|
|
6403
|
+
|
|
6404
|
+
| Element | Size | Weight | Extra |
|
|
6405
|
+
|---------|------|--------|-------|
|
|
6406
|
+
| Page heading | \`1.125rem\` (text-lg) | \`700\` (bold) | — |
|
|
6407
|
+
| Card title | \`1.125rem\` (text-lg) | \`600\` (semibold) | — |
|
|
6408
|
+
| Section label | \`0.6875rem\` | \`600\` (semibold) | \`text-transform: uppercase; letter-spacing: 0.1em\` |
|
|
6409
|
+
| Body text | \`0.875rem\` (text-sm) | \`400\` (regular) | — |
|
|
6410
|
+
| Description | \`0.875rem\` (text-sm) | \`400\` | Color: muted-foreground |
|
|
6411
|
+
| Small label | \`0.75rem\` (text-xs) | \`500\` (medium) | — |
|
|
6412
|
+
| Badge / pill | \`0.625rem\` (10px) | \`600\` | — |
|
|
6413
|
+
|
|
6414
|
+
### Heading Pattern (Section Labels)
|
|
6415
|
+
|
|
6416
|
+
The host uses uppercase, letter-spaced, muted headings to label sections:
|
|
6417
|
+
|
|
6418
|
+
\`\`\`css
|
|
6419
|
+
.section-label {
|
|
6420
|
+
font-size: 0.6875rem;
|
|
6421
|
+
font-weight: 600;
|
|
6422
|
+
text-transform: uppercase;
|
|
6423
|
+
letter-spacing: 0.1em;
|
|
6424
|
+
color: oklch(0.556 0 0); /* muted-foreground */
|
|
6425
|
+
}
|
|
6426
|
+
\`\`\`
|
|
6427
|
+
|
|
6428
|
+
## Border Radius
|
|
6429
|
+
|
|
6430
|
+
| Token | Value |
|
|
6431
|
+
|-------|-------|
|
|
6432
|
+
| radius-sm | \`4px\` |
|
|
6433
|
+
| radius-md | \`6px\` |
|
|
6434
|
+
| radius-lg | \`8px\` (base) |
|
|
6435
|
+
| radius-xl | \`12px\` |
|
|
6436
|
+
|
|
6437
|
+
- **Cards**: \`border-radius: 12px\` (rounded-xl) for marketplace-style cards, \`8px\` (rounded-lg) for standard cards
|
|
6438
|
+
- **Buttons**: \`6px\` (rounded-md)
|
|
6439
|
+
- **Badges**: \`6px\` (rounded-md)
|
|
6440
|
+
- **Inputs**: \`6px\` (rounded-md)
|
|
6441
|
+
|
|
6442
|
+
## Card Patterns
|
|
6443
|
+
|
|
6444
|
+
### Standard Card
|
|
6445
|
+
|
|
6446
|
+
\`\`\`css
|
|
6447
|
+
.card {
|
|
6448
|
+
background: oklch(1 0 0);
|
|
6449
|
+
border: 1px solid oklch(0.922 0 0);
|
|
6450
|
+
border-radius: 8px;
|
|
6451
|
+
padding: 1.5rem;
|
|
6452
|
+
box-shadow: 0 1px 2px oklch(0.145 0 0 / 0.04);
|
|
6453
|
+
}
|
|
6454
|
+
\`\`\`
|
|
6455
|
+
|
|
6456
|
+
### Marketplace Agent Card (Interactive)
|
|
6457
|
+
|
|
6458
|
+
\`\`\`css
|
|
6459
|
+
.agent-card {
|
|
6460
|
+
display: flex;
|
|
6461
|
+
flex-direction: column;
|
|
6462
|
+
background: oklch(1 0 0);
|
|
6463
|
+
border: 1px solid oklch(0.922 0 0);
|
|
6464
|
+
border-radius: 12px;
|
|
6465
|
+
padding: 1rem;
|
|
6466
|
+
cursor: pointer;
|
|
6467
|
+
transition: box-shadow 180ms ease;
|
|
6468
|
+
overflow: hidden;
|
|
6469
|
+
}
|
|
6470
|
+
|
|
6471
|
+
.agent-card:hover {
|
|
6472
|
+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
|
|
6473
|
+
}
|
|
6474
|
+
\`\`\`
|
|
6475
|
+
|
|
6476
|
+
### Builder Card
|
|
6477
|
+
|
|
6478
|
+
\`\`\`css
|
|
6479
|
+
.builder-card {
|
|
6480
|
+
padding: 1rem;
|
|
6481
|
+
border-radius: 8px;
|
|
6482
|
+
border: 1px solid oklch(0.75 0 0); /* gray-300 equivalent */
|
|
6483
|
+
cursor: pointer;
|
|
6484
|
+
transition: background-color 180ms ease;
|
|
6485
|
+
}
|
|
6486
|
+
|
|
6487
|
+
.builder-card:hover {
|
|
6488
|
+
background: oklch(0.97 0 0); /* gray-50 equivalent */
|
|
6489
|
+
}
|
|
6490
|
+
\`\`\`
|
|
6491
|
+
|
|
6492
|
+
### Accent-Highlighted Card
|
|
6493
|
+
|
|
6494
|
+
Use the tertiary color for feature emphasis:
|
|
6495
|
+
|
|
6496
|
+
\`\`\`css
|
|
6497
|
+
.card--accent {
|
|
6498
|
+
background: linear-gradient(
|
|
6499
|
+
135deg,
|
|
6500
|
+
oklch(0.8544 0.1746 90.88 / 0.06),
|
|
6501
|
+
oklch(0.8544 0.1746 90.88 / 0.02)
|
|
6502
|
+
);
|
|
6503
|
+
border-color: oklch(0.8544 0.1746 90.88 / 0.3);
|
|
6504
|
+
}
|
|
6505
|
+
\`\`\`
|
|
6506
|
+
|
|
6507
|
+
## Button Patterns
|
|
6508
|
+
|
|
6509
|
+
### Primary Button
|
|
6510
|
+
|
|
6511
|
+
\`\`\`css
|
|
6512
|
+
.btn-primary {
|
|
6513
|
+
display: inline-flex;
|
|
6514
|
+
align-items: center;
|
|
6515
|
+
justify-content: center;
|
|
6516
|
+
gap: 0.5rem;
|
|
6517
|
+
height: 2.25rem;
|
|
6518
|
+
padding: 0 1rem;
|
|
6519
|
+
border-radius: 6px;
|
|
6520
|
+
font-size: 0.875rem;
|
|
6521
|
+
font-weight: 500;
|
|
6522
|
+
background: oklch(0.205 0 0);
|
|
6523
|
+
color: oklch(0.985 0 0);
|
|
6524
|
+
border: none;
|
|
6525
|
+
cursor: pointer;
|
|
6526
|
+
transition: opacity 150ms ease;
|
|
6527
|
+
}
|
|
6528
|
+
|
|
6529
|
+
.btn-primary:hover {
|
|
6530
|
+
opacity: 0.9;
|
|
6531
|
+
}
|
|
6532
|
+
\`\`\`
|
|
6533
|
+
|
|
6534
|
+
### Button Sizes
|
|
6535
|
+
|
|
6536
|
+
| Size | Height | Padding | Font |
|
|
6537
|
+
|------|--------|---------|------|
|
|
6538
|
+
| xs | \`1.5rem\` | \`0 0.75rem\` | \`0.75rem\` |
|
|
6539
|
+
| sm | \`2rem\` | \`0 0.75rem\` | \`0.875rem\` |
|
|
6540
|
+
| default | \`2.25rem\` | \`0 1rem\` | \`0.875rem\` |
|
|
6541
|
+
| lg | \`2.5rem\` | \`0 1.5rem\` | \`0.875rem\` |
|
|
6542
|
+
|
|
6543
|
+
### Button Variants
|
|
6544
|
+
|
|
6545
|
+
| Variant | Background | Text | Border |
|
|
6546
|
+
|---------|-----------|------|--------|
|
|
6547
|
+
| default | \`oklch(0.205 0 0)\` | \`oklch(0.985 0 0)\` | none |
|
|
6548
|
+
| outline | \`oklch(1 0 0)\` | \`oklch(0.205 0 0)\` | \`1px solid oklch(0.922 0 0)\` |
|
|
6549
|
+
| secondary | \`oklch(0.97 0 0)\` | \`oklch(0.205 0 0)\` | none |
|
|
6550
|
+
| ghost | \`transparent\` | inherit | none (hover: \`oklch(0.97 0 0)\`) |
|
|
6551
|
+
| destructive | \`oklch(0.577 0.245 27.325)\` | \`white\` | none |
|
|
6552
|
+
| highlight | \`oklch(0.85 0.18 95)\` | \`black\` | none |
|
|
6553
|
+
|
|
6554
|
+
### Disabled State
|
|
6555
|
+
|
|
6556
|
+
\`\`\`css
|
|
6557
|
+
.btn:disabled {
|
|
6558
|
+
pointer-events: none;
|
|
6559
|
+
background: oklch(0.9 0 0);
|
|
6560
|
+
color: oklch(0.556 0 0);
|
|
6561
|
+
}
|
|
6562
|
+
\`\`\`
|
|
6563
|
+
|
|
6564
|
+
## Input Patterns
|
|
6565
|
+
|
|
6566
|
+
\`\`\`css
|
|
6567
|
+
.input {
|
|
6568
|
+
height: 2.25rem;
|
|
6569
|
+
width: 100%;
|
|
6570
|
+
border-radius: 6px;
|
|
6571
|
+
border: 1px solid oklch(0.922 0 0);
|
|
6572
|
+
background: transparent;
|
|
6573
|
+
padding: 0.25rem 0.75rem;
|
|
6574
|
+
font-size: 0.875rem;
|
|
6575
|
+
transition: box-shadow 150ms ease, border-color 150ms ease;
|
|
6576
|
+
}
|
|
6577
|
+
|
|
6578
|
+
.input::placeholder {
|
|
6579
|
+
color: oklch(0.556 0 0);
|
|
6580
|
+
}
|
|
6581
|
+
|
|
6582
|
+
.input:focus-visible {
|
|
6583
|
+
border-color: oklch(0.708 0 0);
|
|
6584
|
+
outline: none;
|
|
6585
|
+
box-shadow: 0 0 0 3px oklch(0.708 0 0 / 0.5);
|
|
6586
|
+
}
|
|
6587
|
+
\`\`\`
|
|
6588
|
+
|
|
6589
|
+
## Badge Patterns
|
|
6590
|
+
|
|
6591
|
+
\`\`\`css
|
|
6592
|
+
.badge {
|
|
6593
|
+
display: inline-flex;
|
|
6594
|
+
align-items: center;
|
|
6595
|
+
border-radius: 6px;
|
|
6596
|
+
padding: 0.125rem 0.625rem;
|
|
6597
|
+
font-size: 0.75rem;
|
|
6598
|
+
font-weight: 600;
|
|
6599
|
+
border: 1px solid transparent;
|
|
6600
|
+
}
|
|
6601
|
+
|
|
6602
|
+
.badge--default {
|
|
6603
|
+
background: oklch(0.205 0 0);
|
|
6604
|
+
color: oklch(0.985 0 0);
|
|
6605
|
+
}
|
|
6606
|
+
|
|
6607
|
+
.badge--secondary {
|
|
6608
|
+
background: oklch(0.97 0 0);
|
|
6609
|
+
color: oklch(0.205 0 0);
|
|
6610
|
+
}
|
|
6611
|
+
|
|
6612
|
+
.badge--outline {
|
|
6613
|
+
background: transparent;
|
|
6614
|
+
border-color: oklch(0.922 0 0);
|
|
6615
|
+
color: oklch(0.145 0 0);
|
|
6616
|
+
}
|
|
6617
|
+
\`\`\`
|
|
6618
|
+
|
|
6619
|
+
### Version Badge (Small)
|
|
6620
|
+
|
|
6621
|
+
Used on marketplace cards for version labels:
|
|
6622
|
+
|
|
6623
|
+
\`\`\`css
|
|
6624
|
+
.version-badge {
|
|
6625
|
+
font-size: 0.625rem;
|
|
6626
|
+
line-height: 1;
|
|
6627
|
+
padding: 0.125rem 0.375rem;
|
|
6628
|
+
border-radius: 4px;
|
|
6629
|
+
background: oklch(0.97 0 0);
|
|
6630
|
+
color: oklch(0.45 0 0);
|
|
6631
|
+
border: 1px solid oklch(0.922 0 0);
|
|
6632
|
+
}
|
|
6633
|
+
\`\`\`
|
|
6634
|
+
|
|
6635
|
+
## Layout
|
|
6636
|
+
|
|
6637
|
+
### Content Container
|
|
6638
|
+
|
|
6639
|
+
The host's content area uses responsive horizontal padding and a max-width:
|
|
6640
|
+
|
|
6641
|
+
\`\`\`css
|
|
6642
|
+
.container {
|
|
6643
|
+
margin: 0 auto;
|
|
6644
|
+
width: 100%;
|
|
6645
|
+
padding-left: 1rem;
|
|
6646
|
+
padding-right: 1rem;
|
|
6647
|
+
}
|
|
6648
|
+
|
|
6649
|
+
@media (min-width: 1024px) {
|
|
6650
|
+
.container { padding-left: 1.5rem; padding-right: 1.5rem; }
|
|
6651
|
+
}
|
|
6652
|
+
|
|
6653
|
+
@media (min-width: 1280px) {
|
|
6654
|
+
.container { padding-left: 2rem; padding-right: 2rem; }
|
|
6655
|
+
}
|
|
6656
|
+
\`\`\`
|
|
6657
|
+
|
|
6658
|
+
| Container Size | Max Width |
|
|
6659
|
+
|---------------|-----------|
|
|
6660
|
+
| sm | \`768px\` |
|
|
6661
|
+
| md | \`1440px\` |
|
|
6662
|
+
| lg | \`1600px\` |
|
|
6663
|
+
| xl | none (full width) |
|
|
6664
|
+
|
|
6665
|
+
### Spacing Scale
|
|
6666
|
+
|
|
6667
|
+
| Name | Value | Common Usage |
|
|
6668
|
+
|------|-------|------|
|
|
6669
|
+
| xs | \`0.25rem\` (4px) | Tight gaps |
|
|
6670
|
+
| sm | \`0.5rem\` (8px) | Icon gaps, badge padding |
|
|
6671
|
+
| md | \`0.75rem\` (12px) | Grid gaps, small card gaps |
|
|
6672
|
+
| base | \`1rem\` (16px) | Card padding, component spacing |
|
|
6673
|
+
| lg | \`1.5rem\` (24px) | Card content padding, section gaps |
|
|
6674
|
+
| xl | \`2rem\` (32px) | Page padding, section margin |
|
|
6675
|
+
| 2xl | \`3rem\` (48px) | Large vertical sections |
|
|
6676
|
+
|
|
6677
|
+
### Common Layouts
|
|
6678
|
+
|
|
6679
|
+
**Card Grid (3 columns)**
|
|
6680
|
+
\`\`\`css
|
|
6681
|
+
.card-grid {
|
|
6682
|
+
display: flex;
|
|
6683
|
+
flex-wrap: wrap;
|
|
6684
|
+
gap: 1.5rem;
|
|
6685
|
+
}
|
|
6686
|
+
|
|
6687
|
+
.card-grid > * {
|
|
6688
|
+
flex: 0 0 calc(33.333% - 1rem);
|
|
6689
|
+
}
|
|
6690
|
+
\`\`\`
|
|
6691
|
+
|
|
6692
|
+
**Sidebar + Content**
|
|
6693
|
+
\`\`\`css
|
|
6694
|
+
.layout-with-sidebar {
|
|
6695
|
+
display: flex;
|
|
6696
|
+
gap: 2rem;
|
|
6697
|
+
}
|
|
6698
|
+
|
|
6699
|
+
.sidebar {
|
|
6700
|
+
width: 200px;
|
|
6701
|
+
flex-shrink: 0;
|
|
6702
|
+
}
|
|
6703
|
+
|
|
6704
|
+
.content {
|
|
6705
|
+
flex: 1;
|
|
6706
|
+
min-width: 0;
|
|
6707
|
+
}
|
|
6708
|
+
\`\`\`
|
|
6709
|
+
|
|
6710
|
+
## Shadows
|
|
6711
|
+
|
|
6712
|
+
| Level | Value | Usage |
|
|
6713
|
+
|-------|-------|-------|
|
|
6714
|
+
| xs | \`0 1px 2px oklch(0.145 0 0 / 0.04)\` | Buttons, inputs |
|
|
6715
|
+
| sm | \`0 1px 3px oklch(0.145 0 0 / 0.06)\` | Static cards |
|
|
6716
|
+
| card-hover | \`0 2px 6px rgba(0, 0, 0, 0.15)\` | Interactive card hover |
|
|
6717
|
+
| lg | \`0 10px 15px oklch(0.145 0 0 / 0.1)\` | Dialogs, popovers |
|
|
6718
|
+
|
|
6719
|
+
## Focus States
|
|
6720
|
+
|
|
6721
|
+
All interactive elements must show a visible focus ring for accessibility:
|
|
6722
|
+
|
|
6723
|
+
\`\`\`css
|
|
6724
|
+
.interactive:focus-visible {
|
|
6725
|
+
border-color: oklch(0.708 0 0);
|
|
6726
|
+
outline: none;
|
|
6727
|
+
box-shadow: 0 0 0 3px oklch(0.708 0 0 / 0.5);
|
|
6728
|
+
}
|
|
6729
|
+
\`\`\`
|
|
6730
|
+
|
|
6731
|
+
## Transitions
|
|
6732
|
+
|
|
6733
|
+
Consistent timing across all interactive elements:
|
|
6734
|
+
|
|
6735
|
+
\`\`\`css
|
|
6736
|
+
transition: 180ms ease; /* default for hover/shadow/transform */
|
|
6737
|
+
transition: 150ms ease; /* faster for opacity/color */
|
|
6738
|
+
\`\`\`
|
|
6739
|
+
|
|
6740
|
+
## Navigation Routes
|
|
6741
|
+
|
|
6742
|
+
The host application has these routes. Use \`bridge.navigation.navigate(path)\` to link:
|
|
6743
|
+
|
|
6744
|
+
| Route | Page |
|
|
6745
|
+
|-------|------|
|
|
6746
|
+
| \`/chat\` | Chat with agents |
|
|
6747
|
+
| \`/marketplace\` | Marketplace landing |
|
|
6748
|
+
| \`/marketplace/agents?state=PUBLISHED\` | Published agents |
|
|
6749
|
+
| \`/playground\` | Prompt playground |
|
|
6750
|
+
| \`/builder\` | Agent builder |
|
|
6751
|
+
| \`/documents\` | Document library |
|
|
6752
|
+
| \`/administration\` | Admin panel (admins only) |
|
|
6753
|
+
|
|
6754
|
+
## Dark Mode Support
|
|
6755
|
+
|
|
6756
|
+
Dark mode is toggled via the \`.dark\` class on the \`<html>\` element (class-based, not media query).
|
|
6757
|
+
Use \`bridge.theme.current()\` to detect and \`bridge.events.on("theme-changed", ...)\` to react.
|
|
6758
|
+
|
|
6759
|
+
For CSS-only dark mode in your shadow DOM, use the host's CSS variables with fallbacks:
|
|
6760
|
+
|
|
6761
|
+
\`\`\`css
|
|
6762
|
+
.card {
|
|
6763
|
+
background: var(--card, oklch(1 0 0));
|
|
6764
|
+
color: var(--card-foreground, oklch(0.145 0 0));
|
|
6765
|
+
border-color: var(--border, oklch(0.922 0 0));
|
|
6766
|
+
}
|
|
6767
|
+
\`\`\`
|
|
6768
|
+
|
|
6769
|
+
When the host toggles dark mode, its CSS variables change automatically and your component
|
|
6770
|
+
inherits the new values through the Shadow DOM. No JavaScript needed if you use variables.
|
|
6771
|
+
|
|
6772
|
+
For bridge-driven dark mode with separate value sets:
|
|
6773
|
+
|
|
6774
|
+
${getDarkModeExample(framework)}
|
|
6775
|
+
|
|
6776
|
+
## Icons
|
|
6777
|
+
|
|
6778
|
+
The host uses **Lucide React** icons. Mini-apps should NOT depend on Lucide — it adds
|
|
6779
|
+
unnecessary bundle size. Instead:
|
|
6780
|
+
|
|
6781
|
+
1. **Inline SVG** (preferred) — Copy the SVG paths from [lucide.dev](https://lucide.dev).
|
|
6782
|
+
Use \`viewBox="0 0 24 24"\`, \`fill="none"\`, \`stroke="currentColor"\`, \`stroke-width="2"\`.
|
|
6783
|
+
2. **Single icon import** — If you must use Lucide, import individual icons:
|
|
6784
|
+
\`import { Search } from "lucide-react"\` (NOT the barrel \`lucide-react\` import).
|
|
6785
|
+
|
|
6786
|
+
## Anti-Patterns
|
|
6787
|
+
|
|
6788
|
+
These break visual consistency with the host:
|
|
6789
|
+
|
|
6790
|
+
- **Don't use oklch hue for primary UI.** The host is grayscale-first. Color is reserved for the
|
|
6791
|
+
tertiary accent (\`oklch(0.8544 0.1746 90.88)\`), destructive actions, and chart data.
|
|
6792
|
+
- **Don't use colored backgrounds for sections.** The host uses white/near-white backgrounds with
|
|
6793
|
+
subtle borders to separate content. Colored section backgrounds look foreign.
|
|
6794
|
+
- **Don't use rounded-full on cards.** Cards use \`8px\` or \`12px\` radius, never pill shapes.
|
|
6795
|
+
- **Don't add drop shadows to static elements.** The host uses flat design with \`shadow-sm\` at most.
|
|
6796
|
+
Shadows are interactive cues (hover state), not decoration.
|
|
6797
|
+
- **Don't use custom fonts.** Stick to the Geist font family inherited from the host.
|
|
6798
|
+
- **Don't use thick borders.** The host uses \`1px\` borders exclusively.
|
|
6799
|
+
- **Don't use bright/saturated colors for UI chrome.** The grayscale palette is intentional.
|
|
6800
|
+
|
|
6801
|
+
${stylingApproach}
|
|
6802
|
+
|
|
6803
|
+
## Complete Example: Minimal Card Component
|
|
6804
|
+
|
|
6805
|
+
${getCardExample(framework)}
|
|
6806
|
+
`;
|
|
6807
|
+
}
|
|
6808
|
+
function getStylingApproach(framework) {
|
|
6809
|
+
switch (framework) {
|
|
6810
|
+
case "react":
|
|
6811
|
+
return `## Styling Approach (React)
|
|
6812
|
+
|
|
6813
|
+
Use the \`?inline\` import pattern with \`adoptedStyleSheets\`:
|
|
6814
|
+
|
|
6815
|
+
\`\`\`tsx
|
|
6816
|
+
// src/main.tsx
|
|
6817
|
+
import styles from "./styles.css?inline";
|
|
6818
|
+
|
|
6819
|
+
connectedCallback() {
|
|
6820
|
+
const shadow = this.attachShadow({ mode: "open" });
|
|
6821
|
+
const sheet = new CSSStyleSheet();
|
|
6822
|
+
sheet.replaceSync(styles);
|
|
6823
|
+
shadow.adoptedStyleSheets = [sheet];
|
|
6824
|
+
// ... create container and React root
|
|
6825
|
+
}
|
|
6826
|
+
\`\`\`
|
|
6827
|
+
|
|
6828
|
+
Add a TypeScript declaration for the \`?inline\` import:
|
|
6829
|
+
|
|
6830
|
+
\`\`\`ts
|
|
6831
|
+
// src/vite-env.d.ts
|
|
6832
|
+
declare module "*.css?inline" {
|
|
6833
|
+
const css: string;
|
|
6834
|
+
export default css;
|
|
6835
|
+
}
|
|
6836
|
+
\`\`\`
|
|
6837
|
+
|
|
6838
|
+
Then write plain CSS in \`src/styles.css\` using the token values from this guide.`;
|
|
6839
|
+
case "vue":
|
|
6840
|
+
return `## Styling Approach (Vue)
|
|
6841
|
+
|
|
6842
|
+
Vue SFC \`<style>\` blocks are automatically injected into the shadow DOM when using
|
|
6843
|
+
\`defineCustomElement\`:
|
|
6844
|
+
|
|
6845
|
+
\`\`\`vue
|
|
6846
|
+
<style scoped>
|
|
6847
|
+
.card {
|
|
6848
|
+
background: var(--card, oklch(1 0 0));
|
|
6849
|
+
border: 1px solid var(--border, oklch(0.922 0 0));
|
|
6850
|
+
border-radius: 8px;
|
|
6851
|
+
padding: 1.5rem;
|
|
6852
|
+
}
|
|
6853
|
+
</style>
|
|
6854
|
+
\`\`\`
|
|
6855
|
+
|
|
6856
|
+
Use the oklch token values from this guide in your scoped styles.`;
|
|
6857
|
+
case "vanilla":
|
|
6858
|
+
return `## Styling Approach (Vanilla)
|
|
6859
|
+
|
|
6860
|
+
Use adopted stylesheets for best performance:
|
|
6861
|
+
|
|
6862
|
+
\`\`\`ts
|
|
6863
|
+
const sheet = new CSSStyleSheet();
|
|
6864
|
+
sheet.replaceSync(\`
|
|
6865
|
+
.card {
|
|
6866
|
+
background: oklch(1 0 0);
|
|
6867
|
+
border: 1px solid oklch(0.922 0 0);
|
|
6868
|
+
border-radius: 8px;
|
|
6869
|
+
padding: 1.5rem;
|
|
6870
|
+
}
|
|
6871
|
+
\`);
|
|
6872
|
+
this._shadow.adoptedStyleSheets = [sheet];
|
|
6873
|
+
\`\`\`
|
|
6874
|
+
|
|
6875
|
+
Or use a separate CSS file with Vite's \`?inline\` import.`;
|
|
6876
|
+
default:
|
|
6877
|
+
return "";
|
|
6878
|
+
}
|
|
6879
|
+
}
|
|
6880
|
+
function getDarkModeExample(framework) {
|
|
6881
|
+
switch (framework) {
|
|
6882
|
+
case "react":
|
|
6883
|
+
return `\`\`\`tsx
|
|
6884
|
+
function App({ bridge }: VibeProps) {
|
|
6885
|
+
const [theme, setTheme] = useState(bridge.theme?.current() ?? "light");
|
|
6886
|
+
|
|
6887
|
+
useEffect(() => {
|
|
6888
|
+
const unsub = bridge.events?.on("theme-changed", (payload) => {
|
|
6889
|
+
setTheme((payload as { theme: string }).theme);
|
|
6890
|
+
});
|
|
6891
|
+
return unsub;
|
|
6892
|
+
}, [bridge]);
|
|
6893
|
+
|
|
6894
|
+
const isDark = theme === "dark";
|
|
6895
|
+
// Use isDark to toggle class names or inline styles
|
|
6896
|
+
}
|
|
6897
|
+
\`\`\``;
|
|
6898
|
+
case "vue":
|
|
6899
|
+
return `\`\`\`vue
|
|
6900
|
+
<script setup lang="ts">
|
|
6901
|
+
import { ref, onMounted, onUnmounted } from "vue";
|
|
6902
|
+
import type { Bridge } from "@aiworkbench/vibe-types";
|
|
6903
|
+
|
|
6904
|
+
const props = defineProps<{ bridge: Bridge }>();
|
|
6905
|
+
const theme = ref(props.bridge.theme?.current() ?? "light");
|
|
6906
|
+
let unsub: (() => void) | undefined;
|
|
6907
|
+
|
|
6908
|
+
onMounted(() => {
|
|
6909
|
+
unsub = props.bridge.events?.on("theme-changed", (payload) => {
|
|
6910
|
+
theme.value = (payload as { theme: string }).theme;
|
|
6911
|
+
});
|
|
6912
|
+
});
|
|
6913
|
+
onUnmounted(() => unsub?.());
|
|
6914
|
+
</script>
|
|
6915
|
+
\`\`\``;
|
|
6916
|
+
case "vanilla":
|
|
6917
|
+
return `\`\`\`ts
|
|
6918
|
+
set bridge(b: Bridge) {
|
|
6919
|
+
this._bridge = b;
|
|
6920
|
+
this._theme = b.theme?.current() ?? "light";
|
|
6921
|
+
|
|
6922
|
+
this._cleanups.push(
|
|
6923
|
+
b.events?.on("theme-changed", (payload) => {
|
|
6924
|
+
this._theme = (payload as { theme: string }).theme;
|
|
6925
|
+
this.updateTheme();
|
|
6926
|
+
}) ?? (() => {})
|
|
6927
|
+
);
|
|
6928
|
+
|
|
6929
|
+
this.render();
|
|
6930
|
+
}
|
|
6931
|
+
\`\`\``;
|
|
6932
|
+
default:
|
|
6933
|
+
return "";
|
|
6934
|
+
}
|
|
6935
|
+
}
|
|
6936
|
+
function getCardExample(framework) {
|
|
6937
|
+
switch (framework) {
|
|
6938
|
+
case "react":
|
|
6939
|
+
return `\`\`\`tsx
|
|
6940
|
+
interface CardProps {
|
|
6941
|
+
title: string;
|
|
6942
|
+
description: string;
|
|
6943
|
+
onClick?: () => void;
|
|
6944
|
+
}
|
|
6945
|
+
|
|
6946
|
+
function Card({ title, description, onClick }: CardProps) {
|
|
6947
|
+
return (
|
|
6948
|
+
<div
|
|
6949
|
+
className="card"
|
|
6950
|
+
role={onClick ? "button" : undefined}
|
|
6951
|
+
tabIndex={onClick ? 0 : undefined}
|
|
6952
|
+
onClick={onClick}
|
|
6953
|
+
onKeyDown={(e) => {
|
|
6954
|
+
if (onClick && (e.key === "Enter" || e.key === " ")) {
|
|
6955
|
+
e.preventDefault();
|
|
6956
|
+
onClick();
|
|
6957
|
+
}
|
|
6958
|
+
}}
|
|
6959
|
+
>
|
|
6960
|
+
<div className="card-title">{title}</div>
|
|
6961
|
+
<div className="card-desc">{description}</div>
|
|
6962
|
+
</div>
|
|
6963
|
+
);
|
|
6964
|
+
}
|
|
6965
|
+
\`\`\`
|
|
6966
|
+
|
|
6967
|
+
\`\`\`css
|
|
6968
|
+
/* styles.css */
|
|
6969
|
+
.card {
|
|
6970
|
+
background: var(--card, oklch(1 0 0));
|
|
6971
|
+
color: var(--card-foreground, oklch(0.145 0 0));
|
|
6972
|
+
border: 1px solid var(--border, oklch(0.922 0 0));
|
|
6973
|
+
border-radius: 12px;
|
|
6974
|
+
padding: 1rem;
|
|
6975
|
+
cursor: pointer;
|
|
6976
|
+
transition: box-shadow 180ms ease;
|
|
6977
|
+
user-select: none;
|
|
6978
|
+
}
|
|
6979
|
+
|
|
6980
|
+
.card:hover {
|
|
6981
|
+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
|
|
6982
|
+
}
|
|
6983
|
+
|
|
6984
|
+
.card-title {
|
|
6985
|
+
font-size: 1.125rem;
|
|
6986
|
+
font-weight: 600;
|
|
6987
|
+
color: var(--foreground, oklch(0.205 0 0));
|
|
6988
|
+
}
|
|
6989
|
+
|
|
6990
|
+
.card-desc {
|
|
6991
|
+
margin-top: 0.5rem;
|
|
6992
|
+
font-size: 0.875rem;
|
|
6993
|
+
color: var(--muted-foreground, oklch(0.556 0 0));
|
|
6994
|
+
line-height: 1.5;
|
|
6995
|
+
}
|
|
6996
|
+
\`\`\``;
|
|
6997
|
+
case "vue":
|
|
6998
|
+
return `\`\`\`vue
|
|
6999
|
+
<template>
|
|
7000
|
+
<div
|
|
7001
|
+
class="card"
|
|
7002
|
+
:role="onClick ? 'button' : undefined"
|
|
7003
|
+
:tabindex="onClick ? 0 : undefined"
|
|
7004
|
+
@click="onClick?.()"
|
|
7005
|
+
@keydown.enter.space.prevent="onClick?.()"
|
|
7006
|
+
>
|
|
7007
|
+
<div class="card-title">{{ title }}</div>
|
|
7008
|
+
<div class="card-desc">{{ description }}</div>
|
|
7009
|
+
</div>
|
|
7010
|
+
</template>
|
|
7011
|
+
|
|
7012
|
+
<script setup lang="ts">
|
|
7013
|
+
defineProps<{
|
|
7014
|
+
title: string;
|
|
7015
|
+
description: string;
|
|
7016
|
+
onClick?: () => void;
|
|
7017
|
+
}>();
|
|
7018
|
+
</script>
|
|
7019
|
+
|
|
7020
|
+
<style scoped>
|
|
7021
|
+
.card {
|
|
7022
|
+
background: var(--card, oklch(1 0 0));
|
|
7023
|
+
color: var(--card-foreground, oklch(0.145 0 0));
|
|
7024
|
+
border: 1px solid var(--border, oklch(0.922 0 0));
|
|
7025
|
+
border-radius: 12px;
|
|
7026
|
+
padding: 1rem;
|
|
7027
|
+
cursor: pointer;
|
|
7028
|
+
transition: box-shadow 180ms ease;
|
|
7029
|
+
user-select: none;
|
|
7030
|
+
}
|
|
7031
|
+
|
|
7032
|
+
.card:hover {
|
|
7033
|
+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
|
|
7034
|
+
}
|
|
7035
|
+
|
|
7036
|
+
.card-title {
|
|
7037
|
+
font-size: 1.125rem;
|
|
7038
|
+
font-weight: 600;
|
|
7039
|
+
}
|
|
7040
|
+
|
|
7041
|
+
.card-desc {
|
|
7042
|
+
margin-top: 0.5rem;
|
|
7043
|
+
font-size: 0.875rem;
|
|
7044
|
+
color: var(--muted-foreground, oklch(0.556 0 0));
|
|
7045
|
+
line-height: 1.5;
|
|
7046
|
+
}
|
|
7047
|
+
</style>
|
|
7048
|
+
\`\`\``;
|
|
7049
|
+
case "vanilla":
|
|
7050
|
+
return `\`\`\`ts
|
|
7051
|
+
private render() {
|
|
7052
|
+
const sheet = new CSSStyleSheet();
|
|
7053
|
+
sheet.replaceSync(\`
|
|
7054
|
+
.card {
|
|
7055
|
+
background: var(--card, oklch(1 0 0));
|
|
7056
|
+
color: var(--card-foreground, oklch(0.145 0 0));
|
|
7057
|
+
border: 1px solid var(--border, oklch(0.922 0 0));
|
|
7058
|
+
border-radius: 12px;
|
|
7059
|
+
padding: 1rem;
|
|
7060
|
+
cursor: pointer;
|
|
7061
|
+
transition: box-shadow 180ms ease;
|
|
7062
|
+
user-select: none;
|
|
7063
|
+
}
|
|
7064
|
+
.card:hover {
|
|
7065
|
+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
|
|
7066
|
+
}
|
|
7067
|
+
.card-title {
|
|
7068
|
+
font-size: 1.125rem;
|
|
7069
|
+
font-weight: 600;
|
|
7070
|
+
}
|
|
7071
|
+
.card-desc {
|
|
7072
|
+
margin-top: 0.5rem;
|
|
7073
|
+
font-size: 0.875rem;
|
|
7074
|
+
color: var(--muted-foreground, oklch(0.556 0 0));
|
|
7075
|
+
line-height: 1.5;
|
|
7076
|
+
}
|
|
7077
|
+
\`);
|
|
7078
|
+
this._shadow.adoptedStyleSheets = [sheet];
|
|
7079
|
+
|
|
7080
|
+
const card = document.createElement("div");
|
|
7081
|
+
card.className = "card";
|
|
7082
|
+
card.innerHTML = \`
|
|
7083
|
+
<div class="card-title">\${this.escapeHtml(this.title)}</div>
|
|
7084
|
+
<div class="card-desc">\${this.escapeHtml(this.description)}</div>
|
|
7085
|
+
\`;
|
|
7086
|
+
this._shadow.appendChild(card);
|
|
7087
|
+
}
|
|
7088
|
+
\`\`\``;
|
|
7089
|
+
default:
|
|
7090
|
+
return "";
|
|
7091
|
+
}
|
|
7092
|
+
}
|
|
7093
|
+
|
|
6303
7094
|
// src/scaffold/write-agent-docs.ts
|
|
6304
7095
|
var PERMISSION_DOCS = {
|
|
6305
7096
|
auth: `### auth
|
|
@@ -6496,6 +7287,33 @@ cleanups.forEach((fn) => fn());
|
|
|
6496
7287
|
| "Unresolved external" build warning | Dependency not in Vite external config | Add to \`rollupOptions.external\` or bundle it |
|
|
6497
7288
|
| HMR not reflecting changes | Custom element re-registration conflict | Hard refresh the page (Cmd+Shift+R / Ctrl+Shift+R) |
|
|
6498
7289
|
|
|
7290
|
+
## Skills Reference
|
|
7291
|
+
|
|
7292
|
+
This project includes detailed skill guides for specific topics. Skills are **not loaded by
|
|
7293
|
+
default** to keep context focused. **Load the relevant skill before writing code** whenever the
|
|
7294
|
+
user's request touches that area. When in doubt, load the skill — it's better to have the
|
|
7295
|
+
reference than to guess.
|
|
7296
|
+
|
|
7297
|
+
| Skill | Load when… |
|
|
7298
|
+
|-------|-----------|
|
|
7299
|
+
| \`bridge-usage\` | Using any bridge capability (auth, api, storage, events, theme, toast, navigation) |
|
|
7300
|
+
| \`component-patterns\` | Creating or modifying components, lifecycle hooks, shadow DOM patterns |
|
|
7301
|
+
| \`manifest-guide\` | Editing manifest.json, adding or changing permissions |
|
|
7302
|
+
| \`security-rules\` | Reviewing code for policy violations, or unsure if a pattern is allowed |
|
|
7303
|
+
| \`vite-config\` | Changing build configuration, adding Vite plugins, optimizing bundles |
|
|
7304
|
+
| \`accessibility\` | Adding interactive elements, forms, ARIA attributes, keyboard navigation |
|
|
7305
|
+
| \`error-handling\` | Implementing try/catch, error boundaries, or graceful degradation |
|
|
7306
|
+
| \`performance\` | Optimizing bundle size, render performance, or memory usage |
|
|
7307
|
+
| \`debugging\` | Troubleshooting issues, tracing bridge calls, fixing HMR problems |
|
|
7308
|
+
| \`navigation-patterns\` | Building multi-view UIs, tabs, wizards, or steppers (no URL routing) |
|
|
7309
|
+
| \`asset-handling\` | Working with images, SVGs, fonts, or other static assets |
|
|
7310
|
+
| \`host-design-system\` | Styling components to match the host application's design tokens and visual language |
|
|
7311
|
+
${testing ? `| \`testing-guide\` | Writing or modifying tests, mocking the bridge, test setup |
|
|
7312
|
+
` : ""}
|
|
7313
|
+
**How to use skills:** Read the skill file for the relevant topic before implementing. Multiple
|
|
7314
|
+
skills can apply to a single task — for example, building a new form might involve
|
|
7315
|
+
\`component-patterns\`, \`accessibility\`, and \`bridge-usage\` (if the form submits via the bridge API).
|
|
7316
|
+
|
|
6499
7317
|
## Build & Dev
|
|
6500
7318
|
- \`bun run dev\` — Start Vite dev server with hot reload
|
|
6501
7319
|
- \`bun run build\` — Production build (ES module, < 50kb gzipped)
|
|
@@ -6530,7 +7348,8 @@ function generateEmbeddedSkills(config) {
|
|
|
6530
7348
|
{ name: "Performance", content: generatePerformance(config) },
|
|
6531
7349
|
{ name: "Debugging", content: generateDebugging(config) },
|
|
6532
7350
|
{ name: "Navigation Patterns", content: generateNavigationPatterns(config) },
|
|
6533
|
-
{ name: "Asset Handling", content: generateAssetHandling(config) }
|
|
7351
|
+
{ name: "Asset Handling", content: generateAssetHandling(config) },
|
|
7352
|
+
{ name: "Host Design System", content: generateHostDesignSystem(config) }
|
|
6534
7353
|
];
|
|
6535
7354
|
if (config.testing) {
|
|
6536
7355
|
skills.push({ name: "Testing Guide", content: generateTestingGuide(config) });
|
|
@@ -6867,6 +7686,11 @@ var SKILL_DEFS = [
|
|
|
6867
7686
|
name: "asset-handling",
|
|
6868
7687
|
description: "Inline SVGs, imported data URLs, and CDN patterns for production assets",
|
|
6869
7688
|
generate: generateAssetHandling
|
|
7689
|
+
},
|
|
7690
|
+
{
|
|
7691
|
+
name: "host-design-system",
|
|
7692
|
+
description: "Host app design tokens, typography, spacing, colors, and component patterns",
|
|
7693
|
+
generate: generateHostDesignSystem
|
|
6870
7694
|
}
|
|
6871
7695
|
];
|
|
6872
7696
|
async function writeFolderSkill(baseDir, skill, content) {
|
|
@@ -6920,12 +7744,16 @@ function ciWorkflow(registryRepo, githubHost) {
|
|
|
6920
7744
|
` : "";
|
|
6921
7745
|
return `# Auto-generated by vibe-kit — CI/CD for this mini-app.
|
|
6922
7746
|
#
|
|
6923
|
-
# Required repository secrets:
|
|
7747
|
+
# Required repository secrets (dev):
|
|
6924
7748
|
# VIBE_STORAGE_ACCOUNT_NAME — Azure Storage account name
|
|
6925
7749
|
# VIBE_STORAGE_ACCOUNT_KEY — Azure Storage account key
|
|
6926
7750
|
# VIBE_STORAGE_CONTAINER_NAME — Azure container for bundles
|
|
6927
7751
|
# VIBE_REGISTRY_REPO — e.g. "${registryRepo}"
|
|
6928
7752
|
# VIBE_REGISTRY_TOKEN — PAT with repo write access to the registry
|
|
7753
|
+
#
|
|
7754
|
+
# For staging/prod, use environment-scoped secrets (e.g. VIBE_STORAGE_ACCOUNT_KEY_STAGING).
|
|
7755
|
+
# Each environment should use separate Azure Storage accounts so that dev credentials
|
|
7756
|
+
# cannot write to staging/prod. See vibe-publish docs for the full scoping model.
|
|
6929
7757
|
${gheComment}
|
|
6930
7758
|
name: CI
|
|
6931
7759
|
|
|
@@ -7122,6 +7950,19 @@ async function createCommand(rawName) {
|
|
|
7122
7950
|
}
|
|
7123
7951
|
projectName = converted;
|
|
7124
7952
|
}
|
|
7953
|
+
if (!isValidCustomElementName(projectName)) {
|
|
7954
|
+
const suggested = `vibe-${projectName}`;
|
|
7955
|
+
warn(`"${projectName}" is not a valid custom element name (must contain a hyphen).`);
|
|
7956
|
+
const ok = await dist_default3({
|
|
7957
|
+
message: `Use "${suggested}" instead?`,
|
|
7958
|
+
default: true
|
|
7959
|
+
});
|
|
7960
|
+
if (!ok) {
|
|
7961
|
+
error("Aborted.");
|
|
7962
|
+
process.exit(1);
|
|
7963
|
+
}
|
|
7964
|
+
projectName = suggested;
|
|
7965
|
+
}
|
|
7125
7966
|
const outputDir = resolve2(process.cwd(), projectName);
|
|
7126
7967
|
if (await dirExists(outputDir)) {
|
|
7127
7968
|
const overwrite = await dist_default3({
|