stylegallery 0.1.10 → 0.1.12

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 (94) hide show
  1. package/AGENTS.md +2 -2
  2. package/GOVERNANCE.md +1 -1
  3. package/README.md +38 -35
  4. package/consumer-reference/agent-native/README.md +5 -5
  5. package/consumer-reference/agent-native/v2/material-registry.json +1 -1
  6. package/design-engineering/loading-and-feedback.md +1 -0
  7. package/design-engineering/native-interaction-contracts.md +2 -0
  8. package/design-engineering/state-management/patterns/latest-request-wins.md +2 -0
  9. package/design-engineering/state-management/patterns/optimistic-overlay.md +1 -0
  10. package/design-engineering/state-management/patterns/single-flight.md +2 -0
  11. package/design-engineering/state-management/patterns/unsaved-navigation.md +2 -0
  12. package/design-engineering/state-management/patterns/url-state.md +1 -0
  13. package/design-engineering/state-management/recipes/delete-undo.md +1 -0
  14. package/design-engineering/text-input-and-internationalization.md +1 -0
  15. package/expression/directions/nocturne-editorial.md +1 -0
  16. package/expression/directions/warm-print.md +1 -0
  17. package/expression/techniques/gradient-atmosphere.md +1 -0
  18. package/expression/techniques/grain-and-texture.md +1 -0
  19. package/expression/techniques/webgl-hero.md +1 -0
  20. package/guides/decision-tree.md +2 -0
  21. package/guides/webpage-generation-workflow.md +2 -0
  22. package/log.md +29 -0
  23. package/motion/accessible-motion.md +2 -0
  24. package/motion/interruption-and-retargeting.md +2 -0
  25. package/motion/rendering-and-performance.md +1 -0
  26. package/motion/techniques/kinetic-type.md +1 -0
  27. package/motion/techniques/scroll-choreography.md +2 -0
  28. package/package.json +14 -8
  29. package/patterns/centering/center.md +1 -0
  30. package/patterns/centering/super-center.md +2 -0
  31. package/patterns/containment/box.md +1 -0
  32. package/patterns/containment/clamped-card.md +1 -0
  33. package/patterns/containment/content-limiter.md +2 -0
  34. package/patterns/containment/fluid-styles.md +1 -0
  35. package/patterns/grid-repetition/card-grid.md +2 -0
  36. package/patterns/grid-repetition/columns.md +1 -0
  37. package/patterns/grid-repetition/dense-grid.md +1 -0
  38. package/patterns/grid-repetition/grid-wrapper.md +1 -0
  39. package/patterns/grid-repetition/masonry-approx.md +1 -0
  40. package/patterns/grid-repetition/page-grid.md +1 -0
  41. package/patterns/grid-repetition/ram-grid.md +2 -0
  42. package/patterns/grid-repetition/twelve-span-grid.md +1 -0
  43. package/patterns/in-line-grouping/badge-list.md +1 -0
  44. package/patterns/in-line-grouping/breadcrumb.md +1 -0
  45. package/patterns/in-line-grouping/cluster.md +1 -0
  46. package/patterns/in-line-grouping/deconstructed-pancake.md +1 -0
  47. package/patterns/in-line-grouping/pagination.md +1 -0
  48. package/patterns/in-line-grouping/reel.md +2 -0
  49. package/patterns/in-line-grouping/split-nav.md +1 -0
  50. package/patterns/in-line-grouping/tab-strip.md +1 -0
  51. package/patterns/in-line-grouping/wrap-row.md +1 -0
  52. package/patterns/media-fit/frame.md +2 -0
  53. package/patterns/media-fit/icon-frame.md +1 -0
  54. package/patterns/overlay-exception/imposter.md +1 -0
  55. package/patterns/overlay-exception/overlay-stack.md +1 -0
  56. package/patterns/split-sidebar/list-detail.md +1 -0
  57. package/patterns/split-sidebar/main-with-rail.md +1 -0
  58. package/patterns/split-sidebar/media-object.md +1 -0
  59. package/patterns/split-sidebar/sidebar.md +2 -0
  60. package/patterns/split-sidebar/split-screen.md +1 -0
  61. package/patterns/split-sidebar/sticky-aside.md +2 -0
  62. package/patterns/split-sidebar/supporting-pane.md +1 -0
  63. package/patterns/split-sidebar/switcher.md +2 -0
  64. package/patterns/stacking/feed.md +1 -0
  65. package/patterns/stacking/line-up.md +2 -0
  66. package/patterns/stacking/stack.md +1 -0
  67. package/patterns/stacking/step-nav.md +1 -0
  68. package/patterns/viewport-shell/cover.md +1 -0
  69. package/patterns/viewport-shell/fixed-sidenav-shell.md +2 -0
  70. package/patterns/viewport-shell/holy-grail.md +2 -0
  71. package/patterns/viewport-shell/panel-layout.md +1 -0
  72. package/patterns/viewport-shell/scroll-body-shell.md +2 -0
  73. package/patterns/viewport-shell/sticky-footer.md +2 -0
  74. package/patterns/viewport-shell/sticky-header.md +2 -0
  75. package/platform-guides/preferences-and-accessibility.md +1 -0
  76. package/recipes/article-page.md +1 -0
  77. package/recipes/command-surface.md +1 -0
  78. package/recipes/dashboard.md +1 -0
  79. package/recipes/form-flow.md +1 -0
  80. package/recipes/homepage.md +2 -0
  81. package/recipes/list-detail.md +1 -0
  82. package/recipes/saas-settings.md +1 -0
  83. package/scripts/agent-native/v2/material-cli-adapter.mjs +7 -5
  84. package/scripts/agent-native/v2/material-queries.mjs +21 -0
  85. package/scripts/agent-native/v2/material-search-v3.mjs +409 -0
  86. package/scripts/compiler/README.md +16 -16
  87. package/scripts/compiler/mcp.mjs +38 -2
  88. package/scripts/legacy-sg-material-mcp.mjs +9 -0
  89. package/scripts/legacy-sg-material.mjs +4 -0
  90. package/scripts/pattern-data.mjs +409 -0
  91. package/scripts/sg-entry.mjs +2 -2
  92. package/scripts/sg-material-mcp.mjs +1 -1
  93. package/scripts/stylegallery-cli.mjs +130 -0
  94. package/skills/stylegallery-search/SKILL.md +34 -0
@@ -323,3 +323,412 @@ export const patterns = [
323
323
  ["masonry-approx", "Grid / Repetition", "Approximate staggered content with columns when exact row alignment is not needed.", "block", "fluid", sources.mdnCookbook, [[".masonry_approx", { "column-gap": "1rem", "column-width": "14rem" }]]],
324
324
  ["main-with-rail", "Split / Sidebar", "Keep primary content dominant with a narrow secondary rail.", "inline", "reflow", sources.govukLayout, [[".main_with_rail", { display: "grid", gap: "1rem", "grid-template-columns": "repeat(auto-fit, minmax(min(18rem, 100%), 1fr))" }], [".main_with_rail_main", { "min-inline-size": "0" }], [".main_with_rail_side", { "min-inline-size": "0" }]]],
325
325
  ];
326
+
327
+ // Search-only metadata: English and Korean names an agent may use for each pattern,
328
+ // and questions the pattern's sections answer. Emitted as frontmatter aliases/questions.
329
+ export const searchMetadata = {
330
+ "sticky-header": {
331
+ "aliases": [
332
+ "pinned top bar",
333
+ "sticky top navigation",
334
+ "헤더 고정",
335
+ "고정 헤더",
336
+ "상단 고정 메뉴"
337
+ ],
338
+ "questions": [
339
+ "How do I keep the header visible while the page scrolls?"
340
+ ]
341
+ },
342
+ "sticky-footer": {
343
+ "aliases": [
344
+ "footer at bottom",
345
+ "push footer down",
346
+ "푸터 고정",
347
+ "하단 푸터",
348
+ "푸터를 화면 아래에 붙이기"
349
+ ],
350
+ "questions": [
351
+ "How do I keep the footer at the bottom when content is short?"
352
+ ]
353
+ },
354
+ "scroll-body-shell": {
355
+ "aliases": [
356
+ "fixed header and footer with scrolling body",
357
+ "app shell",
358
+ "스크롤 영역",
359
+ "본문만 스크롤"
360
+ ],
361
+ "questions": [
362
+ "How do I make only the body scroll between a fixed header and footer?"
363
+ ]
364
+ },
365
+ "fixed-sidenav-shell": {
366
+ "aliases": [
367
+ "fixed side navigation",
368
+ "sidenav shell",
369
+ "고정 사이드 내비게이션",
370
+ "사이드바 레이아웃",
371
+ "고정 사이드바"
372
+ ],
373
+ "questions": [
374
+ "How do I keep side navigation fixed while the main content scrolls?"
375
+ ]
376
+ },
377
+ "holy-grail": {
378
+ "aliases": [
379
+ "header footer two sidebars",
380
+ "three column page layout",
381
+ "홀리 그레일 레이아웃",
382
+ "3단 레이아웃"
383
+ ],
384
+ "questions": [
385
+ "How do I lay out a header, footer, two sidebars, and main content?"
386
+ ]
387
+ },
388
+ "cover": {
389
+ "aliases": [
390
+ "full height hero",
391
+ "vertically centered hero",
392
+ "커버 레이아웃",
393
+ "전체 높이 히어로"
394
+ ]
395
+ },
396
+ "panel-layout": {
397
+ "aliases": [
398
+ "main and utility panels",
399
+ "패널 레이아웃"
400
+ ]
401
+ },
402
+ "sidebar": {
403
+ "aliases": [
404
+ "wrapping sidebar",
405
+ "intrinsic sidebar",
406
+ "사이드바",
407
+ "사이드바 레이아웃"
408
+ ],
409
+ "questions": [
410
+ "How do I make a sidebar wrap under the content when space is tight?"
411
+ ]
412
+ },
413
+ "sticky-aside": {
414
+ "aliases": [
415
+ "sticky sidebar",
416
+ "sticky table of contents",
417
+ "고정 사이드 영역",
418
+ "스티키 사이드바"
419
+ ],
420
+ "questions": [
421
+ "How do I keep an aside visible during long reads?"
422
+ ]
423
+ },
424
+ "switcher": {
425
+ "aliases": [
426
+ "row to stack without media query",
427
+ "flex switcher",
428
+ "가로 세로 전환"
429
+ ],
430
+ "questions": [
431
+ "How do I switch equal regions from a row to a stack without a breakpoint?"
432
+ ]
433
+ },
434
+ "list-detail": {
435
+ "aliases": [
436
+ "master detail",
437
+ "list and detail panes",
438
+ "목록 상세",
439
+ "리스트 디테일"
440
+ ]
441
+ },
442
+ "split-screen": {
443
+ "aliases": [
444
+ "two column split",
445
+ "50/50 split",
446
+ "화면 분할",
447
+ "2단 분할"
448
+ ]
449
+ },
450
+ "main-with-rail": {
451
+ "aliases": [
452
+ "content with right rail",
453
+ "secondary rail",
454
+ "메인과 보조 레일"
455
+ ]
456
+ },
457
+ "media-object": {
458
+ "aliases": [
459
+ "image beside text",
460
+ "avatar with text",
461
+ "미디어 오브젝트",
462
+ "이미지와 텍스트 나란히"
463
+ ]
464
+ },
465
+ "supporting-pane": {
466
+ "aliases": [
467
+ "supporting panel",
468
+ "보조 패널"
469
+ ]
470
+ },
471
+ "ram-grid": {
472
+ "aliases": [
473
+ "repeat auto-fit minmax",
474
+ "responsive grid without media queries",
475
+ "auto-fit grid",
476
+ "반응형 그리드",
477
+ "반응형 카드 그리드"
478
+ ],
479
+ "questions": [
480
+ "How do I make a grid that fits as many columns as space allows without media queries?"
481
+ ]
482
+ },
483
+ "card-grid": {
484
+ "aliases": [
485
+ "responsive card grid",
486
+ "cards in rows and columns",
487
+ "카드 그리드",
488
+ "반응형 카드 그리드",
489
+ "카드 목록"
490
+ ],
491
+ "questions": [
492
+ "How do I align repeating cards into a responsive grid?"
493
+ ]
494
+ },
495
+ "dense-grid": {
496
+ "aliases": [
497
+ "compact grid",
498
+ "grid-auto-flow dense",
499
+ "촘촘한 그리드"
500
+ ]
501
+ },
502
+ "twelve-span-grid": {
503
+ "aliases": [
504
+ "12 column grid",
505
+ "twelve column layout",
506
+ "12단 그리드"
507
+ ]
508
+ },
509
+ "page-grid": {
510
+ "aliases": [
511
+ "page margins and gutters",
512
+ "central content track",
513
+ "페이지 그리드"
514
+ ]
515
+ },
516
+ "grid-wrapper": {
517
+ "aliases": [
518
+ "full bleed breakout",
519
+ "full-width breakout",
520
+ "풀 블리드",
521
+ "전체 폭 확장"
522
+ ]
523
+ },
524
+ "columns": {
525
+ "aliases": [
526
+ "multi-column text",
527
+ "css columns",
528
+ "다단 텍스트"
529
+ ]
530
+ },
531
+ "masonry-approx": {
532
+ "aliases": [
533
+ "masonry",
534
+ "pinterest style",
535
+ "staggered layout",
536
+ "메이슨리",
537
+ "핀터레스트 스타일"
538
+ ]
539
+ },
540
+ "reel": {
541
+ "aliases": [
542
+ "horizontal scroll row",
543
+ "carousel row",
544
+ "scrollable row",
545
+ "가로 스크롤",
546
+ "가로 스크롤 목록"
547
+ ],
548
+ "questions": [
549
+ "How do I make a row scroll horizontally instead of wrapping?"
550
+ ]
551
+ },
552
+ "cluster": {
553
+ "aliases": [
554
+ "inline group that wraps",
555
+ "tag group",
556
+ "항목 묶음",
557
+ "줄바꿈 그룹"
558
+ ]
559
+ },
560
+ "breadcrumb": {
561
+ "aliases": [
562
+ "breadcrumbs",
563
+ "hierarchy links",
564
+ "브레드크럼",
565
+ "경로 표시"
566
+ ]
567
+ },
568
+ "pagination": {
569
+ "aliases": [
570
+ "page numbers",
571
+ "page controls",
572
+ "페이지네이션",
573
+ "페이지 번호"
574
+ ]
575
+ },
576
+ "tab-strip": {
577
+ "aliases": [
578
+ "tabs row",
579
+ "tab bar",
580
+ "탭 바",
581
+ "탭 메뉴"
582
+ ]
583
+ },
584
+ "split-nav": {
585
+ "aliases": [
586
+ "navbar with left and right items",
587
+ "primary and secondary nav",
588
+ "내비게이션 바",
589
+ "좌우 분리 내비게이션"
590
+ ]
591
+ },
592
+ "wrap-row": {
593
+ "aliases": [
594
+ "wrapping toolbar",
595
+ "button row that wraps",
596
+ "버튼 줄바꿈"
597
+ ]
598
+ },
599
+ "badge-list": {
600
+ "aliases": [
601
+ "tags with counts",
602
+ "labels with trailing counts",
603
+ "배지 목록",
604
+ "개수 표시 목록"
605
+ ]
606
+ },
607
+ "deconstructed-pancake": {
608
+ "aliases": [
609
+ "cards stretch then stack",
610
+ "flex wrap cards",
611
+ "카드 가로 배치 후 세로 쌓기"
612
+ ]
613
+ },
614
+ "stack": {
615
+ "aliases": [
616
+ "vertical rhythm",
617
+ "vertical spacing between children",
618
+ "스택",
619
+ "세로 간격"
620
+ ]
621
+ },
622
+ "feed": {
623
+ "aliases": [
624
+ "content feed",
625
+ "activity feed",
626
+ "피드"
627
+ ]
628
+ },
629
+ "line-up": {
630
+ "aliases": [
631
+ "equal height cards",
632
+ "buttons aligned at bottom",
633
+ "card footer alignment",
634
+ "카드 버튼 하단 정렬"
635
+ ],
636
+ "questions": [
637
+ "How do I align card footer actions at the bottom?"
638
+ ]
639
+ },
640
+ "step-nav": {
641
+ "aliases": [
642
+ "stepper",
643
+ "steps list",
644
+ "단계 표시",
645
+ "스텝 내비게이션"
646
+ ]
647
+ },
648
+ "center": {
649
+ "aliases": [
650
+ "center horizontally",
651
+ "max width centered",
652
+ "가운데 정렬",
653
+ "수평 가운데 정렬"
654
+ ]
655
+ },
656
+ "super-center": {
657
+ "aliases": [
658
+ "center horizontally and vertically",
659
+ "center a div",
660
+ "place-items center",
661
+ "가운데 정렬",
662
+ "정중앙 정렬"
663
+ ],
664
+ "questions": [
665
+ "How do I center an element both horizontally and vertically?"
666
+ ]
667
+ },
668
+ "box": {
669
+ "aliases": [
670
+ "padded box",
671
+ "내부 여백 박스"
672
+ ]
673
+ },
674
+ "clamped-card": {
675
+ "aliases": [
676
+ "card max width clamp",
677
+ "카드 폭 제한"
678
+ ]
679
+ },
680
+ "content-limiter": {
681
+ "aliases": [
682
+ "readable line length",
683
+ "max measure",
684
+ "prose width",
685
+ "읽기 좋은 줄 길이",
686
+ "본문 폭 제한"
687
+ ],
688
+ "questions": [
689
+ "How do I keep prose at a readable line length?"
690
+ ]
691
+ },
692
+ "fluid-styles": {
693
+ "aliases": [
694
+ "fluid width with max",
695
+ "유동 폭"
696
+ ]
697
+ },
698
+ "frame": {
699
+ "aliases": [
700
+ "aspect ratio box",
701
+ "responsive image slot",
702
+ "object-fit",
703
+ "이미지 비율 유지",
704
+ "종횡비"
705
+ ],
706
+ "questions": [
707
+ "How do I keep media at a fixed aspect ratio?"
708
+ ]
709
+ },
710
+ "icon-frame": {
711
+ "aliases": [
712
+ "icon slot",
713
+ "square icon box",
714
+ "아이콘 정렬"
715
+ ]
716
+ },
717
+ "imposter": {
718
+ "aliases": [
719
+ "overlay over parent",
720
+ "positioned overlay",
721
+ "modal over card",
722
+ "오버레이",
723
+ "겹쳐 띄우기"
724
+ ]
725
+ },
726
+ "overlay-stack": {
727
+ "aliases": [
728
+ "stack in one grid cell",
729
+ "text over image",
730
+ "겹치는 레이어",
731
+ "이미지 위 텍스트"
732
+ ]
733
+ }
734
+ };
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  try {
4
- const { runSgCli } = await import("./compiler/cli.mjs");
4
+ const { runStylegalleryCli } = await import("./stylegallery-cli.mjs");
5
5
  const controller = new AbortController();
6
6
  const cancel = () => controller.abort();
7
7
  process.once("SIGINT", cancel);
8
8
  process.once("SIGTERM", cancel);
9
9
  try {
10
- const result = await runSgCli(process.argv.slice(2), { signal: controller.signal });
10
+ const result = await runStylegalleryCli(process.argv.slice(2), { signal: controller.signal });
11
11
  process.stdout.write(result.output);
12
12
  process.exitCode = result.exitCode;
13
13
  } finally {
@@ -54,7 +54,7 @@ export class MaterialMcpStdin extends Transform {
54
54
  }
55
55
  }
56
56
 
57
- async function main() {
57
+ export async function main() {
58
58
  const server = createMaterialMcpServer();
59
59
  const input = new MaterialMcpStdin();
60
60
  const transport = new StdioServerTransport(input);
@@ -0,0 +1,130 @@
1
+ // The single `stylegallery` command. search/read use search v3; context with
2
+ // --query uses material v2; retrieve uses the v1 registry; every other command
3
+ // (discover, resolve, claims, context <ref>, ops, registrar, conservator,
4
+ // compiler stages) goes to the existing governed CLI unchanged.
5
+ import fs from "node:fs";
6
+ import path from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+
9
+ const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
10
+
11
+ export function packageVersion() {
12
+ return JSON.parse(fs.readFileSync(path.join(packageRoot, "package.json"), "utf8")).version;
13
+ }
14
+
15
+ export const HELP_TEXT = `stylegallery - search and read the StyleGallery knowledge corpus, plus governed records and site compilation.
16
+
17
+ Usage: stylegallery <command> [options]
18
+
19
+ Find and read documents (offline, deterministic):
20
+ search <query...> Rank documents; prints JSON (schema 3.0).
21
+ --query-en <text> English rewrite of a non-English query. Agents: always pass one for Korean queries.
22
+ --limit <n> Results to return, 1-50 (default 5).
23
+ --paths-only Print repository-relative paths only.
24
+ --detailed Add scores, hash identities, and ranking terms.
25
+ read <id|path> Read one document by id (sg:layout/sticky-header), path, or StableRef.
26
+ --outline List headings with section slugs instead of the content.
27
+ --section <slug> Read one section only.
28
+ context --query <text> Build a bounded, provenance-linked material context package.
29
+ --budget-tokens <n> Token budget, 256-32768 (default 8192).
30
+
31
+ Governed records:
32
+ discover List interfaces, domains, and operations.
33
+ resolve <ref> Read one governed record.
34
+ claims <ref> List claims and evidence for a record.
35
+ context <ref> Build a governed record context package.
36
+ retrieve <query> Search governed records (v1 registry).
37
+ ops List operations.
38
+ registrar | conservator Check claim records | measure Layout patterns in Chromium.
39
+
40
+ Site compilation: compile, timeline, transcribe, sale, gate, build, shots, probe, workflow (see stylegallery workflow).
41
+
42
+ help, --help Show this help.
43
+ version, --version Show the package version.
44
+
45
+ Typical agent loop: stylegallery search "sticky header" -> stylegallery read <id> --outline -> stylegallery read <id> --section <slug>.
46
+ MCP server: stylegallery-mcp (tools: search, read, plus governed and compiler tools).
47
+ `;
48
+
49
+ function report(value) {
50
+ return { report: value, exitCode: value.ok ? 0 : 1, output: `${JSON.stringify(value, null, 2)}\n` };
51
+ }
52
+ function failure(operation, code, message) { return report({ ok: false, operation, failures: [{ code, message }] }); }
53
+
54
+ function parseOptions(command, args, specs) {
55
+ const values = {};
56
+ const positional = [];
57
+ for (let index = 0; index < args.length; index += 1) {
58
+ const argument = args[index];
59
+ if (!argument.startsWith("--")) { positional.push(argument); continue; }
60
+ const spec = specs[argument];
61
+ if (!spec) return { error: failure(command, "argument_unknown", `unknown option ${argument}; run stylegallery help`) };
62
+ if (Object.hasOwn(values, spec.field)) return { error: failure(command, "argument_duplicate", `${argument} was supplied more than once`) };
63
+ if (spec.flag) { values[spec.field] = true; continue; }
64
+ const value = args[index + 1];
65
+ if (value === undefined || value.startsWith("--")) return { error: failure(command, "argument_value_required", `${argument} requires a value`) };
66
+ if (spec.integer) {
67
+ if (!/^[0-9]+$/.test(value)) return { error: failure(command, "argument_integer_invalid", `${argument} must be an unsigned integer`) };
68
+ values[spec.field] = Number(value);
69
+ } else values[spec.field] = value;
70
+ index += 1;
71
+ }
72
+ return { values, positional };
73
+ }
74
+
75
+ async function runSearch(args) {
76
+ const parsed = parseOptions("search", args, {
77
+ "--query": { field: "query" }, "--query-en": { field: "query_en" }, "--limit": { field: "limit", integer: true },
78
+ "--paths-only": { field: "paths_only", flag: true }, "--detailed": { field: "detailed", flag: true },
79
+ });
80
+ if (parsed.error) return parsed.error;
81
+ const { values, positional } = parsed;
82
+ if (values.query !== undefined && positional.length > 0) return failure("search", "argument_inapplicable", "give the query as words or --query, not both");
83
+ const query = values.query ?? positional.join(" ");
84
+ if (!query) return failure("search", "argument_value_required", "a query is required: stylegallery search \"sticky header\"");
85
+ const { detailed, ...rest } = values;
86
+ const input = { ...rest, query, ...(detailed ? { response_format: "detailed" } : {}) };
87
+ const { invokeSearchOperation } = await import("./agent-native/v2/material-search-v3.mjs");
88
+ const { materialRuntimeOptions } = await import("./agent-native/v2/material-cli-adapter.mjs");
89
+ return report(invokeSearchOperation("search", input, materialRuntimeOptions()));
90
+ }
91
+
92
+ async function runRead(args) {
93
+ const parsed = parseOptions("read", args, { "--section": { field: "section" }, "--outline": { field: "outline", flag: true } });
94
+ if (parsed.error) return parsed.error;
95
+ if (parsed.positional.length !== 1) return failure("read", "argument_value_required", "give exactly one id, path, or StableRef: stylegallery read sg:layout/sticky-header");
96
+ const { invokeSearchOperation } = await import("./agent-native/v2/material-search-v3.mjs");
97
+ const { materialRuntimeOptions } = await import("./agent-native/v2/material-cli-adapter.mjs");
98
+ return report(invokeSearchOperation("read", { reference: parsed.positional[0], ...parsed.values }, materialRuntimeOptions()));
99
+ }
100
+
101
+ async function runRetrieve(args) {
102
+ const parsed = parseOptions("retrieve", args, { "--query": { field: "query" }, "--limit": { field: "limit", integer: true }, "--format": { field: "format" } });
103
+ if (parsed.error) return parsed.error;
104
+ const { format, ...values } = parsed.values;
105
+ if (format !== undefined && format !== "json") return failure("retrieve", "format_unsupported", "Only --format json is supported.");
106
+ const query = values.query ?? parsed.positional.join(" ");
107
+ if (!query) return failure("retrieve", "argument_value_required", "a query is required");
108
+ const { agentNativeRegistry } = await import("./agent-native/registry.mjs");
109
+ return report(agentNativeRegistry.invoke("retrieve", { ...values, query }));
110
+ }
111
+
112
+ export async function runStylegalleryCli(argv, config = {}) {
113
+ const [command, ...rest] = argv;
114
+ if (command === undefined || command === "help" || command === "--help" || command === "-h") {
115
+ return { exitCode: 0, output: HELP_TEXT, report: { ok: true, operation: "help" } };
116
+ }
117
+ if (command === "version" || command === "--version" || command === "-v") {
118
+ return { exitCode: 0, output: `${packageVersion()}\n`, report: { ok: true, operation: "version" } };
119
+ }
120
+ if (rest.includes("--help")) return { exitCode: 0, output: HELP_TEXT, report: { ok: true, operation: "help" } };
121
+ if (command === "search") return runSearch(rest);
122
+ if (command === "read") return runRead(rest);
123
+ if (command === "retrieve") return runRetrieve(rest);
124
+ if (command === "context" && rest.includes("--query")) {
125
+ const { runMaterialCli } = await import("./agent-native/v2/material-cli-adapter.mjs");
126
+ return runMaterialCli(["context", ...rest]);
127
+ }
128
+ const { runSgCli } = await import("./compiler/cli.mjs");
129
+ return runSgCli(argv, config);
130
+ }
@@ -0,0 +1,34 @@
1
+ ---
2
+ type: Agent Skill
3
+ name: stylegallery-search
4
+ description: Find and read StyleGallery guidance (layout patterns, recipes, motion, state management, platform guides, design terminology, expression) with the stylegallery CLI or the stylegallery-mcp search/read tools. Use when a UI task needs a layout pattern, recipe, or interaction contract and the right document is not already known.
5
+ ---
6
+
7
+ # StyleGallery search
8
+
9
+ 1. Search with a short task phrase. Pass an English rewrite when you ask in another language:
10
+
11
+ ```sh
12
+ stylegallery search "sticky header"
13
+ stylegallery search "헤더 고정" --query-en "sticky header"
14
+ ```
15
+
16
+ MCP: `search { "query": "헤더 고정", "query_en": "sticky header" }`.
17
+
18
+ 2. Pick a result by `title`, `description`, and the verbatim `snippets`. Each result has a readable `id` such as `sg:layout/sticky-header` and a `next.read` command.
19
+
20
+ 3. Read only what you need:
21
+
22
+ ```sh
23
+ stylegallery read sg:layout/sticky-header --outline
24
+ stylegallery read sg:layout/sticky-header --section css
25
+ ```
26
+
27
+ MCP: `read { "reference": "sg:layout/sticky-header", "section": "css" }`.
28
+
29
+ Notes:
30
+
31
+ - Results default to 5; use `--limit` (1-50) and `--paths-only` when you will open files yourself.
32
+ - `results: []` is a normal answer. Follow `hint`: add `--query-en`, use fewer words, or browse with `stylegallery discover`.
33
+ - `--detailed` (MCP `response_format: "detailed"`) adds scores and hash identities; you rarely need it.
34
+ - With the repository checked out, you can also read the returned `path` directly.