wizz-method 2.21.0 → 2.22.0
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/THIRD-PARTY-NOTICES.md +18 -0
- package/package.json +4 -2
- package/skills-registry.yaml +41 -0
- package/src/bmm-skills/1-analysis/wizz-set-feature/SKILL.md +1 -1
- package/src/bmm-skills/4-implementation/wizz-code-review/SKILL.md +1 -1
- package/src/bmm-skills/4-implementation/wizz-create-story/SKILL.md +1 -1
- package/src/bmm-skills/4-implementation/wizz-dev-story/SKILL.md +8 -1
- package/src/bmm-skills/4-implementation/wizz-quick-dev/SKILL.md +2 -2
- package/src/bmm-skills/4-implementation/wizz-quick-dev/step-03-implement.md +2 -0
- package/src/bmm-skills/4-implementation/wizz-sprint-status/SKILL.md +1 -1
- package/src/core-skills/wizz-party-mode/customize.toml +3 -3
- package/src/modules/lowticket/skills/wizz-lowticket-trafego/references/reguas.md +2 -0
- package/src/modules/wizz/_shared/cerebro.md +1 -1
- package/src/modules/wizz/_shared/organizacao.md +2 -2
- package/src/modules/wizz/agents/wizz-copy/SKILL.md +1 -0
- package/src/modules/wizz/agents/wizz-copy/customize.toml +5 -0
- package/src/modules/wizz/agents/wizz-copy/knowledge/playbook.md +2 -1
- package/src/modules/wizz/agents/wizz-social/knowledge/blueprint-roteiro-viral.md +14 -0
- package/src/modules/wizz/agents/wizz-social/knowledge/legenda-instagram.md +12 -0
- package/src/skills-lib/wizz-cerebro/SKILL.md +18 -5
- package/src/skills-lib/wizz-design-needs/SKILL.md +7 -0
- package/src/skills-lib/wizz-design-needs/references/design-state.md +34 -2
- package/src/skills-lib/wizz-design-needs/references/gap-analysis.md +1 -1
- package/src/skills-lib/wizz-design-needs/scripts/design_state.py +305 -0
- package/src/skills-lib/wizz-design-needs/scripts/tests/test_design_state.py +143 -0
- package/src/skills-lib/wizz-impeccable/references/design-rules.md +18 -0
- package/src/skills-lib/wizz-motion-3d-director/references/motion-paths.md +2 -0
- package/src/skills-lib/wizz-paid-ads/SKILL.md +2 -1
- package/src/skills-lib/wizz-premium-landing-ui-researcher/SKILL.md +6 -2
- package/src/skills-lib/wizz-premium-landing-ui-researcher/references/audit-protocol.md +7 -34
- package/src/skills-lib/wizz-premium-landing-ui-researcher/references/component-sources.md +2 -0
- package/src/skills-lib/wizz-premium-landing-ui-researcher/references/design-sources.yaml +252 -0
- package/src/skills-lib/wizz-premium-landing-ui-researcher/references/mandatory-process.md +1 -1
- package/src/skills-lib/wizz-premium-landing-ui-researcher/references/mining-rubric.md +123 -0
- package/src/skills-lib/wizz-premium-landing-ui-researcher/references/source-first-protocol.md +10 -4
- package/src/skills-lib/wizz-premium-landing-ui-researcher/references/web-access-and-evidence.md +1 -1
- package/src/skills-lib/wizz-premium-landing-ui-researcher/scripts/design_sources.py +221 -0
- package/src/skills-lib/wizz-premium-landing-ui-researcher/scripts/tests/test_design_sources.py +130 -0
- package/src/skills-lib/wizz-router/references/routing-table-flat.md +2 -0
- package/src/skills-lib/wizz-taste-skill/references/anti-slop-tells.md +8 -0
- package/src/skills-lib/wizz-ui-component-curator/SKILL.md +8 -7
- package/src/skills-lib/wizz-video-effects/LICENSE-motionmaxxing.txt +202 -0
- package/src/skills-lib/wizz-video-effects/SKILL.md +5 -2
- package/src/skills-lib/wizz-video-effects/assets/chrome/collect_layout.js +113 -0
- package/src/skills-lib/wizz-video-effects/assets/effects.config.template.json +35 -0
- package/src/skills-lib/wizz-video-effects/references/data-contract.md +30 -1
- package/src/skills-lib/wizz-video-effects/references/gates.md +3 -1
- package/src/skills-lib/wizz-video-effects/scripts/check_chrome.py +376 -0
- package/src/skills-lib/wizz-video-effects/scripts/check_dead_frames.py +193 -0
- package/src/skills-lib/wizz-video-effects/scripts/config.py +13 -0
- package/src/skills-lib/wizz-video-effects/scripts/test_chrome.py +181 -0
- package/src/skills-lib/wizz-video-effects/scripts/test_dead_frames.py +171 -0
- package/src/skills-lib/wizz-video-styles/SKILL.md +6 -2
- package/src/skills-lib/wizz-video-styles/references/motion-laws.md +62 -0
- package/src/skills-lib/wizz-video-styles/references/styles/desafio-numero.md +1 -0
- package/src/skills-lib/wizz-video-styles/scripts/blind_review.py +159 -0
- package/src/skills-lib/wizz-video-styles/scripts/taste.mjs +110 -0
- package/src/skills-lib/wizz-video-styles/scripts/test_blind_review.py +82 -0
- package/src/skills-lib/wizz-vsl/LICENSE +49 -0
- package/src/skills-lib/wizz-vsl/SKILL.md +122 -0
- package/src/skills-lib/wizz-vsl/references/assembly-qa.md +123 -0
- package/src/skills-lib/wizz-vsl/references/blocks-and-leads.md +149 -0
- package/src/skills-lib/wizz-vsl/references/diagnosis.md +95 -0
- package/src/skills-lib/wizz-vsl/references/intake.md +200 -0
- package/src/skills-lib/wizz-vsl/references/mechanisms.md +138 -0
- package/src/skills-lib/wizz-vsl/references/niches.md +40 -0
- package/src/skills-lib/wizz-vsl/references/offer.md +91 -0
- package/src/skills-lib/wizz-vsl/references/production.md +75 -0
- package/tools/hooks/README.md +10 -9
- package/tools/hooks/wizz-arrumar.js +1 -0
- package/tools/hooks/wizz-artifact-guard.js +31 -5
- package/tools/hooks/wizz-cerebro-lib.js +36 -13
- package/tools/hooks/wizz-feature-lib.js +4 -1
- package/tools/hooks/wizz-feature.js +66 -76
- package/tools/hooks/wizz-sprint-archive-lib.js +311 -0
- package/tools/installer/core/hooks-settings.js +1 -0
- package/tools/installer/core/installer.js +6 -0
- package/tools/installer/modules/core-seed.js +72 -0
- package/tools/installer/modules/mcp-config.js +3 -0
- package/tools/installer/ui.js +16 -26
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# Design sources, as data. Read by scripts/design_sources.py (list by need tag,
|
|
2
|
+
# cache freshness, refresh) so the miner does not load the whole prose catalogue
|
|
3
|
+
# to pick one source. The prose in component-sources.md stays as the reference
|
|
4
|
+
# for policy and nuance (Clone Policy, Paid Source Policy, visual inspiration
|
|
5
|
+
# rules); this file is the one to query.
|
|
6
|
+
#
|
|
7
|
+
# Fields:
|
|
8
|
+
# kind code | registry | engine | visual | taste | extractor
|
|
9
|
+
# (code/registry = evidence bar of code; visual = pattern only, rebuilt)
|
|
10
|
+
# license what was read, with the date of the reading in `checked`; null = none
|
|
11
|
+
# access free | free+paid | paid | login
|
|
12
|
+
# need_tags what the source answers; matched by `design_sources.py list --need`
|
|
13
|
+
# registry shadcn namespace and item URL template, when it has one
|
|
14
|
+
# cache folder name under ~/.claude/design-sources/, when there is a local clone
|
|
15
|
+
# study_only true when the code must never be copied (no license)
|
|
16
|
+
version: 1
|
|
17
|
+
cache_root: "~/.claude/design-sources"
|
|
18
|
+
max_cache_age_days: 30
|
|
19
|
+
registry_index: "https://ui.shadcn.com/r/registries.json"
|
|
20
|
+
|
|
21
|
+
sources:
|
|
22
|
+
- id: react-bits
|
|
23
|
+
kind: registry
|
|
24
|
+
url: "https://github.com/DavidHDev/react-bits.git"
|
|
25
|
+
registry: { namespace: "@react-bits" }
|
|
26
|
+
license: "MIT + Commons Clause"
|
|
27
|
+
checked: 2026-09-06
|
|
28
|
+
access: free+paid
|
|
29
|
+
cache: react-bits
|
|
30
|
+
need_tags: [text-animation, background, scroll, hover, card, micro-interaction, loader, hero, particles, cursor]
|
|
31
|
+
note: "React Bits Pro is never a mandatory dependency."
|
|
32
|
+
|
|
33
|
+
- id: cult-ui
|
|
34
|
+
kind: registry
|
|
35
|
+
url: "https://github.com/nolly-studio/cult-ui"
|
|
36
|
+
docs: "https://www.cult-ui.com/docs"
|
|
37
|
+
registry: { namespace: "@cult-ui" }
|
|
38
|
+
license: null
|
|
39
|
+
checked: null
|
|
40
|
+
access: free+paid
|
|
41
|
+
cache: cult-ui
|
|
42
|
+
need_tags: [marketing-section, hero, button, card, landing-section]
|
|
43
|
+
note: "Read the license of the item; public/open resources only unless paid access is confirmed."
|
|
44
|
+
|
|
45
|
+
- id: ali-imam
|
|
46
|
+
kind: visual
|
|
47
|
+
url: "https://github.com/aliimam-in/aliimam.git"
|
|
48
|
+
license: null
|
|
49
|
+
checked: 2026-10-15
|
|
50
|
+
access: free
|
|
51
|
+
cache: aliimam
|
|
52
|
+
study_only: true
|
|
53
|
+
need_tags: [shader, liquid, ripple, border-glow, bento, typewriter, canvas, experimental]
|
|
54
|
+
note: "No license: study the technique, never copy the code."
|
|
55
|
+
|
|
56
|
+
- id: watermelon
|
|
57
|
+
kind: registry
|
|
58
|
+
url: "https://github.com/WatermelonCorp/watermellon-registry.git"
|
|
59
|
+
registry: { namespace: "@watermelon", template: "https://registry.watermelon.sh/r/{name}.json" }
|
|
60
|
+
license: null
|
|
61
|
+
checked: null
|
|
62
|
+
access: free
|
|
63
|
+
cache: watermelon
|
|
64
|
+
need_tags: [dashboard, saas, card, app-section, data-viz, product-ui]
|
|
65
|
+
|
|
66
|
+
- id: styleui
|
|
67
|
+
kind: registry
|
|
68
|
+
url: "https://github.com/heyfabrika/styleui.git"
|
|
69
|
+
registry: { namespace: "@styleui" }
|
|
70
|
+
license: null
|
|
71
|
+
checked: 2026-10-15
|
|
72
|
+
access: free
|
|
73
|
+
cache: styleui
|
|
74
|
+
need_tags: [layout, template, landing-section, base-page]
|
|
75
|
+
note: "Marked degraded in the shadcn index on 2026-10-15: check health before relying on it."
|
|
76
|
+
|
|
77
|
+
- id: componentry
|
|
78
|
+
kind: registry
|
|
79
|
+
url: "https://componentry.dev/"
|
|
80
|
+
registry: { namespace: "@componentry", template: "https://componentry.fun/r/{name}.json" }
|
|
81
|
+
license: null
|
|
82
|
+
checked: null
|
|
83
|
+
access: free
|
|
84
|
+
need_tags: [text-animation, background, hover, micro-interaction, animated-component]
|
|
85
|
+
|
|
86
|
+
- id: bklit-ui
|
|
87
|
+
kind: registry
|
|
88
|
+
url: "https://github.com/bklit/bklit-ui"
|
|
89
|
+
registry: { namespace: "@bklit" }
|
|
90
|
+
license: MIT
|
|
91
|
+
checked: null
|
|
92
|
+
access: free
|
|
93
|
+
need_tags: [chart, data-viz, dashboard, metrics]
|
|
94
|
+
note: "Install from the registry, do not clone."
|
|
95
|
+
|
|
96
|
+
- id: skiper-ui
|
|
97
|
+
kind: registry
|
|
98
|
+
url: null
|
|
99
|
+
registry: { namespace: "@skiper-ui" }
|
|
100
|
+
license: null
|
|
101
|
+
checked: null
|
|
102
|
+
access: free+paid
|
|
103
|
+
need_tags: [distinctive-effect, premium-section, advanced-animation]
|
|
104
|
+
note: "Must not be cloned: npx shadcn add @skiper-ui/<item>. Premium only with confirmed access."
|
|
105
|
+
|
|
106
|
+
- id: shadcn-ui
|
|
107
|
+
kind: registry
|
|
108
|
+
url: "https://ui.shadcn.com/"
|
|
109
|
+
license: MIT
|
|
110
|
+
checked: null
|
|
111
|
+
access: free
|
|
112
|
+
need_tags: [base, form, dialog, navigation, carousel, layout]
|
|
113
|
+
|
|
114
|
+
- id: embla
|
|
115
|
+
kind: code
|
|
116
|
+
url: "https://www.embla-carousel.com/"
|
|
117
|
+
license: MIT
|
|
118
|
+
checked: null
|
|
119
|
+
access: free
|
|
120
|
+
need_tags: [carousel]
|
|
121
|
+
|
|
122
|
+
- id: animmaster
|
|
123
|
+
kind: code
|
|
124
|
+
url: "https://animmasterlib.dev/"
|
|
125
|
+
license: "commercial"
|
|
126
|
+
checked: null
|
|
127
|
+
access: paid
|
|
128
|
+
need_tags: [animated-component]
|
|
129
|
+
note: "Only with authorized access; what the user already bought counts as local material."
|
|
130
|
+
|
|
131
|
+
- id: gsap
|
|
132
|
+
kind: engine
|
|
133
|
+
url: "https://github.com/greensock/GSAP.git"
|
|
134
|
+
license: "free since v3.13, all plugins"
|
|
135
|
+
checked: null
|
|
136
|
+
access: free
|
|
137
|
+
need_tags: [scroll-storytelling, scroll, timeline, text-reveal, svg-morph]
|
|
138
|
+
|
|
139
|
+
- id: animejs
|
|
140
|
+
kind: engine
|
|
141
|
+
url: "https://github.com/juliangarnier/anime.git"
|
|
142
|
+
license: MIT
|
|
143
|
+
checked: null
|
|
144
|
+
access: free
|
|
145
|
+
need_tags: [micro-interaction, stagger, svg, counter]
|
|
146
|
+
|
|
147
|
+
- id: design-motion-principles
|
|
148
|
+
kind: taste
|
|
149
|
+
url: "https://github.com/kylezantos/design-motion-principles.git"
|
|
150
|
+
license: null
|
|
151
|
+
checked: null
|
|
152
|
+
access: free
|
|
153
|
+
need_tags: [motion-principles, easing, timing]
|
|
154
|
+
|
|
155
|
+
- id: vibe-code-components
|
|
156
|
+
kind: visual
|
|
157
|
+
url: "https://vibecodecomponents.com/"
|
|
158
|
+
license: null
|
|
159
|
+
checked: null
|
|
160
|
+
access: free
|
|
161
|
+
need_tags: [visual-direction, section-idea]
|
|
162
|
+
|
|
163
|
+
- id: landing-love
|
|
164
|
+
kind: visual
|
|
165
|
+
url: "https://www.landing.love/"
|
|
166
|
+
license: null
|
|
167
|
+
checked: null
|
|
168
|
+
access: free
|
|
169
|
+
need_tags: [visual-direction, scroll, hero, landing-section]
|
|
170
|
+
|
|
171
|
+
- id: recent
|
|
172
|
+
kind: visual
|
|
173
|
+
url: "https://recent.design/"
|
|
174
|
+
license: null
|
|
175
|
+
checked: 2026-10-15
|
|
176
|
+
access: free
|
|
177
|
+
need_tags: [visual-direction, typography, editorial, art-direction]
|
|
178
|
+
|
|
179
|
+
- id: design-spells
|
|
180
|
+
kind: visual
|
|
181
|
+
url: "https://www.designspells.com/"
|
|
182
|
+
license: null
|
|
183
|
+
checked: null
|
|
184
|
+
access: free
|
|
185
|
+
need_tags: [micro-interaction, delight, hover]
|
|
186
|
+
|
|
187
|
+
- id: spline
|
|
188
|
+
kind: visual
|
|
189
|
+
url: "https://spline.design/"
|
|
190
|
+
license: null
|
|
191
|
+
checked: null
|
|
192
|
+
access: free+paid
|
|
193
|
+
need_tags: [3d, hero]
|
|
194
|
+
|
|
195
|
+
- id: unicorn-studio
|
|
196
|
+
kind: visual
|
|
197
|
+
url: "https://www.unicorn.studio/"
|
|
198
|
+
license: null
|
|
199
|
+
checked: null
|
|
200
|
+
access: free+paid
|
|
201
|
+
need_tags: [webgl, background, shader, particles]
|
|
202
|
+
|
|
203
|
+
- id: refero
|
|
204
|
+
kind: visual
|
|
205
|
+
url: "https://refero.design/"
|
|
206
|
+
license: null
|
|
207
|
+
checked: 2026-10-15
|
|
208
|
+
access: login
|
|
209
|
+
need_tags: [ux-flow, dashboard, pricing, onboarding]
|
|
210
|
+
note: "Refero MCP is paid."
|
|
211
|
+
|
|
212
|
+
- id: refero-styles
|
|
213
|
+
kind: taste
|
|
214
|
+
url: "https://styles.refero.design/"
|
|
215
|
+
license: null
|
|
216
|
+
checked: null
|
|
217
|
+
access: free
|
|
218
|
+
need_tags: [design-md, typography, palette, spacing]
|
|
219
|
+
|
|
220
|
+
- id: awesome-design-md
|
|
221
|
+
kind: taste
|
|
222
|
+
url: "https://github.com/VoltAgent/awesome-design-md"
|
|
223
|
+
license: MIT
|
|
224
|
+
checked: 2026-10-15
|
|
225
|
+
access: free
|
|
226
|
+
need_tags: [design-md, typography, palette, spacing]
|
|
227
|
+
|
|
228
|
+
- id: mobbin
|
|
229
|
+
kind: visual
|
|
230
|
+
url: "https://mobbin.com/"
|
|
231
|
+
license: null
|
|
232
|
+
checked: 2026-10-15
|
|
233
|
+
access: login
|
|
234
|
+
need_tags: [ux-flow, onboarding, pricing, dashboard, mobile]
|
|
235
|
+
note: "Mobbin MCP is paid."
|
|
236
|
+
|
|
237
|
+
- id: screensdesign
|
|
238
|
+
kind: visual
|
|
239
|
+
url: "https://screensdesign.com/"
|
|
240
|
+
license: null
|
|
241
|
+
checked: 2026-10-15
|
|
242
|
+
access: login
|
|
243
|
+
need_tags: [mobile, onboarding, paywall, subscription]
|
|
244
|
+
|
|
245
|
+
- id: dembrandt
|
|
246
|
+
kind: extractor
|
|
247
|
+
url: "https://github.com/dembrandt/dembrandt"
|
|
248
|
+
license: MIT
|
|
249
|
+
checked: 2026-10-15
|
|
250
|
+
access: free
|
|
251
|
+
need_tags: [typography, palette, spacing, design-md]
|
|
252
|
+
note: "npx -y dembrandt@0.39.2 <url> --design-md: measures a site the user named."
|
|
@@ -8,7 +8,7 @@ Always follow this process. **Steps 6, 7, and 8 are SOURCE CHECKPOINTS and must
|
|
|
8
8
|
4. Define the visual direction.
|
|
9
9
|
5. Decide whether it needs a landing page, dashboard, 3D/WebGL, or a combination.
|
|
10
10
|
6. **CHECKPOINT: Inventory of the user's sources.** List and inspect (ls + minimal reading of READMEs/package.json) the current project and the models at the paths provided by the user; reuse the memory summary from the handoff. Identify which components/effects the user already has that can be reused before any external source.
|
|
11
|
-
7. **CHECKPOINT: Source-First Protocol (mandatory).** Run [source-first-protocol](source-first-protocol.md): search public sources, open demos and code/registry, check revision, license, and dependencies. Log evidence and failures in the research artifact;
|
|
11
|
+
7. **CHECKPOINT: Source-First Protocol (mandatory).** Run [source-first-protocol](source-first-protocol.md): search public sources, open demos and code/registry, check revision, license, and dependencies. Log evidence and failures in the research artifact; judge each verified candidate with [mining-rubric](mining-rubric.md) and show the selected one per need, with at most two runners-up and their verdicts.
|
|
12
12
|
8. **CHECKPOINT: Choose sources.** Recommend the appropriate combination. With direction and implementation already authorized, proceed; only ask if a material decision is missing.
|
|
13
13
|
9. Recommend components and animations (already curated in the previous checkpoints).
|
|
14
14
|
10. Write copy and structure.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Mining rubric: entry conditions, score, verdict, stop and adaptation
|
|
2
|
+
|
|
3
|
+
Shared by `wizz-premium-landing-ui-researcher` and `wizz-ui-component-curator`. Read it before judging the first candidate of a need. It turns "this looks good" into a verdict that the next session, the implementer and QA can read back from `design-state.yaml`.
|
|
4
|
+
|
|
5
|
+
The discipline is ported from the offer miner (`wizz-lowticket-minerador`): conditions checked before any score, a 0-10 score with a cut at 6, an enumerated verdict, a stop rule per need, observation kept apart from inference, and a fixed read order that rebuilds instead of copying.
|
|
6
|
+
|
|
7
|
+
Order of work for each candidate, always the same:
|
|
8
|
+
|
|
9
|
+
1. **Evidence gate** ([web-access-and-evidence](web-access-and-evidence.md)). Missing any of the five fields = `evidence: unverified`. Unverified is not scored and never selected; it can be verified later.
|
|
10
|
+
2. **Dedup.** Its `pattern_key` is already `selected` in the project → `status: rejected`, `dup_of: <that discovery>`. Not scored.
|
|
11
|
+
3. **Entry conditions.** One unmet = `verdict: DESCARTAR` with the code in `disqualifiers`. Not scored.
|
|
12
|
+
4. **Score** the five criteria, sum, read the verdict from the band.
|
|
13
|
+
5. **Select or keep searching**, by the selection and stop rules below.
|
|
14
|
+
6. **Adapt** the selected one with the five-step protocol.
|
|
15
|
+
|
|
16
|
+
## Entry conditions
|
|
17
|
+
|
|
18
|
+
Each one is a condition of use, not a ban: the line says what makes the candidate eligible. A candidate that does not meet a condition is recorded with the code and the reason, so the next round does not open it again.
|
|
19
|
+
|
|
20
|
+
| Code | The candidate is eligible when | Unmet means |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| `licenca` | a code source (`kind: code` or `registry`) has a license that allows use in this project | no license or an incompatible one. Reclassify it as `kind: visual` and it is scored as a pattern to rebuild, never as code to copy |
|
|
23
|
+
| `acesso_pago` | paid access is already authorized by the user | access or cost not confirmed (the user decides, it is a faixa C item) |
|
|
24
|
+
| `dependencia` | its dependencies fit the stack and the bundle budget of `design-state.stack` | it pulls a dependency outside the stack or above the budget, and the user has not approved going over |
|
|
25
|
+
| `reduced_motion` | it honours `prefers-reduced-motion`, or the adaptation plan writes that path | it ignores reduced motion and nobody wrote the alternative |
|
|
26
|
+
| `contraste` | its contrast passes AA once the project's tokens are applied | the effect itself breaks AA (text over moving image with no scrim, glow under body text) |
|
|
27
|
+
| `nivel` | the motion is allowed at the site level ([site-levels](site-levels.md)) | the level lists that motion as one to avoid |
|
|
28
|
+
| `proibido` | it does not land on a capability in the `proibidos` block | it does. A reference the user chose already moved its item out of `proibidos` (derivation rule 4.4 of `wizz-design-needs`), so it is eligible |
|
|
29
|
+
|
|
30
|
+
## Score
|
|
31
|
+
|
|
32
|
+
Five criteria, summed to 0-10. Score only what was observed in this session; a criterion that rests on an inference is scored from what was seen and the inference is written in `inferred`.
|
|
33
|
+
|
|
34
|
+
| Criterion | Range | Top of the range | Bottom of the range |
|
|
35
|
+
|---|---|---|---|
|
|
36
|
+
| `aderencia` | 0-3 | answers the need's `question` and fits the style DNA and brief signals as is | adjacent to the need, does not answer it |
|
|
37
|
+
| `execucao` | 0-2 | polished in the live demo: timing, states, resize, mobile | broken or janky. Inspected static only: at most 1 |
|
|
38
|
+
| `custo_adaptacao` | 0-2, inverted | token-level adaptation (colour, type, spacing) | most of it has to be rewritten |
|
|
39
|
+
| `custo_performance` | 0-2, inverted | no new dependency, no layout thrash | heavy runtime (WebGL, video, large library) for what it adds |
|
|
40
|
+
| `originalidade` | 0-1 | not the default look of the stack or the catalogue | reads as template |
|
|
41
|
+
|
|
42
|
+
Middle values: `aderencia` 2 = answers the question with visible restyling, 1 = answers part of it; `execucao` 1 = works with rough edges; `custo_adaptacao` 1 = markup or API changes; `custo_performance` 1 = a new dependency inside the budget, or a measurable runtime cost.
|
|
43
|
+
|
|
44
|
+
## Verdict
|
|
45
|
+
|
|
46
|
+
| Verdict | Score | Use |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| `ASSINATURA` | 9-10 | the piece that defines the surface. At most one selected per surface |
|
|
49
|
+
| `FORTE` | 7-8 | enters |
|
|
50
|
+
| `UTILITARIO` | 6 | enters only when the need has nothing better |
|
|
51
|
+
| `DESCARTAR` | 0-5, or an unmet entry condition | does not enter; the reason stays recorded |
|
|
52
|
+
|
|
53
|
+
The cut is 6. A need's `floor` can raise it for that need, never lower it: a 7 on a need with `floor: 8` stays `FORTE` and is not selected for that need.
|
|
54
|
+
|
|
55
|
+
The signature cap is what stops a page from becoming a collage of impressive effects. When a second candidate on the same surface scores 9 or 10, it is recorded as `FORTE` with `reason: "teto de assinatura"`.
|
|
56
|
+
|
|
57
|
+
## Selection
|
|
58
|
+
|
|
59
|
+
Per need, one discovery is selected: the highest-scoring verified, eligible candidate at or above the need's floor.
|
|
60
|
+
|
|
61
|
+
- **Faixa A, silent:** the first leads the second by 2 points or more and the need is not `signature: true`. Select and move on.
|
|
62
|
+
- **Faixa B, announced:** a tie within 1 point, or the signature piece of a surface. Select, then say which one won, the runner-up and why. The swap costs one edit to the state file.
|
|
63
|
+
- `UTILITARIO` is selected only when no `FORTE` or `ASSINATURA` is eligible for that need.
|
|
64
|
+
- Everything else on the need stays `proposed` or goes to `rejected` with a `reason`.
|
|
65
|
+
|
|
66
|
+
## Stop conditions
|
|
67
|
+
|
|
68
|
+
The miner stops on the first one that applies. Each stop writes the need's status and reason to the state file.
|
|
69
|
+
|
|
70
|
+
| Scope | Stops when | Need status |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| Need, early | an eligible candidate scores 9 or more | `selected` |
|
|
73
|
+
| Need, budget | the sources opened reach `budget.fontes` | `selected` if anything eligible, else `unmet` |
|
|
74
|
+
| Need, diminishing returns | 2 sources in a row with nothing eligible at or above the floor | `unmet`, with what was tried. A result, not a failure |
|
|
75
|
+
| Dedup | the need's question is already answered by a selected discovery on another surface | `dropped`, `reason: "resolvido por <need-id>"` |
|
|
76
|
+
| Surface | the selected behaviour discoveries reach the level's behaviour ceiling (derivation rule 3 of `wizz-design-needs`) | the rest `deferred` |
|
|
77
|
+
| Global | every need is `selected`, `unmet`, `dropped` or `deferred` | mining is over. This is "I have enough information" |
|
|
78
|
+
|
|
79
|
+
Count the spend on the need itself (`spent.fontes`, `spent.secas`) so a reopened need starts from what was already paid.
|
|
80
|
+
|
|
81
|
+
## Observation and inference
|
|
82
|
+
|
|
83
|
+
Every discovery keeps two lists. `observed`: what was actually seen in this session (a duration in the code, an import, the demo jank at 375 px). `inferred`: the reading of it ("probably uses GSAP ScrollTrigger"). A score rests on `observed`. An inference written as an observation is the failure mode this split exists to catch.
|
|
84
|
+
|
|
85
|
+
## Adaptation protocol
|
|
86
|
+
|
|
87
|
+
Fixed read order, the design twin of the offer miner's "Demanda → Hook → Promessa…":
|
|
88
|
+
|
|
89
|
+
**Pattern → Why it works → Invariant → Variable → Reimplementation**
|
|
90
|
+
|
|
91
|
+
- **Pattern** (`padrao`): what happens mechanically, in one sentence, with no brand name.
|
|
92
|
+
- **Why it works** (`por_que`): the perceptual or conversion reason. If it cannot be written, the discovery was not understood: it goes back to evaluation and is not selected.
|
|
93
|
+
- **Invariant** (`invariante`): what cannot change without breaking the effect.
|
|
94
|
+
- **Variable** (`variavel`): what is free (easing, duration, direction, colour, density).
|
|
95
|
+
- **Reimplementation** (`reimplementacao`): the plan in the project's tokens and vocabulary.
|
|
96
|
+
|
|
97
|
+
Closing rule, in the same spirit as the offer miner's: **a visual reference gives structure and principle, never CSS.** A code source with a license can be copied with attribution; a visual source is rebuilt.
|
|
98
|
+
|
|
99
|
+
## Machine-readable block
|
|
100
|
+
|
|
101
|
+
The eval (`evals/design-mining/`) and the state checker (`wizz-design-needs/scripts/design_state.py`) read the numbers from this block. Change a band here and both follow; nothing else holds a copy.
|
|
102
|
+
|
|
103
|
+
```yaml
|
|
104
|
+
# mining-rubric:v1
|
|
105
|
+
cut: 6
|
|
106
|
+
criteria:
|
|
107
|
+
aderencia: [0, 3]
|
|
108
|
+
execucao: [0, 2]
|
|
109
|
+
custo_adaptacao: [0, 2]
|
|
110
|
+
custo_performance: [0, 2]
|
|
111
|
+
originalidade: [0, 1]
|
|
112
|
+
verdicts:
|
|
113
|
+
- { id: ASSINATURA, min: 9, max: 10 }
|
|
114
|
+
- { id: FORTE, min: 7, max: 8 }
|
|
115
|
+
- { id: UTILITARIO, min: 6, max: 6 }
|
|
116
|
+
- { id: DESCARTAR, min: 0, max: 5 }
|
|
117
|
+
disqualifiers: [licenca, acesso_pago, dependencia, reduced_motion, contraste, nivel, proibido]
|
|
118
|
+
signature_per_surface: 1
|
|
119
|
+
signature_cap_reason: "teto de assinatura"
|
|
120
|
+
faixa_a_lead: 2
|
|
121
|
+
early_stop_score: 9
|
|
122
|
+
dry_sources_to_unmet: 2
|
|
123
|
+
```
|
package/src/skills-lib/wizz-premium-landing-ui-researcher/references/source-first-protocol.md
CHANGED
|
@@ -12,7 +12,7 @@ Log the real paths of the resources found. If there are no local models, proceed
|
|
|
12
12
|
|
|
13
13
|
## Phase 2: Search and inspect public sources
|
|
14
14
|
|
|
15
|
-
Choose sources
|
|
15
|
+
Choose sources by querying the catalogue as data instead of reading the whole prose: `uv run --no-cache scripts/design_sources.py list --need <tag>` (run from this skill's folder; tags such as `hover`, `scroll`, `card`, `dashboard`, `chart`, `shader`, `typography`) returns the matching sources from [design-sources.yaml](design-sources.yaml) with kind, access, license and `study_only`. Without `uv`, read the YAML directly. [component-sources](component-sources.md) keeps the policy and nuance (clone, paid, visual inspiration) and [source-links](source-links.md) the links; open them when a source needs that detail. The quick map, for orientation:
|
|
16
16
|
|
|
17
17
|
| Need | Initial sources |
|
|
18
18
|
|---|---|
|
|
@@ -50,7 +50,7 @@ Most sources are shadcn registries. Read them live instead of cloning:
|
|
|
50
50
|
2. **Read the item.** Replace `{name}` in the URL template and fetch the JSON: it carries the files, dependencies and registry dependencies, which is the evidence the gate asks for. When the shadcn MCP is configured (`npx shadcn@latest mcp init`), it does the same lookup for you.
|
|
51
51
|
3. **Repos outside the index** (and offline work) use the local cache.
|
|
52
52
|
|
|
53
|
-
An existing design cache (for example `~/.claude/design-sources/`) can be inspected. Don't treat it as up to date just because it exists:
|
|
53
|
+
An existing design cache (for example `~/.claude/design-sources/`) can be inspected. Don't treat it as up to date just because it exists. One command answers it: `uv run --no-cache scripts/design_sources.py freshness` gives each cached clone's revision, last sync and `stale` past 30 days (`--remote` also compares with origin). A stale cache is still a source for a pattern, never for an API. `design_sources.py refresh` fast-forwards only the clones with no local changes and reports the rest; run it when the user agrees to update. The rules below still hold:
|
|
54
54
|
|
|
55
55
|
- Check origin, branch, revision, and local changes before updating.
|
|
56
56
|
- Check the remote revision when there's network access; the folder's modification date is not proof of being up to date.
|
|
@@ -70,10 +70,16 @@ Log in the existing design artifact (or create `design-research.md` in the proje
|
|
|
70
70
|
|
|
71
71
|
Also include searches with no results and unavailable sources. Never fill in component names, paths, license, or test results by assumption. A row missing any of the five fields in [web-access-and-evidence](web-access-and-evidence.md) is UNVERIFIED and cannot be the recommendation.
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
Judge every verified candidate with [mining-rubric](mining-rubric.md): dedup, entry conditions, the 0-10 score with the cut at 6, the verdict, and the selection rule. With a `design-state.yaml`, each candidate is written as a discovery with its need id, scores, verdict and status; the table above is the human-readable view of the same rows.
|
|
74
|
+
|
|
75
|
+
Show the selected candidate per need and at most two runners-up, each with its verdict and score. If the user has already authorized the implementation and defined the direction, the selection rule decides and you proceed. Only ask when a material decision about direction, paid access, or scope change is missing.
|
|
74
76
|
|
|
75
77
|
## Phase 5: Adapt and verify
|
|
76
78
|
|
|
77
|
-
|
|
79
|
+
Write the adaptation in the five-step order of [mining-rubric](mining-rubric.md) (pattern, why it works, invariant, variable, reimplementation) before touching code. Then adapt tokens, typography, spacing, content, and motion to the project. Verify responsiveness, keyboard navigation, focus, contrast, reduced-motion, and rendering cost as appropriate for the component. Link the result back to the logged sources.
|
|
78
80
|
|
|
79
81
|
Building from scratch is acceptable for trivial primitives or when the documented research finds no compatible option and the implementation is authorized. Explain the reason. Don't claim something doesn't exist in any catalog; only report the sources actually researched.
|
|
82
|
+
|
|
83
|
+
## Phase 6: Stop
|
|
84
|
+
|
|
85
|
+
Mining stops by rule, not by patience. Per need: an eligible candidate at 9 or more, the source budget spent, or 2 sources in a row with nothing eligible (`unmet`, with what was tried). Per surface: the level's behaviour ceiling. Globally: every need in a terminal status. The table and the status each stop writes are in [mining-rubric](mining-rubric.md). Report which stop closed each need.
|
package/src/skills-lib/wizz-premium-landing-ui-researcher/references/web-access-and-evidence.md
CHANGED
|
@@ -36,6 +36,6 @@ Every candidate needs all five, collected in this session:
|
|
|
36
36
|
| Dependencies | Read from the actual imports or registry JSON | Guessed from the component's name |
|
|
37
37
|
| Source read | The code file was opened and its imports checked | The demo alone |
|
|
38
38
|
|
|
39
|
-
A candidate missing any field is **UNVERIFIED**. UNVERIFIED items go in a separate section of the report, with what is missing and why. They are never recommended and never
|
|
39
|
+
A candidate missing any field is **UNVERIFIED**. UNVERIFIED items go in a separate section of the report, with what is missing and why. They are never recommended and never scored or selected by the [mining-rubric](mining-rubric.md), and the implementation plan never depends on them. If every candidate for a need is UNVERIFIED, the need is reported as `unmet`, not filled.
|
|
40
40
|
|
|
41
41
|
Before closing, check the delivery against this gate once: every recommended item has its five fields in the research log (`design-research.md` or the project's design artifact), and the access line from Step 0 is in the report.
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# /// script
|
|
2
|
+
# requires-python = ">=3.10"
|
|
3
|
+
# dependencies = ["ruamel.yaml>=0.18"]
|
|
4
|
+
# ///
|
|
5
|
+
"""Query the design-source catalogue and keep the local cache honest.
|
|
6
|
+
|
|
7
|
+
Prints ONLY JSON to stdout. Reads ../references/design-sources.yaml.
|
|
8
|
+
|
|
9
|
+
Subcommands:
|
|
10
|
+
list Sources that answer a need tag (--need, repeatable), optionally
|
|
11
|
+
filtered by --kind. Paid sources are listed with their access so
|
|
12
|
+
the miner can apply the paid-source condition; study_only sources
|
|
13
|
+
say so.
|
|
14
|
+
freshness For every source with a `cache` folder: revision, last commit,
|
|
15
|
+
last sync with the remote (FETCH_HEAD, else the clone date), age
|
|
16
|
+
of that sync in days, local changes, and `stale` when the age
|
|
17
|
+
passes max_cache_age_days. --remote also compares HEAD with
|
|
18
|
+
origin (network). Exit 0 always; the JSON carries the verdict.
|
|
19
|
+
refresh Fast-forward the cached clones that have no local changes
|
|
20
|
+
(`git fetch` + `git merge --ff-only`). A clone with local changes
|
|
21
|
+
is skipped and reported, never reset. --id limits it to one source.
|
|
22
|
+
|
|
23
|
+
Run with `uv run --no-cache scripts/design_sources.py <subcommand>`: uv
|
|
24
|
+
provisions ruamel.yaml from the header above.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
import argparse
|
|
28
|
+
import datetime as dt
|
|
29
|
+
import json
|
|
30
|
+
import os
|
|
31
|
+
import subprocess
|
|
32
|
+
import sys
|
|
33
|
+
from pathlib import Path
|
|
34
|
+
|
|
35
|
+
HERE = Path(__file__).resolve().parent
|
|
36
|
+
CATALOGUE = HERE.parent / "references" / "design-sources.yaml"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def emit(payload, code=0):
|
|
40
|
+
print(json.dumps(payload, ensure_ascii=False, indent=2, default=str))
|
|
41
|
+
sys.exit(code)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def load_catalogue(path):
|
|
45
|
+
from ruamel.yaml import YAML
|
|
46
|
+
|
|
47
|
+
yaml = YAML(typ="safe")
|
|
48
|
+
with open(path, encoding="utf-8") as handle:
|
|
49
|
+
data = yaml.load(handle)
|
|
50
|
+
if not isinstance(data, dict) or not isinstance(data.get("sources"), list):
|
|
51
|
+
raise ValueError(f"{path}: expected a mapping with a `sources` list")
|
|
52
|
+
return data
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def cmd_list(data, needs, kind):
|
|
56
|
+
wanted = {tag.lower() for tag in needs}
|
|
57
|
+
rows = []
|
|
58
|
+
for source in data["sources"]:
|
|
59
|
+
tags = {str(tag).lower() for tag in source.get("need_tags") or []}
|
|
60
|
+
if wanted and not wanted & tags:
|
|
61
|
+
continue
|
|
62
|
+
if kind and source.get("kind") != kind:
|
|
63
|
+
continue
|
|
64
|
+
rows.append(
|
|
65
|
+
{
|
|
66
|
+
"id": source["id"],
|
|
67
|
+
"kind": source.get("kind"),
|
|
68
|
+
"access": source.get("access"),
|
|
69
|
+
"license": source.get("license"),
|
|
70
|
+
"study_only": bool(source.get("study_only")),
|
|
71
|
+
"matches": sorted(wanted & tags) if wanted else [],
|
|
72
|
+
"url": source.get("url"),
|
|
73
|
+
"registry": source.get("registry"),
|
|
74
|
+
"note": source.get("note"),
|
|
75
|
+
}
|
|
76
|
+
)
|
|
77
|
+
rows.sort(key=lambda row: (-len(row["matches"]), row["access"] != "free", row["id"]))
|
|
78
|
+
return {"need": sorted(wanted), "count": len(rows), "sources": rows}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def git(repo, *args):
|
|
82
|
+
result = subprocess.run(
|
|
83
|
+
["git", "-C", str(repo), *args], capture_output=True, text=True, timeout=120
|
|
84
|
+
)
|
|
85
|
+
if result.returncode != 0:
|
|
86
|
+
raise RuntimeError(result.stderr.strip() or f"git {' '.join(args)} failed")
|
|
87
|
+
return result.stdout.strip()
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def cache_root(data, override):
|
|
91
|
+
root = override or data.get("cache_root") or "~/.claude/design-sources"
|
|
92
|
+
return Path(os.path.expanduser(root))
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def last_sync(repo):
|
|
96
|
+
"""When the clone last talked to its remote.
|
|
97
|
+
|
|
98
|
+
FETCH_HEAD is rewritten by every fetch. A clone that was never fetched has
|
|
99
|
+
no FETCH_HEAD, so the last HEAD reflog entry (the clone itself, or the last
|
|
100
|
+
pull) is used. The .git folder's mtime is not: `git status` touches it.
|
|
101
|
+
"""
|
|
102
|
+
git_dir = repo / ".git"
|
|
103
|
+
marker = git_dir / "FETCH_HEAD"
|
|
104
|
+
if marker.exists():
|
|
105
|
+
return dt.date.fromtimestamp(marker.stat().st_mtime)
|
|
106
|
+
reflog = git_dir / "logs" / "HEAD"
|
|
107
|
+
if reflog.exists():
|
|
108
|
+
lines = [line for line in reflog.read_text(encoding="utf-8").splitlines() if line.strip()]
|
|
109
|
+
if lines:
|
|
110
|
+
identity = lines[-1].split("\t", 1)[0].split()
|
|
111
|
+
return dt.date.fromtimestamp(int(identity[-2]))
|
|
112
|
+
return None
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def remote_status(repo, revision):
|
|
116
|
+
try:
|
|
117
|
+
line = git(repo, "ls-remote", "origin", "HEAD")
|
|
118
|
+
except RuntimeError as error:
|
|
119
|
+
return {"remote": f"unreachable: {error}"}
|
|
120
|
+
remote = line.split()[0] if line else ""
|
|
121
|
+
return {"remote": "current" if remote.startswith(revision) else "behind", "remote_revision": remote[:8]}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def inspect_cache(repo, max_age, today, check_remote):
|
|
125
|
+
if not (repo / ".git").exists():
|
|
126
|
+
return {"present": repo.is_dir(), "error": None if not repo.is_dir() else "not a git clone"}
|
|
127
|
+
try:
|
|
128
|
+
revision = git(repo, "rev-parse", "--short", "HEAD")
|
|
129
|
+
committed = git(repo, "log", "-1", "--format=%cs")
|
|
130
|
+
dirty = bool(git(repo, "status", "--porcelain"))
|
|
131
|
+
except RuntimeError as error:
|
|
132
|
+
return {"present": True, "error": str(error)}
|
|
133
|
+
synced = last_sync(repo)
|
|
134
|
+
if synced is None:
|
|
135
|
+
return {"present": True, "revision": revision, "last_commit": committed, "error": "no fetch or reflog record"}
|
|
136
|
+
age = (today - synced).days
|
|
137
|
+
row = {
|
|
138
|
+
"present": True,
|
|
139
|
+
"revision": revision,
|
|
140
|
+
"last_commit": committed,
|
|
141
|
+
"last_sync": synced.isoformat(),
|
|
142
|
+
"age_days": age,
|
|
143
|
+
"local_changes": dirty,
|
|
144
|
+
"stale": age > max_age,
|
|
145
|
+
}
|
|
146
|
+
if check_remote:
|
|
147
|
+
row.update(remote_status(repo, revision))
|
|
148
|
+
return row
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def cmd_freshness(data, root, today, check_remote=False):
|
|
152
|
+
max_age = int(data.get("max_cache_age_days") or 30)
|
|
153
|
+
rows = []
|
|
154
|
+
for source in data["sources"]:
|
|
155
|
+
if not source.get("cache"):
|
|
156
|
+
continue
|
|
157
|
+
row = {"id": source["id"], "path": str(root / source["cache"])}
|
|
158
|
+
row.update(inspect_cache(root / source["cache"], max_age, today, check_remote))
|
|
159
|
+
rows.append(row)
|
|
160
|
+
stale = [row["id"] for row in rows if row.get("stale")]
|
|
161
|
+
return {"max_age_days": max_age, "today": today.isoformat(), "stale": stale, "caches": rows}
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def cmd_refresh(data, root, only_id):
|
|
165
|
+
rows = []
|
|
166
|
+
for source in data["sources"]:
|
|
167
|
+
if not source.get("cache") or (only_id and source["id"] != only_id):
|
|
168
|
+
continue
|
|
169
|
+
repo = root / source["cache"]
|
|
170
|
+
row = {"id": source["id"], "path": str(repo)}
|
|
171
|
+
if not repo.is_dir():
|
|
172
|
+
row["result"] = "absent"
|
|
173
|
+
else:
|
|
174
|
+
try:
|
|
175
|
+
if git(repo, "status", "--porcelain"):
|
|
176
|
+
row["result"] = "skipped: local changes"
|
|
177
|
+
else:
|
|
178
|
+
before = git(repo, "rev-parse", "--short", "HEAD")
|
|
179
|
+
git(repo, "fetch", "--quiet")
|
|
180
|
+
git(repo, "merge", "--ff-only", "--quiet", "@{u}")
|
|
181
|
+
after = git(repo, "rev-parse", "--short", "HEAD")
|
|
182
|
+
row["result"] = "updated" if after != before else "already current"
|
|
183
|
+
row["revision"] = after
|
|
184
|
+
except RuntimeError as error:
|
|
185
|
+
row["result"] = f"error: {error}"
|
|
186
|
+
rows.append(row)
|
|
187
|
+
return {"caches": rows}
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def main(argv=None):
|
|
191
|
+
parser = argparse.ArgumentParser(prog="design_sources.py")
|
|
192
|
+
parser.add_argument("--catalogue", default=str(CATALOGUE))
|
|
193
|
+
parser.add_argument("--cache-root", default=None)
|
|
194
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
195
|
+
listing = sub.add_parser("list")
|
|
196
|
+
listing.add_argument("--need", action="append", default=[])
|
|
197
|
+
listing.add_argument("--kind", default=None)
|
|
198
|
+
fresh = sub.add_parser("freshness")
|
|
199
|
+
fresh.add_argument("--today", default=None, help="YYYY-MM-DD, for tests")
|
|
200
|
+
fresh.add_argument("--remote", action="store_true", help="compare HEAD with origin (network)")
|
|
201
|
+
refresh = sub.add_parser("refresh")
|
|
202
|
+
refresh.add_argument("--id", default=None)
|
|
203
|
+
try:
|
|
204
|
+
args = parser.parse_args(argv)
|
|
205
|
+
except SystemExit as error:
|
|
206
|
+
emit({"error": "invalid arguments"}, int(error.code or 2))
|
|
207
|
+
try:
|
|
208
|
+
data = load_catalogue(args.catalogue)
|
|
209
|
+
except (OSError, ValueError, ImportError) as error:
|
|
210
|
+
emit({"error": str(error)}, 1)
|
|
211
|
+
root = cache_root(data, args.cache_root)
|
|
212
|
+
if args.command == "list":
|
|
213
|
+
emit(cmd_list(data, args.need, args.kind))
|
|
214
|
+
if args.command == "freshness":
|
|
215
|
+
today = dt.date.fromisoformat(args.today) if args.today else dt.date.today()
|
|
216
|
+
emit(cmd_freshness(data, root, today, args.remote))
|
|
217
|
+
emit(cmd_refresh(data, root, args.id))
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
if __name__ == "__main__":
|
|
221
|
+
main()
|