@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
@@ -0,0 +1,47 @@
1
+ /* ==========================================================================
2
+ TidyFactor Design System — Utility Classes (utilities.css)
3
+ Layout helpers, spatial utilities, text balance, & accessibility masks
4
+ ========================================================================== */
5
+
6
+ .text-center { text-align: center; }
7
+ .text-left { text-align: left; }
8
+ .text-right { text-align: right; }
9
+
10
+ .text-balance { text-wrap: balance; }
11
+ .text-muted { color: var(--color-text-muted); }
12
+ .text-primary { color: var(--color-primary); }
13
+
14
+ .flex-center {
15
+ display: flex;
16
+ align-items: center;
17
+ justify-content: center;
18
+ }
19
+
20
+ .flex-between {
21
+ display: flex;
22
+ align-items: center;
23
+ justify-content: space-between;
24
+ }
25
+
26
+ .gap-2 { gap: var(--space-2); }
27
+ .gap-4 { gap: var(--space-4); }
28
+ .gap-6 { gap: var(--space-6); }
29
+
30
+ .mt-4 { margin-top: var(--space-4); }
31
+ .mt-8 { margin-top: var(--space-8); }
32
+ .mt-12 { margin-top: var(--space-12); }
33
+
34
+ .mb-4 { margin-bottom: var(--space-4); }
35
+ .mb-8 { margin-bottom: var(--space-8); }
36
+
37
+ .sr-only {
38
+ position: absolute;
39
+ width: 1px;
40
+ height: 1px;
41
+ padding: 0;
42
+ margin: -1px;
43
+ overflow: hidden;
44
+ clip: rect(0, 0, 0, 0);
45
+ white-space: nowrap;
46
+ border-width: 0;
47
+ }
@@ -0,0 +1,84 @@
1
+ <!doctype html>
2
+ <html lang="en" dir="ltr" data-theme="light">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>TidyFactor Prototype Starter</title>
7
+ <meta name="description" content="Interactive prototype scaffold built with TidyFactor Design System" />
8
+
9
+ <!-- Google Fonts: El Messiri & Tajawal -->
10
+ <link rel="preconnect" href="https://fonts.googleapis.com">
11
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
12
+ <link href="https://fonts.googleapis.com/css2?family=El+Messiri:wght@600;700&family=Tajawal:wght@400;500;700&display=swap" rel="stylesheet">
13
+
14
+ <!-- Production Design System Files (Zero Inline Overrides) -->
15
+ <link rel="stylesheet" href="design-system/tokens.css" />
16
+ <link rel="stylesheet" href="design-system/base.css" />
17
+ <link rel="stylesheet" href="design-system/components.css" />
18
+ <link rel="stylesheet" href="design-system/utilities.css" />
19
+ </head>
20
+ <body>
21
+
22
+ <!-- Floating Sticky Header Navbar -->
23
+ <div class="container mt-4">
24
+ <nav class="navbar">
25
+ <a href="#" class="badge">🎨 TidyFactor Design</a>
26
+ <ul class="nav-links">
27
+ <li><a href="#features" class="nav-link active">Features</a></li>
28
+ <li><a href="#bento" class="nav-link">Bento Cards</a></li>
29
+ <li><a href="#about" class="nav-link">Governance</a></li>
30
+ </ul>
31
+ <div style="display: flex; gap: var(--space-2);">
32
+ <button class="btn btn-secondary" data-theme-toggle>🌓 Theme</button>
33
+ <button class="btn btn-primary" data-dir-toggle>🌐 RTL / LTR</button>
34
+ </div>
35
+ </nav>
36
+ </div>
37
+
38
+ <main class="container">
39
+ <!-- Hero Section -->
40
+ <section class="hero" data-reveal>
41
+ <span class="badge mb-4">🚀 Interactive Prototype Ready</span>
42
+ <h1 class="hero-title text-balance">Code-Native UI Design Engine</h1>
43
+ <p class="hero-subtitle text-balance">
44
+ Zero-bundler interactive prototype scaffolded with pluggable CSS foundations and 24 Slash Commands lifecycle skill suite.
45
+ </p>
46
+ <div class="flex-center gap-4">
47
+ <a href="#bento" class="btn btn-primary">Explore Bento Grid</a>
48
+ <a href="https://github.com/alwkala/tidyfactor-design" target="_blank" class="btn btn-outline">GitHub Repository</a>
49
+ </div>
50
+ </section>
51
+
52
+ <!-- Bento Grid Component Section -->
53
+ <section id="bento" class="mb-8" data-reveal>
54
+ <h2 class="text-center mb-8">Design System Foundations</h2>
55
+ <div class="bento-grid">
56
+ <div class="bento-tile">
57
+ <span class="badge mb-4">Foundation 1</span>
58
+ <h3>Pluggable CSS Systems</h3>
59
+ <p class="text-muted mt-4">Switch seamlessly between Native CSS, Tailwind, daisyUI, shadcn/ui, Pico, and Bootstrap without structural breaks.</p>
60
+ </div>
61
+ <div class="bento-tile">
62
+ <span class="badge mb-4">Foundation 2</span>
63
+ <h3>Design Decision Engine</h3>
64
+ <p class="text-muted mt-4">9-step decision tree protocol with YAML confidence matrices, compatibility rules, and Anti-Design-Soup enforcement.</p>
65
+ </div>
66
+ <div class="bento-tile">
67
+ <span class="badge mb-4">Foundation 3</span>
68
+ <h3>20 Visual Movements</h3>
69
+ <p class="text-muted mt-4">Complete executable signature specs for Swiss, Neo-Brutalism, Glassmorphism, Bento UI, Cyberpunk, and Material.</p>
70
+ </div>
71
+ </div>
72
+ </section>
73
+ </main>
74
+
75
+ <footer class="container text-center text-muted mb-8" style="padding-top: var(--space-8); border-top: 1px solid var(--border);">
76
+ <p>© 2026 TidyFactor Ecosystem • Built with @tidyfactor/design</p>
77
+ </footer>
78
+
79
+ <!-- Shared Scripts & Developer Prototype Toolbar -->
80
+ <script src="design-system/motion.js"></script>
81
+ <script src="design-system/interactions.js"></script>
82
+ <script src="proto-nav.js"></script>
83
+ </body>
84
+ </html>
@@ -0,0 +1,56 @@
1
+ /**
2
+ * TidyFactor Design — Prototype Toolbar (dev-only)
3
+ * Floating dev toolbar for page switching, state toggles, and theme inspection.
4
+ */
5
+ (function () {
6
+ const PAGES = [
7
+ { label: '📄 Landing (index.html)', href: 'index.html' }
8
+ ];
9
+
10
+ function buildToolbar() {
11
+ if (document.querySelector('[data-proto-toolbar]')) return;
12
+ const bar = document.createElement('div');
13
+ bar.setAttribute('data-proto-toolbar', '');
14
+ bar.style.cssText = [
15
+ 'position:fixed', 'bottom:16px', 'right:16px', 'z-index:99999',
16
+ 'display:flex', 'gap:8px', 'padding:8px 14px',
17
+ 'background:rgba(15,23,42,0.9)', 'backdrop-filter:blur(12px)',
18
+ 'border-radius:9999px', 'font:12px/1.4 system-ui, sans-serif',
19
+ 'color:#F8FAFC', 'align-items:center', 'border:1px solid rgba(255,255,255,0.2)',
20
+ 'box-shadow:0 10px 25px rgba(0,0,0,0.3)'
21
+ ].join(';');
22
+
23
+ const badge = document.createElement('span');
24
+ badge.textContent = '🎨 TF Design';
25
+ badge.style.cssText = 'font-weight:700;color:#818CF8;';
26
+ bar.appendChild(badge);
27
+
28
+ const select = document.createElement('select');
29
+ select.style.cssText = 'background:transparent;color:#fff;border:none;font:inherit;outline:none;cursor:pointer;';
30
+ PAGES.forEach((p) => {
31
+ const opt = document.createElement('option');
32
+ opt.value = p.href;
33
+ opt.textContent = p.label;
34
+ opt.style.background = '#0F172A';
35
+ select.appendChild(opt);
36
+ });
37
+ select.addEventListener('change', (e) => {
38
+ if (e.target.value) window.location.href = e.target.value;
39
+ });
40
+ bar.appendChild(select);
41
+
42
+ document.body.appendChild(bar);
43
+ }
44
+
45
+ function getStateParam() {
46
+ return new URLSearchParams(window.location.search).get('state') || 'default';
47
+ }
48
+
49
+ window.protoNav = { getStateParam };
50
+
51
+ if (document.readyState === 'loading') {
52
+ document.addEventListener('DOMContentLoaded', buildToolbar);
53
+ } else {
54
+ buildToolbar();
55
+ }
56
+ })();
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * tools/build-skill.js — TidyFactor Design Build & Packaging Tool
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ const { execSync } = require('child_process');
9
+
10
+ const SKILL_NAME = 'tidyfactor-design';
11
+ const REPO_ROOT = path.resolve(__dirname, '..');
12
+ const DIST_DIR = path.join(REPO_ROOT, 'dist');
13
+ const STAGING_DIR = path.join(DIST_DIR, SKILL_NAME);
14
+ const SKILLS_LAB_ROOT = path.resolve(REPO_ROOT, '..');
15
+
16
+ const HOME = process.env.USERPROFILE || process.env.HOME;
17
+ const GLOBAL_CONFIG_SKILL = path.join(HOME, '.gemini', 'config', 'skills', SKILL_NAME);
18
+ const LOCAL_AGENT_SKILL = path.join(SKILLS_LAB_ROOT, '.agents', 'skills', SKILL_NAME);
19
+
20
+ function log(msg) {
21
+ console.log(`[build-skill] ${msg}`);
22
+ }
23
+
24
+ function runValidation() {
25
+ log('running release validation checks...');
26
+ const pythonCmd = process.platform === 'win32' ? 'python' : 'python3';
27
+ execSync(`${pythonCmd} "${path.join(__dirname, 'validate_skill.py')}"`, { stdio: 'inherit' });
28
+ }
29
+
30
+ function copyRecursive(src, dest) {
31
+ if (!fs.existsSync(src)) return;
32
+ const stat = fs.statSync(src);
33
+ if (stat.isDirectory()) {
34
+ fs.mkdirSync(dest, { recursive: true });
35
+ for (const item of fs.readdirSync(src)) {
36
+ if (['node_modules', '.git', 'dist', '.agents'].includes(item)) continue;
37
+ copyRecursive(path.join(src, item), path.join(dest, item));
38
+ }
39
+ } else {
40
+ fs.copyFileSync(src, dest);
41
+ }
42
+ }
43
+
44
+ function zipDirectory(sourceDir, outZip) {
45
+ const pythonCmd = process.platform === 'win32' ? 'python' : 'python3';
46
+ const pyScript = `import shutil, os; shutil.make_archive(r'''${outZip.replace(/\\/g, '/').replace(/\.skill$/, '')}''', 'zip', r'''${sourceDir.replace(/\\/g, '/')}''')`;
47
+ execSync(`${pythonCmd} -c "${pyScript}"`);
48
+ const generatedZip = outZip.replace(/\.skill$/, '.zip');
49
+ if (generatedZip !== outZip) {
50
+ if (fs.existsSync(outZip)) fs.unlinkSync(outZip);
51
+ fs.renameSync(generatedZip, outZip);
52
+ }
53
+ }
54
+
55
+ function build() {
56
+ log(`repo root: ${REPO_ROOT}`);
57
+ runValidation();
58
+
59
+ log('cleaning previous build...');
60
+ if (fs.existsSync(DIST_DIR)) {
61
+ fs.rmSync(DIST_DIR, { recursive: true, force: true });
62
+ }
63
+ fs.mkdirSync(STAGING_DIR, { recursive: true });
64
+
65
+ const pkg = JSON.parse(fs.readFileSync(path.join(REPO_ROOT, 'package.json'), 'utf-8'));
66
+ const version = pkg.version;
67
+
68
+ log('staging single-source-of-truth files from repo root...');
69
+ const whitelist = [
70
+ 'SKILL.md',
71
+ 'references',
72
+ 'memory',
73
+ 'templates',
74
+ 'scripts',
75
+ 'tools',
76
+ 'assets',
77
+ 'bin',
78
+ 'brand.json',
79
+ '.tidyfactor',
80
+ 'package.json',
81
+ 'AGENTS.md',
82
+ 'README.md',
83
+ 'README.ar.md',
84
+ 'LICENSE',
85
+ 'CHANGELOG.md'
86
+ ];
87
+
88
+ for (const item of whitelist) {
89
+ const srcPath = path.join(REPO_ROOT, item);
90
+ if (fs.existsSync(srcPath)) {
91
+ log(` + ${item}`);
92
+ copyRecursive(srcPath, path.join(STAGING_DIR, item));
93
+ }
94
+ }
95
+
96
+ log('zipping skill archive...');
97
+ const archiveName = `${SKILL_NAME}.skill`;
98
+ const versionedArchiveName = `${SKILL_NAME}-v${version}.skill`;
99
+ const archivePath = path.join(DIST_DIR, archiveName);
100
+ const versionedArchivePath = path.join(DIST_DIR, versionedArchiveName);
101
+
102
+ zipDirectory(STAGING_DIR, archivePath);
103
+ fs.copyFileSync(archivePath, versionedArchivePath);
104
+
105
+ const stats = fs.statSync(archivePath);
106
+ log(`done → dist\\${archiveName} (${(stats.size / 1024).toFixed(1)} KB)`);
107
+ log(`✓ Created versioned archive → dist\\${versionedArchiveName}`);
108
+
109
+ // Copy to Skills-LAB root
110
+ fs.copyFileSync(archivePath, path.join(SKILLS_LAB_ROOT, archiveName));
111
+ fs.copyFileSync(versionedArchivePath, path.join(SKILLS_LAB_ROOT, versionedArchiveName));
112
+ log(`✓ Updated Skills-LAB root archives → ${archiveName} & ${versionedArchiveName}`);
113
+
114
+ // Cross-agent synchronization
115
+ const targets = [LOCAL_AGENT_SKILL, GLOBAL_CONFIG_SKILL];
116
+ for (const target of targets) {
117
+ log(`synchronizing to target location: ${target}`);
118
+ if (fs.existsSync(target)) {
119
+ fs.rmSync(target, { recursive: true, force: true });
120
+ }
121
+ copyRecursive(STAGING_DIR, target);
122
+ }
123
+ log('✓ Completed cross-agent synchronization across all target locations.');
124
+ }
125
+
126
+ build();
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * validate-skill.js — Validates TidyFactor Design skill structure, frontmatter,
4
+ * command specifications, memory files, and parity between .agents, .claude-skill, and root wrappers.
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ const ROOT = path.resolve(__dirname, '..');
11
+ const AGENTS_SKILL_DIR = path.join(ROOT, '.agents', 'skills', 'tidyfactor-design');
12
+ const CLAUDE_SKILL_DIR = path.join(ROOT, '.claude-skill');
13
+
14
+ const REQUIRED_COMMANDS = [
15
+ 'study', 'brief', 'init', 'brand', 'typography', 'school', 'tokens', 'palette',
16
+ 'assets', 'layout', 'nav-footer', 'components', 'page', 'dashboard', 'motion',
17
+ 'states', 'flow', 'i18n', 'perf', 'audit', 'clone', 'retrofit', 'handoff', 'deploy'
18
+ ];
19
+
20
+ const autoSync = process.argv.includes('--sync') || process.argv.includes('--fix');
21
+
22
+ let errors = [];
23
+ let warnings = [];
24
+
25
+ function log(msg) {
26
+ console.log(`[validate-skill] ${msg}`);
27
+ }
28
+
29
+ function checkFrontmatter(filePath) {
30
+ if (!fs.existsSync(filePath)) {
31
+ errors.push(`Missing SKILL.md file: ${path.relative(ROOT, filePath)}`);
32
+ return;
33
+ }
34
+ const content = fs.readFileSync(filePath, 'utf8');
35
+ if (!content.startsWith('---')) {
36
+ errors.push(`SKILL.md frontmatter must start with '---': ${path.relative(ROOT, filePath)}`);
37
+ return;
38
+ }
39
+ const parts = content.split('---');
40
+ if (parts.length < 3) {
41
+ errors.push(`Invalid frontmatter format in: ${path.relative(ROOT, filePath)}`);
42
+ return;
43
+ }
44
+ const yaml = parts[1];
45
+ if (!yaml.includes('name:') || !yaml.includes('description:')) {
46
+ errors.push(`Frontmatter missing required 'name' or 'description': ${path.relative(ROOT, filePath)}`);
47
+ } else {
48
+ log(`✓ Frontmatter valid for ${path.relative(ROOT, filePath)}`);
49
+ }
50
+ }
51
+
52
+ function checkCommandsAndParity() {
53
+ const agentsCmdDir = path.join(AGENTS_SKILL_DIR, 'references', 'commands');
54
+ const claudeCmdDir = path.join(CLAUDE_SKILL_DIR, 'references', 'commands');
55
+ const rootCmdDir = path.join(ROOT, 'references', 'commands');
56
+
57
+ // Sync root SKILL.md and .claude-skill SKILL.md from .agents/skills/tidyfactor-design/SKILL.md if --sync
58
+ const canonicalSkillMd = path.join(AGENTS_SKILL_DIR, 'SKILL.md');
59
+ if (fs.existsSync(canonicalSkillMd)) {
60
+ const canonicalContent = fs.readFileSync(canonicalSkillMd, 'utf8');
61
+ const rootSkillMd = path.join(ROOT, 'SKILL.md');
62
+ const claudeSkillMd = path.join(CLAUDE_SKILL_DIR, 'SKILL.md');
63
+
64
+ if (autoSync) {
65
+ fs.writeFileSync(rootSkillMd, canonicalContent, 'utf8');
66
+ fs.writeFileSync(claudeSkillMd, canonicalContent, 'utf8');
67
+ log(`⚡ Auto-synced SKILL.md to root and .claude-skill`);
68
+ }
69
+ }
70
+
71
+ for (const cmd of REQUIRED_COMMANDS) {
72
+ const agentsFile = path.join(agentsCmdDir, `${cmd}.md`);
73
+ const claudeFile = path.join(claudeCmdDir, `${cmd}.md`);
74
+ const rootFile = path.join(rootCmdDir, `${cmd}.md`);
75
+
76
+ if (!fs.existsSync(agentsFile)) {
77
+ errors.push(`Missing Antigravity command spec for '${cmd}': ${path.relative(ROOT, agentsFile)}`);
78
+ continue;
79
+ }
80
+
81
+ if (autoSync) {
82
+ fs.mkdirSync(path.dirname(claudeFile), { recursive: true });
83
+ fs.mkdirSync(path.dirname(rootFile), { recursive: true });
84
+ fs.copyFileSync(agentsFile, claudeFile);
85
+ fs.copyFileSync(agentsFile, rootFile);
86
+ log(`⚡ Auto-synced '${cmd}.md' across wrappers`);
87
+ } else {
88
+ if (!fs.existsSync(claudeFile)) errors.push(`Missing Claude command spec for '${cmd}'`);
89
+ if (!fs.existsSync(rootFile)) errors.push(`Missing root command spec for '${cmd}'`);
90
+ }
91
+ }
92
+ log(`✓ All ${REQUIRED_COMMANDS.length} command specs verified with parity check across targets`);
93
+ }
94
+
95
+ function checkDirectory(dirName, label) {
96
+ const targetDir = path.join(ROOT, dirName);
97
+ if (!fs.existsSync(targetDir)) {
98
+ errors.push(`Missing required directory: ${dirName}`);
99
+ } else {
100
+ log(`✓ Directory verified: ${label}`);
101
+ }
102
+ }
103
+
104
+ function checkMemoryFiles() {
105
+ const memoryDir = path.join(ROOT, 'memory');
106
+ if (!fs.existsSync(memoryDir)) return;
107
+ const files = fs.readdirSync(memoryDir).filter(f => f.endsWith('.md'));
108
+ log(`✓ Verified ${files.length} memory reference files in memory/`);
109
+ }
110
+
111
+ function main() {
112
+ log('Starting skill validation check...');
113
+
114
+ checkFrontmatter(path.join(AGENTS_SKILL_DIR, 'SKILL.md'));
115
+ checkFrontmatter(path.join(CLAUDE_SKILL_DIR, 'SKILL.md'));
116
+ checkFrontmatter(path.join(ROOT, 'SKILL.md'));
117
+
118
+ checkCommandsAndParity();
119
+ checkDirectory('memory', 'memory');
120
+ checkMemoryFiles();
121
+ checkDirectory('templates', 'templates/layouts');
122
+
123
+ const agentsMd = path.join(ROOT, 'AGENTS.md');
124
+ if (!fs.existsSync(agentsMd)) {
125
+ errors.push('Missing root AGENTS.md');
126
+ } else {
127
+ log('✓ Root AGENTS.md verified');
128
+ }
129
+
130
+ if (warnings.length > 0) {
131
+ console.warn('\n⚠ Validation warnings:');
132
+ warnings.forEach(w => console.warn(` ${w}`));
133
+ }
134
+
135
+ if (errors.length > 0) {
136
+ console.error('\n✖ Validation failed with errors:');
137
+ errors.forEach(e => console.error(` ❌ ${e}`));
138
+ process.exit(1);
139
+ }
140
+
141
+ log('✨ All skill validation checks passed successfully!\n');
142
+ }
143
+
144
+ main();
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ validate_skill.py — TidyFactor Design Release & Integrity Validator.
4
+ Checks:
5
+ 1. SemVer synchronization across package.json, .tidyfactor, brand.json, CHANGELOG.md.
6
+ 2. License consistency (Apache-2.0).
7
+ 3. Existence of all files referenced in SKILL.md.
8
+ 4. Validation checklists in all workflow files.
9
+ 5. Absence of machine-specific absolute paths.
10
+ """
11
+
12
+ import sys
13
+ import os
14
+ import json
15
+ import re
16
+ from pathlib import Path
17
+
18
+ # Ensure UTF-8 output on Windows terminal
19
+ if sys.platform == "win32":
20
+ sys.stdout.reconfigure(encoding="utf-8")
21
+ sys.stderr.reconfigure(encoding="utf-8")
22
+
23
+ def main():
24
+ root = Path(__file__).resolve().parent.parent
25
+ errors = []
26
+
27
+ print("=" * 60)
28
+ print(" RUNNING TIDYFACTOR DESIGN RELEASE VALIDATION")
29
+ print("=" * 60)
30
+
31
+ # 1. SemVer Synchronization Check
32
+ print("\n[1] Checking SemVer synchronization across metadata...")
33
+ pkg_file = root / "package.json"
34
+ tf_file = root / ".tidyfactor"
35
+ brand_file = root / "brand.json"
36
+ cl_file = root / "CHANGELOG.md"
37
+
38
+ pkg_ver = json.loads(pkg_file.read_text(encoding="utf-8")).get("version") if pkg_file.exists() else None
39
+ tf_ver = json.loads(tf_file.read_text(encoding="utf-8")).get("version") if tf_file.exists() else None
40
+
41
+ brand_data = json.loads(brand_file.read_text(encoding="utf-8")) if brand_file.exists() else {}
42
+ brand_ver = brand_data.get("version") or brand_data.get("meta", {}).get("version")
43
+
44
+ print(f" package.json : {pkg_ver}")
45
+ print(f" .tidyfactor : {tf_ver}")
46
+ print(f" brand.json : {brand_ver}")
47
+
48
+ if not (pkg_ver and tf_ver and brand_ver and pkg_ver == tf_ver == brand_ver):
49
+ errors.append(f"Version mismatch: package.json({pkg_ver}) vs .tidyfactor({tf_ver}) vs brand.json({brand_ver})")
50
+ else:
51
+ print(f" [OK] Version {pkg_ver} synchronized across all JSON metadata.")
52
+
53
+ if cl_file.exists():
54
+ cl_text = cl_file.read_text(encoding="utf-8")
55
+ if f"## [{pkg_ver}]" not in cl_text and f"[{pkg_ver}]" not in cl_text:
56
+ errors.append(f"CHANGELOG.md is missing release entry for version [{pkg_ver}].")
57
+ else:
58
+ print(f" [OK] CHANGELOG.md contains release entry for [{pkg_ver}].")
59
+ else:
60
+ errors.append("Missing CHANGELOG.md.")
61
+
62
+ # 2. License check
63
+ print("\n[2] Checking license consistency...")
64
+ license_file = root / "LICENSE"
65
+ if license_file.exists():
66
+ print(" [OK] LICENSE file exists (Apache-2.0).")
67
+ else:
68
+ errors.append("Missing LICENSE file.")
69
+
70
+ # 3. Check referenced files in SKILL.md
71
+ print("\n[3] Checking SKILL.md referenced files exist on disk...")
72
+ skill_md = root / "SKILL.md"
73
+ if skill_md.exists():
74
+ content = skill_md.read_text(encoding="utf-8")
75
+ refs = re.findall(r'(?:references|memory|commands|workflows)/[a-zA-Z0-9_\-\./]+(?:\.md|\.json)?', content)
76
+ for ref in sorted(set(refs)):
77
+ target = root / ref
78
+ if not target.exists() and not (root / "references" / ref).exists():
79
+ if not (root / ref).is_dir() and not (root / "references" / ref).is_dir():
80
+ errors.append(f"SKILL.md references non-existent file: {ref}")
81
+ else:
82
+ print(f" [OK] Found {ref}")
83
+ else:
84
+ errors.append("Missing SKILL.md.")
85
+
86
+ # 4. Check workflow validation checklists
87
+ print("\n[4] Checking workflow checklists...")
88
+ wf_dir = root / "references" / "workflows"
89
+ if wf_dir.exists():
90
+ for wf in wf_dir.glob("*.md"):
91
+ txt = wf.read_text(encoding="utf-8").lower()
92
+ if "validation checklist" not in txt:
93
+ errors.append(f"Workflow {wf.name} missing '## Validation checklist'")
94
+ else:
95
+ print(f" [OK] {wf.name} has Validation checklist.")
96
+
97
+ # 5. Audit for leaked machine paths
98
+ print("\n[5] Auditing for leaked machine-specific absolute paths...")
99
+ for ext in ["*.md", "*.json", "*.js", "*.py"]:
100
+ for file in root.rglob(ext):
101
+ if any(part in file.parts for part in [".git", "node_modules", "dist", "assets"]):
102
+ continue
103
+ text = file.read_text(encoding="utf-8", errors="ignore")
104
+ if re.search(r'[A-Za-z]:\\(?:Users|wamp64|Dev-Studio)', text, re.IGNORECASE):
105
+ if file.name not in ["release_suite.py", "audit_all_skills.py"]:
106
+ errors.append(f"Machine-specific absolute path found in: {file.relative_to(root)}")
107
+
108
+ print("\n" + "=" * 60)
109
+ if errors:
110
+ print(f"[FAIL] {len(errors)} validation error(s) found:")
111
+ for err in errors:
112
+ print(f" - {err}")
113
+ print("=" * 60)
114
+ sys.exit(1)
115
+ else:
116
+ print("[SUCCESS] ALL SKILL INTEGRITY CHECKS PASSED!")
117
+ print("=" * 60)
118
+ sys.exit(0)
119
+
120
+ if __name__ == "__main__":
121
+ main()