@tidyfactor/design 1.5.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 (136) hide show
  1. package/.tidyfactor +52 -0
  2. package/AGENTS.md +75 -0
  3. package/CHANGELOG.md +210 -0
  4. package/LICENSE +17 -0
  5. package/README.ar.md +398 -0
  6. package/README.de.md +44 -0
  7. package/README.es.md +44 -0
  8. package/README.fa.md +44 -0
  9. package/README.fr.md +44 -0
  10. package/README.md +418 -0
  11. package/README.pt.md +44 -0
  12. package/README.zh.md +44 -0
  13. package/SKILL-REGISTRY.md +69 -0
  14. package/SKILL.md +46 -0
  15. package/VISION.md +43 -0
  16. package/assets/blog.png +0 -0
  17. package/assets/content_layout.png +0 -0
  18. package/assets/content_output.png +0 -0
  19. package/assets/dark.png +0 -0
  20. package/assets/dashboard_layout.png +0 -0
  21. package/assets/dashboard_output.png +0 -0
  22. package/assets/ecommerce_layout.png +0 -0
  23. package/assets/ecommerce_output.png +0 -0
  24. package/assets/github-social-preview-2.png +0 -0
  25. package/assets/github-social-preview.png +0 -0
  26. package/assets/hero-banner.png +0 -0
  27. package/assets/light.png +0 -0
  28. package/assets/media_layout.png +0 -0
  29. package/assets/media_output.png +0 -0
  30. package/assets/og-default.png +0 -0
  31. package/assets/video.png +0 -0
  32. package/bin/add-skill.js +31 -0
  33. package/bin/create-kit.js +372 -0
  34. package/bin/remove-skill.js +137 -0
  35. package/brand.json +279 -0
  36. package/memory/01-design-schools.md +85 -0
  37. package/memory/02-design-tokens.md +41 -0
  38. package/memory/03-narrative-conversion.md +47 -0
  39. package/memory/04-motion-principles.md +44 -0
  40. package/memory/05-component-anatomy.md +34 -0
  41. package/memory/06-quality-bar.md +83 -0
  42. package/memory/07-consistency-contract.md +33 -0
  43. package/memory/08-arabic-bilingual.md +54 -0
  44. package/memory/09-prototype-flow.md +36 -0
  45. package/memory/10-python-tooling.md +64 -0
  46. package/memory/11-brand-json-v2.md +86 -0
  47. package/memory/12-typography-matrix.md +31 -0
  48. package/memory/13-layout-archetypes.md +30 -0
  49. package/memory/14-nav-footer-catalog.md +26 -0
  50. package/memory/15-performance-budget.md +18 -0
  51. package/memory/16-design-movements-guide.md +1084 -0
  52. package/memory/17-storytelling-industries-ux.md +143 -0
  53. package/memory/18-design-decision-engine.md +81 -0
  54. package/package.json +64 -0
  55. package/references/commands/_template.md +27 -0
  56. package/references/commands/assets.md +35 -0
  57. package/references/commands/audit.md +15 -0
  58. package/references/commands/brand.md +85 -0
  59. package/references/commands/brief.md +107 -0
  60. package/references/commands/clone.md +26 -0
  61. package/references/commands/components.md +46 -0
  62. package/references/commands/dashboard.md +45 -0
  63. package/references/commands/deploy.md +45 -0
  64. package/references/commands/flow.md +44 -0
  65. package/references/commands/handoff.md +53 -0
  66. package/references/commands/i18n.md +64 -0
  67. package/references/commands/init.md +30 -0
  68. package/references/commands/layout.md +81 -0
  69. package/references/commands/motion.md +62 -0
  70. package/references/commands/nav-footer.md +54 -0
  71. package/references/commands/page.md +45 -0
  72. package/references/commands/palette.md +35 -0
  73. package/references/commands/perf.md +57 -0
  74. package/references/commands/retrofit.md +15 -0
  75. package/references/commands/school.md +41 -0
  76. package/references/commands/states.md +48 -0
  77. package/references/commands/study.md +98 -0
  78. package/references/commands/tokens.md +45 -0
  79. package/references/commands/typography.md +87 -0
  80. package/references/foundations/daisyui.md +44 -0
  81. package/references/foundations/hybrid.md +32 -0
  82. package/references/foundations/native.md +31 -0
  83. package/references/foundations/tailwind-utility.md +43 -0
  84. package/references/memory/01-design-schools.md +85 -0
  85. package/references/memory/02-design-tokens.md +41 -0
  86. package/references/memory/03-narrative-conversion.md +47 -0
  87. package/references/memory/04-motion-principles.md +44 -0
  88. package/references/memory/05-component-anatomy.md +34 -0
  89. package/references/memory/06-quality-bar.md +83 -0
  90. package/references/memory/07-consistency-contract.md +33 -0
  91. package/references/memory/08-arabic-bilingual.md +54 -0
  92. package/references/memory/09-prototype-flow.md +36 -0
  93. package/references/memory/10-python-tooling.md +64 -0
  94. package/references/memory/11-brand-json-v2.md +86 -0
  95. package/references/memory/12-typography-matrix.md +31 -0
  96. package/references/memory/13-layout-archetypes.md +30 -0
  97. package/references/memory/14-nav-footer-catalog.md +26 -0
  98. package/references/memory/15-performance-budget.md +18 -0
  99. package/references/memory/16-design-movements-guide.md +1084 -0
  100. package/references/memory/17-storytelling-industries-ux.md +143 -0
  101. package/references/memory/18-design-decision-engine.md +81 -0
  102. package/references/memory/architecture.md +39 -0
  103. package/references/memory/decision-points.md +50 -0
  104. package/references/memory/foundations.md +15 -0
  105. package/references/memory/quality-bar.md +20 -0
  106. package/references/tidyfactor-vision.md +66 -0
  107. package/references/workflow.md +49 -0
  108. package/references/workflows/audit-prototype.md +26 -0
  109. package/references/workflows/brief.md +30 -0
  110. package/references/workflows/clone-prototype.md +27 -0
  111. package/references/workflows/init-prototype.md +28 -0
  112. package/references/workflows/retrofit-prototype.md +25 -0
  113. package/scripts/__pycache__/_utils.cpython-312.pyc +0 -0
  114. package/scripts/_utils.py +60 -0
  115. package/scripts/build.py +194 -0
  116. package/scripts/check_alpha.py +52 -0
  117. package/scripts/extract_palette.py +139 -0
  118. package/scripts/generate_transitions.py +105 -0
  119. package/scripts/inspect_images.py +48 -0
  120. package/scripts/minify_assets.py +140 -0
  121. package/scripts/optimize_assets.py +91 -0
  122. package/scripts/optimize_images.py +176 -0
  123. package/scripts/prepare_images.py +67 -0
  124. package/scripts/remove_backgrounds.py +61 -0
  125. package/scripts/test_build.py +228 -0
  126. package/templates/design-system/base.css +75 -0
  127. package/templates/design-system/components.css +229 -0
  128. package/templates/design-system/interactions.js +31 -0
  129. package/templates/design-system/motion.js +42 -0
  130. package/templates/design-system/tokens.css +81 -0
  131. package/templates/design-system/utilities.css +47 -0
  132. package/templates/index.html +84 -0
  133. package/templates/proto-nav.js +56 -0
  134. package/tools/build-skill.js +126 -0
  135. package/tools/validate-skill.js +144 -0
  136. package/tools/validate_skill.py +121 -0
package/VISION.md ADDED
@@ -0,0 +1,43 @@
1
+ # TidyFactor Vision
2
+
3
+ This skill is part of the **TidyFactor Ecosystem**.
4
+
5
+ The TidyFactor Vision is maintained as the single source of truth at the Skills-LAB level:
6
+
7
+ 👉 **[Read the full TidyFactor Vision](../TidyFactor-VISION.md)**
8
+
9
+ ---
10
+
11
+ ## TidyFactor-Design — Track Summary
12
+
13
+ **TidyFactor-Design** is the code-native interactive design & prototyping track within the TidyFactor ecosystem (an AI-era alternative to Figma).
14
+
15
+ It builds interactive, clickable, animated HTML/CSS/JS prototypes while structurally guaranteeing visual consistency across all screens — zero per-page CSS/JS, zero build step.
16
+
17
+ ### How this track fits the TidyFactor vision
18
+
19
+ | TidyFactor Principle | How Design Delivers It |
20
+ |---|---|
21
+ | **Structure over Complexity** | Centralized `design-system/` directory — pages carry HTML markup ONLY |
22
+ | **Content over Code** | Design tokens (`tokens.css` & `brand.json`) define the system independently of presentation |
23
+ | **AI Native** | Full `AGENTS.md` + `SKILL.md` — designed to be driven by any AI coding agent |
24
+ | **Open by Design** | MIT Licensed, published on npm, zero proprietary file formats |
25
+ | **Convention over Configuration** | Pluggable CSS foundations (Native, Tailwind, daisyUI, Hybrid) chosen once per project |
26
+ | **Evolution over Replacement** | Prototypes evolve directly into production code without re-architecture |
27
+
28
+ ### TidyFactor Ecosystem Relationship
29
+
30
+ ```
31
+ TidyFactor Ecosystem
32
+ ├── tidyfactor-html — Static content sites
33
+ ├── tidyfactor-php — Full-stack server-rendered PHP
34
+ ├── tidyfactor-js — Framework-free SPAs
35
+ ├── tidyfactor-htmx — Server-driven interactivity
36
+ ├── TidyFactor-Cinematic — Luxury scroll-driven landing pages
37
+ ├── TidyFactor-Design — Interactive prototyping & design systems ← this track
38
+ └── ...
39
+ ```
40
+
41
+ **Commercial partner:** [Alwkala](https://alwkala.com) — provides expertise, implementation, consulting, and long-term support.
42
+ **NPM package:** [`@tidyfactor/design`](https://www.npmjs.com/package/@tidyfactor/design)
43
+ **GitHub:** [alwkala/tidyfactor-design](https://github.com/alwkala/tidyfactor-design)
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * bin/add-skill.js — CLI installer wrapper for tidyfactor-design
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ const targetDir = process.cwd();
10
+ const skillSource = path.resolve(__dirname, '..');
11
+ const agentSkillsDir = path.join(targetDir, '.agents', 'skills', 'tidyfactor-design');
12
+
13
+ fs.mkdirSync(agentSkillsDir, { recursive: true });
14
+
15
+ function copyRecursive(src, dest) {
16
+ const entries = fs.readdirSync(src, { withFileTypes: true });
17
+ for (const entry of entries) {
18
+ const srcPath = path.join(src, entry.name);
19
+ const destPath = path.join(dest, entry.name);
20
+ if (['.git', 'node_modules', 'dist'].includes(entry.name)) continue;
21
+ if (entry.isDirectory()) {
22
+ fs.mkdirSync(destPath, { recursive: true });
23
+ copyRecursive(srcPath, destPath);
24
+ } else {
25
+ fs.copyFileSync(srcPath, destPath);
26
+ }
27
+ }
28
+ }
29
+
30
+ copyRecursive(skillSource, agentSkillsDir);
31
+ console.log('✓ Successfully injected tidyfactor-design skill into .agents/skills/tidyfactor-design');
@@ -0,0 +1,372 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const readline = require('readline');
6
+ const { execSync } = require('child_process');
7
+
8
+ /* Lightweight Zero-Dependency ANSI formatting */
9
+ const chalk = {
10
+ cyan: (str) => `\x1b[36m${str}\x1b[0m`,
11
+ green: (str) => `\x1b[32m${str}\x1b[0m`,
12
+ yellow: (str) => `\x1b[33m${str}\x1b[0m`,
13
+ red: (str) => `\x1b[31m${str}\x1b[0m`,
14
+ bold: (str) => `\x1b[1m${str}\x1b[0m`,
15
+ dim: (str) => `\x1b[2m${str}\x1b[0m`,
16
+ };
17
+
18
+ const PACKAGE_ROOT = path.resolve(__dirname, '..');
19
+ const pkg = require(path.join(PACKAGE_ROOT, 'package.json'));
20
+
21
+ /* Subcommand delegation */
22
+ const firstArg = process.argv[2];
23
+ const SUBCOMMANDS_ADD = new Set(['add-skill', 'add-design-skill', 'skill', 'install-skill']);
24
+ const SUBCOMMANDS_REMOVE = new Set(['remove-skill', 'remove-design-skill', 'uninstall-skill', 'clean-skill']);
25
+
26
+ if (firstArg && SUBCOMMANDS_ADD.has(firstArg.toLowerCase())) {
27
+ process.argv.splice(2, 1);
28
+ require('./add-skill.js');
29
+ process.exit(0);
30
+ }
31
+
32
+ if (firstArg && SUBCOMMANDS_REMOVE.has(firstArg.toLowerCase())) {
33
+ process.argv.splice(2, 1);
34
+ require('./remove-skill.js');
35
+ process.exit(0);
36
+ }
37
+
38
+ const FOUNDATIONS = [
39
+ {
40
+ name: 'native',
41
+ emoji: '🎨',
42
+ label: 'Native CSS',
43
+ desc: 'Pure CSS custom properties & semantic component classes (zero dependencies)',
44
+ },
45
+ {
46
+ name: 'tailwind',
47
+ emoji: '⚡',
48
+ label: 'Tailwind Utility',
49
+ desc: 'Tailwind CDN with utility-first class mapping',
50
+ },
51
+ {
52
+ name: 'daisyui',
53
+ emoji: '🌼',
54
+ label: 'daisyUI Components',
55
+ desc: 'Tailwind CDN + daisyUI component library themed via tokens',
56
+ },
57
+ {
58
+ name: 'hybrid',
59
+ emoji: '🔀',
60
+ label: 'Hybrid Foundation',
61
+ desc: 'daisyUI composite app widgets + Native CSS signature brand styling',
62
+ },
63
+ {
64
+ name: 'shadcn',
65
+ emoji: '📦',
66
+ label: 'shadcn/ui Primitives',
67
+ desc: 'Tailwind v4 + Radix UI accessible primitive tokens & components',
68
+ },
69
+ {
70
+ name: 'pico',
71
+ emoji: '🌱',
72
+ label: 'Pico CSS v2',
73
+ desc: 'Semantic classless/lightweight CSS foundation for minimalist sites',
74
+ },
75
+ {
76
+ name: 'bootstrap',
77
+ emoji: '🅱️',
78
+ label: 'Bootstrap 5.3',
79
+ desc: 'Enterprise-ready CSS custom properties & native dark mode themes',
80
+ },
81
+ {
82
+ name: 'alpine',
83
+ emoji: '🏔️',
84
+ label: 'Alpine + Tailwind',
85
+ desc: 'Alpine.js micro-interactions + Tailwind v4 utility engine',
86
+ },
87
+ ];
88
+
89
+ const SCHOOLS = [
90
+ 'minimalist',
91
+ 'brutalism',
92
+ 'glassmorphism',
93
+ 'neumorphism',
94
+ 'swiss',
95
+ 'luxury',
96
+ 'bauhaus',
97
+ 'industrial',
98
+ 'bento',
99
+ 'aurora',
100
+ 'cyberpunk',
101
+ 'claymorphism'
102
+ ];
103
+
104
+ const FOUNDATION_BY_NAME = new Map(FOUNDATIONS.map(f => [f.name, f]));
105
+
106
+ function isInteractiveTerminal() {
107
+ return (
108
+ Boolean(process.stdin.isTTY) &&
109
+ Boolean(process.stdout.isTTY) &&
110
+ !process.env.CI &&
111
+ !process.env.AGENT_MODE &&
112
+ process.env.NO_PROMPT !== '1'
113
+ );
114
+ }
115
+
116
+ function parseCliArgs() {
117
+ const args = process.argv.slice(2);
118
+ const positionalArgs = [];
119
+ let flags = {
120
+ foundation: undefined,
121
+ school: undefined,
122
+ palette: undefined,
123
+ yes: false,
124
+ help: false,
125
+ version: false,
126
+ };
127
+
128
+ for (const arg of args) {
129
+ if (arg === '--help' || arg === '-h') {
130
+ flags.help = true;
131
+ } else if (arg === '--version' || arg === '-v') {
132
+ flags.version = true;
133
+ } else if (arg.startsWith('--foundation=')) {
134
+ flags.foundation = arg.split('=')[1];
135
+ } else if (arg.startsWith('--school=')) {
136
+ flags.school = arg.split('=')[1];
137
+ } else if (arg.startsWith('--palette=')) {
138
+ flags.palette = arg.split('=')[1];
139
+ } else if (arg === '--yes' || arg === '-y') {
140
+ flags.yes = true;
141
+ } else if (!arg.startsWith('--')) {
142
+ positionalArgs.push(arg);
143
+ }
144
+ }
145
+
146
+ const targetDirArg = positionalArgs.length > 0 ? positionalArgs.join(' ') : null;
147
+
148
+ return { targetDirArg, flags };
149
+ }
150
+
151
+ function printBanner() {
152
+ const v = `v${pkg.version}`;
153
+ console.log('');
154
+ console.log(chalk.cyan(' ╔═══════════════════════════════════════════════════════╗'));
155
+ console.log(chalk.cyan(' ║') + chalk.bold(' 🎨 TidyFactor Design CLI ') + chalk.dim(v.padEnd(7)) + ' ' + chalk.cyan('║'));
156
+ console.log(chalk.cyan(' ║') + chalk.dim(' Code-native UI design engine & anti-slop system suite ') + chalk.cyan('║'));
157
+ console.log(chalk.cyan(' ║') + chalk.green(' 🌐 RTL & Bilingual Ready (El Messiri / Tajawal) ') + chalk.cyan('║'));
158
+ console.log(chalk.cyan(' ╚═══════════════════════════════════════════════════════╝'));
159
+ console.log('');
160
+ }
161
+
162
+ function printHelp() {
163
+ printBanner();
164
+ console.log(` ${chalk.bold('Usage:')}`);
165
+ console.log(` $ npx @tidyfactor/cli-design [project-dir] [options]\n`);
166
+ console.log(` ${chalk.bold('Subcommands:')}`);
167
+ console.log(` ${chalk.cyan('add-skill')} Inject Agent Skill, rules & memory into an existing workspace\n`);
168
+ console.log(` ${chalk.bold('Options:')}`);
169
+ console.log(` ${chalk.cyan('--foundation=<name>')} Select CSS foundation (native|tailwind|daisyui|hybrid|shadcn|pico|bootstrap|alpine)`);
170
+ console.log(` ${chalk.cyan('--school=<name>')} Select design school (minimalist|brutalism|glassmorphism|swiss|luxury|bento|cyberpunk)`);
171
+ console.log(` ${chalk.cyan('--palette=<image>')} Extract brand color palette from logo/screenshot`);
172
+ console.log(` ${chalk.cyan('-y, --yes')} Accept all defaults non-interactively`);
173
+ console.log(` ${chalk.cyan('-v, --version')} Display version number`);
174
+ console.log(` ${chalk.cyan('-h, --help')} Display this help message\n`);
175
+ }
176
+
177
+ function askQuestion(rl, query) {
178
+ return new Promise((resolve) => rl.question(query, (ans) => resolve(ans.trim())));
179
+ }
180
+
181
+ async function runInteractiveWizard(targetDir, foundation, school, palette) {
182
+ const rl = readline.createInterface({
183
+ input: process.stdin,
184
+ output: process.stdout,
185
+ });
186
+
187
+ // Handle SIGINT (Ctrl+C) gracefully
188
+ rl.on('SIGINT', () => {
189
+ console.log(chalk.red('\n\n ✖ Operation cancelled.\n'));
190
+ rl.close();
191
+ process.exit(0);
192
+ });
193
+
194
+ console.log(chalk.cyan(' 🧙 Interactive TidyFactor Design Wizard\n'));
195
+
196
+ // 1. Target Directory Prompt
197
+ const dirAns = await askQuestion(rl, chalk.bold(` [1/4] Target Directory [${targetDir}]: `));
198
+ if (dirAns) {
199
+ targetDir = dirAns;
200
+ }
201
+ console.log(chalk.green(` ✓ Target Directory: ${targetDir}`));
202
+
203
+ // 2. CSS Foundation Prompt
204
+ console.log(chalk.bold('\n [2/4] Select CSS Foundation:'));
205
+ FOUNDATIONS.forEach((f, idx) => {
206
+ const defaultTag = f.name === foundation ? chalk.green(' (default)') : '';
207
+ console.log(` ${chalk.cyan(`[${idx + 1}]`)} ${f.emoji} ${f.label.padEnd(16)} — ${chalk.dim(f.desc)}${defaultTag}`);
208
+ });
209
+
210
+ let validFound = false;
211
+ while (!validFound) {
212
+ const foundAns = await askQuestion(rl, chalk.bold(` Choose [1-${FOUNDATIONS.length}] (Enter for default): `));
213
+ if (!foundAns) {
214
+ validFound = true;
215
+ } else {
216
+ const foundIdx = parseInt(foundAns, 10) - 1;
217
+ if (!isNaN(foundIdx) && FOUNDATIONS[foundIdx]) {
218
+ foundation = FOUNDATIONS[foundIdx].name;
219
+ validFound = true;
220
+ } else {
221
+ console.log(chalk.yellow(` ⚠ Invalid choice. Please select a number between 1 and ${FOUNDATIONS.length}.`));
222
+ }
223
+ }
224
+ }
225
+ const chosenF = FOUNDATION_BY_NAME.get(foundation);
226
+ console.log(chalk.green(` ✓ Foundation Selected: ${chosenF.emoji} ${chosenF.label}`));
227
+
228
+ // 3. Design School Prompt
229
+ console.log(chalk.bold('\n [3/4] Select Visual Design School:'));
230
+ SCHOOLS.forEach((s, idx) => {
231
+ const defaultTag = s === school ? chalk.green(' (default)') : '';
232
+ console.log(` ${chalk.cyan(`[${idx + 1}]`.padEnd(5))} ${s.padEnd(16)}${defaultTag}`);
233
+ });
234
+
235
+ let validSchool = false;
236
+ while (!validSchool) {
237
+ const schoolAns = await askQuestion(rl, chalk.bold(` Choose [1-${SCHOOLS.length}] (Enter for default): `));
238
+ if (!schoolAns) {
239
+ validSchool = true;
240
+ } else {
241
+ const schoolIdx = parseInt(schoolAns, 10) - 1;
242
+ if (!isNaN(schoolIdx) && SCHOOLS[schoolIdx]) {
243
+ school = SCHOOLS[schoolIdx];
244
+ validSchool = true;
245
+ } else {
246
+ console.log(chalk.yellow(` ⚠ Invalid choice. Please select a number between 1 and ${SCHOOLS.length}.`));
247
+ }
248
+ }
249
+ }
250
+ console.log(chalk.green(` ✓ Design School Selected: ${school}`));
251
+
252
+ // 4. Color Palette Extraction Prompt
253
+ const palAns = await askQuestion(rl, chalk.bold(`\n [4/4] Path to brand logo/image to extract colors (optional, press Enter to skip): `));
254
+ if (palAns && fs.existsSync(palAns)) {
255
+ palette = palAns;
256
+ console.log(chalk.green(` ✓ Palette Image Locked: ${palette}`));
257
+ } else if (palAns) {
258
+ console.log(chalk.yellow(` ⚠ Image file "${palAns}" not found. Skipping extraction.`));
259
+ }
260
+
261
+ rl.close();
262
+ console.log('');
263
+ return { targetDir, foundation, school, palette };
264
+ }
265
+
266
+ function copyDirectory(src, dest) {
267
+ if (!fs.existsSync(src)) return;
268
+ fs.mkdirSync(dest, { recursive: true });
269
+ for (const item of fs.readdirSync(src)) {
270
+ const sPath = path.join(src, item);
271
+ const dPath = path.join(dest, item);
272
+ if (fs.statSync(sPath).isDirectory()) {
273
+ copyDirectory(sPath, dPath);
274
+ } else {
275
+ fs.copyFileSync(sPath, dPath);
276
+ }
277
+ }
278
+ }
279
+
280
+ async function main() {
281
+ const { targetDirArg, flags } = parseCliArgs();
282
+
283
+ if (flags.version) {
284
+ console.log(`v${pkg.version}`);
285
+ process.exit(0);
286
+ }
287
+
288
+ if (flags.help) {
289
+ printHelp();
290
+ process.exit(0);
291
+ }
292
+
293
+ printBanner();
294
+
295
+ let targetDir = targetDirArg || '.';
296
+ let foundation = flags.foundation || 'native';
297
+ let school = flags.school || 'minimalist';
298
+
299
+ // Interactive Wizard Trigger if live interactive terminal & no skip flags passed
300
+ const isInteractive = isInteractiveTerminal() && !flags.yes && !flags.foundation && !flags.school;
301
+ if (isInteractive) {
302
+ const wizardRes = await runInteractiveWizard(targetDir, foundation, school, flags.palette);
303
+ targetDir = wizardRes.targetDir;
304
+ foundation = wizardRes.foundation;
305
+ school = wizardRes.school;
306
+ flags.palette = wizardRes.palette;
307
+ }
308
+
309
+ if (!FOUNDATION_BY_NAME.has(foundation)) {
310
+ console.log(chalk.yellow(`⚠ Unknown foundation "${foundation}", falling back to "native".`));
311
+ foundation = 'native';
312
+ }
313
+
314
+ if (!SCHOOLS.includes(school)) {
315
+ school = 'minimalist';
316
+ }
317
+
318
+ const chosenFound = FOUNDATION_BY_NAME.get(foundation);
319
+ const targetPath = path.resolve(process.cwd(), targetDir);
320
+
321
+ console.log(chalk.green(` 🚀 Scaffolding TidyFactor Design project in ${chalk.bold(targetPath)}`));
322
+ console.log(chalk.dim(` Foundation: ${chosenFound.emoji} ${chosenFound.label} (${chosenFound.name})`));
323
+ console.log(chalk.dim(` Design School: ${school}\n`));
324
+
325
+ fs.mkdirSync(targetPath, { recursive: true });
326
+
327
+ // 1. Copy design system & prototype templates
328
+ const templatesDir = path.join(PACKAGE_ROOT, 'templates');
329
+ if (fs.existsSync(templatesDir)) {
330
+ copyDirectory(templatesDir, targetPath);
331
+ }
332
+
333
+ // 2. Copy brand.json v2
334
+ const defaultBrand = path.join(PACKAGE_ROOT, 'brand.json');
335
+ const targetBrand = path.join(targetPath, 'brand.json');
336
+ if (fs.existsSync(defaultBrand) && !fs.existsSync(targetBrand)) {
337
+ fs.copyFileSync(defaultBrand, targetBrand);
338
+ }
339
+
340
+ // 3. Auto-inject AI Agent Skill & Rules (.agents, .claude-skill, memory, AGENTS.md)
341
+ console.log(chalk.cyan(' 🤖 Auto-injecting AI Agent Skill & Design Decision Engine...'));
342
+ copyDirectory(path.join(PACKAGE_ROOT, '.agents'), path.join(targetPath, '.agents'));
343
+ copyDirectory(path.join(PACKAGE_ROOT, '.claude-skill'), path.join(targetPath, '.claude-skill'));
344
+ copyDirectory(path.join(PACKAGE_ROOT, 'memory'), path.join(targetPath, 'memory'));
345
+
346
+ const agentsMdSrc = path.join(PACKAGE_ROOT, 'AGENTS.md');
347
+ const agentsMdDest = path.join(targetPath, 'AGENTS.md');
348
+ if (fs.existsSync(agentsMdSrc) && !fs.existsSync(agentsMdDest)) {
349
+ fs.copyFileSync(agentsMdSrc, agentsMdDest);
350
+ }
351
+
352
+ // 4. Handle --palette extraction if provided
353
+ if (flags.palette && fs.existsSync(flags.palette)) {
354
+ console.log(chalk.cyan(` 🎨 Extracting color palette from ${flags.palette}...`));
355
+ const extractScript = path.join(PACKAGE_ROOT, 'scripts', 'extract_palette.py');
356
+ try {
357
+ execSync(`python "${extractScript}" "${flags.palette}" --json "${targetBrand}"`, { stdio: 'inherit' });
358
+ } catch (err) {
359
+ console.log(chalk.yellow('⚠ Palette extraction skipped (Python/Pillow not found).'));
360
+ }
361
+ }
362
+
363
+ console.log(chalk.green('\n ✅ Project & AI Skill scaffolded successfully!'));
364
+ console.log('');
365
+ console.log(` ${chalk.bold('Next Steps:')}`);
366
+ if (targetDir !== '.') {
367
+ console.log(` $ cd "${targetDir}"`);
368
+ }
369
+ console.log(` $ python -m http.server 8123 # Preview interactive prototype in browser\n`);
370
+ }
371
+
372
+ main();
@@ -0,0 +1,137 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ /* Lightweight Zero-Dependency ANSI formatting */
7
+ const chalk = {
8
+ cyan: (str) => `\x1b[36m${str}\x1b[0m`,
9
+ green: (str) => `\x1b[32m${str}\x1b[0m`,
10
+ yellow: (str) => `\x1b[33m${str}\x1b[0m`,
11
+ red: (str) => `\x1b[31m${str}\x1b[0m`,
12
+ bold: (str) => `\x1b[1m${str}\x1b[0m`,
13
+ dim: (str) => `\x1b[2m${str}\x1b[0m`,
14
+ };
15
+
16
+ const PACKAGE_ROOT = path.resolve(__dirname, '..');
17
+ const pkg = require(path.join(PACKAGE_ROOT, 'package.json'));
18
+
19
+ function parseCliArgs() {
20
+ const args = process.argv.slice(2);
21
+ let flags = {
22
+ help: false,
23
+ version: false,
24
+ yes: false,
25
+ };
26
+
27
+ for (const arg of args) {
28
+ if (arg === '--help' || arg === '-h') {
29
+ flags.help = true;
30
+ } else if (arg === '--version' || arg === '-v') {
31
+ flags.version = true;
32
+ } else if (arg === '--yes' || arg === '-y') {
33
+ flags.yes = true;
34
+ }
35
+ }
36
+
37
+ return flags;
38
+ }
39
+
40
+ function printBanner() {
41
+ const v = `v${pkg.version}`;
42
+ console.log('');
43
+ console.log(chalk.cyan(' ╔═══════════════════════════════════════════════════════╗'));
44
+ console.log(chalk.cyan(' ║') + chalk.bold(' 🗑️ TidyFactor Design Skill Uninstaller ') + chalk.dim(v.padEnd(7)) + ' ' + chalk.cyan('║'));
45
+ console.log(chalk.cyan(' ║') + chalk.dim(' Safely remove injected AI agent skill & rules ') + chalk.cyan('║'));
46
+ console.log(chalk.cyan(' ╚═══════════════════════════════════════════════════════╝'));
47
+ console.log('');
48
+ }
49
+
50
+ function printHelp() {
51
+ printBanner();
52
+ console.log(` ${chalk.bold('Usage:')}`);
53
+ console.log(` $ npx @tidyfactor/cli-design remove-skill [options]\n`);
54
+ console.log(` ${chalk.bold('Options:')}`);
55
+ console.log(` ${chalk.cyan('-y, --yes')} Accept uninstallation steps non-interactively`);
56
+ console.log(` ${chalk.cyan('-v, --version')} Display uninstaller version number`);
57
+ console.log(` ${chalk.cyan('-h, --help')} Display this help message\n`);
58
+ }
59
+
60
+ function printSuccessSummary(removedItems) {
61
+ console.log('');
62
+ console.log(chalk.yellow(' ╔═══════════════════════════════════════════════════════╗'));
63
+ console.log(chalk.yellow(' ║') + chalk.bold(' 🗑️ Design Skill Removed Successfully! ') + chalk.yellow('║'));
64
+ console.log(chalk.yellow(' ╠═══════════════════════════════════════════════════════╣'));
65
+ removedItems.forEach(item => {
66
+ console.log(chalk.yellow(' ║') + ` ✓ ${chalk.cyan(item.padEnd(52))}` + chalk.yellow('║'));
67
+ });
68
+ console.log(chalk.yellow(' ╚═══════════════════════════════════════════════════════╝'));
69
+ console.log('');
70
+ }
71
+
72
+ function rmrf(p) {
73
+ if (fs.existsSync(p)) {
74
+ fs.rmSync(p, { recursive: true, force: true });
75
+ return true;
76
+ }
77
+ return false;
78
+ }
79
+
80
+ function main() {
81
+ const flags = parseCliArgs();
82
+
83
+ if (flags.version) {
84
+ console.log(`v${pkg.version}`);
85
+ process.exit(0);
86
+ }
87
+
88
+ if (flags.help) {
89
+ printHelp();
90
+ process.exit(0);
91
+ }
92
+
93
+ printBanner();
94
+
95
+ const cwd = process.cwd();
96
+ const removedItems = [];
97
+
98
+ console.log(chalk.cyan(' 🧹 Removing TidyFactor Design Agent Skill files...'));
99
+
100
+ // 1. Remove .agents/skills/tidyfactor-design
101
+ const agentSkillPath = path.join(cwd, '.agents', 'skills', 'tidyfactor-design');
102
+ if (rmrf(agentSkillPath)) {
103
+ removedItems.push('.agents/skills/tidyfactor-design/');
104
+ }
105
+
106
+ // 2. Remove .claude-skill
107
+ const claudeSkillPath = path.join(cwd, '.claude-skill');
108
+ if (rmrf(claudeSkillPath)) {
109
+ removedItems.push('.claude-skill/');
110
+ }
111
+
112
+ // 3. Remove memory reference folder
113
+ const memoryPath = path.join(cwd, 'memory');
114
+ if (rmrf(memoryPath)) {
115
+ removedItems.push('memory/');
116
+ }
117
+
118
+ // 4. Remove AGENTS.md if it was generated by tidyfactor-design
119
+ const agentsMdPath = path.join(cwd, 'AGENTS.md');
120
+ if (fs.existsSync(agentsMdPath)) {
121
+ try {
122
+ const content = fs.readFileSync(agentsMdPath, 'utf-8');
123
+ if (content.includes('TidyFactor Design System') || content.includes('tidyfactor-design')) {
124
+ fs.unlinkSync(agentsMdPath);
125
+ removedItems.push('AGENTS.md');
126
+ }
127
+ } catch (e) {}
128
+ }
129
+
130
+ if (removedItems.length === 0) {
131
+ console.log(chalk.yellow(' ⚠ No installed TidyFactor Design skill files found in this workspace.\n'));
132
+ } else {
133
+ printSuccessSummary(removedItems);
134
+ }
135
+ }
136
+
137
+ main();