@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,309 @@
1
+ ---
2
+ name: cypress-selectors
3
+ description: |
4
+ 3-level selector system for testing: CORE_SELECTORS + BLOCK_SELECTORS + THEME_SELECTORS.
5
+ Provides helpers sel(), cySelector(), entitySelectors() for components and POMs.
6
+ Use this skill when working with data-cy attributes, POMs, or Cypress tests.
7
+ allowed-tools: Read, Glob, Grep, Bash(python:*)
8
+ version: 1.1.0
9
+ ---
10
+
11
+ # Cypress Selectors System
12
+
13
+ Centralized `data-cy` selector system for Cypress testing.
14
+
15
+ ## Architecture Overview
16
+
17
+ ```
18
+ ┌─────────────────────────────────────────┐
19
+ │ CORE (Read-Only) │
20
+ │ core/lib/test/core-selectors.ts │
21
+ │ core/lib/test/selector-factory.ts │
22
+ └─────────────────┬───────────────────────┘
23
+ │ imports
24
+
25
+ ┌─────────────────────────────────────────┐
26
+ │ THEME (Editable) │
27
+ │ contents/themes/{theme}/lib/selectors.ts│
28
+ │ ├── BLOCK_SELECTORS │
29
+ │ ├── DEVTOOLS_SELECTORS │
30
+ │ ├── THEME_SELECTORS = { │
31
+ │ │ ...CORE_SELECTORS, │
32
+ │ │ blocks: BLOCK_SELECTORS, │
33
+ │ │ devtools: DEVTOOLS_SELECTORS │
34
+ │ │ } │
35
+ │ └── exports: sel, cySelector, etc. │
36
+ └─────────────────┬───────────────────────┘
37
+ │ re-exports
38
+
39
+ ┌─────────────────────────────────────────┐
40
+ │ tests/cypress/src/selectors.ts │
41
+ │ (re-exports for test files) │
42
+ └─────────────────┬───────────────────────┘
43
+ │ imports
44
+ ┌─────────┴─────────┐
45
+ ▼ ▼
46
+ ┌───────────────┐ ┌───────────────┐
47
+ │ Components │ │ POMs │
48
+ │ sel('x.y') │ │ cySelector() │
49
+ └───────────────┘ └───────────────┘
50
+ ```
51
+
52
+ ## When to Use This Skill
53
+
54
+ - Adding `data-cy` attributes to components
55
+ - Creating new BLOCK_SELECTORS for a block
56
+ - Working with Page Object Models (POMs)
57
+ - Validating selector coverage in UI
58
+ - Writing Cypress E2E tests
59
+
60
+ ## Key Functions
61
+
62
+ ### `sel(path: string, replacements?: object)`
63
+
64
+ Use in **components** to get the selector string for `data-cy`:
65
+
66
+ ```typescript
67
+ // In block component: contents/themes/{theme}/blocks/{block-name}/component.tsx
68
+ import { sel } from '../../lib/selectors'
69
+
70
+ // Static selector - note the 'blocks.' prefix for block selectors
71
+ <section data-cy={sel('blocks.hero.container')}>
72
+ <h2 data-cy={sel('blocks.hero.title')}>{title}</h2>
73
+ </section>
74
+
75
+ // Dynamic selector with replacement
76
+ {items.map((item, index) => (
77
+ <div data-cy={sel('blocks.faqAccordion.item', { index: String(index) })}>
78
+ {item.content}
79
+ </div>
80
+ ))}
81
+
82
+ // Core selectors (no 'blocks.' prefix)
83
+ <button data-cy={sel('auth.login.submit')}>Login</button>
84
+ ```
85
+
86
+ ### `cySelector(path: string, replacements?: object)`
87
+
88
+ Use in **POMs and Cypress tests** to get the CSS selector `[data-cy="..."]`:
89
+
90
+ ```typescript
91
+ // In POM: contents/themes/{theme}/tests/cypress/src/features/MyPOM.ts
92
+ import { BasePOM } from '../core/BasePOM'
93
+ import { cySelector } from '../selectors'
94
+
95
+ export class HeroPOM extends BasePOM {
96
+ get selectors() {
97
+ return {
98
+ container: cySelector('blocks.hero.container'),
99
+ title: cySelector('blocks.hero.title'),
100
+ }
101
+ }
102
+
103
+ // Dynamic selectors
104
+ getItem(index: number) {
105
+ return cy.get(cySelector('blocks.faqAccordion.item', { index: String(index) }))
106
+ }
107
+
108
+ // Factory method
109
+ static create(): HeroPOM {
110
+ return new HeroPOM()
111
+ }
112
+ }
113
+ ```
114
+
115
+ ```typescript
116
+ // In test file: contents/themes/{theme}/tests/cypress/e2e/blocks/hero.cy.ts
117
+ import { cySelector } from '../../src/selectors'
118
+
119
+ describe('Hero Block', () => {
120
+ it('should display the hero', () => {
121
+ cy.get(cySelector('blocks.hero.container')).should('be.visible')
122
+ })
123
+ })
124
+ ```
125
+
126
+ ### `entitySelectors(slug: string)`
127
+
128
+ Get all selectors for a specific entity:
129
+
130
+ ```typescript
131
+ import { entitySelectors } from '../../src/selectors'
132
+
133
+ const taskSelectors = entitySelectors('tasks')
134
+ // Returns: { table, row, createBtn, editBtn, ... }
135
+ ```
136
+
137
+ ## Selector Paths
138
+
139
+ **IMPORTANT:** Block selectors use the `blocks.` prefix because BLOCK_SELECTORS is nested under `blocks:` in THEME_SELECTORS:
140
+
141
+ ```typescript
142
+ // Block selectors - use 'blocks.' prefix
143
+ sel('blocks.hero.container') // → 'block-hero'
144
+ sel('blocks.faqAccordion.item', { index: '0' }) // → 'faq-item-0'
145
+ sel('blocks.pricingTable.plan', { index: '1' }) // → 'pricing-plan-1'
146
+
147
+ // Core selectors - no prefix
148
+ sel('auth.login.form') // → 'login-form'
149
+ sel('entity.table', { slug: 'tasks' }) // → 'tasks-table'
150
+
151
+ // Devtools selectors - use 'devtools.' prefix
152
+ sel('devtools.scheduledActions.table') // → 'scheduled-actions-table'
153
+ ```
154
+
155
+ ## Naming Conventions
156
+
157
+ ### Static Selectors
158
+ ```
159
+ domain-element
160
+ ```
161
+ Examples:
162
+ - `block-hero` (block container)
163
+ - `login-form` (core component)
164
+ - `nav-main` (navigation element)
165
+
166
+ ### Dynamic Selectors with Placeholders
167
+ ```
168
+ {placeholder}-element-{placeholder}
169
+ ```
170
+ Placeholders:
171
+ - `{index}` - Array index (most common for blocks)
172
+ - `{slug}` - Entity slug (tasks, customers, pages)
173
+ - `{id}` - Record ID
174
+ - `{name}` - Field name
175
+ - `{action}` - Action name (edit, delete)
176
+
177
+ Examples:
178
+ - `faq-item-{index}` → `faq-item-0`
179
+ - `{slug}-row-{id}` → `tasks-row-123`
180
+ - `field-{name}` → `field-email`
181
+
182
+ ## File Locations
183
+
184
+ | Type | Location | Who Modifies |
185
+ |------|----------|--------------|
186
+ | Core selectors | `core/lib/test/core-selectors.ts` | Core maintainers only |
187
+ | Selector factory | `core/lib/test/selector-factory.ts` | Core maintainers only |
188
+ | Block selectors | `contents/themes/{theme}/lib/selectors.ts` | Theme developers |
189
+ | Test re-exports | `contents/themes/{theme}/tests/cypress/src/selectors.ts` | Auto (re-exports) |
190
+ | POMs | `contents/themes/{theme}/tests/cypress/src/features/*POM.ts` | Test developers |
191
+
192
+ ## Adding New Selectors
193
+
194
+ ### For Block Components
195
+
196
+ Edit `contents/themes/{theme}/lib/selectors.ts`, add to BLOCK_SELECTORS:
197
+
198
+ ```typescript
199
+ export const BLOCK_SELECTORS = {
200
+ // ... existing blocks
201
+ myNewBlock: {
202
+ container: 'block-my-new-block',
203
+ title: 'my-block-title',
204
+ item: 'my-block-item-{index}',
205
+ }
206
+ }
207
+ ```
208
+
209
+ Then use in component with `blocks.` prefix:
210
+ ```tsx
211
+ // contents/themes/{theme}/blocks/my-new-block/component.tsx
212
+ import { sel } from '../../lib/selectors'
213
+
214
+ <section data-cy={sel('blocks.myNewBlock.container')}>
215
+ <h2 data-cy={sel('blocks.myNewBlock.title')}>{title}</h2>
216
+ </section>
217
+ ```
218
+
219
+ ### For Core Components
220
+
221
+ Edit `core/lib/test/core-selectors.ts`:
222
+
223
+ ```typescript
224
+ export const CORE_SELECTORS = {
225
+ // ... existing selectors
226
+ myNewFeature: {
227
+ container: 'my-feature-container',
228
+ list: 'my-feature-list',
229
+ item: 'my-feature-item-{id}',
230
+ }
231
+ }
232
+ ```
233
+
234
+ ### For DevTools Components
235
+
236
+ Edit `contents/themes/{theme}/lib/selectors.ts`, add to DEVTOOLS_SELECTORS:
237
+
238
+ ```typescript
239
+ export const DEVTOOLS_SELECTORS = {
240
+ // ... existing selectors
241
+ myDevTool: {
242
+ page: 'devtools-my-tool-page',
243
+ table: 'my-tool-table',
244
+ }
245
+ }
246
+ ```
247
+
248
+ ## Anti-Patterns
249
+
250
+ ```typescript
251
+ // ❌ NEVER: Hardcoded data-cy in component
252
+ <button data-cy="submit-btn">
253
+
254
+ // ❌ NEVER: Direct selector string in test
255
+ cy.get('[data-cy="submit-btn"]')
256
+
257
+ // ❌ NEVER: Missing 'blocks.' prefix for block selectors
258
+ sel('hero.container') // Wrong!
259
+ sel('blocks.hero.container') // Correct!
260
+
261
+ // ❌ NEVER: Import from core in theme components
262
+ import { sel } from '@/core/lib/test' // Wrong!
263
+ import { sel } from '../../lib/selectors' // Correct!
264
+
265
+ // ❌ NEVER: Add selector without UI element
266
+ // Only add selectors for existing UI elements
267
+ ```
268
+
269
+ ## Validation Scripts
270
+
271
+ ### Validate all selectors use sel()
272
+ ```bash
273
+ python .claude/skills/cypress-selectors/scripts/validate-selectors.py
274
+ ```
275
+
276
+ ### Find elements missing data-cy
277
+ ```bash
278
+ python .claude/skills/cypress-selectors/scripts/extract-missing.py --path contents/themes/default/blocks/
279
+ ```
280
+
281
+ ### Generate block selectors for new block
282
+ ```bash
283
+ # Basic generation
284
+ python .claude/skills/cypress-selectors/scripts/generate-block-selectors.py --block my-new-block
285
+
286
+ # Analyze existing block and generate full example
287
+ python .claude/skills/cypress-selectors/scripts/generate-block-selectors.py --block faq-accordion --analyze --full
288
+
289
+ # Just show selector entry without instructions
290
+ python .claude/skills/cypress-selectors/scripts/generate-block-selectors.py --block my-block --dry-run
291
+ ```
292
+
293
+ ## Checklist
294
+
295
+ Before committing UI changes:
296
+
297
+ - [ ] All interactive elements have `data-cy={sel('...')}`
298
+ - [ ] Block selectors use `sel('blocks.{blockName}.{element}')` path
299
+ - [ ] New selectors added to BLOCK_SELECTORS or CORE_SELECTORS
300
+ - [ ] POM updated with new selectors using `cySelector()`
301
+ - [ ] Selector validation test created in `_selectors/*.cy.ts`
302
+ - [ ] No hardcoded `data-cy` strings in components
303
+ - [ ] No direct core imports in theme files
304
+
305
+ ## References
306
+
307
+ - Load `references/architecture.md` for detailed architecture
308
+ - Load `references/naming-conventions.md` for naming rules
309
+ - Load `references/anti-patterns.md` for common mistakes
@@ -0,0 +1,243 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Extract Missing Selectors Script
4
+
5
+ Finds interactive elements (buttons, inputs, links, forms) that are missing
6
+ data-cy attributes.
7
+
8
+ Usage:
9
+ python extract-missing.py --path PATH [--output OUTPUT]
10
+
11
+ Options:
12
+ --path PATH Directory to scan
13
+ --output OUTPUT Output file for results (default: stdout)
14
+ --format FORMAT Output format: text, json, markdown (default: text)
15
+ """
16
+
17
+ import os
18
+ import re
19
+ import sys
20
+ import json
21
+ import argparse
22
+ from pathlib import Path
23
+ from typing import List, Dict, Set
24
+
25
+ # Interactive elements that should have data-cy
26
+ INTERACTIVE_ELEMENTS = [
27
+ 'button',
28
+ 'Button',
29
+ 'input',
30
+ 'Input',
31
+ 'select',
32
+ 'Select',
33
+ 'textarea',
34
+ 'Textarea',
35
+ 'form',
36
+ 'Form',
37
+ 'a',
38
+ 'Link',
39
+ ]
40
+
41
+ # Pattern to find JSX elements
42
+ JSX_ELEMENT_PATTERN = re.compile(
43
+ r'<(' + '|'.join(INTERACTIVE_ELEMENTS) + r')\s+([^>]*?)(?:/>|>)',
44
+ re.IGNORECASE | re.DOTALL
45
+ )
46
+
47
+ # Pattern to check if data-cy exists
48
+ DATA_CY_PATTERN = re.compile(r'data-cy')
49
+
50
+
51
+ def find_tsx_files(path: str) -> List[Path]:
52
+ """Find all TSX files in the given path."""
53
+ root = Path(path)
54
+ return list(root.rglob("*.tsx"))
55
+
56
+
57
+ def analyze_file(file_path: Path) -> Dict:
58
+ """Find interactive elements missing data-cy."""
59
+ missing = []
60
+ has_selector = []
61
+
62
+ with open(file_path, 'r', encoding='utf-8') as f:
63
+ content = f.read()
64
+ lines = content.split('\n')
65
+
66
+ # Track line numbers
67
+ for line_num, line in enumerate(lines, 1):
68
+ for match in JSX_ELEMENT_PATTERN.finditer(line):
69
+ element_type = match.group(1)
70
+ attributes = match.group(2)
71
+
72
+ element_info = {
73
+ 'line': line_num,
74
+ 'element': element_type,
75
+ 'attributes': attributes[:100] + '...' if len(attributes) > 100 else attributes,
76
+ 'context': line.strip()[:120]
77
+ }
78
+
79
+ if DATA_CY_PATTERN.search(attributes):
80
+ has_selector.append(element_info)
81
+ else:
82
+ # Skip if it has onClick/onChange but might be internal
83
+ if 'data-cy' not in line:
84
+ missing.append(element_info)
85
+
86
+ return {
87
+ 'file': str(file_path),
88
+ 'missing': missing,
89
+ 'has_selector': has_selector,
90
+ 'coverage': len(has_selector) / (len(missing) + len(has_selector)) * 100 if (missing or has_selector) else 100
91
+ }
92
+
93
+
94
+ def suggest_selector(element: str, attributes: str, file_path: str) -> str:
95
+ """Suggest a selector name based on context."""
96
+ # Extract common attributes that might give hints
97
+ name_match = re.search(r'name=["\']([^"\']+)["\']', attributes)
98
+ id_match = re.search(r'id=["\']([^"\']+)["\']', attributes)
99
+ type_match = re.search(r'type=["\']([^"\']+)["\']', attributes)
100
+
101
+ # Get component name from file path
102
+ component = Path(file_path).stem.lower().replace('-', '.').replace('_', '.')
103
+
104
+ if name_match:
105
+ return f"{component}.{name_match.group(1)}"
106
+ if id_match:
107
+ return f"{component}.{id_match.group(1)}"
108
+ if type_match:
109
+ return f"{component}.{type_match.group(1)}.{element.lower()}"
110
+
111
+ return f"{component}.{element.lower()}"
112
+
113
+
114
+ def print_text_report(results: List[Dict]):
115
+ """Print plain text report."""
116
+ total_missing = 0
117
+ total_with = 0
118
+
119
+ print("\n" + "=" * 70)
120
+ print("MISSING DATA-CY ATTRIBUTES REPORT")
121
+ print("=" * 70)
122
+
123
+ for result in results:
124
+ if result['missing']:
125
+ print(f"\n{result['file']}")
126
+ print(f"Coverage: {result['coverage']:.1f}%")
127
+ print("-" * 50)
128
+
129
+ for elem in result['missing']:
130
+ total_missing += 1
131
+ suggestion = suggest_selector(elem['element'], elem['attributes'], result['file'])
132
+ print(f" Line {elem['line']}: <{elem['element']}> missing data-cy")
133
+ print(f" Suggestion: data-cy={{sel('{suggestion}')}}")
134
+
135
+ total_with += len(result['has_selector'])
136
+
137
+ print("\n" + "=" * 70)
138
+ print(f"SUMMARY")
139
+ print("-" * 70)
140
+ print(f"Files scanned: {len(results)}")
141
+ print(f"Elements with data-cy: {total_with}")
142
+ print(f"Elements missing data-cy: {total_missing}")
143
+
144
+ if total_missing + total_with > 0:
145
+ coverage = total_with / (total_missing + total_with) * 100
146
+ print(f"Overall coverage: {coverage:.1f}%")
147
+ print("=" * 70 + "\n")
148
+
149
+
150
+ def print_markdown_report(results: List[Dict]):
151
+ """Print markdown report."""
152
+ print("# Missing data-cy Attributes Report\n")
153
+
154
+ total_missing = sum(len(r['missing']) for r in results)
155
+ total_with = sum(len(r['has_selector']) for r in results)
156
+
157
+ print(f"**Files scanned:** {len(results)}")
158
+ print(f"**Elements with data-cy:** {total_with}")
159
+ print(f"**Elements missing data-cy:** {total_missing}\n")
160
+
161
+ for result in results:
162
+ if result['missing']:
163
+ print(f"## {result['file']}\n")
164
+ print(f"Coverage: {result['coverage']:.1f}%\n")
165
+ print("| Line | Element | Suggested Selector |")
166
+ print("|------|---------|-------------------|")
167
+
168
+ for elem in result['missing']:
169
+ suggestion = suggest_selector(elem['element'], elem['attributes'], result['file'])
170
+ print(f"| {elem['line']} | `<{elem['element']}>` | `{suggestion}` |")
171
+
172
+ print("")
173
+
174
+
175
+ def print_json_report(results: List[Dict]):
176
+ """Print JSON report."""
177
+ output = {
178
+ 'summary': {
179
+ 'files_scanned': len(results),
180
+ 'total_missing': sum(len(r['missing']) for r in results),
181
+ 'total_with_selector': sum(len(r['has_selector']) for r in results),
182
+ },
183
+ 'files': []
184
+ }
185
+
186
+ for result in results:
187
+ if result['missing']:
188
+ file_data = {
189
+ 'path': result['file'],
190
+ 'coverage': result['coverage'],
191
+ 'missing': []
192
+ }
193
+ for elem in result['missing']:
194
+ file_data['missing'].append({
195
+ 'line': elem['line'],
196
+ 'element': elem['element'],
197
+ 'suggestion': suggest_selector(elem['element'], elem['attributes'], result['file'])
198
+ })
199
+ output['files'].append(file_data)
200
+
201
+ print(json.dumps(output, indent=2))
202
+
203
+
204
+ def main():
205
+ parser = argparse.ArgumentParser(description='Find elements missing data-cy')
206
+ parser.add_argument('--path', required=True, help='Directory to scan')
207
+ parser.add_argument('--format', choices=['text', 'json', 'markdown'], default='text')
208
+ parser.add_argument('--output', help='Output file (default: stdout)')
209
+
210
+ args = parser.parse_args()
211
+
212
+ # Find files
213
+ files = find_tsx_files(args.path)
214
+
215
+ if not files:
216
+ print(f"No .tsx files found in {args.path}")
217
+ return 1
218
+
219
+ # Analyze files
220
+ results = [analyze_file(f) for f in files]
221
+
222
+ # Output
223
+ if args.output:
224
+ original_stdout = sys.stdout
225
+ sys.stdout = open(args.output, 'w')
226
+
227
+ if args.format == 'json':
228
+ print_json_report(results)
229
+ elif args.format == 'markdown':
230
+ print_markdown_report(results)
231
+ else:
232
+ print_text_report(results)
233
+
234
+ if args.output:
235
+ sys.stdout.close()
236
+ sys.stdout = original_stdout
237
+ print(f"Report written to {args.output}")
238
+
239
+ return 0
240
+
241
+
242
+ if __name__ == '__main__':
243
+ sys.exit(main())