clamper-ai 1.3.0 → 1.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clamper-ai",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Transform your OpenClaw agent into a production-ready AI assistant with memory, skills, and a dashboard",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,307 @@
1
+ ---
2
+ name: Anthropic Frontend Design
3
+ description: Frontend design system and UI/UX best practices following Anthropic's design philosophy for building polished, accessible interfaces
4
+ author: clamper
5
+ version: 1.0.0
6
+ tier: pro
7
+ category: Developer
8
+ tags: [frontend, design, ui, ux, css, react, tailwind, accessibility, design-system]
9
+ triggers: [frontend design, ui design, design system, build ui, make it look good, anthropic style, modern design]
10
+ api_auth: none
11
+ ---
12
+
13
+ # Anthropic Frontend Design
14
+
15
+ A comprehensive frontend design skill that guides building polished, modern, and accessible user interfaces. Follows Anthropic's design philosophy: clean, minimal, functional, and human-centered. No API required — this is a design system and code generation skill.
16
+
17
+ ## Design Principles
18
+
19
+ 1. **Clarity over cleverness** — Every element should have a clear purpose
20
+ 2. **Generous whitespace** — Let content breathe with ample padding and margins
21
+ 3. **Subtle depth** — Use soft shadows and borders instead of harsh contrasts
22
+ 4. **Consistent rhythm** — Maintain a spacing scale and type hierarchy
23
+ 5. **Accessible by default** — WCAG 2.1 AA minimum, semantic HTML, keyboard navigation
24
+ 6. **Progressive disclosure** — Show only what's needed, reveal complexity on demand
25
+
26
+ ## Color System
27
+
28
+ ### Light Theme
29
+ ```css
30
+ :root {
31
+ --color-bg-primary: #FFFFFF;
32
+ --color-bg-secondary: #F7F7F8;
33
+ --color-bg-tertiary: #ECECF1;
34
+ --color-bg-accent: #F0EEFF;
35
+
36
+ --color-text-primary: #1A1A2E;
37
+ --color-text-secondary: #6B6B80;
38
+ --color-text-tertiary: #9B9BAF;
39
+ --color-text-inverse: #FFFFFF;
40
+
41
+ --color-border-default: #E5E5EA;
42
+ --color-border-hover: #C8C8D0;
43
+
44
+ --color-accent-primary: #6B4EFF;
45
+ --color-accent-hover: #5A3DE8;
46
+ --color-accent-subtle: #F0EEFF;
47
+
48
+ --color-success: #00A67E;
49
+ --color-warning: #F5A623;
50
+ --color-error: #EF4444;
51
+ --color-info: #3B82F6;
52
+ }
53
+ ```
54
+
55
+ ### Dark Theme
56
+ ```css
57
+ [data-theme="dark"] {
58
+ --color-bg-primary: #1A1A2E;
59
+ --color-bg-secondary: #23233A;
60
+ --color-bg-tertiary: #2D2D48;
61
+ --color-bg-accent: #2A2545;
62
+
63
+ --color-text-primary: #ECECF1;
64
+ --color-text-secondary: #9B9BAF;
65
+ --color-text-tertiary: #6B6B80;
66
+ --color-text-inverse: #1A1A2E;
67
+
68
+ --color-border-default: #3A3A52;
69
+ --color-border-hover: #4A4A65;
70
+
71
+ --color-accent-primary: #8B7AFF;
72
+ --color-accent-hover: #9D8FFF;
73
+ --color-accent-subtle: #2A2545;
74
+ }
75
+ ```
76
+
77
+ ## Typography
78
+
79
+ ```css
80
+ :root {
81
+ --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
82
+ --font-mono: 'JetBrains Mono', 'Fira Code', 'SF Mono', monospace;
83
+
84
+ --text-xs: 0.75rem; /* 12px */
85
+ --text-sm: 0.875rem; /* 14px */
86
+ --text-base: 1rem; /* 16px */
87
+ --text-lg: 1.125rem; /* 18px */
88
+ --text-xl: 1.25rem; /* 20px */
89
+ --text-2xl: 1.5rem; /* 24px */
90
+ --text-3xl: 1.875rem; /* 30px */
91
+ --text-4xl: 2.25rem; /* 36px */
92
+
93
+ --leading-tight: 1.25;
94
+ --leading-normal: 1.5;
95
+ --leading-relaxed: 1.75;
96
+
97
+ --tracking-tight: -0.025em;
98
+ --tracking-normal: 0;
99
+ --tracking-wide: 0.025em;
100
+ }
101
+ ```
102
+
103
+ ## Spacing Scale
104
+
105
+ ```css
106
+ :root {
107
+ --space-0: 0;
108
+ --space-1: 0.25rem; /* 4px */
109
+ --space-2: 0.5rem; /* 8px */
110
+ --space-3: 0.75rem; /* 12px */
111
+ --space-4: 1rem; /* 16px */
112
+ --space-5: 1.25rem; /* 20px */
113
+ --space-6: 1.5rem; /* 24px */
114
+ --space-8: 2rem; /* 32px */
115
+ --space-10: 2.5rem; /* 40px */
116
+ --space-12: 3rem; /* 48px */
117
+ --space-16: 4rem; /* 64px */
118
+ --space-20: 5rem; /* 80px */
119
+ --space-24: 6rem; /* 96px */
120
+ }
121
+ ```
122
+
123
+ ## Component Patterns
124
+
125
+ ### Button
126
+ ```jsx
127
+ function Button({ variant = "primary", size = "md", children, ...props }) {
128
+ const base = "inline-flex items-center justify-center font-medium rounded-lg transition-all duration-150 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-accent-primary disabled:opacity-50 disabled:cursor-not-allowed";
129
+
130
+ const variants = {
131
+ primary: "bg-accent-primary text-white hover:bg-accent-hover shadow-sm",
132
+ secondary: "bg-bg-secondary text-text-primary border border-border-default hover:border-border-hover hover:bg-bg-tertiary",
133
+ ghost: "text-text-secondary hover:text-text-primary hover:bg-bg-secondary",
134
+ danger: "bg-error text-white hover:bg-red-600",
135
+ };
136
+
137
+ const sizes = {
138
+ sm: "px-3 py-1.5 text-sm",
139
+ md: "px-4 py-2 text-base",
140
+ lg: "px-6 py-3 text-lg",
141
+ };
142
+
143
+ return (
144
+ <button className={`${base} ${variants[variant]} ${sizes[size]}`} {...props}>
145
+ {children}
146
+ </button>
147
+ );
148
+ }
149
+ ```
150
+
151
+ ### Card
152
+ ```jsx
153
+ function Card({ title, description, children, className = "" }) {
154
+ return (
155
+ <div className={`bg-bg-primary border border-border-default rounded-xl p-6 shadow-sm hover:shadow-md transition-shadow ${className}`}>
156
+ {title && <h3 className="text-lg font-semibold text-text-primary mb-1">{title}</h3>}
157
+ {description && <p className="text-sm text-text-secondary mb-4">{description}</p>}
158
+ {children}
159
+ </div>
160
+ );
161
+ }
162
+ ```
163
+
164
+ ### Input
165
+ ```jsx
166
+ function Input({ label, error, helper, ...props }) {
167
+ return (
168
+ <div className="space-y-1.5">
169
+ {label && <label className="block text-sm font-medium text-text-primary">{label}</label>}
170
+ <input
171
+ className={`w-full px-3 py-2 rounded-lg border text-text-primary bg-bg-primary placeholder:text-text-tertiary transition-colors focus:outline-none focus:ring-2 focus:ring-accent-primary focus:border-transparent ${
172
+ error ? "border-error" : "border-border-default hover:border-border-hover"
173
+ }`}
174
+ {...props}
175
+ />
176
+ {error && <p className="text-sm text-error">{error}</p>}
177
+ {helper && !error && <p className="text-sm text-text-tertiary">{helper}</p>}
178
+ </div>
179
+ );
180
+ }
181
+ ```
182
+
183
+ ### Modal / Dialog
184
+ ```jsx
185
+ function Modal({ open, onClose, title, children }) {
186
+ if (!open) return null;
187
+
188
+ return (
189
+ <div className="fixed inset-0 z-50 flex items-center justify-center">
190
+ <div className="fixed inset-0 bg-black/50 backdrop-blur-sm" onClick={onClose} />
191
+ <div className="relative bg-bg-primary rounded-2xl shadow-2xl border border-border-default max-w-lg w-full mx-4 p-6 animate-in fade-in zoom-in-95 duration-200">
192
+ <div className="flex items-center justify-between mb-4">
193
+ <h2 className="text-xl font-semibold text-text-primary">{title}</h2>
194
+ <button onClick={onClose} className="p-1 rounded-lg hover:bg-bg-secondary text-text-tertiary hover:text-text-primary transition-colors">
195
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" strokeWidth="2">
196
+ <path d="M5 5l10 10M15 5L5 15" />
197
+ </svg>
198
+ </button>
199
+ </div>
200
+ {children}
201
+ </div>
202
+ </div>
203
+ );
204
+ }
205
+ ```
206
+
207
+ ### Toast / Notification
208
+ ```jsx
209
+ function Toast({ type = "info", message, onDismiss }) {
210
+ const icons = { success: "check-circle", error: "x-circle", warning: "alert-triangle", info: "info" };
211
+ const colors = { success: "text-success", error: "text-error", warning: "text-warning", info: "text-info" };
212
+
213
+ return (
214
+ <div className="flex items-center gap-3 px-4 py-3 bg-bg-primary border border-border-default rounded-xl shadow-lg animate-in slide-in-from-right duration-300">
215
+ <span className={colors[type]}>●</span>
216
+ <p className="text-sm text-text-primary flex-1">{message}</p>
217
+ <button onClick={onDismiss} className="text-text-tertiary hover:text-text-primary text-sm">Dismiss</button>
218
+ </div>
219
+ );
220
+ }
221
+ ```
222
+
223
+ ## Layout Patterns
224
+
225
+ ### Page Layout
226
+ ```jsx
227
+ function PageLayout({ children }) {
228
+ return (
229
+ <div className="min-h-screen bg-bg-secondary">
230
+ <nav className="sticky top-0 z-40 bg-bg-primary/80 backdrop-blur-lg border-b border-border-default">
231
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center justify-between">
232
+ {/* Logo + Navigation */}
233
+ </div>
234
+ </nav>
235
+ <main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
236
+ {children}
237
+ </main>
238
+ </div>
239
+ );
240
+ }
241
+ ```
242
+
243
+ ### Sidebar Layout
244
+ ```jsx
245
+ function SidebarLayout({ sidebar, children }) {
246
+ return (
247
+ <div className="flex min-h-screen">
248
+ <aside className="w-64 bg-bg-primary border-r border-border-default p-4 flex-shrink-0">
249
+ {sidebar}
250
+ </aside>
251
+ <main className="flex-1 p-8 bg-bg-secondary overflow-auto">
252
+ {children}
253
+ </main>
254
+ </div>
255
+ );
256
+ }
257
+ ```
258
+
259
+ ## Accessibility Checklist
260
+
261
+ - [ ] All interactive elements are keyboard accessible
262
+ - [ ] Focus indicators are visible (never `outline: none` without replacement)
263
+ - [ ] Color contrast ratios meet WCAG AA (4.5:1 for text, 3:1 for large text)
264
+ - [ ] Form inputs have associated labels
265
+ - [ ] Images have alt text
266
+ - [ ] ARIA landmarks used for page regions
267
+ - [ ] Modals trap focus and return it on close
268
+ - [ ] Animations respect `prefers-reduced-motion`
269
+ - [ ] Text is resizable up to 200% without loss of content
270
+
271
+ ```css
272
+ @media (prefers-reduced-motion: reduce) {
273
+ *, *::before, *::after {
274
+ animation-duration: 0.01ms !important;
275
+ transition-duration: 0.01ms !important;
276
+ }
277
+ }
278
+ ```
279
+
280
+ ## Clamper Integration
281
+
282
+ When the user asks for frontend design help:
283
+ 1. Identify the component or layout they need
284
+ 2. Generate code using the design system tokens above
285
+ 3. Default to React + Tailwind CSS unless specified otherwise
286
+ 4. Always include accessibility features
287
+ 5. Offer both light and dark theme support
288
+ 6. Provide responsive variants for mobile/tablet/desktop
289
+
290
+ ### Example Interaction
291
+ ```
292
+ User: Build me a settings page
293
+ Assistant: *generates a settings page with sidebar navigation, form sections, and save/cancel buttons following the design system*
294
+
295
+ User: Make it dark mode
296
+ Assistant: *adds data-theme="dark" support and updates color tokens*
297
+ ```
298
+
299
+ ## Setup
300
+
301
+ No installation required. This skill provides design guidance and code generation using standard web technologies (HTML, CSS, React, Tailwind CSS).
302
+
303
+ Recommended dependencies for projects:
304
+ ```bash
305
+ npm install tailwindcss @tailwindcss/forms @tailwindcss/typography
306
+ npm install @fontsource/inter
307
+ ```
@@ -0,0 +1,295 @@
1
+ ---
2
+ name: AnyList
3
+ description: Shopping list management, meal planning, and recipe organization via AnyList integration
4
+ author: clamper
5
+ version: 1.0.0
6
+ tier: pro
7
+ category: Productivity
8
+ tags: [shopping, grocery, lists, meal-planning, recipes, anylist, organization]
9
+ triggers: [shopping list, grocery list, add to list, meal plan, anylist, what do i need to buy]
10
+ api_auth: credentials
11
+ ---
12
+
13
+ # AnyList
14
+
15
+ Manage shopping lists, meal plans, and recipes through AnyList. Add items, organize lists, plan meals for the week, and share lists with family. Uses the unofficial AnyList API via reverse-engineered endpoints.
16
+
17
+ ## Dependencies
18
+
19
+ ```bash
20
+ pip install anylist
21
+ ```
22
+
23
+ The `anylist` Python package provides an unofficial API client.
24
+
25
+ ## Setup
26
+
27
+ ### Environment Variables
28
+ ```bash
29
+ export ANYLIST_EMAIL="your-email@example.com"
30
+ export ANYLIST_PASSWORD="your-password"
31
+ ```
32
+
33
+ ### Authentication
34
+ ```python
35
+ import asyncio
36
+ from anylist import AnyList
37
+
38
+ async def connect():
39
+ anylist = AnyList(email="your-email@example.com", password="your-password")
40
+ await anylist.login()
41
+ return anylist
42
+
43
+ client = asyncio.run(connect())
44
+ ```
45
+
46
+ ## Usage
47
+
48
+ ### List All Shopping Lists
49
+
50
+ ```python
51
+ import asyncio
52
+ from anylist import AnyList
53
+
54
+ async def get_lists():
55
+ al = AnyList(email=EMAIL, password=PASSWORD)
56
+ await al.login()
57
+
58
+ for lst in al.lists:
59
+ item_count = len([i for i in lst.items if not i.checked])
60
+ print(f"- {lst.name}: {item_count} items remaining")
61
+
62
+ await al.teardown()
63
+
64
+ asyncio.run(get_lists())
65
+ ```
66
+
67
+ Output:
68
+ ```
69
+ - Grocery: 12 items remaining
70
+ - Costco: 5 items remaining
71
+ - Target: 3 items remaining
72
+ ```
73
+
74
+ ### Get Items from a List
75
+
76
+ ```python
77
+ async def get_items(list_name):
78
+ al = AnyList(email=EMAIL, password=PASSWORD)
79
+ await al.login()
80
+
81
+ lst = al.get_list(list_name)
82
+ if lst:
83
+ print(f"\n{lst.name}:")
84
+ for item in lst.items:
85
+ status = "x" if item.checked else " "
86
+ detail = f" ({item.detail})" if item.detail else ""
87
+ print(f" [{status}] {item.name}{detail}")
88
+
89
+ await al.teardown()
90
+
91
+ asyncio.run(get_items("Grocery"))
92
+ ```
93
+
94
+ Output:
95
+ ```
96
+ Grocery:
97
+ [ ] Milk (whole, organic)
98
+ [ ] Eggs (dozen)
99
+ [ ] Bread
100
+ [x] Butter
101
+ [ ] Chicken breast (2 lbs)
102
+ ```
103
+
104
+ ### Add Item to List
105
+
106
+ ```python
107
+ async def add_item(list_name, item_name, detail=None):
108
+ al = AnyList(email=EMAIL, password=PASSWORD)
109
+ await al.login()
110
+
111
+ lst = al.get_list(list_name)
112
+ if lst:
113
+ item = al.create_item(name=item_name, detail=detail)
114
+ lst.add_item(item)
115
+ await al.save()
116
+ print(f"Added '{item_name}' to {list_name}")
117
+
118
+ await al.teardown()
119
+
120
+ asyncio.run(add_item("Grocery", "Avocados", "4 ripe"))
121
+ ```
122
+
123
+ ### Add Multiple Items
124
+
125
+ ```python
126
+ async def add_multiple(list_name, items):
127
+ al = AnyList(email=EMAIL, password=PASSWORD)
128
+ await al.login()
129
+
130
+ lst = al.get_list(list_name)
131
+ if lst:
132
+ for name, detail in items:
133
+ item = al.create_item(name=name, detail=detail)
134
+ lst.add_item(item)
135
+ await al.save()
136
+ print(f"Added {len(items)} items to {list_name}")
137
+
138
+ await al.teardown()
139
+
140
+ items = [
141
+ ("Bananas", "1 bunch"),
142
+ ("Greek Yogurt", "plain, large"),
143
+ ("Spinach", "baby, 1 bag"),
144
+ ("Salmon", "2 fillets"),
145
+ ]
146
+ asyncio.run(add_multiple("Grocery", items))
147
+ ```
148
+
149
+ ### Check Off / Remove Items
150
+
151
+ ```python
152
+ async def check_item(list_name, item_name):
153
+ al = AnyList(email=EMAIL, password=PASSWORD)
154
+ await al.login()
155
+
156
+ lst = al.get_list(list_name)
157
+ if lst:
158
+ for item in lst.items:
159
+ if item.name.lower() == item_name.lower():
160
+ item.checked = True
161
+ await al.save()
162
+ print(f"Checked off '{item_name}'")
163
+ break
164
+
165
+ await al.teardown()
166
+
167
+ asyncio.run(check_item("Grocery", "Milk"))
168
+ ```
169
+
170
+ ### Create a New List
171
+
172
+ ```python
173
+ async def create_list(name):
174
+ al = AnyList(email=EMAIL, password=PASSWORD)
175
+ await al.login()
176
+
177
+ new_list = al.create_list(name=name)
178
+ await al.save()
179
+ print(f"Created list: {name}")
180
+
181
+ await al.teardown()
182
+
183
+ asyncio.run(create_list("Party Supplies"))
184
+ ```
185
+
186
+ ### Get Recipes
187
+
188
+ ```python
189
+ async def get_recipes():
190
+ al = AnyList(email=EMAIL, password=PASSWORD)
191
+ await al.login()
192
+
193
+ for recipe in al.recipes[:10]:
194
+ print(f"- {recipe.name}")
195
+ if recipe.note:
196
+ print(f" Note: {recipe.note}")
197
+
198
+ await al.teardown()
199
+
200
+ asyncio.run(get_recipes())
201
+ ```
202
+
203
+ ### Add Recipe Ingredients to Shopping List
204
+
205
+ ```python
206
+ async def recipe_to_list(recipe_name, list_name):
207
+ al = AnyList(email=EMAIL, password=PASSWORD)
208
+ await al.login()
209
+
210
+ recipe = None
211
+ for r in al.recipes:
212
+ if r.name.lower() == recipe_name.lower():
213
+ recipe = r
214
+ break
215
+
216
+ if recipe:
217
+ lst = al.get_list(list_name)
218
+ for ingredient in recipe.ingredients:
219
+ item = al.create_item(name=ingredient.name, detail=ingredient.detail)
220
+ lst.add_item(item)
221
+ await al.save()
222
+ print(f"Added {len(recipe.ingredients)} ingredients from '{recipe_name}' to '{list_name}'")
223
+
224
+ await al.teardown()
225
+
226
+ asyncio.run(recipe_to_list("Chicken Parmesan", "Grocery"))
227
+ ```
228
+
229
+ ## Meal Planning
230
+
231
+ ### View Meal Plan
232
+ ```python
233
+ async def get_meal_plan():
234
+ al = AnyList(email=EMAIL, password=PASSWORD)
235
+ await al.login()
236
+
237
+ for day in al.meal_plan:
238
+ print(f"\n{day.date}:")
239
+ for meal in day.meals:
240
+ print(f" {meal.type}: {meal.recipe_name or meal.name}")
241
+
242
+ await al.teardown()
243
+
244
+ asyncio.run(get_meal_plan())
245
+ ```
246
+
247
+ Output:
248
+ ```
249
+ Monday:
250
+ Breakfast: Overnight Oats
251
+ Lunch: Chicken Caesar Salad
252
+ Dinner: Pasta Bolognese
253
+
254
+ Tuesday:
255
+ Breakfast: Smoothie Bowl
256
+ Dinner: Grilled Salmon
257
+ ```
258
+
259
+ ## Clamper Integration
260
+
261
+ When the user wants to manage shopping/grocery lists:
262
+ 1. Authenticate with stored AnyList credentials
263
+ 2. List available shopping lists when asked
264
+ 3. Add items naturally: "add milk and eggs to grocery list"
265
+ 4. Parse quantities and details from natural language
266
+ 5. Support meal planning queries: "what's for dinner this week?"
267
+ 6. Add recipe ingredients to shopping list on request
268
+
269
+ ### Example Interaction
270
+ ```
271
+ User: Add these to my grocery list: 2 lbs chicken breast, a dozen eggs, whole milk, and bread
272
+ Assistant: *connects to AnyList, adds 4 items*
273
+ Added to Grocery list:
274
+ - Chicken breast (2 lbs)
275
+ - Eggs (dozen)
276
+ - Whole milk
277
+ - Bread
278
+
279
+ User: What's on my Costco list?
280
+ Assistant: *fetches Costco list*
281
+ Your Costco list has 5 items:
282
+ - [ ] Paper towels (bulk pack)
283
+ - [ ] Olive oil (2L)
284
+ - [ ] Rotisserie chicken
285
+ - [x] Laundry detergent
286
+ - [ ] Trash bags
287
+ ```
288
+
289
+ ## Setup
290
+
291
+ 1. Install the AnyList Python package: `pip install anylist`
292
+ 2. Set `ANYLIST_EMAIL` and `ANYLIST_PASSWORD` environment variables
293
+ 3. AnyList account required (free tier works, AnyList+ unlocks extra features)
294
+
295
+ **Note:** This uses an unofficial API. Functionality may change if AnyList updates their backend.