onemore-design 1.0.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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/SKILL.md +180 -0
  3. package/bin/onemore.js +23 -0
  4. package/data/audit/hig-checklist.csv +39 -0
  5. package/data/components/content.csv +17 -0
  6. package/data/components/controls.csv +21 -0
  7. package/data/components/feedback.csv +17 -0
  8. package/data/components/input.csv +11 -0
  9. package/data/components/navigation.csv +15 -0
  10. package/data/foundations/colors.csv +38 -0
  11. package/data/foundations/corners.csv +13 -0
  12. package/data/foundations/elevation.csv +17 -0
  13. package/data/foundations/spacing.csv +21 -0
  14. package/data/foundations/typography.csv +26 -0
  15. package/data/patterns/animation.csv +24 -0
  16. package/data/patterns/gestures.csv +11 -0
  17. package/data/patterns/interaction.csv +16 -0
  18. package/data/patterns/layout.csv +20 -0
  19. package/data/platforms/ios.csv +21 -0
  20. package/data/platforms/macos.csv +16 -0
  21. package/data/platforms/visionos.csv +11 -0
  22. package/data/platforms/watchos.csv +11 -0
  23. package/data/platforms/web-apple.csv +21 -0
  24. package/data/reasoning/apple-reasoning.csv +16 -0
  25. package/data/stacks/astro.csv +21 -0
  26. package/data/stacks/flutter.csv +29 -0
  27. package/data/stacks/html-tailwind.csv +26 -0
  28. package/data/stacks/nativewind.csv +26 -0
  29. package/data/stacks/nextjs.csv +26 -0
  30. package/data/stacks/nuxtjs.csv +21 -0
  31. package/data/stacks/react-native.csv +26 -0
  32. package/data/stacks/react.csv +26 -0
  33. package/data/stacks/shadcn.csv +25 -0
  34. package/data/stacks/svelte.csv +21 -0
  35. package/data/stacks/swiftui.csv +31 -0
  36. package/data/stacks/uikit.csv +21 -0
  37. package/data/stacks/vue.csv +21 -0
  38. package/package.json +51 -0
  39. package/scripts/__init__.py +0 -0
  40. package/scripts/__pycache__/__init__.cpython-314.pyc +0 -0
  41. package/scripts/__pycache__/core.cpython-314.pyc +0 -0
  42. package/scripts/__pycache__/design_system.cpython-314.pyc +0 -0
  43. package/scripts/__pycache__/exporter.cpython-314.pyc +0 -0
  44. package/scripts/__pycache__/platforms.cpython-314.pyc +0 -0
  45. package/scripts/__pycache__/redesign.cpython-314.pyc +0 -0
  46. package/scripts/core.py +242 -0
  47. package/scripts/design_system.py +291 -0
  48. package/scripts/exporter.py +717 -0
  49. package/scripts/platforms.py +309 -0
  50. package/scripts/redesign.py +758 -0
  51. package/scripts/search.py +426 -0
@@ -0,0 +1,309 @@
1
+ #!/usr/bin/env python3
2
+ """OneMore Multi-Platform Distribution"""
3
+
4
+ import os
5
+ import shutil
6
+ from pathlib import Path
7
+
8
+ PROJECT_DIR = Path(__file__).parent.parent
9
+
10
+ PLATFORMS = {
11
+ "claude-code": {
12
+ "type": "global", "path": "~/.claude/skills/onemore", "name": "Claude Code",
13
+ "detect": {"dirs": ["~/.claude"], "commands": ["claude"]}
14
+ },
15
+ "codex": {
16
+ "type": "global", "path": "~/.codex/skills/onemore", "name": "Codex",
17
+ "detect": {"dirs": ["~/.codex"], "commands": ["codex"]}
18
+ },
19
+ "qoder": {
20
+ "type": "global", "path": "~/.qoder/skills/onemore", "name": "Qoder",
21
+ "detect": {"dirs": ["~/.qoder"], "commands": ["qoder"]}
22
+ },
23
+ "antigravity": {
24
+ "type": "global", "path": "~/.antigravity/plugins/onemore", "name": "Antigravity",
25
+ "detect": {"dirs": ["~/.antigravity"], "commands": ["antigravity"]}
26
+ },
27
+ "cursor": {
28
+ "type": "project", "path": ".cursor/rules/onemore.mdc", "name": "Cursor",
29
+ "detect": {"project_dirs": [".cursor"], "commands": ["cursor"]}
30
+ },
31
+ "windsurf": {
32
+ "type": "project", "path": ".windsurf/rules/onemore.md", "name": "Windsurf",
33
+ "detect": {"project_dirs": [".windsurf"], "commands": ["windsurf"]}
34
+ },
35
+ "copilot": {
36
+ "type": "project", "path": ".github/copilot-instructions.md", "name": "GitHub Copilot", "mode": "append",
37
+ "detect": {"project_dirs": [".github"], "commands": ["gh"]}
38
+ },
39
+ "gemini": {
40
+ "type": "project", "path": "GEMINI.md", "name": "Gemini CLI", "mode": "append",
41
+ "detect": {"dirs": [], "commands": ["gemini"]}
42
+ },
43
+ "cline": {
44
+ "type": "project", "path": ".clinerules/onemore.md", "name": "Cline",
45
+ "detect": {"project_dirs": [".clinerules"], "commands": []}
46
+ },
47
+ "roo": {
48
+ "type": "project", "path": ".roo/rules/onemore.md", "name": "Roo Code",
49
+ "detect": {"project_dirs": [".roo"], "commands": []}
50
+ },
51
+ "kiro": {
52
+ "type": "project", "path": ".kiro/rules/onemore.md", "name": "Kiro",
53
+ "detect": {"project_dirs": [".kiro"], "commands": ["kiro"]}
54
+ },
55
+ }
56
+
57
+ def generate_project_rules():
58
+ """Generate condensed Apple HIG rules for project-level installs."""
59
+ return '''# OneMore — Apple HIG Design Rules
60
+
61
+ > Apply these rules when building UI. Every element should look like an Apple product.
62
+
63
+ ## Core Principles
64
+ 1. **Clarity** — Legible text, precise icons, subtle adornments
65
+ 2. **Deference** — UI serves content, never competes
66
+ 3. **Depth** — Visual layers and motion convey hierarchy
67
+ 4. **Consistency** — Familiar standards and paradigms
68
+ 5. **Direct Manipulation** — Immediate visible results
69
+ 6. **Feedback** — Perceptible response to every action
70
+
71
+ ## Priority Rules
72
+
73
+ | # | Category | Key Rule |
74
+ |---|----------|----------|
75
+ | 1 | Accessibility | 4.5:1 contrast, VoiceOver/aria labels, Dynamic Type |
76
+ | 2 | Touch Targets | 44pt min (iOS), 60pt (visionOS), 20pt (macOS) |
77
+ | 3 | Typography | SF Pro (native) or Inter/system-ui (web). Body: 17pt iOS, 13pt macOS |
78
+ | 4 | Colors | Semantic tokens only. Support dark mode. Never hardcode hex |
79
+ | 5 | Spacing | 4pt grid: 4/8/12/16/20/24/32/48 |
80
+ | 6 | Components | Native controls. Continuous corners (borderCurve: continuous) |
81
+ | 7 | Animation | Spring physics only. Never linear/ease for UI transitions |
82
+ | 8 | Platform | iOS != macOS != visionOS. Use platform-appropriate patterns |
83
+
84
+ ## Apple Color System
85
+ - Text: semantic `label` color (#1d1d1f on web, NOT pure black)
86
+ - Background: semantic `systemBackground` (#fbfbfd on web, NOT pure white)
87
+ - Accent: `systemBlue` #007AFF (light) / #0A84FF (dark)
88
+ - Destructive: `systemRed` #FF3B30 / #FF453A
89
+ - Success: `systemGreen` #34C759 / #30D158
90
+ - Grays: systemGray through systemGray6 (6 levels, different light/dark)
91
+
92
+ ## Apple Typography Scale (iOS)
93
+ | Style | Size | Weight |
94
+ |-------|------|--------|
95
+ | largeTitle | 34pt | Regular |
96
+ | title1 | 28pt | Regular |
97
+ | title2 | 22pt | Regular |
98
+ | headline | 17pt | Semibold |
99
+ | body | 17pt | Regular |
100
+ | callout | 16pt | Regular |
101
+ | subheadline | 15pt | Regular |
102
+ | footnote | 13pt | Regular |
103
+ | caption1 | 12pt | Regular |
104
+
105
+ ## Apple Spacing Scale
106
+ 4 → 8 → 12 → 16 → 20 → 24 → 32 → 40 → 48 (pt)
107
+
108
+ ## Spring Animation Presets
109
+ | Preset | Response | Damping | Use |
110
+ |--------|----------|---------|-----|
111
+ | smooth | 0.5 | 1.0 | General transitions |
112
+ | snappy | 0.35 | 1.0 | Quick actions |
113
+ | bouncy | 0.5 | 0.7 | Playful interactions |
114
+ | interactive | 0.15 | 0.86 | Gesture-driven |
115
+
116
+ ## Web Font Stack
117
+ ```css
118
+ font-family: -apple-system, BlinkMacSystemFont, "Inter", system-ui, sans-serif;
119
+ ```
120
+ SF Pro only on Apple platforms. Inter is the closest web fallback.
121
+
122
+ ## Pre-Delivery Checklist
123
+ - [ ] 4pt grid spacing, no arbitrary values
124
+ - [ ] SF Pro (native) or Inter/system-ui (web) typography
125
+ - [ ] Semantic color tokens, dark mode working
126
+ - [ ] Continuous corners (not standard border-radius)
127
+ - [ ] Touch targets >= 44pt
128
+ - [ ] Spring animations, no linear/ease
129
+ - [ ] Dynamic Type / font scaling
130
+ - [ ] No emoji icons — SF Symbols or Lucide
131
+ - [ ] Platform-appropriate navigation
132
+ - [ ] VoiceOver/aria labels, 4.5:1 contrast
133
+ - [ ] Safe areas respected
134
+
135
+ ## Anti-Patterns
136
+ | Don\'t | Do |
137
+ |--------|-----|
138
+ | border-radius: 8px | Continuous corners, correct radii (12pt buttons, 16pt cards) |
139
+ | Arial/Helvetica | SF Pro (native), Inter (web) |
140
+ | Random spacing | 4pt grid |
141
+ | Flat UI | Materials, vibrancy, shadows |
142
+ | ease-in-out | Spring physics |
143
+ | #000000 text | Semantic label color |
144
+ | Emoji icons | SF Symbols or SVG icon set |
145
+
146
+ ---
147
+ *Generated by [OneMore](https://github.com/onemore) — Apple HIG Design Intelligence*
148
+ '''
149
+
150
+
151
+ def init_platform(platform_name, project_dir=None):
152
+ """Initialize OneMore for a specific platform."""
153
+ if platform_name not in PLATFORMS:
154
+ return {"error": f"Unknown platform: {platform_name}", "available": list(PLATFORMS.keys())}
155
+
156
+ config = PLATFORMS[platform_name]
157
+
158
+ if config["type"] == "global":
159
+ return _init_global(platform_name, config)
160
+ else:
161
+ return _init_project(platform_name, config, project_dir or Path.cwd())
162
+
163
+
164
+ def _init_global(platform_name, config):
165
+ """Install OneMore globally for a platform (symlink or copy)."""
166
+ target = Path(config["path"]).expanduser()
167
+ target.parent.mkdir(parents=True, exist_ok=True)
168
+
169
+ if target.exists() or target.is_symlink():
170
+ return {"status": "already_installed", "platform": config["name"], "path": str(target)}
171
+
172
+ # Symlink the entire project directory
173
+ os.symlink(str(PROJECT_DIR), str(target))
174
+ return {"status": "installed", "platform": config["name"], "path": str(target), "method": "symlink"}
175
+
176
+
177
+ def _init_project(platform_name, config, project_dir):
178
+ """Install OneMore rules into a project directory."""
179
+ target = Path(project_dir) / config["path"]
180
+ target.parent.mkdir(parents=True, exist_ok=True)
181
+
182
+ rules = generate_project_rules()
183
+
184
+ # Cursor needs frontmatter
185
+ if platform_name == "cursor":
186
+ content = f"---\ndescription: Apple HIG design rules - apply when building UI\nglobs: \"**/*.{{tsx,jsx,vue,svelte,swift,html,css,scss}}\"\nalwaysApply: false\n---\n\n{rules}"
187
+ elif config.get("mode") == "append":
188
+ # Append mode: add to existing file
189
+ header = "\n\n<!-- OneMore: Apple HIG Design Rules -->\n"
190
+ footer = "\n<!-- /OneMore -->\n"
191
+ if target.exists():
192
+ existing = target.read_text()
193
+ if "OneMore" in existing:
194
+ return {"status": "already_installed", "platform": config["name"], "path": str(target)}
195
+ content = existing + header + rules + footer
196
+ else:
197
+ content = header.lstrip() + rules + footer
198
+ else:
199
+ content = rules
200
+
201
+ target.write_text(content)
202
+ return {"status": "installed", "platform": config["name"], "path": str(target)}
203
+
204
+
205
+ def detect_platforms(project_dir=None):
206
+ """Auto-detect which AI platforms are installed.
207
+
208
+ Detection strategy:
209
+ - Global platforms: check if config dir exists in home (~/.claude, ~/.codex, etc) OR command in PATH
210
+ - Project platforms: check if project dir exists (.cursor/, .windsurf/, etc) OR command in PATH
211
+
212
+ Returns list of dicts with platform name, detected (bool), and reason.
213
+ """
214
+ project_dir = Path(project_dir) if project_dir else Path.cwd()
215
+ results = []
216
+
217
+ for name, config in PLATFORMS.items():
218
+ detect = config.get("detect", {})
219
+ detected = False
220
+ reason = ""
221
+
222
+ # Check global dirs (home directory)
223
+ for d in detect.get("dirs", []):
224
+ expanded = Path(d).expanduser()
225
+ if expanded.exists():
226
+ detected = True
227
+ reason = f"found {d}"
228
+ break
229
+
230
+ # Check project dirs (current project)
231
+ if not detected:
232
+ for d in detect.get("project_dirs", []):
233
+ if (project_dir / d).exists():
234
+ detected = True
235
+ reason = f"found {d}/ in project"
236
+ break
237
+
238
+ # Check commands in PATH
239
+ if not detected:
240
+ for cmd in detect.get("commands", []):
241
+ if shutil.which(cmd):
242
+ detected = True
243
+ reason = f"'{cmd}' command found"
244
+ break
245
+
246
+ # Check if OneMore already installed for this platform
247
+ if config["type"] == "global":
248
+ install_path = Path(config["path"]).expanduser()
249
+ else:
250
+ install_path = project_dir / config["path"]
251
+ already_installed = install_path.exists() or install_path.is_symlink()
252
+
253
+ results.append({
254
+ "platform": name,
255
+ "name": config["name"],
256
+ "type": config["type"],
257
+ "detected": detected,
258
+ "reason": reason,
259
+ "already_installed": already_installed
260
+ })
261
+
262
+ return results
263
+
264
+
265
+ def auto_init(project_dir=None):
266
+ """Detect platforms and install OneMore for all detected ones.
267
+
268
+ Returns dict with detected platforms, installed platforms, and skipped (already installed).
269
+ """
270
+ detected = detect_platforms(project_dir)
271
+ installed = []
272
+ skipped = []
273
+ not_detected = []
274
+
275
+ for p in detected:
276
+ if not p["detected"]:
277
+ not_detected.append(p)
278
+ continue
279
+ if p["already_installed"]:
280
+ skipped.append(p)
281
+ continue
282
+ result = init_platform(p["platform"], project_dir=project_dir)
283
+ if result.get("status") == "installed":
284
+ installed.append(p)
285
+ else:
286
+ skipped.append(p)
287
+
288
+ return {
289
+ "detected": [p for p in detected if p["detected"]],
290
+ "installed": installed,
291
+ "skipped": skipped,
292
+ "not_detected": not_detected
293
+ }
294
+
295
+
296
+ def list_platforms():
297
+ """List all platforms with install status."""
298
+ results = []
299
+ for name, config in PLATFORMS.items():
300
+ path = Path(config["path"]).expanduser() if config["type"] == "global" else Path(config["path"])
301
+ installed = path.exists() or path.is_symlink()
302
+ results.append({
303
+ "platform": name,
304
+ "name": config["name"],
305
+ "type": config["type"],
306
+ "path": config["path"],
307
+ "installed": installed
308
+ })
309
+ return results