@getcoherent/cli 0.6.9 → 0.6.11

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.
@@ -194,48 +194,172 @@ NEVER include app-style elements (sidebar widgets, data tables, filters) on mark
194
194
  var DESIGN_QUALITY_APP = `
195
195
  ## DESIGN QUALITY \u2014 APP PAGES
196
196
 
197
+ ### Reference Patterns (COPY these exact patterns)
198
+
199
+ PAGE HEADER:
200
+ \`\`\`
201
+ <div className="flex items-center justify-between">
202
+ <div className="space-y-1">
203
+ <h1 className="text-2xl font-bold tracking-tight">Page Title</h1>
204
+ <p className="text-sm text-muted-foreground">Page description</p>
205
+ </div>
206
+ <Button><Plus className="size-4 mr-2 shrink-0" />New Item</Button>
207
+ </div>
208
+ \`\`\`
209
+
210
+ FILTER TOOLBAR (search + dropdowns + action):
211
+ \`\`\`
212
+ <div className="flex flex-wrap items-center gap-2">
213
+ <div className="relative flex-1">
214
+ <Search className="absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground shrink-0" />
215
+ <Input placeholder="Search..." className="pl-9" />
216
+ </div>
217
+ <Select>
218
+ <SelectTrigger className="w-[180px]">
219
+ <SelectValue placeholder="All Status" />
220
+ </SelectTrigger>
221
+ <SelectContent>
222
+ <SelectItem value="all">All Status</SelectItem>
223
+ <SelectItem value="active">Active</SelectItem>
224
+ </SelectContent>
225
+ </Select>
226
+ <Button><Plus className="size-4 mr-2 shrink-0" />New Item</Button>
227
+ </div>
228
+ \`\`\`
229
+ CRITICAL: NEVER use <Select> with native <option> elements. Always use the shadcn compound pattern above (SelectTrigger + SelectValue + SelectContent + SelectItem).
230
+ Do NOT add standalone filter icon buttons. The Select dropdowns ARE the filters.
231
+
232
+ STATS GRID:
233
+ \`\`\`
234
+ <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
235
+ <Card>
236
+ <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
237
+ <CardTitle className="text-sm font-medium">Metric Name</CardTitle>
238
+ <TrendingUp className="size-4 text-muted-foreground shrink-0" />
239
+ </CardHeader>
240
+ <CardContent>
241
+ <div className="text-2xl font-bold">1,234</div>
242
+ <p className="text-xs text-muted-foreground">+12% from last month</p>
243
+ </CardContent>
244
+ </Card>
245
+ </div>
246
+ \`\`\`
247
+
248
+ DATA TABLE:
249
+ \`\`\`
250
+ <div className="overflow-x-auto">
251
+ <Table>
252
+ <TableHeader>
253
+ <TableRow>
254
+ <TableHead>Name</TableHead>
255
+ <TableHead>Status</TableHead>
256
+ <TableHead className="w-[50px]"></TableHead>
257
+ </TableRow>
258
+ </TableHeader>
259
+ <TableBody>
260
+ <TableRow className="hover:bg-muted/50">
261
+ <TableCell className="font-medium">Item name</TableCell>
262
+ <TableCell><Badge variant="default">Active</Badge></TableCell>
263
+ <TableCell>
264
+ <DropdownMenu>
265
+ <DropdownMenuTrigger asChild>
266
+ <Button variant="ghost" size="icon"><MoreHorizontal className="size-4 shrink-0" /></Button>
267
+ </DropdownMenuTrigger>
268
+ <DropdownMenuContent align="end">
269
+ <DropdownMenuItem>Edit</DropdownMenuItem>
270
+ <DropdownMenuItem className="text-destructive">Delete</DropdownMenuItem>
271
+ </DropdownMenuContent>
272
+ </DropdownMenu>
273
+ </TableCell>
274
+ </TableRow>
275
+ </TableBody>
276
+ </Table>
277
+ </div>
278
+ \`\`\`
279
+
280
+ EMPTY STATE (when list/table has zero items):
281
+ \`\`\`
282
+ <div className="flex flex-col items-center justify-center py-12 text-center">
283
+ <Inbox className="size-12 text-muted-foreground mb-4 shrink-0" />
284
+ <h3 className="text-lg font-semibold">No items yet</h3>
285
+ <p className="text-sm text-muted-foreground mt-1 max-w-sm">Create your first item to get started.</p>
286
+ <Button className="mt-4"><Plus className="size-4 mr-2 shrink-0" />Create Item</Button>
287
+ </div>
288
+ \`\`\`
289
+
290
+ DATA CARD GRID:
291
+ \`\`\`
292
+ <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
293
+ <Card className="hover:border-border/30 transition-colors">
294
+ <CardHeader className="flex flex-row items-start justify-between space-y-0">
295
+ <div className="space-y-1">
296
+ <CardTitle>Item Name</CardTitle>
297
+ <p className="text-sm text-muted-foreground">Description</p>
298
+ </div>
299
+ <DropdownMenu>
300
+ <DropdownMenuTrigger asChild>
301
+ <Button variant="ghost" size="icon"><MoreHorizontal className="size-4 shrink-0" /></Button>
302
+ </DropdownMenuTrigger>
303
+ <DropdownMenuContent align="end">
304
+ <DropdownMenuItem>Edit</DropdownMenuItem>
305
+ <DropdownMenuItem className="text-destructive">Delete</DropdownMenuItem>
306
+ </DropdownMenuContent>
307
+ </DropdownMenu>
308
+ </CardHeader>
309
+ <CardContent>...</CardContent>
310
+ </Card>
311
+ </div>
312
+ \`\`\`
313
+
197
314
  ### Spacing
198
315
  - gap-4 md:gap-6 between sections
199
316
  - p-4 lg:p-6 content padding
200
- - Within cards: p-4 to p-6 (compact)
201
- - Between cards in grid: gap-4 (tight)
202
-
203
- ### Layout
204
- - Data tables, card grids, filters, stat rows
205
317
  - Page wrapper: flex flex-1 flex-col gap-4 p-4 lg:p-6
206
- - Stats grid: grid gap-4 md:grid-cols-2 lg:grid-cols-4
207
- - Content: functional, scannable, data-dense
208
-
209
- ### Toolbars & Filters
210
- - Filter row: flex flex-wrap items-center gap-2 (plain div, NOT inside a Card)
211
- - Search input: MUST use flex-1 to fill remaining horizontal space. NEVER fixed-width search.
212
- - Filters/selects: fixed width (w-[180px] or auto), do NOT flex-grow
213
- - On mobile (sm:): search full width, filters wrap to next line
214
- - Do NOT wrap search/filter toolbars in Card components. They are plain flex rows above content.
215
-
216
- ### Tabs
217
- - Always use <TabsList variant="line"> for a clean underline style (not the pill/segmented control default)
218
- - The variant="line" prop removes the bg-muted pill container and uses an underline indicator instead
219
318
 
220
319
  NEVER include marketing sections (hero, pricing, testimonials) on app pages.
221
320
  `;
222
321
  var DESIGN_QUALITY_AUTH = `
223
322
  ## DESIGN QUALITY \u2014 AUTH PAGES
224
323
 
225
- ### Layout
226
- - The auth layout ALREADY provides centering (flex items-center justify-center min-h-svh). Do NOT add your own centering wrapper or min-h-svh.
227
- - Just output: <div className="w-full max-w-md"> containing a Card
324
+ ### Reference Pattern (COPY this exact pattern)
325
+
326
+ AUTH CARD:
327
+ \`\`\`
328
+ <div className="w-full max-w-md">
329
+ <Card>
330
+ <CardHeader className="space-y-1">
331
+ <CardTitle className="font-bold text-center">Welcome back</CardTitle>
332
+ <p className="text-sm text-muted-foreground text-center">Enter your credentials</p>
333
+ </CardHeader>
334
+ <CardContent>
335
+ <form className="space-y-4">
336
+ <div className="space-y-2">
337
+ <Label htmlFor="email">Email</Label>
338
+ <Input id="email" type="email" placeholder="Enter your email" />
339
+ </div>
340
+ <div className="space-y-2">
341
+ <Label htmlFor="password">Password</Label>
342
+ <Input id="password" type="password" placeholder="Enter your password" />
343
+ </div>
344
+ <Button type="submit" className="w-full">Sign in</Button>
345
+ </form>
346
+ </CardContent>
347
+ <CardFooter className="text-center">
348
+ <p className="text-sm text-muted-foreground">
349
+ Don't have an account?{' '}
350
+ <Link href="/register" className="text-sm text-muted-foreground underline underline-offset-4 hover:text-foreground transition-colors">Sign up</Link>
351
+ </p>
352
+ </CardFooter>
353
+ </Card>
354
+ </div>
355
+ \`\`\`
356
+
357
+ ### Rules
358
+ - The auth layout ALREADY provides centering (flex items-center justify-center min-h-svh). Do NOT add your own centering wrapper.
228
359
  - Card width: w-full max-w-md
229
- - No navigation, no section containers, no sidebar
230
- - Single focused form with clear CTA
231
- - Card \u2192 CardHeader (title + description) \u2192 CardContent (form with space-y-4) \u2192 CardFooter (link to other auth page)
232
-
233
- ### Form Spacing
234
360
  - Form fields inside CardContent: space-y-4 between field groups
235
- - Ensure visible gap between the last input field and the submit button (use space-y-4 or space-y-6)
236
361
  - Each field group (Label + Input): space-y-2
237
-
238
- NEVER include navigation bars, sidebars, or multi-section layouts on auth pages.
362
+ - No navigation bars, sidebars, or multi-section layouts on auth pages.
239
363
  `;
240
364
  var DESIGN_QUALITY_CRITICAL = `
241
365
  ## CRITICAL CODE RULES (violations will be auto-corrected)
@@ -267,7 +391,17 @@ function inferPageTypeFromRoute(route) {
267
391
  "forgot-password",
268
392
  "reset-password"
269
393
  ]);
270
- const marketingSlugs = /* @__PURE__ */ new Set(["pricing", "features", "about", "blog", "contact", "terms", "privacy", "landing", "home"]);
394
+ const marketingSlugs = /* @__PURE__ */ new Set([
395
+ "pricing",
396
+ "features",
397
+ "about",
398
+ "blog",
399
+ "contact",
400
+ "terms",
401
+ "privacy",
402
+ "landing",
403
+ "home"
404
+ ]);
271
405
  if (authSlugs.has(slug)) return "auth";
272
406
  if (marketingSlugs.has(slug) || slug === "") return "marketing";
273
407
  return "app";
@@ -356,9 +490,7 @@ MULTI-SELECT / TAG INPUT:
356
490
  var RULES_DATA_DISPLAY = `
357
491
  DATA DISPLAY RULES:
358
492
 
359
- STAT / METRIC CARDS:
360
- - Pattern: Card > CardHeader(flex flex-row items-center justify-between space-y-0 pb-2) > CardTitle(text-sm font-medium) + Icon(size-4 text-muted-foreground) ; CardContent > metric(text-2xl font-bold) + change(text-xs text-muted-foreground).
361
- - Grid: grid gap-4 md:grid-cols-2 lg:grid-cols-4.
493
+ STAT / METRIC CARDS: See the Stats Grid reference pattern in DESIGN QUALITY \u2014 APP PAGES. Follow that exact pattern.
362
494
  - Trend up: text-emerald-600 (light) / text-emerald-400 (dark) \u2014 exception to semantic-only rule for trend indicators.
363
495
  - Trend down: text-destructive.
364
496
  - Trend icon: ArrowUp / ArrowDown className="size-3 inline mr-1".
@@ -379,12 +511,7 @@ PAGINATION:
379
511
  - Placement: below the list/table, centered. <div className="flex justify-center mt-4">
380
512
  - For short lists (<20 items): no pagination. For feeds: "Load more" button (variant="outline" className="w-full").
381
513
 
382
- EMPTY STATES:
383
- - Pattern: <div className="flex flex-col items-center justify-center py-12 text-center">
384
- - Icon: size-12 text-muted-foreground mb-4 (larger than normal icons \u2014 exception).
385
- - Title: <h3 className="text-lg font-semibold">No projects yet</h3>
386
- - Description: <p className="text-sm text-muted-foreground mt-1 max-w-sm">Create your first project to get started.</p>
387
- - CTA: <Button className="mt-4">Create project</Button>
514
+ EMPTY STATES: See the Empty State reference pattern in DESIGN QUALITY \u2014 APP PAGES. Follow that exact pattern.
388
515
  - Search empty: "No results for 'query'. Try different keywords." + clear search button.
389
516
  - Filtered empty: "No items match your filters." + reset filters button.
390
517
 
@@ -421,9 +548,7 @@ TRUNCATION:
421
548
  - When to truncate: card descriptions (2 lines), table cells (single line), list item subtitles (1-2 lines).
422
549
  - Always set title={fullText} for accessibility on truncated text.
423
550
 
424
- SEARCH INPUT:
425
- - Pattern: <div className="relative"><Search className="absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" /><Input placeholder="Search..." className="pl-9" /></div>
426
- - Placement: top of the list/table it filters, max-w-sm.
551
+ SEARCH INPUT: See the Filter Toolbar reference pattern in DESIGN QUALITY \u2014 APP PAGES. Use the search input + Select layout shown there.
427
552
  - Clear button: X icon on right when value is not empty.
428
553
  - Debounce: 300ms on keystroke. No search button.
429
554
  `;
@@ -1115,6 +1240,8 @@ async function generateSharedComponentsFromPlan(plan, styleContext, projectRoot,
1115
1240
  const componentSpecs = plan.sharedComponents.map(
1116
1241
  (c) => `- ${c.name}: ${c.description}. Props: ${c.props}. Type: ${c.type}. shadcn deps: ${c.shadcnDeps.join(", ") || "none"}`
1117
1242
  ).join("\n");
1243
+ const designRules = `${CORE_CONSTRAINTS}
1244
+ ${getDesignQualityForType("app")}`;
1118
1245
  const prompt = `Generate React components as separate files. For EACH component below, return an add-page request with name and pageCode fields.
1119
1246
 
1120
1247
  Components to generate:
@@ -1122,6 +1249,8 @@ ${componentSpecs}
1122
1249
 
1123
1250
  Style context: ${styleContext || "default"}
1124
1251
 
1252
+ ${designRules}
1253
+
1125
1254
  Requirements:
1126
1255
  - Each component MUST have \`export default function ComponentName\`
1127
1256
  - Use shadcn/ui imports from @/components/ui/*
@@ -1173,6 +1302,7 @@ Return JSON with { requests: [{ type: "add-page", changes: { name: "ComponentNam
1173
1302
  export {
1174
1303
  DESIGN_THINKING,
1175
1304
  CORE_CONSTRAINTS,
1305
+ DESIGN_QUALITY_COMMON,
1176
1306
  getDesignQualityForType,
1177
1307
  inferPageTypeFromRoute,
1178
1308
  DESIGN_QUALITY,