@nextsparkjs/ai-workflow 0.1.0-beta.100

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 (272) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +115 -0
  3. package/claude/_docs/workflows-optimizations.md +359 -0
  4. package/claude/agents/api-tester.md +634 -0
  5. package/claude/agents/architecture-supervisor.md +1351 -0
  6. package/claude/agents/backend-developer.md +997 -0
  7. package/claude/agents/backend-validator.md +417 -0
  8. package/claude/agents/bdd-docs-writer.md +737 -0
  9. package/claude/agents/block-developer.md +677 -0
  10. package/claude/agents/code-reviewer.md +1432 -0
  11. package/claude/agents/db-developer.md +721 -0
  12. package/claude/agents/db-validator.md +407 -0
  13. package/claude/agents/demo-video-generator.md +493 -0
  14. package/claude/agents/documentation-writer.md +1268 -0
  15. package/claude/agents/frontend-developer.md +1234 -0
  16. package/claude/agents/frontend-validator.md +777 -0
  17. package/claude/agents/functional-validator.md +630 -0
  18. package/claude/agents/mock-analyst.md +387 -0
  19. package/claude/agents/product-manager.md +963 -0
  20. package/claude/agents/qa-automation.md +1762 -0
  21. package/claude/agents/release-manager.md +634 -0
  22. package/claude/agents/selectors-translator.md +262 -0
  23. package/claude/agents/unit-test-writer.md +785 -0
  24. package/claude/agents/visual-comparator.md +329 -0
  25. package/claude/agents/workflow-maintainer.md +352 -0
  26. package/claude/commands/do/README.md +88 -0
  27. package/claude/commands/do/create-api.md +64 -0
  28. package/claude/commands/do/create-entity.md +66 -0
  29. package/claude/commands/do/create-migration.md +64 -0
  30. package/claude/commands/do/create-plugin.md +56 -0
  31. package/claude/commands/do/create-theme.md +70 -0
  32. package/claude/commands/do/mock-data.md +67 -0
  33. package/claude/commands/do/reset-db.md +71 -0
  34. package/claude/commands/do/setup-scheduled-action.md +75 -0
  35. package/claude/commands/do/sync-code-review.md +117 -0
  36. package/claude/commands/do/update-selectors.md +112 -0
  37. package/claude/commands/do/use-skills.md +90 -0
  38. package/claude/commands/do/validate-blocks.md +69 -0
  39. package/claude/commands/how-to/README.md +261 -0
  40. package/claude/commands/how-to/add-metadata.md +692 -0
  41. package/claude/commands/how-to/add-taxonomies.md +806 -0
  42. package/claude/commands/how-to/add-translations.md +571 -0
  43. package/claude/commands/how-to/create-api.md +577 -0
  44. package/claude/commands/how-to/create-block.md +575 -0
  45. package/claude/commands/how-to/create-child-entities.md +771 -0
  46. package/claude/commands/how-to/create-entity.md +597 -0
  47. package/claude/commands/how-to/create-migrations.md +605 -0
  48. package/claude/commands/how-to/create-plugin.md +654 -0
  49. package/claude/commands/how-to/customize-app.md +481 -0
  50. package/claude/commands/how-to/customize-dashboard.md +553 -0
  51. package/claude/commands/how-to/customize-theme.md +438 -0
  52. package/claude/commands/how-to/define-features-flows.md +632 -0
  53. package/claude/commands/how-to/deploy.md +507 -0
  54. package/claude/commands/how-to/handle-file-uploads.md +746 -0
  55. package/claude/commands/how-to/implement-search.md +1001 -0
  56. package/claude/commands/how-to/install-plugins.md +352 -0
  57. package/claude/commands/how-to/manage-test-coverage.md +984 -0
  58. package/claude/commands/how-to/run-tests.md +400 -0
  59. package/claude/commands/how-to/set-app-languages.md +601 -0
  60. package/claude/commands/how-to/set-plans-and-permissions.md +575 -0
  61. package/claude/commands/how-to/set-scheduled-actions.md +527 -0
  62. package/claude/commands/how-to/set-user-roles-and-permissions.md +550 -0
  63. package/claude/commands/how-to/setup-authentication.md +388 -0
  64. package/claude/commands/how-to/setup-claude-code.md +440 -0
  65. package/claude/commands/how-to/setup-database.md +274 -0
  66. package/claude/commands/how-to/setup-email-providers.md +598 -0
  67. package/claude/commands/how-to/setup-mobile-dev.md +627 -0
  68. package/claude/commands/how-to/start.md +500 -0
  69. package/claude/commands/how-to/use-devtools.md +639 -0
  70. package/claude/commands/how-to/use-superadmin.md +622 -0
  71. package/claude/commands/session/README.md +193 -0
  72. package/claude/commands/session/block-create.md +190 -0
  73. package/claude/commands/session/block-list.md +203 -0
  74. package/claude/commands/session/block-update.md +192 -0
  75. package/claude/commands/session/block-validate.md +218 -0
  76. package/claude/commands/session/changelog.md +115 -0
  77. package/claude/commands/session/close.md +225 -0
  78. package/claude/commands/session/commit.md +174 -0
  79. package/claude/commands/session/db-entity.md +206 -0
  80. package/claude/commands/session/db-fix.md +212 -0
  81. package/claude/commands/session/db-sample.md +206 -0
  82. package/claude/commands/session/demo.md +178 -0
  83. package/claude/commands/session/doc-bdd.md +207 -0
  84. package/claude/commands/session/doc-feature.md +218 -0
  85. package/claude/commands/session/doc-read.md +225 -0
  86. package/claude/commands/session/execute.md +204 -0
  87. package/claude/commands/session/explain.md +202 -0
  88. package/claude/commands/session/fix-bug.md +210 -0
  89. package/claude/commands/session/fix-build.md +182 -0
  90. package/claude/commands/session/fix-test.md +189 -0
  91. package/claude/commands/session/pending.md +232 -0
  92. package/claude/commands/session/refine.md +188 -0
  93. package/claude/commands/session/resume.md +192 -0
  94. package/claude/commands/session/review.md +192 -0
  95. package/claude/commands/session/scope-change.md +181 -0
  96. package/claude/commands/session/start-blocks.md +347 -0
  97. package/claude/commands/session/start.md +604 -0
  98. package/claude/commands/session/status.md +169 -0
  99. package/claude/commands/session/test-fix.md +221 -0
  100. package/claude/commands/session/test-run.md +203 -0
  101. package/claude/commands/session/test-write.md +242 -0
  102. package/claude/commands/session/validate.md +162 -0
  103. package/claude/config/context.json +40 -0
  104. package/claude/config/github.json +69 -0
  105. package/claude/config/github.schema.json +106 -0
  106. package/claude/config/team.json +46 -0
  107. package/claude/config/team.schema.json +106 -0
  108. package/claude/config/workspace.json +43 -0
  109. package/claude/config/workspace.schema.json +75 -0
  110. package/claude/skills/README.md +228 -0
  111. package/claude/skills/accessibility/SKILL.md +573 -0
  112. package/claude/skills/api-bypass-layers/SKILL.md +550 -0
  113. package/claude/skills/asana-integration/SKILL.md +499 -0
  114. package/claude/skills/better-auth/SKILL.md +666 -0
  115. package/claude/skills/billing-subscriptions/SKILL.md +660 -0
  116. package/claude/skills/block-decision-matrix/SKILL.md +359 -0
  117. package/claude/skills/clickup-integration/SKILL.md +434 -0
  118. package/claude/skills/core-theme-responsibilities/SKILL.md +485 -0
  119. package/claude/skills/create-plugin/SKILL.md +425 -0
  120. package/claude/skills/create-theme/SKILL.md +331 -0
  121. package/claude/skills/cypress-api/SKILL.md +511 -0
  122. package/claude/skills/cypress-api/scripts/generate-api-controller.py +329 -0
  123. package/claude/skills/cypress-api/scripts/generate-api-test.py +930 -0
  124. package/claude/skills/cypress-e2e/SKILL.md +526 -0
  125. package/claude/skills/cypress-e2e/scripts/extract-selectors.py +383 -0
  126. package/claude/skills/cypress-e2e/scripts/generate-uat-test.py +788 -0
  127. package/claude/skills/cypress-selectors/SKILL.md +309 -0
  128. package/claude/skills/cypress-selectors/scripts/extract-missing.py +243 -0
  129. package/claude/skills/cypress-selectors/scripts/generate-block-selectors.py +283 -0
  130. package/claude/skills/cypress-selectors/scripts/validate-selectors.py +145 -0
  131. package/claude/skills/database-migrations/SKILL.md +335 -0
  132. package/claude/skills/database-migrations/scripts/generate-sample-data.py +284 -0
  133. package/claude/skills/database-migrations/scripts/validate-migration.py +323 -0
  134. package/claude/skills/design-system/SKILL.md +682 -0
  135. package/claude/skills/documentation/SKILL.md +540 -0
  136. package/claude/skills/entity-api/SKILL.md +482 -0
  137. package/claude/skills/entity-system/SKILL.md +635 -0
  138. package/claude/skills/entity-system/scripts/generate-child-migration.py +298 -0
  139. package/claude/skills/entity-system/scripts/generate-metas-migration.py +233 -0
  140. package/claude/skills/entity-system/scripts/generate-migration.py +382 -0
  141. package/claude/skills/entity-system/scripts/generate-sample-data.py +418 -0
  142. package/claude/skills/entity-system/scripts/scaffold-entity.py +661 -0
  143. package/claude/skills/github/SKILL.md +467 -0
  144. package/claude/skills/i18n-nextintl/SKILL.md +302 -0
  145. package/claude/skills/i18n-nextintl/scripts/add-translation.py +243 -0
  146. package/claude/skills/i18n-nextintl/scripts/extract-hardcoded.py +246 -0
  147. package/claude/skills/i18n-nextintl/scripts/validate-translations.py +260 -0
  148. package/claude/skills/impact-analysis/SKILL.md +203 -0
  149. package/claude/skills/jest-unit/SKILL.md +306 -0
  150. package/claude/skills/jest-unit/references/component-testing.md +371 -0
  151. package/claude/skills/jest-unit/references/mocking-patterns.md +380 -0
  152. package/claude/skills/jest-unit/references/service-hook-testing.md +454 -0
  153. package/claude/skills/jira-integration/SKILL.md +539 -0
  154. package/claude/skills/media-library/SKILL.md +743 -0
  155. package/claude/skills/mock-analysis/SKILL.md +276 -0
  156. package/claude/skills/monorepo-architecture/SKILL.md +162 -0
  157. package/claude/skills/nextjs-api-development/SKILL.md +364 -0
  158. package/claude/skills/nextjs-api-development/scripts/generate-crud-tests.py +456 -0
  159. package/claude/skills/nextjs-api-development/scripts/scaffold-endpoint.py +481 -0
  160. package/claude/skills/nextjs-api-development/scripts/validate-api.py +283 -0
  161. package/claude/skills/notion-integration/SKILL.md +641 -0
  162. package/claude/skills/npm-development-workflow/SKILL.md +480 -0
  163. package/claude/skills/page-builder-blocks/SKILL.md +530 -0
  164. package/claude/skills/page-builder-blocks/scripts/scaffold-block.py +444 -0
  165. package/claude/skills/permissions-system/SKILL.md +619 -0
  166. package/claude/skills/plugins/SKILL.md +340 -0
  167. package/claude/skills/plugins/references/plugin-templates.md +414 -0
  168. package/claude/skills/plugins/references/plugin-testing.md +353 -0
  169. package/claude/skills/plugins/references/plugin-types.md +198 -0
  170. package/claude/skills/plugins/scripts/scaffold-plugin.py +443 -0
  171. package/claude/skills/pom-patterns/SKILL.md +452 -0
  172. package/claude/skills/pom-patterns/scripts/generate-pom.py +392 -0
  173. package/claude/skills/rate-limiting/SKILL.md +342 -0
  174. package/claude/skills/react-best-practices/AGENTS.md +2410 -0
  175. package/claude/skills/react-best-practices/README.md +123 -0
  176. package/claude/skills/react-best-practices/SKILL.md +125 -0
  177. package/claude/skills/react-best-practices/metadata.json +15 -0
  178. package/claude/skills/react-best-practices/rules/_sections.md +46 -0
  179. package/claude/skills/react-best-practices/rules/_template.md +28 -0
  180. package/claude/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  181. package/claude/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
  182. package/claude/skills/react-best-practices/rules/async-api-routes.md +38 -0
  183. package/claude/skills/react-best-practices/rules/async-defer-await.md +80 -0
  184. package/claude/skills/react-best-practices/rules/async-dependencies.md +36 -0
  185. package/claude/skills/react-best-practices/rules/async-parallel.md +28 -0
  186. package/claude/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
  187. package/claude/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
  188. package/claude/skills/react-best-practices/rules/bundle-conditional.md +31 -0
  189. package/claude/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
  190. package/claude/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  191. package/claude/skills/react-best-practices/rules/bundle-preload.md +50 -0
  192. package/claude/skills/react-best-practices/rules/client-event-listeners.md +74 -0
  193. package/claude/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
  194. package/claude/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
  195. package/claude/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
  196. package/claude/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
  197. package/claude/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
  198. package/claude/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  199. package/claude/skills/react-best-practices/rules/js-cache-storage.md +70 -0
  200. package/claude/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  201. package/claude/skills/react-best-practices/rules/js-early-exit.md +50 -0
  202. package/claude/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  203. package/claude/skills/react-best-practices/rules/js-index-maps.md +37 -0
  204. package/claude/skills/react-best-practices/rules/js-length-check-first.md +49 -0
  205. package/claude/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  206. package/claude/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  207. package/claude/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  208. package/claude/skills/react-best-practices/rules/rendering-activity.md +26 -0
  209. package/claude/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  210. package/claude/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
  211. package/claude/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  212. package/claude/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  213. package/claude/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  214. package/claude/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  215. package/claude/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  216. package/claude/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  217. package/claude/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  218. package/claude/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
  219. package/claude/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  220. package/claude/skills/react-best-practices/rules/rerender-memo.md +44 -0
  221. package/claude/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  222. package/claude/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
  223. package/claude/skills/react-best-practices/rules/server-cache-lru.md +41 -0
  224. package/claude/skills/react-best-practices/rules/server-cache-react.md +76 -0
  225. package/claude/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
  226. package/claude/skills/react-best-practices/rules/server-serialization.md +38 -0
  227. package/claude/skills/react-patterns/SKILL.md +688 -0
  228. package/claude/skills/registry-system/SKILL.md +331 -0
  229. package/claude/skills/scheduled-actions/SKILL.md +671 -0
  230. package/claude/skills/scope-enforcement/SKILL.md +542 -0
  231. package/claude/skills/scope-enforcement/scripts/validate-scope.py +357 -0
  232. package/claude/skills/server-actions/SKILL.md +493 -0
  233. package/claude/skills/service-layer/SKILL.md +587 -0
  234. package/claude/skills/session-management/SKILL.md +266 -0
  235. package/claude/skills/session-management/scripts/create-session.py +166 -0
  236. package/claude/skills/session-management/scripts/iteration-close.sh +105 -0
  237. package/claude/skills/session-management/scripts/iteration-init.sh +180 -0
  238. package/claude/skills/session-management/scripts/session-archive.sh +87 -0
  239. package/claude/skills/session-management/scripts/session-close.sh +133 -0
  240. package/claude/skills/session-management/scripts/session-init.sh +225 -0
  241. package/claude/skills/session-management/scripts/session-list.sh +163 -0
  242. package/claude/skills/session-management/scripts/split-plan.sh +116 -0
  243. package/claude/skills/shadcn-components/SKILL.md +586 -0
  244. package/claude/skills/shadcn-theming/SKILL.md +446 -0
  245. package/claude/skills/suspense-loading/SKILL.md +280 -0
  246. package/claude/skills/tailwind-theming/SKILL.md +507 -0
  247. package/claude/skills/tanstack-query/SKILL.md +608 -0
  248. package/claude/skills/test-coverage/SKILL.md +239 -0
  249. package/claude/skills/web-design-guidelines/SKILL.md +39 -0
  250. package/claude/skills/zod-validation/SKILL.md +537 -0
  251. package/claude/templates/blocks/progress.md +86 -0
  252. package/claude/templates/iteration/changes.md +61 -0
  253. package/claude/templates/iteration/progress.md +55 -0
  254. package/claude/templates/log.md +31 -0
  255. package/claude/templates/story/context.md +77 -0
  256. package/claude/templates/story/pendings.md +37 -0
  257. package/claude/templates/story/plan.md +299 -0
  258. package/claude/templates/story/requirements.md +109 -0
  259. package/claude/templates/story/scope.json +10 -0
  260. package/claude/templates/story/tests.md +91 -0
  261. package/claude/templates/task/progress.md +58 -0
  262. package/claude/templates/task/requirements.md +54 -0
  263. package/claude/workflows/README.md +154 -0
  264. package/claude/workflows/blocks.md +614 -0
  265. package/claude/workflows/story.md +1207 -0
  266. package/claude/workflows/task.md +927 -0
  267. package/claude/workflows/tweak.md +527 -0
  268. package/cursor/.gitkeep +0 -0
  269. package/package.json +35 -0
  270. package/scripts/postinstall.mjs +198 -0
  271. package/scripts/setup.mjs +282 -0
  272. package/scripts/sync.mjs +209 -0
@@ -0,0 +1,246 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Extract Hardcoded Strings Script
4
+
5
+ Finds hardcoded user-facing strings in React/TypeScript components that should
6
+ be translated using next-intl.
7
+
8
+ Usage:
9
+ python extract-hardcoded.py --path PATH [--dry-run]
10
+
11
+ Options:
12
+ --path PATH Path to scan for hardcoded strings
13
+ --dry-run Preview findings without file details
14
+ --ignore-tests Skip test files (*.test.*, *.spec.*, *.cy.*)
15
+ """
16
+
17
+ import os
18
+ import re
19
+ import sys
20
+ import argparse
21
+ from pathlib import Path
22
+ from typing import List, Dict, Tuple
23
+
24
+
25
+ def get_active_theme() -> str:
26
+ """Get active theme from environment or default."""
27
+ return os.environ.get('NEXT_PUBLIC_ACTIVE_THEME', 'default')
28
+
29
+
30
+ def should_ignore_file(file_path: str, ignore_tests: bool) -> bool:
31
+ """Check if file should be ignored."""
32
+ ignore_patterns = [
33
+ 'node_modules',
34
+ '.next',
35
+ 'dist',
36
+ '.git',
37
+ '__pycache__',
38
+ 'messages/', # Translation files themselves
39
+ '.json',
40
+ '.md',
41
+ '.css',
42
+ '.scss',
43
+ ]
44
+
45
+ if ignore_tests:
46
+ ignore_patterns.extend(['.test.', '.spec.', '.cy.'])
47
+
48
+ for pattern in ignore_patterns:
49
+ if pattern in file_path:
50
+ return True
51
+
52
+ return False
53
+
54
+
55
+ def extract_jsx_strings(content: str, file_path: str) -> List[Dict]:
56
+ """Extract potential hardcoded strings from JSX/TSX content."""
57
+ findings = []
58
+
59
+ # Pattern 1: Strings in JSX text content (between > and <)
60
+ # Matches: >Hello World< but not >{variable}<
61
+ jsx_text_pattern = r'>([A-Z][^<>{}\n]{2,})<'
62
+ for match in re.finditer(jsx_text_pattern, content):
63
+ text = match.group(1).strip()
64
+ if text and not text.startswith('{') and len(text) > 2:
65
+ line_num = content[:match.start()].count('\n') + 1
66
+ findings.append({
67
+ 'type': 'jsx_text',
68
+ 'text': text[:80] + ('...' if len(text) > 80 else ''),
69
+ 'line': line_num,
70
+ 'file': file_path,
71
+ 'suggestion': suggest_key(text)
72
+ })
73
+
74
+ # Pattern 2: Hardcoded strings in common props (title, placeholder, label, etc.)
75
+ prop_patterns = [
76
+ (r'title=["\']([^"\']+)["\']', 'title_prop'),
77
+ (r'placeholder=["\']([^"\']+)["\']', 'placeholder_prop'),
78
+ (r'label=["\']([^"\']+)["\']', 'label_prop'),
79
+ (r'alt=["\']([^"\']+)["\']', 'alt_prop'),
80
+ (r'aria-label=["\']([^"\']+)["\']', 'aria_label_prop'),
81
+ (r'description=["\']([^"\']+)["\']', 'description_prop'),
82
+ ]
83
+
84
+ for pattern, prop_type in prop_patterns:
85
+ for match in re.finditer(pattern, content, re.IGNORECASE):
86
+ text = match.group(1).strip()
87
+ # Skip if it looks like a variable or translation key
88
+ if text and not text.startswith('{') and not is_likely_non_text(text):
89
+ line_num = content[:match.start()].count('\n') + 1
90
+ findings.append({
91
+ 'type': prop_type,
92
+ 'text': text[:60] + ('...' if len(text) > 60 else ''),
93
+ 'line': line_num,
94
+ 'file': file_path,
95
+ 'suggestion': suggest_key(text)
96
+ })
97
+
98
+ # Pattern 3: String literals that look like user-facing text
99
+ # This catches: const message = "Welcome back!"
100
+ string_literal_pattern = r'(?:const|let|var)\s+\w+\s*=\s*["\']([A-Z][^"\']{5,})["\']'
101
+ for match in re.finditer(string_literal_pattern, content):
102
+ text = match.group(1).strip()
103
+ if not is_likely_non_text(text):
104
+ line_num = content[:match.start()].count('\n') + 1
105
+ findings.append({
106
+ 'type': 'string_literal',
107
+ 'text': text[:60] + ('...' if len(text) > 60 else ''),
108
+ 'line': line_num,
109
+ 'file': file_path,
110
+ 'suggestion': suggest_key(text)
111
+ })
112
+
113
+ return findings
114
+
115
+
116
+ def is_likely_non_text(text: str) -> bool:
117
+ """Check if string is likely NOT user-facing text."""
118
+ # Skip URLs, paths, technical strings
119
+ non_text_indicators = [
120
+ text.startswith('http'),
121
+ text.startswith('/'),
122
+ text.startswith('@'),
123
+ text.startswith('#'),
124
+ '.com' in text,
125
+ '.org' in text,
126
+ text.isupper() and '_' in text, # Constants like API_URL
127
+ len(text.split()) == 1 and text.islower(), # Single lowercase word
128
+ re.match(r'^[a-z-]+$', text), # kebab-case identifiers
129
+ re.match(r'^[a-zA-Z]+\.[a-zA-Z.]+$', text), # Dot notation
130
+ ]
131
+ return any(non_text_indicators)
132
+
133
+
134
+ def suggest_key(text: str) -> str:
135
+ """Suggest a translation key based on the text."""
136
+ # Take first few words, convert to camelCase
137
+ words = re.sub(r'[^a-zA-Z\s]', '', text).lower().split()[:4]
138
+ if not words:
139
+ return 'common.text'
140
+
141
+ # Convert to camelCase
142
+ key = words[0] + ''.join(w.title() for w in words[1:])
143
+ return f'common.{key}'
144
+
145
+
146
+ def scan_directory(path: str, ignore_tests: bool) -> List[Dict]:
147
+ """Scan directory for hardcoded strings."""
148
+ all_findings = []
149
+ path_obj = Path(path)
150
+
151
+ if path_obj.is_file():
152
+ files = [path_obj]
153
+ else:
154
+ files = list(path_obj.rglob('*.tsx')) + list(path_obj.rglob('*.ts'))
155
+
156
+ for file_path in files:
157
+ str_path = str(file_path)
158
+ if should_ignore_file(str_path, ignore_tests):
159
+ continue
160
+
161
+ try:
162
+ with open(file_path, 'r', encoding='utf-8') as f:
163
+ content = f.read()
164
+
165
+ # Skip files that already use translations properly
166
+ if 'useTranslations' in content or 'getTranslations' in content:
167
+ # Still check for any remaining hardcoded strings
168
+ pass
169
+
170
+ findings = extract_jsx_strings(content, str_path)
171
+ all_findings.extend(findings)
172
+
173
+ except Exception as e:
174
+ print(f"Warning: Could not read {file_path}: {e}")
175
+
176
+ return all_findings
177
+
178
+
179
+ def main():
180
+ parser = argparse.ArgumentParser(description='Find hardcoded strings')
181
+ parser.add_argument('--path', required=True, help='Path to scan')
182
+ parser.add_argument('--dry-run', action='store_true', help='Preview without details')
183
+ parser.add_argument('--ignore-tests', action='store_true', help='Skip test files')
184
+
185
+ args = parser.parse_args()
186
+
187
+ if not os.path.exists(args.path):
188
+ print(f"Error: Path not found: {args.path}")
189
+ return 1
190
+
191
+ print(f"\n{'=' * 60}")
192
+ print(f"SCANNING FOR HARDCODED STRINGS")
193
+ print(f"{'=' * 60}")
194
+ print(f"Path: {args.path}")
195
+ print(f"Ignore tests: {args.ignore_tests}")
196
+ print(f"{'=' * 60}\n")
197
+
198
+ findings = scan_directory(args.path, args.ignore_tests)
199
+
200
+ if not findings:
201
+ print("No hardcoded strings found.")
202
+ return 0
203
+
204
+ # Group by file
205
+ by_file: Dict[str, List[Dict]] = {}
206
+ for finding in findings:
207
+ file_path = finding['file']
208
+ if file_path not in by_file:
209
+ by_file[file_path] = []
210
+ by_file[file_path].append(finding)
211
+
212
+ print(f"Found {len(findings)} potential hardcoded strings in {len(by_file)} files:\n")
213
+
214
+ if args.dry_run:
215
+ # Summary only
216
+ for file_path, file_findings in sorted(by_file.items()):
217
+ rel_path = os.path.relpath(file_path)
218
+ print(f" {rel_path}: {len(file_findings)} findings")
219
+ else:
220
+ # Detailed output
221
+ for file_path, file_findings in sorted(by_file.items()):
222
+ rel_path = os.path.relpath(file_path)
223
+ print(f"\n{'-' * 60}")
224
+ print(f"FILE: {rel_path}")
225
+ print(f"{'-' * 60}")
226
+
227
+ for finding in file_findings:
228
+ print(f" Line {finding['line']}: [{finding['type']}]")
229
+ print(f" Text: \"{finding['text']}\"")
230
+ print(f" Suggested key: {finding['suggestion']}")
231
+ print()
232
+
233
+ print(f"\n{'=' * 60}")
234
+ print(f"SUMMARY: {len(findings)} hardcoded strings in {len(by_file)} files")
235
+ print(f"{'=' * 60}")
236
+ print("\nTo fix:")
237
+ print(" 1. Import useTranslations: import { useTranslations } from 'next-intl'")
238
+ print(" 2. Add translations to core/messages/{locale}/ or theme messages")
239
+ print(" 3. Replace hardcoded text with t('key')")
240
+ print()
241
+
242
+ return 0
243
+
244
+
245
+ if __name__ == '__main__':
246
+ sys.exit(main())
@@ -0,0 +1,260 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Validate Translations Script
4
+
5
+ Compares translation files between locales to find missing keys.
6
+ Validates EN and ES translation completeness.
7
+
8
+ Usage:
9
+ python validate-translations.py [--theme THEME] [--strict]
10
+
11
+ Options:
12
+ --theme THEME Theme to validate (default: from NEXT_PUBLIC_ACTIVE_THEME or 'default')
13
+ --strict Exit with error if missing keys found
14
+ --core-only Only validate core messages
15
+ --theme-only Only validate theme messages
16
+ """
17
+
18
+ import os
19
+ import sys
20
+ import json
21
+ import argparse
22
+ from pathlib import Path
23
+ from typing import Dict, List, Set, Tuple
24
+
25
+
26
+ def get_active_theme() -> str:
27
+ """Get active theme from environment or default."""
28
+ return os.environ.get('NEXT_PUBLIC_ACTIVE_THEME', 'default')
29
+
30
+
31
+ def flatten_keys(obj: dict, prefix: str = '') -> Set[str]:
32
+ """Flatten nested dict to set of dot-notation keys."""
33
+ keys = set()
34
+ for key, value in obj.items():
35
+ full_key = f"{prefix}.{key}" if prefix else key
36
+ if isinstance(value, dict):
37
+ keys.update(flatten_keys(value, full_key))
38
+ else:
39
+ keys.add(full_key)
40
+ return keys
41
+
42
+
43
+ def load_json_file(file_path: Path) -> dict:
44
+ """Load JSON file and return dict."""
45
+ try:
46
+ with open(file_path, 'r', encoding='utf-8') as f:
47
+ return json.load(f)
48
+ except FileNotFoundError:
49
+ return {}
50
+ except json.JSONDecodeError as e:
51
+ print(f" Warning: Invalid JSON in {file_path}: {e}")
52
+ return {}
53
+
54
+
55
+ def load_core_messages(locale: str) -> dict:
56
+ """Load core messages for a locale by combining all JSON files."""
57
+ core_path = Path(f'core/messages/{locale}')
58
+ if not core_path.exists():
59
+ return {}
60
+
61
+ combined = {}
62
+ for json_file in core_path.glob('*.json'):
63
+ data = load_json_file(json_file)
64
+ # Use filename (without extension) as namespace
65
+ namespace = json_file.stem
66
+ if namespace == 'index':
67
+ continue
68
+ combined[namespace] = data
69
+
70
+ return combined
71
+
72
+
73
+ def load_theme_messages(theme: str, locale: str) -> dict:
74
+ """Load theme messages for a locale."""
75
+ theme_path = Path(f'contents/themes/{theme}/messages/{locale}.json')
76
+ return load_json_file(theme_path)
77
+
78
+
79
+ def compare_translations(
80
+ en_keys: Set[str],
81
+ es_keys: Set[str],
82
+ source_name: str
83
+ ) -> Tuple[Set[str], Set[str]]:
84
+ """Compare EN and ES keys, return missing in each."""
85
+ missing_in_es = en_keys - es_keys
86
+ missing_in_en = es_keys - en_keys
87
+ return missing_in_es, missing_in_en
88
+
89
+
90
+ def validate_core_messages() -> Tuple[int, int]:
91
+ """Validate core messages between EN and ES."""
92
+ print("\n" + "=" * 60)
93
+ print("VALIDATING CORE MESSAGES")
94
+ print("=" * 60)
95
+
96
+ en_messages = load_core_messages('en')
97
+ es_messages = load_core_messages('es')
98
+
99
+ if not en_messages:
100
+ print(" Warning: No English core messages found at core/messages/en/")
101
+ return 0, 0
102
+
103
+ en_keys = flatten_keys(en_messages)
104
+ es_keys = flatten_keys(es_messages)
105
+
106
+ print(f" EN keys: {len(en_keys)}")
107
+ print(f" ES keys: {len(es_keys)}")
108
+
109
+ missing_in_es, missing_in_en = compare_translations(en_keys, es_keys, "core")
110
+
111
+ total_missing = len(missing_in_es) + len(missing_in_en)
112
+
113
+ if missing_in_es:
114
+ print(f"\n Missing in ES ({len(missing_in_es)}):")
115
+ for key in sorted(missing_in_es)[:20]:
116
+ print(f" - {key}")
117
+ if len(missing_in_es) > 20:
118
+ print(f" ... and {len(missing_in_es) - 20} more")
119
+
120
+ if missing_in_en:
121
+ print(f"\n Extra in ES (not in EN) ({len(missing_in_en)}):")
122
+ for key in sorted(missing_in_en)[:10]:
123
+ print(f" - {key}")
124
+ if len(missing_in_en) > 10:
125
+ print(f" ... and {len(missing_in_en) - 10} more")
126
+
127
+ if total_missing == 0:
128
+ print("\n Core messages: COMPLETE")
129
+
130
+ return len(missing_in_es), len(missing_in_en)
131
+
132
+
133
+ def validate_theme_messages(theme: str) -> Tuple[int, int]:
134
+ """Validate theme messages between EN and ES."""
135
+ print("\n" + "=" * 60)
136
+ print(f"VALIDATING THEME MESSAGES: {theme}")
137
+ print("=" * 60)
138
+
139
+ en_messages = load_theme_messages(theme, 'en')
140
+ es_messages = load_theme_messages(theme, 'es')
141
+
142
+ if not en_messages:
143
+ print(f" Warning: No English theme messages found for theme '{theme}'")
144
+ return 0, 0
145
+
146
+ en_keys = flatten_keys(en_messages)
147
+ es_keys = flatten_keys(es_messages)
148
+
149
+ print(f" EN keys: {len(en_keys)}")
150
+ print(f" ES keys: {len(es_keys)}")
151
+
152
+ missing_in_es, missing_in_en = compare_translations(en_keys, es_keys, f"theme-{theme}")
153
+
154
+ total_missing = len(missing_in_es) + len(missing_in_en)
155
+
156
+ if missing_in_es:
157
+ print(f"\n Missing in ES ({len(missing_in_es)}):")
158
+ for key in sorted(missing_in_es)[:20]:
159
+ print(f" - {key}")
160
+ if len(missing_in_es) > 20:
161
+ print(f" ... and {len(missing_in_es) - 20} more")
162
+
163
+ if missing_in_en:
164
+ print(f"\n Extra in ES (not in EN) ({len(missing_in_en)}):")
165
+ for key in sorted(missing_in_en)[:10]:
166
+ print(f" - {key}")
167
+ if len(missing_in_en) > 10:
168
+ print(f" ... and {len(missing_in_en) - 10} more")
169
+
170
+ if total_missing == 0:
171
+ print("\n Theme messages: COMPLETE")
172
+
173
+ return len(missing_in_es), len(missing_in_en)
174
+
175
+
176
+ def check_custom_roles_in_core() -> List[str]:
177
+ """Check if custom roles are incorrectly defined in core messages."""
178
+ print("\n" + "=" * 60)
179
+ print("CHECKING CUSTOM ROLES POLICY")
180
+ print("=" * 60)
181
+
182
+ core_en = load_core_messages('en')
183
+ violations = []
184
+
185
+ # Custom roles that should NEVER be in core
186
+ forbidden_roles = ['editor', 'moderator', 'contributor', 'reviewer', 'publisher']
187
+
188
+ # Check teams.roles namespace
189
+ teams_roles = core_en.get('teams', {}).get('roles', {})
190
+ for role in forbidden_roles:
191
+ if role in teams_roles:
192
+ violations.append(f"teams.roles.{role}")
193
+
194
+ if violations:
195
+ print(f"\n VIOLATION: Custom roles found in core/messages/")
196
+ print(f" These should be in theme messages only:")
197
+ for v in violations:
198
+ print(f" - {v}")
199
+ else:
200
+ print("\n Custom roles policy: OK")
201
+
202
+ return violations
203
+
204
+
205
+ def main():
206
+ parser = argparse.ArgumentParser(description='Validate translations')
207
+ parser.add_argument('--theme', default=None, help='Theme to validate')
208
+ parser.add_argument('--strict', action='store_true', help='Exit with error if issues found')
209
+ parser.add_argument('--core-only', action='store_true', help='Only validate core messages')
210
+ parser.add_argument('--theme-only', action='store_true', help='Only validate theme messages')
211
+
212
+ args = parser.parse_args()
213
+
214
+ theme = args.theme or get_active_theme()
215
+
216
+ print(f"\n{'=' * 60}")
217
+ print(f"TRANSLATION VALIDATION")
218
+ print(f"{'=' * 60}")
219
+ print(f"Theme: {theme}")
220
+ print(f"Strict mode: {args.strict}")
221
+ print(f"{'=' * 60}")
222
+
223
+ total_issues = 0
224
+
225
+ # Validate core messages
226
+ if not args.theme_only:
227
+ missing_es, extra_es = validate_core_messages()
228
+ total_issues += missing_es
229
+
230
+ # Check custom roles policy
231
+ role_violations = check_custom_roles_in_core()
232
+ total_issues += len(role_violations)
233
+
234
+ # Validate theme messages
235
+ if not args.core_only:
236
+ missing_es, extra_es = validate_theme_messages(theme)
237
+ total_issues += missing_es
238
+
239
+ # Summary
240
+ print("\n" + "=" * 60)
241
+ print("SUMMARY")
242
+ print("=" * 60)
243
+
244
+ if total_issues == 0:
245
+ print(" All translations are complete!")
246
+ print("=" * 60 + "\n")
247
+ return 0
248
+ else:
249
+ print(f" Total issues found: {total_issues}")
250
+ print("=" * 60 + "\n")
251
+
252
+ if args.strict:
253
+ print("Strict mode: Exiting with error due to missing translations")
254
+ return 1
255
+
256
+ return 0
257
+
258
+
259
+ if __name__ == '__main__':
260
+ sys.exit(main())
@@ -0,0 +1,203 @@
1
+ ---
2
+ name: impact-analysis
3
+ description: |
4
+ Impact analysis for understanding how code changes affect the system.
5
+ Covers git diff analysis, entity mapping, flow identification, and regression suggestions.
6
+ Use this skill when analyzing branches, planning testing, or understanding change scope.
7
+ allowed-tools: Read, Glob, Grep, Bash(git:*)
8
+ version: 1.0.0
9
+ ---
10
+
11
+ # Impact Analysis Skill
12
+
13
+ Analyze the potential impact of code changes on the system.
14
+
15
+ ## Overview
16
+
17
+ Impact analysis identifies what parts of the system may be affected by a code change. Think of it like a **domino effect** - pushing one domino (making a change) may cause others to fall.
18
+
19
+ ```
20
+ ┌─────────────────────────────────────────────────────────────┐
21
+ │ 1. Git Diff │
22
+ │ ↓ │
23
+ │ Gets list of modified files │
24
+ │ │
25
+ │ 2. Classification │
26
+ │ ↓ │
27
+ │ Groups by type: API, UI, DB, Tests │
28
+ │ │
29
+ │ 3. Entity Mapping │
30
+ │ ↓ │
31
+ │ Relates files to system entities │
32
+ │ │
33
+ │ 4. Flow Lookup │
34
+ │ ↓ │
35
+ │ Queries registries for related flows │
36
+ │ │
37
+ │ 5. Suggestions │
38
+ │ ↓ │
39
+ │ Generates list of potentially affected areas │
40
+ └─────────────────────────────────────────────────────────────┘
41
+ ```
42
+
43
+ ## When to Use This Skill
44
+
45
+ - Analyzing a feature branch before merge
46
+ - Planning regression testing scope
47
+ - Understanding the blast radius of a change
48
+ - Identifying related tests to run
49
+ - Code review impact assessment
50
+
51
+ ## Analysis Capabilities
52
+
53
+ ### What It CAN Identify
54
+
55
+ | Capability | Example |
56
+ |------------|---------|
57
+ | Modified files | "5 files changed in /products" |
58
+ | Direct dependencies | "Orders depends on Products" |
59
+ | Existing tests | "3 tests cover this area" |
60
+ | Documented flows | "Checkout flow uses this component" |
61
+ | Entity relationships | "FK relationship to customers" |
62
+
63
+ ### What It CANNOT Identify
64
+
65
+ | Limitation | Reason |
66
+ |------------|--------|
67
+ | Business impact | Doesn't know business rules |
68
+ | Real severity | Cannot prioritize by criticality |
69
+ | Undocumented dependencies | Only sees what's in code |
70
+ | Complex side effects | Doesn't execute the code |
71
+ | Runtime behavior | Static analysis only |
72
+
73
+ ## Output Format
74
+
75
+ ```markdown
76
+ ## Impact Analysis: feature/new-pricing
77
+
78
+ ### Files Modified (23 files)
79
+ | Type | Count | Key Files |
80
+ |------|-------|-----------|
81
+ | API | 5 | orders/service.ts, payments/route.ts |
82
+ | UI | 12 | CheckoutForm.tsx, OrderSummary.tsx |
83
+ | DB | 2 | 001_add_payment_status.sql |
84
+ | Tests | 4 | checkout.cy.ts |
85
+
86
+ ### Entities Affected
87
+ - **products**: API and UI modifications
88
+ - **orders**: Potentially affected (FK relationship)
89
+ - **payments**: New functionality
90
+
91
+ ### Flows Potentially Impacted
92
+ - Complete checkout flow
93
+ - Order confirmation flow
94
+ - Payment processing flow
95
+
96
+ ### Regression Suggestions
97
+ | Confidence | Area | Reason |
98
+ |------------|------|--------|
99
+ | High | Product CRUD | Direct changes |
100
+ | Medium | Order totals | Uses pricing |
101
+ | Low | Sales reports | May reference products |
102
+
103
+ ### Related Tests
104
+ - checkout.cy.ts (@uat, @flow-checkout)
105
+ - orders.cy.ts (@api, @entity-orders)
106
+ - payments.cy.ts (@api)
107
+ ```
108
+
109
+ ## Confidence Levels
110
+
111
+ | Level | Meaning | Recommendation |
112
+ |-------|---------|----------------|
113
+ | **High** | Direct dependency found | Test this area |
114
+ | **Medium** | Indirect dependency | Consider testing |
115
+ | **Low** | Possible relationship | Evaluate with context |
116
+
117
+ ## Interpreting Results
118
+
119
+ ### Correct Interpretation
120
+
121
+ - "Analysis suggests pricing is directly affected"
122
+ - "Orders might be affected because it uses prices"
123
+ - "Should verify with dev team about reports impact"
124
+
125
+ ### Incorrect Interpretation
126
+
127
+ - "Analysis says I MUST test everything listed"
128
+ - "If not in the list, there's no risk"
129
+ - "This is the complete list of affected areas"
130
+
131
+ ## Complementing the Analysis
132
+
133
+ Technical analysis should be complemented with:
134
+
135
+ ### 1. Business Knowledge
136
+
137
+ - What areas are critical for the business?
138
+ - Are there special seasons or events?
139
+ - Which customers use these features?
140
+
141
+ ### 2. Bug History
142
+
143
+ - Have there been bugs in these areas before?
144
+ - Are there known "fragile" areas?
145
+
146
+ ### 3. Developer Conversation
147
+
148
+ - What exactly changed?
149
+ - Are there impacts the code doesn't show?
150
+ - Are there affected external dependencies?
151
+
152
+ ## Usage Examples
153
+
154
+ ### Analyze a Branch
155
+
156
+ ```bash
157
+ # Get diff from main
158
+ git diff main...feature/checkout-v2 --name-only
159
+
160
+ # Classify files
161
+ # API: src/app/api/**
162
+ # UI: src/components/**, src/app/(routes)/**
163
+ # DB: migrations/**
164
+ # Tests: cypress/**, __tests__/**
165
+ ```
166
+
167
+ ### Map to Entities
168
+
169
+ ```typescript
170
+ // File path patterns to entities
171
+ const entityPatterns = {
172
+ 'entities/products': 'products',
173
+ 'entities/orders': 'orders',
174
+ 'api/v1/products': 'products',
175
+ 'components/Product': 'products',
176
+ }
177
+ ```
178
+
179
+ ### Lookup Related Flows
180
+
181
+ ```typescript
182
+ // Query FLOW_REGISTRY for flows using affected entities
183
+ const affectedFlows = Object.entries(FLOW_REGISTRY)
184
+ .filter(([_, flow]) =>
185
+ flow.entities.some(e => affectedEntities.includes(e))
186
+ )
187
+ ```
188
+
189
+ ## Commands
190
+
191
+ | Command | Description |
192
+ |---------|-------------|
193
+ | `/impact:analyze [branch]` | Analyze branch impact |
194
+ | `/impact:regression [feature]` | Identify regression areas |
195
+
196
+ ## Important Notes
197
+
198
+ 1. **This is a starting point** - not a definitive list
199
+ 2. **Complements human judgment** - doesn't replace it
200
+ 3. **Static analysis only** - cannot predict runtime behavior
201
+ 4. **Business context required** - you decide what's critical
202
+
203
+ The analysis is an **assistance tool**. YOU decide what to test and with what priority.