@tidyfactor/marketing 1.3.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 (50) hide show
  1. package/.tidyfactor +52 -0
  2. package/AGENTS.md +41 -0
  3. package/CHANGELOG.md +53 -0
  4. package/LICENSE +17 -0
  5. package/README.ar.md +299 -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 +320 -0
  11. package/README.pt.md +44 -0
  12. package/README.zh.md +44 -0
  13. package/SKILL-REGISTRY.md +36 -0
  14. package/SKILL.md +30 -0
  15. package/VISION.md +25 -0
  16. package/assets/hero-banner.png +0 -0
  17. package/assets/og-default.png +0 -0
  18. package/bin/add-skill.js +50 -0
  19. package/bin/create-kit.js +101 -0
  20. package/bin/remove-skill.js +24 -0
  21. package/brand.json +67 -0
  22. package/package.json +73 -0
  23. package/references/commands/advertising.md +27 -0
  24. package/references/commands/brief.md +17 -0
  25. package/references/commands/content.md +26 -0
  26. package/references/commands/email.md +26 -0
  27. package/references/commands/growth.md +27 -0
  28. package/references/commands/promotions.md +26 -0
  29. package/references/commands/social.md +27 -0
  30. package/references/commands/strategy.md +25 -0
  31. package/references/memory/ad-copy-templates.md +93 -0
  32. package/references/memory/arabic-writing.md +71 -0
  33. package/references/memory/decision-points.md +73 -0
  34. package/references/memory/frameworks.md +86 -0
  35. package/references/memory/lifecycle-flows.md +106 -0
  36. package/references/memory/metrics-benchmarks.md +70 -0
  37. package/references/memory/philosophy.md +16 -0
  38. package/references/memory/platform-specs.md +75 -0
  39. package/references/memory/promotions-math.md +56 -0
  40. package/references/memory/quality-bar.md +55 -0
  41. package/references/workflows/brief.md +72 -0
  42. package/references/workflows/campaign-launch.md +73 -0
  43. package/references/workflows/content-engine.md +68 -0
  44. package/references/workflows/email-lifecycle.md +55 -0
  45. package/references/workflows/paid-acquisition.md +66 -0
  46. package/references/workflows/promo-conversion.md +58 -0
  47. package/references/workflows/social-growth.md +65 -0
  48. package/references/workflows/viral-retention.md +63 -0
  49. package/tools/build-skill.js +206 -0
  50. package/tools/validate_skill.py +112 -0
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ validate_skill.py — TidyFactor Marketing integrity and release validation script.
4
+ Verifies:
5
+ 1. Version synchronization across .tidyfactor, package.json, brand.json, and CHANGELOG.md.
6
+ 2. License consistency across files.
7
+ 3. Link integrity between SKILL.md and referenced command/workflow/memory files.
8
+ 4. Absence of hardcoded absolute machine paths in markdown files.
9
+ """
10
+
11
+ import sys
12
+ import os
13
+ import re
14
+ import json
15
+ from pathlib import Path
16
+
17
+ ROOT = Path(__file__).resolve().parent.parent
18
+
19
+ # Set stdout/stderr encoding to UTF-8 on Windows
20
+ if sys.platform == "win32":
21
+ sys.stdout.reconfigure(encoding="utf-8")
22
+ sys.stderr.reconfigure(encoding="utf-8")
23
+
24
+ def validate():
25
+ failures = []
26
+ print("=" * 60)
27
+ print(" RUNNING TIDYFACTOR MARKETING RELEASE VALIDATION")
28
+ print("=" * 60)
29
+
30
+ # 1. Version Sync Check
31
+ print("\n[1] Checking SemVer synchronization across metadata...")
32
+ with open(ROOT / "package.json", "r", encoding="utf-8") as f:
33
+ pkg_ver = json.load(f).get("version")
34
+ with open(ROOT / ".tidyfactor", "r", encoding="utf-8") as f:
35
+ tf_ver = json.load(f).get("version")
36
+ with open(ROOT / "brand.json", "r", encoding="utf-8") as f:
37
+ brand_ver = json.load(f).get("version")
38
+
39
+ with open(ROOT / "CHANGELOG.md", "r", encoding="utf-8") as f:
40
+ changelog_content = f.read()
41
+
42
+ print(f" package.json : {pkg_ver}")
43
+ print(f" .tidyfactor : {tf_ver}")
44
+ print(f" brand.json : {brand_ver}")
45
+
46
+ if not (pkg_ver == tf_ver == brand_ver):
47
+ failures.append(f"Version mismatch: package.json({pkg_ver}) vs .tidyfactor({tf_ver}) vs brand.json({brand_ver})")
48
+ else:
49
+ print(f" [OK] Version {pkg_ver} synchronized across all JSON metadata.")
50
+
51
+ if f"## [{pkg_ver}]" not in changelog_content:
52
+ failures.append(f"CHANGELOG.md is missing release entry for version [{pkg_ver}].")
53
+ else:
54
+ print(f" [OK] CHANGELOG.md contains release entry for [{pkg_ver}].")
55
+
56
+ # 2. License Consistency Check
57
+ print("\n[2] Checking license consistency...")
58
+ with open(ROOT / "package.json", "r", encoding="utf-8") as f:
59
+ pkg_lic = json.load(f).get("license")
60
+ with open(ROOT / "README.md", "r", encoding="utf-8") as f:
61
+ readme_en = f.read()
62
+ with open(ROOT / "README.ar.md", "r", encoding="utf-8") as f:
63
+ readme_ar = f.read()
64
+
65
+ if "License-MIT" in readme_en or "License-MIT" in readme_ar:
66
+ failures.append("README contains MIT badge while package is licensed under Apache-2.0.")
67
+ else:
68
+ print(" [OK] License badges match Apache-2.0.")
69
+
70
+ # 3. Path reference and link checks from SKILL.md
71
+ print("\n[3] Checking SKILL.md referenced files exist on disk...")
72
+ with open(ROOT / "SKILL.md", "r", encoding="utf-8") as f:
73
+ skill_content = f.read()
74
+
75
+ # Find all references like references/commands/*.md, workflows/*.md, memory/*.md
76
+ refs = re.findall(r'(?:references/)?((?:commands|workflows|memory)/[a-zA-Z0-9_\-\.\*]+)', skill_content)
77
+ for ref in refs:
78
+ if "*" in ref:
79
+ continue
80
+ full_ref_path = ROOT / "references" / ref
81
+ if not full_ref_path.exists():
82
+ failures.append(f"Broken link in SKILL.md: references/{ref} does not exist on disk.")
83
+ else:
84
+ print(f" [OK] Found references/{ref}")
85
+
86
+ # 4. Check for personal/machine-specific absolute paths
87
+ print("\n[4] Auditing for leaked machine-specific absolute paths...")
88
+ leaked_path_pattern = re.compile(r'[a-zA-Z]:\\[wW]amp64\\', re.IGNORECASE)
89
+ for ext in ["*.md", "*.json", "*.js", "*.py"]:
90
+ for file_path in ROOT.rglob(ext):
91
+ if "dist" in file_path.parts or "__pycache__" in file_path.parts:
92
+ continue
93
+ with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
94
+ content = f.read()
95
+ if leaked_path_pattern.search(content):
96
+ rel = file_path.relative_to(ROOT)
97
+ failures.append(f"Leaked machine-specific absolute path found in {rel}")
98
+
99
+ print("\n" + "=" * 60)
100
+ if failures:
101
+ print(f"[FAIL] {len(failures)} validation error(s) found:")
102
+ for err in failures:
103
+ print(f" - {err}")
104
+ print("=" * 60)
105
+ sys.exit(1)
106
+ else:
107
+ print("[SUCCESS] ALL SKILL INTEGRITY CHECKS PASSED!")
108
+ print("=" * 60)
109
+ sys.exit(0)
110
+
111
+ if __name__ == "__main__":
112
+ validate()