@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.
- package/CHANGELOG.md +5 -0
- package/README.md +8 -8
- package/dist/src/installers/superpowers.js +23 -7
- package/dist/src/installers/superpowers.js.map +1 -1
- package/package.json +5 -5
- package/skills/backend/fastify-best-practices/NOTICE.md +1 -1
- package/skills/backend/fastify-best-practices/rules/authentication.md +13 -0
- package/skills/backend/fastify-best-practices/rules/configuration.md +9 -0
- package/skills/backend/fastify-best-practices/rules/content-type.md +16 -0
- package/skills/backend/fastify-best-practices/rules/cors-security.md +18 -0
- package/skills/backend/fastify-best-practices/rules/database.md +12 -0
- package/skills/backend/fastify-best-practices/rules/decorators.md +14 -0
- package/skills/backend/fastify-best-practices/rules/deployment.md +16 -0
- package/skills/backend/fastify-best-practices/rules/error-handling.md +16 -0
- package/skills/backend/fastify-best-practices/rules/hooks.md +20 -0
- package/skills/backend/fastify-best-practices/rules/http-proxy.md +11 -0
- package/skills/backend/fastify-best-practices/rules/logging.md +18 -0
- package/skills/backend/fastify-best-practices/rules/performance.md +20 -0
- package/skills/backend/fastify-best-practices/rules/plugins.md +14 -0
- package/skills/backend/fastify-best-practices/rules/routes.md +18 -0
- package/skills/backend/fastify-best-practices/rules/schemas.md +20 -0
- package/skills/backend/fastify-best-practices/rules/serialization.md +19 -0
- package/skills/backend/fastify-best-practices/rules/testing.md +17 -0
- package/skills/backend/fastify-best-practices/rules/typescript.md +15 -0
- package/skills/backend/fastify-best-practices/rules/websockets.md +15 -0
- package/skills/backend/go/golang-patterns/NOTICE.md +1 -1
- package/skills/backend/go/golang-patterns/SKILL.md +2 -1
- package/skills/devops/docker-patterns/NOTICE.md +1 -1
- package/skills/devops/docker-patterns/SKILL.md +3 -3
- package/skills/frontend/design/revenue-centric-design/NOTICE.md +1 -1
- package/skills/frontend/design/revenue-centric-design/SKILL.md +6 -4
- package/skills/frontend/design/revenue-centric-design/assets/1985681720104903142__1.jpg +0 -0
- package/skills/frontend/design/revenue-centric-design/assets/1999584679247134761__1.jpg +0 -0
- package/skills/frontend/design/revenue-centric-design/assets/2000930776636940333__1.jpg +0 -0
- package/skills/frontend/design/revenue-centric-design/assets/2018693884449009956__3.jpg +0 -0
- package/skills/frontend/design/revenue-centric-design/assets/2081714430811730162__1.jpg +0 -0
- package/skills/frontend/design/revenue-centric-design/assets/2092692547244007852__q__1.jpg +0 -0
- package/skills/frontend/design/revenue-centric-design/assets/2092692547244007852__q__2.jpg +0 -0
- package/skills/frontend/design/revenue-centric-design/assets/2092692547244007852__q__3.jpg +0 -0
- package/skills/frontend/design/revenue-centric-design/references/checkout-and-forms.md +39 -0
- package/skills/frontend/design/revenue-centric-design/references/churn-and-retention.md +25 -0
- package/skills/frontend/design/revenue-centric-design/references/conversion-and-landing-pages.md +52 -1
- package/skills/frontend/design/revenue-centric-design/references/dashboards-and-data-viz.md +23 -0
- package/skills/frontend/design/revenue-centric-design/references/metrics-and-experimentation.md +13 -0
- package/skills/frontend/design/revenue-centric-design/references/onboarding-and-activation.md +7 -1
- package/skills/frontend/design/revenue-centric-design/references/pricing-and-monetization.md +35 -8
- package/skills/frontend/design/revenue-centric-design/references/product-strategy-and-features.md +37 -0
- package/skills/frontend/design/revenue-centric-design/references/revenue-centric-design.md +2 -2
- package/skills/frontend/design/ui-ux-pro-max/NOTICE.md +6 -4
- package/skills/frontend/design/ui-ux-pro-max/SKILL.md +103 -573
- package/skills/frontend/design/ui-ux-pro-max/data/app-interface.csv +29 -27
- package/skills/frontend/design/ui-ux-pro-max/data/catalog-summary.json +78 -0
- package/skills/frontend/design/ui-ux-pro-max/data/charts.csv +26 -26
- package/skills/frontend/design/ui-ux-pro-max/data/colors.csv +191 -160
- package/skills/frontend/design/ui-ux-pro-max/data/data-provenance.json +1348 -0
- package/skills/frontend/design/ui-ux-pro-max/data/google-font-licenses.json +20185 -0
- package/skills/frontend/design/ui-ux-pro-max/data/google-fonts.csv +1934 -1923
- package/skills/frontend/design/ui-ux-pro-max/data/icons.csv +106 -106
- package/skills/frontend/design/ui-ux-pro-max/data/landing.csv +35 -35
- package/skills/frontend/design/ui-ux-pro-max/data/motion.csv +18 -0
- package/skills/frontend/design/ui-ux-pro-max/data/phosphor-icons-upstream.json +32582 -0
- package/skills/frontend/design/ui-ux-pro-max/data/products.csv +192 -161
- package/skills/frontend/design/ui-ux-pro-max/data/react-performance.csv +37 -37
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/angular.csv +51 -51
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/astro.csv +54 -54
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/avalonia.csv +57 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/flutter.csv +53 -53
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/html-tailwind.csv +60 -56
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/javafx.csv +76 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -53
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/laravel.csv +51 -51
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/nextjs.csv +62 -53
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/nuxt-ui.csv +77 -51
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/nuxtjs.csv +68 -59
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/react-native.csv +52 -52
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/react.csv +67 -54
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/shadcn.csv +69 -61
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/svelte.csv +56 -54
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/swiftui.csv +51 -51
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/threejs.csv +54 -54
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/uno.csv +60 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/uwp.csv +56 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/vue.csv +50 -50
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/winui.csv +60 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/wpf.csv +57 -0
- package/skills/frontend/design/ui-ux-pro-max/data/styles.csv +89 -85
- package/skills/frontend/design/ui-ux-pro-max/data/typography.csv +74 -73
- package/skills/frontend/design/ui-ux-pro-max/data/ui-reasoning.csv +193 -162
- package/skills/frontend/design/ui-ux-pro-max/data/ux-guidelines.csv +30 -10
- package/skills/frontend/design/ui-ux-pro-max/references/pro-rules.md +117 -0
- package/skills/frontend/design/ui-ux-pro-max/references/quick-reference.md +256 -0
- package/skills/frontend/design/ui-ux-pro-max/scripts/core.py +800 -69
- package/skills/frontend/design/ui-ux-pro-max/scripts/design_system.py +700 -180
- package/skills/frontend/design/ui-ux-pro-max/scripts/reasoning_contract.py +123 -0
- package/skills/frontend/design/ui-ux-pro-max/scripts/search.py +105 -42
- package/skills/frontend/design/ui-ux-pro-max/scripts/validate_data.py +1095 -0
- package/skills/frontend/react-native/react-native-unistyles-v3/NOTICE.md +1 -1
- package/skills/frontend/react-native/react-native-unistyles-v3/SKILL.md +33 -24
- package/skills/frontend/react-native/react-native-unistyles-v3/references/api-reference.md +135 -78
- package/skills/frontend/react-native/react-native-unistyles-v3/references/common-issues.md +48 -31
- package/skills/frontend/react-native/react-native-unistyles-v3/references/setup-guide.md +76 -34
- package/skills/frontend/react-native/react-native-unistyles-v3/references/styling-patterns.md +145 -52
- package/skills/frontend/react-native/react-native-unistyles-v3/references/third-party-integration.md +76 -27
- package/skills/media/brag-slim/NOTICE.md +3 -3
- package/skills/media/brag-slim/SKILL.md +4 -0
- package/tools.lock.json +20 -20
- package/skills/frontend/design/revenue-centric-design/assets/2018693884449009956__1.jpg +0 -0
- package/skills/frontend/design/ui-ux-pro-max/data/_sync_all.py +0 -414
- package/skills/frontend/design/ui-ux-pro-max/data/design.csv +0 -1776
- 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,
|
|
10
|
-
Stacks: react, nextjs, vue, svelte, astro, swiftui, react-native, flutter, nuxtjs, nuxt-ui,
|
|
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
|
|
14
|
-
--
|
|
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
|
|
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(
|
|
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(
|
|
41
|
-
|
|
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) >
|
|
49
|
-
value_str = value_str[:
|
|
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,
|
|
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
|
|
69
|
-
parser.add_argument("--page", type=str, default=None, help="Create page-specific override file in design-system
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
print(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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))
|