@ranimontagna/agent-toolkit 0.3.5 → 0.3.7

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 (110) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +8 -8
  3. package/dist/src/installers/superpowers.js +23 -7
  4. package/dist/src/installers/superpowers.js.map +1 -1
  5. package/package.json +5 -5
  6. package/skills/backend/fastify-best-practices/NOTICE.md +1 -1
  7. package/skills/backend/fastify-best-practices/rules/authentication.md +13 -0
  8. package/skills/backend/fastify-best-practices/rules/configuration.md +9 -0
  9. package/skills/backend/fastify-best-practices/rules/content-type.md +16 -0
  10. package/skills/backend/fastify-best-practices/rules/cors-security.md +18 -0
  11. package/skills/backend/fastify-best-practices/rules/database.md +12 -0
  12. package/skills/backend/fastify-best-practices/rules/decorators.md +14 -0
  13. package/skills/backend/fastify-best-practices/rules/deployment.md +16 -0
  14. package/skills/backend/fastify-best-practices/rules/error-handling.md +16 -0
  15. package/skills/backend/fastify-best-practices/rules/hooks.md +20 -0
  16. package/skills/backend/fastify-best-practices/rules/http-proxy.md +11 -0
  17. package/skills/backend/fastify-best-practices/rules/logging.md +18 -0
  18. package/skills/backend/fastify-best-practices/rules/performance.md +20 -0
  19. package/skills/backend/fastify-best-practices/rules/plugins.md +14 -0
  20. package/skills/backend/fastify-best-practices/rules/routes.md +18 -0
  21. package/skills/backend/fastify-best-practices/rules/schemas.md +20 -0
  22. package/skills/backend/fastify-best-practices/rules/serialization.md +19 -0
  23. package/skills/backend/fastify-best-practices/rules/testing.md +17 -0
  24. package/skills/backend/fastify-best-practices/rules/typescript.md +15 -0
  25. package/skills/backend/fastify-best-practices/rules/websockets.md +15 -0
  26. package/skills/backend/go/golang-patterns/NOTICE.md +1 -1
  27. package/skills/backend/go/golang-patterns/SKILL.md +2 -1
  28. package/skills/devops/docker-patterns/NOTICE.md +1 -1
  29. package/skills/devops/docker-patterns/SKILL.md +3 -3
  30. package/skills/frontend/design/revenue-centric-design/NOTICE.md +1 -1
  31. package/skills/frontend/design/revenue-centric-design/SKILL.md +6 -4
  32. package/skills/frontend/design/revenue-centric-design/assets/1985681720104903142__1.jpg +0 -0
  33. package/skills/frontend/design/revenue-centric-design/assets/1999584679247134761__1.jpg +0 -0
  34. package/skills/frontend/design/revenue-centric-design/assets/2000930776636940333__1.jpg +0 -0
  35. package/skills/frontend/design/revenue-centric-design/assets/2018693884449009956__3.jpg +0 -0
  36. package/skills/frontend/design/revenue-centric-design/assets/2081714430811730162__1.jpg +0 -0
  37. package/skills/frontend/design/revenue-centric-design/assets/2092692547244007852__q__1.jpg +0 -0
  38. package/skills/frontend/design/revenue-centric-design/assets/2092692547244007852__q__2.jpg +0 -0
  39. package/skills/frontend/design/revenue-centric-design/assets/2092692547244007852__q__3.jpg +0 -0
  40. package/skills/frontend/design/revenue-centric-design/references/checkout-and-forms.md +39 -0
  41. package/skills/frontend/design/revenue-centric-design/references/churn-and-retention.md +25 -0
  42. package/skills/frontend/design/revenue-centric-design/references/conversion-and-landing-pages.md +52 -1
  43. package/skills/frontend/design/revenue-centric-design/references/dashboards-and-data-viz.md +23 -0
  44. package/skills/frontend/design/revenue-centric-design/references/metrics-and-experimentation.md +13 -0
  45. package/skills/frontend/design/revenue-centric-design/references/onboarding-and-activation.md +7 -1
  46. package/skills/frontend/design/revenue-centric-design/references/pricing-and-monetization.md +35 -8
  47. package/skills/frontend/design/revenue-centric-design/references/product-strategy-and-features.md +37 -0
  48. package/skills/frontend/design/revenue-centric-design/references/revenue-centric-design.md +2 -2
  49. package/skills/frontend/design/ui-ux-pro-max/NOTICE.md +6 -4
  50. package/skills/frontend/design/ui-ux-pro-max/SKILL.md +103 -573
  51. package/skills/frontend/design/ui-ux-pro-max/data/app-interface.csv +29 -27
  52. package/skills/frontend/design/ui-ux-pro-max/data/catalog-summary.json +78 -0
  53. package/skills/frontend/design/ui-ux-pro-max/data/charts.csv +26 -26
  54. package/skills/frontend/design/ui-ux-pro-max/data/colors.csv +191 -160
  55. package/skills/frontend/design/ui-ux-pro-max/data/data-provenance.json +1348 -0
  56. package/skills/frontend/design/ui-ux-pro-max/data/google-font-licenses.json +20185 -0
  57. package/skills/frontend/design/ui-ux-pro-max/data/google-fonts.csv +1934 -1923
  58. package/skills/frontend/design/ui-ux-pro-max/data/icons.csv +106 -106
  59. package/skills/frontend/design/ui-ux-pro-max/data/landing.csv +35 -35
  60. package/skills/frontend/design/ui-ux-pro-max/data/motion.csv +18 -0
  61. package/skills/frontend/design/ui-ux-pro-max/data/phosphor-icons-upstream.json +32582 -0
  62. package/skills/frontend/design/ui-ux-pro-max/data/products.csv +192 -161
  63. package/skills/frontend/design/ui-ux-pro-max/data/react-performance.csv +37 -37
  64. package/skills/frontend/design/ui-ux-pro-max/data/stacks/angular.csv +51 -51
  65. package/skills/frontend/design/ui-ux-pro-max/data/stacks/astro.csv +54 -54
  66. package/skills/frontend/design/ui-ux-pro-max/data/stacks/avalonia.csv +57 -0
  67. package/skills/frontend/design/ui-ux-pro-max/data/stacks/flutter.csv +53 -53
  68. package/skills/frontend/design/ui-ux-pro-max/data/stacks/html-tailwind.csv +60 -56
  69. package/skills/frontend/design/ui-ux-pro-max/data/stacks/javafx.csv +76 -0
  70. package/skills/frontend/design/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -53
  71. package/skills/frontend/design/ui-ux-pro-max/data/stacks/laravel.csv +51 -51
  72. package/skills/frontend/design/ui-ux-pro-max/data/stacks/nextjs.csv +62 -53
  73. package/skills/frontend/design/ui-ux-pro-max/data/stacks/nuxt-ui.csv +77 -51
  74. package/skills/frontend/design/ui-ux-pro-max/data/stacks/nuxtjs.csv +68 -59
  75. package/skills/frontend/design/ui-ux-pro-max/data/stacks/react-native.csv +52 -52
  76. package/skills/frontend/design/ui-ux-pro-max/data/stacks/react.csv +67 -54
  77. package/skills/frontend/design/ui-ux-pro-max/data/stacks/shadcn.csv +69 -61
  78. package/skills/frontend/design/ui-ux-pro-max/data/stacks/svelte.csv +56 -54
  79. package/skills/frontend/design/ui-ux-pro-max/data/stacks/swiftui.csv +51 -51
  80. package/skills/frontend/design/ui-ux-pro-max/data/stacks/threejs.csv +54 -54
  81. package/skills/frontend/design/ui-ux-pro-max/data/stacks/uno.csv +60 -0
  82. package/skills/frontend/design/ui-ux-pro-max/data/stacks/uwp.csv +56 -0
  83. package/skills/frontend/design/ui-ux-pro-max/data/stacks/vue.csv +50 -50
  84. package/skills/frontend/design/ui-ux-pro-max/data/stacks/winui.csv +60 -0
  85. package/skills/frontend/design/ui-ux-pro-max/data/stacks/wpf.csv +57 -0
  86. package/skills/frontend/design/ui-ux-pro-max/data/styles.csv +89 -85
  87. package/skills/frontend/design/ui-ux-pro-max/data/typography.csv +74 -73
  88. package/skills/frontend/design/ui-ux-pro-max/data/ui-reasoning.csv +193 -162
  89. package/skills/frontend/design/ui-ux-pro-max/data/ux-guidelines.csv +30 -10
  90. package/skills/frontend/design/ui-ux-pro-max/references/pro-rules.md +117 -0
  91. package/skills/frontend/design/ui-ux-pro-max/references/quick-reference.md +256 -0
  92. package/skills/frontend/design/ui-ux-pro-max/scripts/core.py +800 -69
  93. package/skills/frontend/design/ui-ux-pro-max/scripts/design_system.py +700 -180
  94. package/skills/frontend/design/ui-ux-pro-max/scripts/reasoning_contract.py +123 -0
  95. package/skills/frontend/design/ui-ux-pro-max/scripts/search.py +105 -42
  96. package/skills/frontend/design/ui-ux-pro-max/scripts/validate_data.py +1095 -0
  97. package/skills/frontend/react-native/react-native-unistyles-v3/NOTICE.md +1 -1
  98. package/skills/frontend/react-native/react-native-unistyles-v3/SKILL.md +33 -24
  99. package/skills/frontend/react-native/react-native-unistyles-v3/references/api-reference.md +135 -78
  100. package/skills/frontend/react-native/react-native-unistyles-v3/references/common-issues.md +48 -31
  101. package/skills/frontend/react-native/react-native-unistyles-v3/references/setup-guide.md +76 -34
  102. package/skills/frontend/react-native/react-native-unistyles-v3/references/styling-patterns.md +145 -52
  103. package/skills/frontend/react-native/react-native-unistyles-v3/references/third-party-integration.md +76 -27
  104. package/skills/media/brag-slim/NOTICE.md +3 -3
  105. package/skills/media/brag-slim/SKILL.md +4 -0
  106. package/tools.lock.json +20 -20
  107. package/skills/frontend/design/revenue-centric-design/assets/2018693884449009956__1.jpg +0 -0
  108. package/skills/frontend/design/ui-ux-pro-max/data/_sync_all.py +0 -414
  109. package/skills/frontend/design/ui-ux-pro-max/data/design.csv +0 -1776
  110. package/skills/frontend/design/ui-ux-pro-max/data/draft.csv +0 -1779
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env python3
2
+ """Closed, non-executable grammar for design-system decision rules."""
3
+
4
+ import json
5
+ import re
6
+
7
+ CONDITION_SIGNALS = {
8
+ "if_booking": ("booking", "appointment", "calendar"),
9
+ "if_boutique": ("boutique",),
10
+ "if_casual": ("casual", "playful"),
11
+ "if_checkout": ("checkout", "payment", "purchase"),
12
+ "if_children": ("child", "children", "kids"),
13
+ "if_collaboration": ("collaboration", "multiplayer", "co-edit"),
14
+ "if_competitive": ("competitive", "leaderboard"),
15
+ "if_content_focused": ("content", "article", "reading", "documentation"),
16
+ "if_conversion_focused": ("conversion", "sales", "signup", "purchase"),
17
+ "if_creative_field": ("creative", "artist", "portfolio"),
18
+ "if_crop_focused": ("crop", "farm", "agriculture"),
19
+ "if_dashboard": ("dashboard", "operations", "monitoring"),
20
+ "if_data_heavy": ("data heavy", "data-heavy", "analytics", "large dataset"),
21
+ "if_delivery": ("delivery", "courier", "shipping"),
22
+ "if_discovery_focused": ("discover", "discovery", "browse", "directory"),
23
+ "if_engagement_metric": ("engagement", "retention", "contribution"),
24
+ "if_experience_focused": ("experience", "immersive", "journey"),
25
+ "if_gamification": ("gamification", "badges", "streak"),
26
+ "if_health": ("health", "medical", "patient"),
27
+ "if_hero_needed": ("hero", "showcase", "launch"),
28
+ "if_large_dataset": ("large dataset", "thousands", "millions"),
29
+ "if_light_mode_needed": ("light mode", "light theme"),
30
+ "if_low_performance": ("low performance", "low-end", "slow device"),
31
+ "if_luxury": ("luxury", "premium", "high-end"),
32
+ "if_medication": ("medication", "medicine", "prescription"),
33
+ "if_meditation": ("meditation", "breathing", "mindfulness"),
34
+ "if_minimal_portfolio": ("minimal portfolio", "simple portfolio"),
35
+ "if_mobile": ("mobile", "phone", "tablet", "ios", "android"),
36
+ "if_personalized": ("personalized", "personalised", "recommendation"),
37
+ "if_pre_launch": ("pre-launch", "prelaunch", "coming soon", "waitlist"),
38
+ "if_salary_focused": ("salary", "compensation", "pay range"),
39
+ "if_team_collaboration": ("team collaboration", "team workspace"),
40
+ "if_trust_needed": ("trust", "secure", "verified", "authority"),
41
+ "if_ux_focused": ("ux", "usability", "accessibility", "accessible"),
42
+ "if_video_ready": ("video ready", "product video", "demo video"),
43
+ }
44
+
45
+ ALLOWED_CONDITIONS = {"must_have", *CONDITION_SIGNALS}
46
+ ACTION_PREFIXES = {"constraint", "style", "pattern", "mode"}
47
+ TOKEN_ACTION_PREFIXES = {"constraint", "style"}
48
+ TOKEN_RE = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")
49
+ CONDITION_PATTERNS = {
50
+ condition: tuple(
51
+ re.compile(r"(?<!\w)" + re.escape(signal) + r"(?!\w)")
52
+ for signal in signals
53
+ )
54
+ for condition, signals in CONDITION_SIGNALS.items()
55
+ }
56
+
57
+
58
+ def _object_without_duplicates(pairs):
59
+ result = {}
60
+ for key, value in pairs:
61
+ if key in result:
62
+ raise ValueError("duplicate decision-rule key: {}".format(key))
63
+ result[key] = value
64
+ return result
65
+
66
+
67
+ def parse_decision_rules(raw):
68
+ """Parse the canonical condition -> action-array representation."""
69
+ try:
70
+ rules = json.loads(raw or "{}", object_pairs_hook=_object_without_duplicates)
71
+ except json.JSONDecodeError as error:
72
+ raise ValueError("invalid decision-rule JSON: {}".format(error)) from error
73
+ if not isinstance(rules, dict):
74
+ raise ValueError("decision rules must be a JSON object")
75
+ for condition, actions in rules.items():
76
+ if condition not in ALLOWED_CONDITIONS:
77
+ raise ValueError("unknown decision-rule condition: {}".format(condition))
78
+ if not isinstance(actions, list) or not actions:
79
+ raise ValueError("{} must map to a non-empty action array".format(condition))
80
+ for action in actions:
81
+ _validate_action(action)
82
+ if len(actions) != len(set(actions)):
83
+ raise ValueError("{} contains duplicate actions".format(condition))
84
+ return rules
85
+
86
+
87
+ def _validate_action(action):
88
+ if not isinstance(action, str) or ":" not in action:
89
+ raise ValueError("action must use a known prefix: {}".format(action))
90
+ prefix, value = action.split(":", 1)
91
+ if prefix not in ACTION_PREFIXES:
92
+ raise ValueError("unknown decision-rule action: {}".format(action))
93
+ if prefix in TOKEN_ACTION_PREFIXES and not TOKEN_RE.fullmatch(value):
94
+ raise ValueError("invalid {} action value: {}".format(prefix, value))
95
+ if prefix == "pattern" and not value.strip():
96
+ raise ValueError("pattern action must name a pattern")
97
+ if prefix == "mode" and value not in {"dark", "light"}:
98
+ raise ValueError("mode action must be dark or light")
99
+
100
+
101
+ def apply_decision_rules(rules, query):
102
+ """Return deterministic mutations and an audit trail; never execute data."""
103
+ normalized = str(query or "").casefold()
104
+ result = {"activated": [], "style_ids": [], "constraints": [],
105
+ "pattern": None, "mode": None}
106
+ for condition, actions in rules.items():
107
+ active = condition == "must_have" or any(
108
+ pattern.search(normalized)
109
+ for pattern in CONDITION_PATTERNS.get(condition, ()))
110
+ if not active:
111
+ continue
112
+ result["activated"].append({"condition": condition, "actions": list(actions)})
113
+ for action in actions:
114
+ prefix, value = action.split(":", 1)
115
+ if prefix == "style" and value not in result["style_ids"]:
116
+ result["style_ids"].append(value)
117
+ elif prefix == "constraint" and value not in result["constraints"]:
118
+ result["constraints"].append(value)
119
+ elif prefix == "pattern":
120
+ result["pattern"] = value
121
+ elif prefix == "mode":
122
+ result["mode"] = value
123
+ return result
@@ -4,21 +4,33 @@
4
4
  UI/UX Pro Max Search - BM25 search engine for UI/UX style guides
5
5
  Usage: python search.py "<query>" [--domain <domain>] [--stack <stack>] [--max-results 3]
6
6
  python search.py "<query>" --design-system [-p "Project Name"]
7
- python search.py "<query>" --design-system --persist [-p "Project Name"] [--page "dashboard"]
7
+ python search.py "<query>" --design-system --persist [-p "Project Name"] --output-dir "<project-root>" [--page "dashboard"]
8
+ python search.py "<query>" --design-system --variance 8 --motion 9 --density 7
8
9
 
9
- Domains: style, prompt, color, chart, landing, product, ux, typography, google-fonts
10
- Stacks: react, nextjs, vue, svelte, astro, swiftui, react-native, flutter, nuxtjs, nuxt-ui, html-tailwind, shadcn, jetpack-compose, threejs
10
+ Domains: style, color, chart, landing, product, ux, typography, google-fonts, icons, gsap, react, web
11
+ Stacks: react, nextjs, vue, svelte, astro, swiftui, react-native, flutter, nuxtjs, nuxt-ui,
12
+ html-tailwind, shadcn, jetpack-compose, threejs, angular, laravel
13
+
14
+ Design dials (1-10, only with --design-system):
15
+ --variance DESIGN_VARIANCE: 1=centered/minimal, 10=bold/asymmetric
16
+ --motion MOTION_INTENSITY: 1=subtle, 10=complex; attaches a GSAP snippet from motion.csv
17
+ --density VISUAL_DENSITY: 1=spacious, 10=dense/dashboard; overrides the spacing scale
11
18
 
12
19
  Persistence (Master + Overrides pattern):
13
- --persist Save design system to design-system/MASTER.md
14
- --page Also create a page-specific override file in design-system/pages/
20
+ --persist Save design system to design-system/<project-slug>/MASTER.md
21
+ --output-dir Directory the design-system/ folder is created under (defaults to cwd --
22
+ always pass this explicitly, pointed at the project root)
23
+ --page Also create a page-specific override file in design-system/<project-slug>/pages/
24
+ --force Overwrite an existing MASTER.md (without this, persistence is skipped
25
+ if MASTER.md already exists, so prior design decisions aren't lost)
15
26
  """
16
27
 
17
28
  import argparse
29
+ import json as json_module
18
30
  import sys
19
31
  import io
20
- from core import CSV_CONFIG, AVAILABLE_STACKS, MAX_RESULTS, search, search_stack
21
- from design_system import generate_design_system, persist_design_system
32
+ from core import CSV_CONFIG, AVAILABLE_STACKS, MAX_RESULTS, UNTRUNCATED_COLS, search, search_stack
33
+ from design_system import generate_design_system
22
34
 
23
35
  # Force UTF-8 for stdout/stderr to handle emojis on Windows (cp1252 default)
24
36
  if sys.stdout.encoding and sys.stdout.encoding.lower() != 'utf-8':
@@ -26,27 +38,55 @@ if sys.stdout.encoding and sys.stdout.encoding.lower() != 'utf-8':
26
38
  if sys.stderr.encoding and sys.stderr.encoding.lower() != 'utf-8':
27
39
  sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
28
40
 
41
+ TRUNCATE_AT = 300
42
+
29
43
 
30
- def format_output(result):
44
+ def format_output(result, full=False):
31
45
  """Format results for Claude consumption (token-optimized)"""
32
46
  if "error" in result:
33
47
  return f"Error: {result['error']}"
34
48
 
35
49
  output = []
36
50
  if result.get("stack"):
37
- output.append(f"## UI Pro Max Stack Guidelines")
51
+ output.append("## UI Pro Max Stack Guidelines")
38
52
  output.append(f"**Stack:** {result['stack']} | **Query:** {result['query']}")
39
53
  else:
40
- output.append(f"## UI Pro Max Search Results")
41
- output.append(f"**Domain:** {result['domain']} | **Query:** {result['query']}")
54
+ output.append("## UI Pro Max Search Results")
55
+ domain_note = result['domain']
56
+ if result.get("auto_detected"):
57
+ domain_note += " (auto-detected"
58
+ if result.get("runner_up_domain"):
59
+ domain_note += f", runner-up: {result['runner_up_domain']}"
60
+ domain_note += ")"
61
+ output.append(f"**Domain:** {domain_note} | **Query:** {result['query']}")
42
62
  output.append(f"**Source:** {result['file']} | **Found:** {result['count']} results\n")
43
63
 
64
+ if result['count'] == 0:
65
+ redirect = result.get("redirect")
66
+ if redirect:
67
+ output.append(
68
+ "This legacy style label is now modeled in the "
69
+ f"`{redirect['domain']}` domain as `{redirect['id']}`. "
70
+ "Search that domain instead of treating a page composition as a visual style."
71
+ )
72
+ return "\n".join(output)
73
+ output.append(
74
+ "No matches. This is not a match with an empty value -- the query "
75
+ "did not hit the database. Retry with broader/different keywords "
76
+ "before falling back to general defaults, and say explicitly that "
77
+ "no database match was found if you do fall back."
78
+ )
79
+ suggestions = result.get("suggestions") or []
80
+ if suggestions:
81
+ output.append(f"**Closest known terms:** {', '.join(suggestions)}")
82
+ return "\n".join(output)
83
+
44
84
  for i, row in enumerate(result['results'], 1):
45
85
  output.append(f"### Result {i}")
46
86
  for key, value in row.items():
47
87
  value_str = str(value)
48
- if len(value_str) > 300:
49
- value_str = value_str[:300] + "..."
88
+ if not full and key not in UNTRUNCATED_COLS and len(value_str) > TRUNCATE_AT:
89
+ value_str = value_str[:TRUNCATE_AT] + "..."
50
90
  output.append(f"- **{key}:** {value_str}")
51
91
  output.append("")
52
92
 
@@ -58,57 +98,80 @@ if __name__ == "__main__":
58
98
  parser.add_argument("query", help="Search query")
59
99
  parser.add_argument("--domain", "-d", choices=list(CSV_CONFIG.keys()), help="Search domain")
60
100
  parser.add_argument("--stack", "-s", choices=AVAILABLE_STACKS, help=f"Stack-specific search. Available: {', '.join(AVAILABLE_STACKS)}")
61
- parser.add_argument("--max-results", "-n", type=int, default=MAX_RESULTS, help="Max results (default: 3)")
101
+ parser.add_argument("--max-results", "-n", type=int, choices=range(1, 21), default=MAX_RESULTS,
102
+ metavar="1-20", help="Max results (default: 3)")
62
103
  parser.add_argument("--json", action="store_true", help="Output as JSON")
104
+ parser.add_argument("--full", action="store_true", help="Do not truncate long field values in text output")
63
105
  # Design system generation
64
106
  parser.add_argument("--design-system", "-ds", action="store_true", help="Generate complete design system recommendation")
65
107
  parser.add_argument("--project-name", "-p", type=str, default=None, help="Project name for design system output")
66
- parser.add_argument("--format", "-f", choices=["ascii", "markdown"], default="ascii", help="Output format for design system")
108
+ parser.add_argument("--format", "-f", choices=["ascii", "markdown"], default="ascii", help="Output format for design system (ignored if --json)")
67
109
  # Persistence (Master + Overrides pattern)
68
- parser.add_argument("--persist", action="store_true", help="Save design system to design-system/MASTER.md (creates hierarchical structure)")
69
- parser.add_argument("--page", type=str, default=None, help="Create page-specific override file in design-system/pages/")
70
- parser.add_argument("--output-dir", "-o", type=str, default=None, help="Output directory for persisted files (default: current directory)")
110
+ parser.add_argument("--persist", action="store_true", help="Save design system to design-system/<project-slug>/MASTER.md (creates hierarchical structure)")
111
+ parser.add_argument("--page", type=str, default=None, help="Create page-specific override file in design-system/<project-slug>/pages/")
112
+ parser.add_argument("--output-dir", "-o", type=str, default=None, help="Output directory for persisted files (default: current directory -- pass this explicitly, pointed at the project root)")
113
+ parser.add_argument("--force", action="store_true", help="Overwrite an existing MASTER.md when persisting (default: skip if it already exists)")
114
+ # Design dials (1-10), only applied with --design-system
115
+ parser.add_argument("--variance", type=int, choices=range(1, 11), metavar="1-10", help="DESIGN_VARIANCE dial: 1=centered/minimal, 10=bold/asymmetric (only with --design-system)")
116
+ parser.add_argument("--motion", type=int, choices=range(1, 11), metavar="1-10", help="MOTION_INTENSITY dial: 1=subtle, 10=complex; pulls a matching GSAP snippet from motion.csv (only with --design-system)")
117
+ parser.add_argument("--density", type=int, choices=range(1, 11), metavar="1-10", help="VISUAL_DENSITY dial: 1=spacious, 10=dense/dashboard; overrides the spacing scale (only with --design-system)")
71
118
 
72
119
  args = parser.parse_args()
73
120
 
74
121
  # Design system takes priority
75
122
  if args.design_system:
123
+ if args.stack:
124
+ print(
125
+ f"note: --stack {args.stack} is ignored in --design-system mode; "
126
+ "run a separate --stack query for stack-specific guidelines",
127
+ file=sys.stderr,
128
+ )
76
129
  result = generate_design_system(
77
- args.query,
78
- args.project_name,
130
+ args.query,
131
+ args.project_name,
79
132
  args.format,
80
133
  persist=args.persist,
81
134
  page=args.page,
82
- output_dir=args.output_dir
135
+ output_dir=args.output_dir,
136
+ variance=args.variance,
137
+ motion=args.motion,
138
+ density=args.density,
139
+ force=args.force,
83
140
  )
84
- print(result)
85
-
86
- # Print persistence confirmation
87
- if args.persist:
88
- project_slug = args.project_name.lower().replace(' ', '-') if args.project_name else "default"
89
- print("\n" + "=" * 60)
90
- print(f"✅ Design system persisted to design-system/{project_slug}/")
91
- print(f" 📄 design-system/{project_slug}/MASTER.md (Global Source of Truth)")
92
- if args.page:
93
- page_filename = args.page.lower().replace(' ', '-')
94
- print(f" 📄 design-system/{project_slug}/pages/{page_filename}.md (Page Overrides)")
95
- print("")
96
- print(f"📖 Usage: When building a page, check design-system/{project_slug}/pages/[page].md first.")
97
- print(f" If exists, its rules override MASTER.md. Otherwise, use MASTER.md.")
98
- print("=" * 60)
141
+
142
+ if args.json:
143
+ print(json_module.dumps(
144
+ {"design_system": result["design_system"], "persistence": result["persistence"]},
145
+ indent=2, ensure_ascii=False,
146
+ ))
147
+ else:
148
+ print(result["text"])
149
+
150
+ if args.persist:
151
+ persistence = result["persistence"] or {}
152
+ print("\n" + "=" * 60)
153
+ if persistence.get("status") == "skipped_exists":
154
+ print(f"⚠️ {persistence.get('message', 'MASTER.md already exists; not overwritten.')}")
155
+ else:
156
+ ds_dir = persistence.get("design_system_dir", "design-system/<project>")
157
+ print(f"✅ Design system persisted to {ds_dir}/")
158
+ for f in persistence.get("created_files", []):
159
+ print(f" 📄 {f}")
160
+ print("")
161
+ print(f"📖 Usage: When building a page, check {ds_dir}/pages/[page].md first.")
162
+ print(" If it exists, its rules override MASTER.md. Otherwise, use MASTER.md.")
163
+ print("=" * 60)
99
164
  # Stack search
100
165
  elif args.stack:
101
166
  result = search_stack(args.query, args.stack, args.max_results)
102
167
  if args.json:
103
- import json
104
- print(json.dumps(result, indent=2, ensure_ascii=False))
168
+ print(json_module.dumps(result, indent=2, ensure_ascii=False))
105
169
  else:
106
- print(format_output(result))
170
+ print(format_output(result, full=args.full))
107
171
  # Domain search
108
172
  else:
109
173
  result = search(args.query, args.domain, args.max_results)
110
174
  if args.json:
111
- import json
112
- print(json.dumps(result, indent=2, ensure_ascii=False))
175
+ print(json_module.dumps(result, indent=2, ensure_ascii=False))
113
176
  else:
114
- print(format_output(result))
177
+ print(format_output(result, full=args.full))