@etus/seven-skill 0.1.0-beta.2 → 0.1.0-beta.4

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 (570) hide show
  1. package/.agents/skills/seven/SKILL.md +161 -0
  2. package/.agents/skills/seven/agents/seven_asset_producer.toml +37 -0
  3. package/.agents/skills/seven/agents/seven_finish_reviewer.toml +33 -0
  4. package/.agents/skills/seven/agents/seven_manual_edit_applier.toml +43 -0
  5. package/.agents/skills/seven/reference/adapt.md +34 -0
  6. package/.agents/skills/seven/reference/animate.md +31 -0
  7. package/.agents/skills/seven/reference/app-shell.md +152 -0
  8. package/.agents/skills/seven/reference/audit.md +122 -0
  9. package/.agents/skills/seven/reference/bolder.md +34 -0
  10. package/.agents/skills/seven/reference/brand.md +31 -0
  11. package/.agents/skills/seven/reference/clarify.md +76 -0
  12. package/.agents/skills/seven/reference/color-and-contrast.md +84 -0
  13. package/.agents/skills/seven/reference/colorize.md +31 -0
  14. package/.agents/skills/seven/reference/critique.md +53 -0
  15. package/.agents/skills/seven/reference/delight.md +30 -0
  16. package/.agents/skills/seven/reference/distill.md +30 -0
  17. package/.agents/skills/seven/reference/doctor.md +7 -0
  18. package/.agents/skills/seven/reference/document.md +36 -0
  19. package/.agents/skills/seven/reference/evaluations.md +38 -0
  20. package/.agents/skills/seven/reference/exceptions.md +7 -0
  21. package/.agents/skills/seven/reference/extract.md +42 -0
  22. package/.agents/skills/seven/reference/harden.md +36 -0
  23. package/.agents/skills/seven/reference/hooks.md +11 -0
  24. package/.agents/skills/seven/reference/init.md +38 -0
  25. package/.agents/skills/seven/reference/layout.md +33 -0
  26. package/.agents/skills/seven/reference/live.md +106 -0
  27. package/.agents/skills/seven/reference/motion-design.md +71 -0
  28. package/.agents/skills/seven/reference/onboard.md +35 -0
  29. package/.agents/skills/seven/reference/optimize.md +34 -0
  30. package/.agents/skills/seven/reference/overdrive.md +32 -0
  31. package/.agents/skills/seven/reference/polish.md +55 -0
  32. package/.agents/skills/seven/reference/product.md +43 -0
  33. package/.agents/skills/seven/reference/quieter.md +31 -0
  34. package/.agents/skills/seven/reference/routing.md +28 -0
  35. package/.agents/skills/seven/reference/shape.md +85 -0
  36. package/.agents/skills/seven/reference/spatial-design.md +60 -0
  37. package/.agents/skills/seven/reference/typeset.md +28 -0
  38. package/.agents/skills/seven/reference/typography.md +43 -0
  39. package/.agents/skills/seven/reference/ux-writing.md +47 -0
  40. package/.agents/skills/seven/reference/visual-probes.md +36 -0
  41. package/.agents/skills/seven/scripts/context-signals.mjs +94 -0
  42. package/.agents/skills/seven/scripts/critique-storage.mjs +155 -0
  43. package/.agents/skills/seven/scripts/load-context.mjs +93 -0
  44. package/.agents/skills/seven/scripts/update-check.mjs +120 -0
  45. package/.claude/agents/seven-asset-producer.md +40 -0
  46. package/.claude/agents/seven-finish-reviewer.md +36 -0
  47. package/.claude/agents/seven-manual-edit-applier.md +46 -0
  48. package/.claude/skills/seven/SKILL.md +128 -123
  49. package/.claude/skills/seven/reference/adapt.md +34 -0
  50. package/.claude/skills/seven/reference/animate.md +31 -0
  51. package/.claude/skills/seven/reference/app-shell.md +152 -0
  52. package/.claude/skills/seven/reference/audit.md +6 -4
  53. package/.claude/skills/seven/reference/bolder.md +34 -0
  54. package/.claude/skills/seven/reference/brand.md +21 -14
  55. package/.claude/skills/seven/reference/clarify.md +2 -2
  56. package/.claude/skills/seven/reference/colorize.md +31 -0
  57. package/.claude/skills/seven/reference/critique.md +53 -0
  58. package/.claude/skills/seven/reference/delight.md +30 -0
  59. package/.claude/skills/seven/reference/distill.md +30 -0
  60. package/.claude/skills/seven/reference/doctor.md +7 -0
  61. package/.claude/skills/seven/reference/document.md +36 -0
  62. package/.claude/skills/seven/reference/evaluations.md +38 -0
  63. package/.claude/skills/seven/reference/exceptions.md +7 -0
  64. package/.claude/skills/seven/reference/extract.md +42 -0
  65. package/.claude/skills/seven/reference/harden.md +36 -0
  66. package/.claude/skills/seven/reference/hooks.md +11 -0
  67. package/.claude/skills/seven/reference/init.md +38 -0
  68. package/.claude/skills/seven/reference/layout.md +33 -0
  69. package/.claude/skills/seven/reference/live.md +106 -0
  70. package/.claude/skills/seven/reference/motion-design.md +1 -1
  71. package/.claude/skills/seven/reference/onboard.md +35 -0
  72. package/.claude/skills/seven/reference/optimize.md +34 -0
  73. package/.claude/skills/seven/reference/overdrive.md +32 -0
  74. package/.claude/skills/seven/reference/polish.md +5 -5
  75. package/.claude/skills/seven/reference/product.md +2 -4
  76. package/.claude/skills/seven/reference/quieter.md +31 -0
  77. package/.claude/skills/seven/reference/routing.md +28 -0
  78. package/.claude/skills/seven/reference/shape.md +5 -5
  79. package/.claude/skills/seven/reference/spatial-design.md +3 -3
  80. package/.claude/skills/seven/reference/typeset.md +28 -0
  81. package/.claude/skills/seven/reference/typography.md +1 -1
  82. package/.claude/skills/seven/reference/visual-probes.md +36 -0
  83. package/.claude/skills/seven/scripts/context-signals.mjs +94 -0
  84. package/.claude/skills/seven/scripts/critique-storage.mjs +155 -0
  85. package/.claude/skills/seven/scripts/load-context.mjs +68 -59
  86. package/.claude/skills/seven/scripts/update-check.mjs +120 -0
  87. package/.claude-plugin/marketplace.json +2 -2
  88. package/.claude-plugin/plugin.json +8 -3
  89. package/.cursor/skills/seven/SKILL.md +161 -0
  90. package/.cursor/skills/seven/reference/adapt.md +34 -0
  91. package/.cursor/skills/seven/reference/animate.md +31 -0
  92. package/.cursor/skills/seven/reference/app-shell.md +152 -0
  93. package/.cursor/skills/seven/reference/audit.md +122 -0
  94. package/.cursor/skills/seven/reference/bolder.md +34 -0
  95. package/.cursor/skills/seven/reference/brand.md +31 -0
  96. package/.cursor/skills/seven/reference/clarify.md +76 -0
  97. package/.cursor/skills/seven/reference/color-and-contrast.md +84 -0
  98. package/.cursor/skills/seven/reference/colorize.md +31 -0
  99. package/.cursor/skills/seven/reference/critique.md +53 -0
  100. package/.cursor/skills/seven/reference/delight.md +30 -0
  101. package/.cursor/skills/seven/reference/distill.md +30 -0
  102. package/.cursor/skills/seven/reference/doctor.md +7 -0
  103. package/.cursor/skills/seven/reference/document.md +36 -0
  104. package/.cursor/skills/seven/reference/evaluations.md +38 -0
  105. package/.cursor/skills/seven/reference/exceptions.md +7 -0
  106. package/.cursor/skills/seven/reference/extract.md +42 -0
  107. package/.cursor/skills/seven/reference/harden.md +36 -0
  108. package/.cursor/skills/seven/reference/hooks.md +11 -0
  109. package/.cursor/skills/seven/reference/init.md +38 -0
  110. package/.cursor/skills/seven/reference/layout.md +33 -0
  111. package/.cursor/skills/seven/reference/live.md +106 -0
  112. package/.cursor/skills/seven/reference/motion-design.md +71 -0
  113. package/.cursor/skills/seven/reference/onboard.md +35 -0
  114. package/.cursor/skills/seven/reference/optimize.md +34 -0
  115. package/.cursor/skills/seven/reference/overdrive.md +32 -0
  116. package/.cursor/skills/seven/reference/polish.md +55 -0
  117. package/.cursor/skills/seven/reference/product.md +43 -0
  118. package/.cursor/skills/seven/reference/quieter.md +31 -0
  119. package/.cursor/skills/seven/reference/routing.md +28 -0
  120. package/.cursor/skills/seven/reference/shape.md +85 -0
  121. package/.cursor/skills/seven/reference/spatial-design.md +60 -0
  122. package/.cursor/skills/seven/reference/typeset.md +28 -0
  123. package/.cursor/skills/seven/reference/typography.md +43 -0
  124. package/.cursor/skills/seven/reference/ux-writing.md +47 -0
  125. package/.cursor/skills/seven/reference/visual-probes.md +36 -0
  126. package/.cursor/skills/seven/scripts/context-signals.mjs +94 -0
  127. package/.cursor/skills/seven/scripts/critique-storage.mjs +155 -0
  128. package/.cursor/skills/seven/scripts/load-context.mjs +93 -0
  129. package/.cursor/skills/seven/scripts/update-check.mjs +120 -0
  130. package/.gemini/skills/seven/SKILL.md +160 -0
  131. package/.gemini/skills/seven/reference/adapt.md +34 -0
  132. package/.gemini/skills/seven/reference/animate.md +31 -0
  133. package/.gemini/skills/seven/reference/app-shell.md +152 -0
  134. package/.gemini/skills/seven/reference/audit.md +122 -0
  135. package/.gemini/skills/seven/reference/bolder.md +34 -0
  136. package/.gemini/skills/seven/reference/brand.md +31 -0
  137. package/.gemini/skills/seven/reference/clarify.md +76 -0
  138. package/.gemini/skills/seven/reference/color-and-contrast.md +84 -0
  139. package/.gemini/skills/seven/reference/colorize.md +31 -0
  140. package/.gemini/skills/seven/reference/critique.md +53 -0
  141. package/.gemini/skills/seven/reference/delight.md +30 -0
  142. package/.gemini/skills/seven/reference/distill.md +30 -0
  143. package/.gemini/skills/seven/reference/doctor.md +7 -0
  144. package/.gemini/skills/seven/reference/document.md +36 -0
  145. package/.gemini/skills/seven/reference/evaluations.md +38 -0
  146. package/.gemini/skills/seven/reference/exceptions.md +7 -0
  147. package/.gemini/skills/seven/reference/extract.md +42 -0
  148. package/.gemini/skills/seven/reference/harden.md +36 -0
  149. package/.gemini/skills/seven/reference/hooks.md +11 -0
  150. package/.gemini/skills/seven/reference/init.md +38 -0
  151. package/.gemini/skills/seven/reference/layout.md +33 -0
  152. package/.gemini/skills/seven/reference/live.md +106 -0
  153. package/.gemini/skills/seven/reference/motion-design.md +71 -0
  154. package/.gemini/skills/seven/reference/onboard.md +35 -0
  155. package/.gemini/skills/seven/reference/optimize.md +34 -0
  156. package/.gemini/skills/seven/reference/overdrive.md +32 -0
  157. package/.gemini/skills/seven/reference/polish.md +55 -0
  158. package/.gemini/skills/seven/reference/product.md +43 -0
  159. package/.gemini/skills/seven/reference/quieter.md +31 -0
  160. package/.gemini/skills/seven/reference/routing.md +28 -0
  161. package/.gemini/skills/seven/reference/shape.md +85 -0
  162. package/.gemini/skills/seven/reference/spatial-design.md +60 -0
  163. package/.gemini/skills/seven/reference/typeset.md +28 -0
  164. package/.gemini/skills/seven/reference/typography.md +43 -0
  165. package/.gemini/skills/seven/reference/ux-writing.md +47 -0
  166. package/.gemini/skills/seven/reference/visual-probes.md +36 -0
  167. package/.gemini/skills/seven/scripts/context-signals.mjs +94 -0
  168. package/.gemini/skills/seven/scripts/critique-storage.mjs +155 -0
  169. package/.gemini/skills/seven/scripts/load-context.mjs +93 -0
  170. package/.gemini/skills/seven/scripts/update-check.mjs +120 -0
  171. package/.grok/agents/seven-asset-producer.md +40 -0
  172. package/.grok/agents/seven-finish-reviewer.md +36 -0
  173. package/.grok/agents/seven-manual-edit-applier.md +46 -0
  174. package/.grok/skills/seven/SKILL.md +167 -0
  175. package/.grok/skills/seven/reference/adapt.md +34 -0
  176. package/.grok/skills/seven/reference/animate.md +31 -0
  177. package/.grok/skills/seven/reference/app-shell.md +152 -0
  178. package/.grok/skills/seven/reference/audit.md +122 -0
  179. package/.grok/skills/seven/reference/bolder.md +34 -0
  180. package/.grok/skills/seven/reference/brand.md +31 -0
  181. package/.grok/skills/seven/reference/clarify.md +76 -0
  182. package/.grok/skills/seven/reference/color-and-contrast.md +84 -0
  183. package/.grok/skills/seven/reference/colorize.md +31 -0
  184. package/.grok/skills/seven/reference/critique.md +53 -0
  185. package/.grok/skills/seven/reference/delight.md +30 -0
  186. package/.grok/skills/seven/reference/distill.md +30 -0
  187. package/.grok/skills/seven/reference/doctor.md +7 -0
  188. package/.grok/skills/seven/reference/document.md +36 -0
  189. package/.grok/skills/seven/reference/evaluations.md +38 -0
  190. package/.grok/skills/seven/reference/exceptions.md +7 -0
  191. package/.grok/skills/seven/reference/extract.md +42 -0
  192. package/.grok/skills/seven/reference/harden.md +36 -0
  193. package/.grok/skills/seven/reference/hooks.md +11 -0
  194. package/.grok/skills/seven/reference/init.md +38 -0
  195. package/.grok/skills/seven/reference/layout.md +33 -0
  196. package/.grok/skills/seven/reference/live.md +106 -0
  197. package/.grok/skills/seven/reference/motion-design.md +71 -0
  198. package/.grok/skills/seven/reference/onboard.md +35 -0
  199. package/.grok/skills/seven/reference/optimize.md +34 -0
  200. package/.grok/skills/seven/reference/overdrive.md +32 -0
  201. package/.grok/skills/seven/reference/polish.md +55 -0
  202. package/.grok/skills/seven/reference/product.md +43 -0
  203. package/.grok/skills/seven/reference/quieter.md +31 -0
  204. package/.grok/skills/seven/reference/routing.md +28 -0
  205. package/.grok/skills/seven/reference/shape.md +85 -0
  206. package/.grok/skills/seven/reference/spatial-design.md +60 -0
  207. package/.grok/skills/seven/reference/typeset.md +28 -0
  208. package/.grok/skills/seven/reference/typography.md +43 -0
  209. package/.grok/skills/seven/reference/ux-writing.md +47 -0
  210. package/.grok/skills/seven/reference/visual-probes.md +36 -0
  211. package/.grok/skills/seven/scripts/context-signals.mjs +94 -0
  212. package/.grok/skills/seven/scripts/critique-storage.mjs +155 -0
  213. package/.grok/skills/seven/scripts/load-context.mjs +93 -0
  214. package/.grok/skills/seven/scripts/update-check.mjs +120 -0
  215. package/.kiro/skills/seven/SKILL.md +161 -0
  216. package/.kiro/skills/seven/reference/adapt.md +34 -0
  217. package/.kiro/skills/seven/reference/animate.md +31 -0
  218. package/.kiro/skills/seven/reference/app-shell.md +152 -0
  219. package/.kiro/skills/seven/reference/audit.md +122 -0
  220. package/.kiro/skills/seven/reference/bolder.md +34 -0
  221. package/.kiro/skills/seven/reference/brand.md +31 -0
  222. package/.kiro/skills/seven/reference/clarify.md +76 -0
  223. package/.kiro/skills/seven/reference/color-and-contrast.md +84 -0
  224. package/.kiro/skills/seven/reference/colorize.md +31 -0
  225. package/.kiro/skills/seven/reference/critique.md +53 -0
  226. package/.kiro/skills/seven/reference/delight.md +30 -0
  227. package/.kiro/skills/seven/reference/distill.md +30 -0
  228. package/.kiro/skills/seven/reference/doctor.md +7 -0
  229. package/.kiro/skills/seven/reference/document.md +36 -0
  230. package/.kiro/skills/seven/reference/evaluations.md +38 -0
  231. package/.kiro/skills/seven/reference/exceptions.md +7 -0
  232. package/.kiro/skills/seven/reference/extract.md +42 -0
  233. package/.kiro/skills/seven/reference/harden.md +36 -0
  234. package/.kiro/skills/seven/reference/hooks.md +11 -0
  235. package/.kiro/skills/seven/reference/init.md +38 -0
  236. package/.kiro/skills/seven/reference/layout.md +33 -0
  237. package/.kiro/skills/seven/reference/live.md +106 -0
  238. package/.kiro/skills/seven/reference/motion-design.md +71 -0
  239. package/.kiro/skills/seven/reference/onboard.md +35 -0
  240. package/.kiro/skills/seven/reference/optimize.md +34 -0
  241. package/.kiro/skills/seven/reference/overdrive.md +32 -0
  242. package/.kiro/skills/seven/reference/polish.md +55 -0
  243. package/.kiro/skills/seven/reference/product.md +43 -0
  244. package/.kiro/skills/seven/reference/quieter.md +31 -0
  245. package/.kiro/skills/seven/reference/routing.md +28 -0
  246. package/.kiro/skills/seven/reference/shape.md +85 -0
  247. package/.kiro/skills/seven/reference/spatial-design.md +60 -0
  248. package/.kiro/skills/seven/reference/typeset.md +28 -0
  249. package/.kiro/skills/seven/reference/typography.md +43 -0
  250. package/.kiro/skills/seven/reference/ux-writing.md +47 -0
  251. package/.kiro/skills/seven/reference/visual-probes.md +36 -0
  252. package/.kiro/skills/seven/scripts/context-signals.mjs +94 -0
  253. package/.kiro/skills/seven/scripts/critique-storage.mjs +155 -0
  254. package/.kiro/skills/seven/scripts/load-context.mjs +93 -0
  255. package/.kiro/skills/seven/scripts/update-check.mjs +120 -0
  256. package/.opencode/skills/seven/SKILL.md +167 -0
  257. package/.opencode/skills/seven/reference/adapt.md +34 -0
  258. package/.opencode/skills/seven/reference/animate.md +31 -0
  259. package/.opencode/skills/seven/reference/app-shell.md +152 -0
  260. package/.opencode/skills/seven/reference/audit.md +122 -0
  261. package/.opencode/skills/seven/reference/bolder.md +34 -0
  262. package/.opencode/skills/seven/reference/brand.md +31 -0
  263. package/.opencode/skills/seven/reference/clarify.md +76 -0
  264. package/.opencode/skills/seven/reference/color-and-contrast.md +84 -0
  265. package/.opencode/skills/seven/reference/colorize.md +31 -0
  266. package/.opencode/skills/seven/reference/critique.md +53 -0
  267. package/.opencode/skills/seven/reference/delight.md +30 -0
  268. package/.opencode/skills/seven/reference/distill.md +30 -0
  269. package/.opencode/skills/seven/reference/doctor.md +7 -0
  270. package/.opencode/skills/seven/reference/document.md +36 -0
  271. package/.opencode/skills/seven/reference/evaluations.md +38 -0
  272. package/.opencode/skills/seven/reference/exceptions.md +7 -0
  273. package/.opencode/skills/seven/reference/extract.md +42 -0
  274. package/.opencode/skills/seven/reference/harden.md +36 -0
  275. package/.opencode/skills/seven/reference/hooks.md +11 -0
  276. package/.opencode/skills/seven/reference/init.md +38 -0
  277. package/.opencode/skills/seven/reference/layout.md +33 -0
  278. package/.opencode/skills/seven/reference/live.md +106 -0
  279. package/.opencode/skills/seven/reference/motion-design.md +71 -0
  280. package/.opencode/skills/seven/reference/onboard.md +35 -0
  281. package/.opencode/skills/seven/reference/optimize.md +34 -0
  282. package/.opencode/skills/seven/reference/overdrive.md +32 -0
  283. package/.opencode/skills/seven/reference/polish.md +55 -0
  284. package/.opencode/skills/seven/reference/product.md +43 -0
  285. package/.opencode/skills/seven/reference/quieter.md +31 -0
  286. package/.opencode/skills/seven/reference/routing.md +28 -0
  287. package/.opencode/skills/seven/reference/shape.md +85 -0
  288. package/.opencode/skills/seven/reference/spatial-design.md +60 -0
  289. package/.opencode/skills/seven/reference/typeset.md +28 -0
  290. package/.opencode/skills/seven/reference/typography.md +43 -0
  291. package/.opencode/skills/seven/reference/ux-writing.md +47 -0
  292. package/.opencode/skills/seven/reference/visual-probes.md +36 -0
  293. package/.opencode/skills/seven/scripts/context-signals.mjs +94 -0
  294. package/.opencode/skills/seven/scripts/critique-storage.mjs +155 -0
  295. package/.opencode/skills/seven/scripts/load-context.mjs +93 -0
  296. package/.opencode/skills/seven/scripts/update-check.mjs +120 -0
  297. package/.pi/skills/seven/SKILL.md +165 -0
  298. package/.pi/skills/seven/reference/adapt.md +34 -0
  299. package/.pi/skills/seven/reference/animate.md +31 -0
  300. package/.pi/skills/seven/reference/app-shell.md +152 -0
  301. package/.pi/skills/seven/reference/audit.md +122 -0
  302. package/.pi/skills/seven/reference/bolder.md +34 -0
  303. package/.pi/skills/seven/reference/brand.md +31 -0
  304. package/.pi/skills/seven/reference/clarify.md +76 -0
  305. package/.pi/skills/seven/reference/color-and-contrast.md +84 -0
  306. package/.pi/skills/seven/reference/colorize.md +31 -0
  307. package/.pi/skills/seven/reference/critique.md +53 -0
  308. package/.pi/skills/seven/reference/delight.md +30 -0
  309. package/.pi/skills/seven/reference/distill.md +30 -0
  310. package/.pi/skills/seven/reference/doctor.md +7 -0
  311. package/.pi/skills/seven/reference/document.md +36 -0
  312. package/.pi/skills/seven/reference/evaluations.md +38 -0
  313. package/.pi/skills/seven/reference/exceptions.md +7 -0
  314. package/.pi/skills/seven/reference/extract.md +42 -0
  315. package/.pi/skills/seven/reference/harden.md +36 -0
  316. package/.pi/skills/seven/reference/hooks.md +11 -0
  317. package/.pi/skills/seven/reference/init.md +38 -0
  318. package/.pi/skills/seven/reference/layout.md +33 -0
  319. package/.pi/skills/seven/reference/live.md +106 -0
  320. package/.pi/skills/seven/reference/motion-design.md +71 -0
  321. package/.pi/skills/seven/reference/onboard.md +35 -0
  322. package/.pi/skills/seven/reference/optimize.md +34 -0
  323. package/.pi/skills/seven/reference/overdrive.md +32 -0
  324. package/.pi/skills/seven/reference/polish.md +55 -0
  325. package/.pi/skills/seven/reference/product.md +43 -0
  326. package/.pi/skills/seven/reference/quieter.md +31 -0
  327. package/.pi/skills/seven/reference/routing.md +28 -0
  328. package/.pi/skills/seven/reference/shape.md +85 -0
  329. package/.pi/skills/seven/reference/spatial-design.md +60 -0
  330. package/.pi/skills/seven/reference/typeset.md +28 -0
  331. package/.pi/skills/seven/reference/typography.md +43 -0
  332. package/.pi/skills/seven/reference/ux-writing.md +47 -0
  333. package/.pi/skills/seven/reference/visual-probes.md +36 -0
  334. package/.pi/skills/seven/scripts/context-signals.mjs +94 -0
  335. package/.pi/skills/seven/scripts/critique-storage.mjs +155 -0
  336. package/.pi/skills/seven/scripts/load-context.mjs +93 -0
  337. package/.pi/skills/seven/scripts/update-check.mjs +120 -0
  338. package/.qoder/skills/seven/SKILL.md +167 -0
  339. package/.qoder/skills/seven/reference/adapt.md +34 -0
  340. package/.qoder/skills/seven/reference/animate.md +31 -0
  341. package/.qoder/skills/seven/reference/app-shell.md +152 -0
  342. package/.qoder/skills/seven/reference/audit.md +122 -0
  343. package/.qoder/skills/seven/reference/bolder.md +34 -0
  344. package/.qoder/skills/seven/reference/brand.md +31 -0
  345. package/.qoder/skills/seven/reference/clarify.md +76 -0
  346. package/.qoder/skills/seven/reference/color-and-contrast.md +84 -0
  347. package/.qoder/skills/seven/reference/colorize.md +31 -0
  348. package/.qoder/skills/seven/reference/critique.md +53 -0
  349. package/.qoder/skills/seven/reference/delight.md +30 -0
  350. package/.qoder/skills/seven/reference/distill.md +30 -0
  351. package/.qoder/skills/seven/reference/doctor.md +7 -0
  352. package/.qoder/skills/seven/reference/document.md +36 -0
  353. package/.qoder/skills/seven/reference/evaluations.md +38 -0
  354. package/.qoder/skills/seven/reference/exceptions.md +7 -0
  355. package/.qoder/skills/seven/reference/extract.md +42 -0
  356. package/.qoder/skills/seven/reference/harden.md +36 -0
  357. package/.qoder/skills/seven/reference/hooks.md +11 -0
  358. package/.qoder/skills/seven/reference/init.md +38 -0
  359. package/.qoder/skills/seven/reference/layout.md +33 -0
  360. package/.qoder/skills/seven/reference/live.md +106 -0
  361. package/.qoder/skills/seven/reference/motion-design.md +71 -0
  362. package/.qoder/skills/seven/reference/onboard.md +35 -0
  363. package/.qoder/skills/seven/reference/optimize.md +34 -0
  364. package/.qoder/skills/seven/reference/overdrive.md +32 -0
  365. package/.qoder/skills/seven/reference/polish.md +55 -0
  366. package/.qoder/skills/seven/reference/product.md +43 -0
  367. package/.qoder/skills/seven/reference/quieter.md +31 -0
  368. package/.qoder/skills/seven/reference/routing.md +28 -0
  369. package/.qoder/skills/seven/reference/shape.md +85 -0
  370. package/.qoder/skills/seven/reference/spatial-design.md +60 -0
  371. package/.qoder/skills/seven/reference/typeset.md +28 -0
  372. package/.qoder/skills/seven/reference/typography.md +43 -0
  373. package/.qoder/skills/seven/reference/ux-writing.md +47 -0
  374. package/.qoder/skills/seven/reference/visual-probes.md +36 -0
  375. package/.qoder/skills/seven/scripts/context-signals.mjs +94 -0
  376. package/.qoder/skills/seven/scripts/critique-storage.mjs +155 -0
  377. package/.qoder/skills/seven/scripts/load-context.mjs +93 -0
  378. package/.qoder/skills/seven/scripts/update-check.mjs +120 -0
  379. package/.rovodev/skills/seven/SKILL.md +167 -0
  380. package/.rovodev/skills/seven/reference/adapt.md +34 -0
  381. package/.rovodev/skills/seven/reference/animate.md +31 -0
  382. package/.rovodev/skills/seven/reference/app-shell.md +152 -0
  383. package/.rovodev/skills/seven/reference/audit.md +122 -0
  384. package/.rovodev/skills/seven/reference/bolder.md +34 -0
  385. package/.rovodev/skills/seven/reference/brand.md +31 -0
  386. package/.rovodev/skills/seven/reference/clarify.md +76 -0
  387. package/.rovodev/skills/seven/reference/color-and-contrast.md +84 -0
  388. package/.rovodev/skills/seven/reference/colorize.md +31 -0
  389. package/.rovodev/skills/seven/reference/critique.md +53 -0
  390. package/.rovodev/skills/seven/reference/delight.md +30 -0
  391. package/.rovodev/skills/seven/reference/distill.md +30 -0
  392. package/.rovodev/skills/seven/reference/doctor.md +7 -0
  393. package/.rovodev/skills/seven/reference/document.md +36 -0
  394. package/.rovodev/skills/seven/reference/evaluations.md +38 -0
  395. package/.rovodev/skills/seven/reference/exceptions.md +7 -0
  396. package/.rovodev/skills/seven/reference/extract.md +42 -0
  397. package/.rovodev/skills/seven/reference/harden.md +36 -0
  398. package/.rovodev/skills/seven/reference/hooks.md +11 -0
  399. package/.rovodev/skills/seven/reference/init.md +38 -0
  400. package/.rovodev/skills/seven/reference/layout.md +33 -0
  401. package/.rovodev/skills/seven/reference/live.md +106 -0
  402. package/.rovodev/skills/seven/reference/motion-design.md +71 -0
  403. package/.rovodev/skills/seven/reference/onboard.md +35 -0
  404. package/.rovodev/skills/seven/reference/optimize.md +34 -0
  405. package/.rovodev/skills/seven/reference/overdrive.md +32 -0
  406. package/.rovodev/skills/seven/reference/polish.md +55 -0
  407. package/.rovodev/skills/seven/reference/product.md +43 -0
  408. package/.rovodev/skills/seven/reference/quieter.md +31 -0
  409. package/.rovodev/skills/seven/reference/routing.md +28 -0
  410. package/.rovodev/skills/seven/reference/shape.md +85 -0
  411. package/.rovodev/skills/seven/reference/spatial-design.md +60 -0
  412. package/.rovodev/skills/seven/reference/typeset.md +28 -0
  413. package/.rovodev/skills/seven/reference/typography.md +43 -0
  414. package/.rovodev/skills/seven/reference/ux-writing.md +47 -0
  415. package/.rovodev/skills/seven/reference/visual-probes.md +36 -0
  416. package/.rovodev/skills/seven/scripts/context-signals.mjs +94 -0
  417. package/.rovodev/skills/seven/scripts/critique-storage.mjs +155 -0
  418. package/.rovodev/skills/seven/scripts/load-context.mjs +93 -0
  419. package/.rovodev/skills/seven/scripts/update-check.mjs +120 -0
  420. package/.trae/skills/seven/SKILL.md +163 -0
  421. package/.trae/skills/seven/reference/adapt.md +34 -0
  422. package/.trae/skills/seven/reference/animate.md +31 -0
  423. package/.trae/skills/seven/reference/app-shell.md +152 -0
  424. package/.trae/skills/seven/reference/audit.md +122 -0
  425. package/.trae/skills/seven/reference/bolder.md +34 -0
  426. package/.trae/skills/seven/reference/brand.md +31 -0
  427. package/.trae/skills/seven/reference/clarify.md +76 -0
  428. package/.trae/skills/seven/reference/color-and-contrast.md +84 -0
  429. package/.trae/skills/seven/reference/colorize.md +31 -0
  430. package/.trae/skills/seven/reference/critique.md +53 -0
  431. package/.trae/skills/seven/reference/delight.md +30 -0
  432. package/.trae/skills/seven/reference/distill.md +30 -0
  433. package/.trae/skills/seven/reference/doctor.md +7 -0
  434. package/.trae/skills/seven/reference/document.md +36 -0
  435. package/.trae/skills/seven/reference/evaluations.md +38 -0
  436. package/.trae/skills/seven/reference/exceptions.md +7 -0
  437. package/.trae/skills/seven/reference/extract.md +42 -0
  438. package/.trae/skills/seven/reference/harden.md +36 -0
  439. package/.trae/skills/seven/reference/hooks.md +11 -0
  440. package/.trae/skills/seven/reference/init.md +38 -0
  441. package/.trae/skills/seven/reference/layout.md +33 -0
  442. package/.trae/skills/seven/reference/live.md +106 -0
  443. package/.trae/skills/seven/reference/motion-design.md +71 -0
  444. package/.trae/skills/seven/reference/onboard.md +35 -0
  445. package/.trae/skills/seven/reference/optimize.md +34 -0
  446. package/.trae/skills/seven/reference/overdrive.md +32 -0
  447. package/.trae/skills/seven/reference/polish.md +55 -0
  448. package/.trae/skills/seven/reference/product.md +43 -0
  449. package/.trae/skills/seven/reference/quieter.md +31 -0
  450. package/.trae/skills/seven/reference/routing.md +28 -0
  451. package/.trae/skills/seven/reference/shape.md +85 -0
  452. package/.trae/skills/seven/reference/spatial-design.md +60 -0
  453. package/.trae/skills/seven/reference/typeset.md +28 -0
  454. package/.trae/skills/seven/reference/typography.md +43 -0
  455. package/.trae/skills/seven/reference/ux-writing.md +47 -0
  456. package/.trae/skills/seven/reference/visual-probes.md +36 -0
  457. package/.trae/skills/seven/scripts/context-signals.mjs +94 -0
  458. package/.trae/skills/seven/scripts/critique-storage.mjs +155 -0
  459. package/.trae/skills/seven/scripts/load-context.mjs +93 -0
  460. package/.trae/skills/seven/scripts/update-check.mjs +120 -0
  461. package/.trae-cn/skills/seven/SKILL.md +163 -0
  462. package/.trae-cn/skills/seven/reference/adapt.md +34 -0
  463. package/.trae-cn/skills/seven/reference/animate.md +31 -0
  464. package/.trae-cn/skills/seven/reference/app-shell.md +152 -0
  465. package/.trae-cn/skills/seven/reference/audit.md +122 -0
  466. package/.trae-cn/skills/seven/reference/bolder.md +34 -0
  467. package/.trae-cn/skills/seven/reference/brand.md +31 -0
  468. package/.trae-cn/skills/seven/reference/clarify.md +76 -0
  469. package/.trae-cn/skills/seven/reference/color-and-contrast.md +84 -0
  470. package/.trae-cn/skills/seven/reference/colorize.md +31 -0
  471. package/.trae-cn/skills/seven/reference/critique.md +53 -0
  472. package/.trae-cn/skills/seven/reference/delight.md +30 -0
  473. package/.trae-cn/skills/seven/reference/distill.md +30 -0
  474. package/.trae-cn/skills/seven/reference/doctor.md +7 -0
  475. package/.trae-cn/skills/seven/reference/document.md +36 -0
  476. package/.trae-cn/skills/seven/reference/evaluations.md +38 -0
  477. package/.trae-cn/skills/seven/reference/exceptions.md +7 -0
  478. package/.trae-cn/skills/seven/reference/extract.md +42 -0
  479. package/.trae-cn/skills/seven/reference/harden.md +36 -0
  480. package/.trae-cn/skills/seven/reference/hooks.md +11 -0
  481. package/.trae-cn/skills/seven/reference/init.md +38 -0
  482. package/.trae-cn/skills/seven/reference/layout.md +33 -0
  483. package/.trae-cn/skills/seven/reference/live.md +106 -0
  484. package/.trae-cn/skills/seven/reference/motion-design.md +71 -0
  485. package/.trae-cn/skills/seven/reference/onboard.md +35 -0
  486. package/.trae-cn/skills/seven/reference/optimize.md +34 -0
  487. package/.trae-cn/skills/seven/reference/overdrive.md +32 -0
  488. package/.trae-cn/skills/seven/reference/polish.md +55 -0
  489. package/.trae-cn/skills/seven/reference/product.md +43 -0
  490. package/.trae-cn/skills/seven/reference/quieter.md +31 -0
  491. package/.trae-cn/skills/seven/reference/routing.md +28 -0
  492. package/.trae-cn/skills/seven/reference/shape.md +85 -0
  493. package/.trae-cn/skills/seven/reference/spatial-design.md +60 -0
  494. package/.trae-cn/skills/seven/reference/typeset.md +28 -0
  495. package/.trae-cn/skills/seven/reference/typography.md +43 -0
  496. package/.trae-cn/skills/seven/reference/ux-writing.md +47 -0
  497. package/.trae-cn/skills/seven/reference/visual-probes.md +36 -0
  498. package/.trae-cn/skills/seven/scripts/context-signals.mjs +94 -0
  499. package/.trae-cn/skills/seven/scripts/critique-storage.mjs +155 -0
  500. package/.trae-cn/skills/seven/scripts/load-context.mjs +93 -0
  501. package/.trae-cn/skills/seven/scripts/update-check.mjs +120 -0
  502. package/.vibe/skills/seven/SKILL.md +166 -0
  503. package/.vibe/skills/seven/reference/adapt.md +34 -0
  504. package/.vibe/skills/seven/reference/animate.md +31 -0
  505. package/.vibe/skills/seven/reference/app-shell.md +152 -0
  506. package/.vibe/skills/seven/reference/audit.md +122 -0
  507. package/.vibe/skills/seven/reference/bolder.md +34 -0
  508. package/.vibe/skills/seven/reference/brand.md +31 -0
  509. package/.vibe/skills/seven/reference/clarify.md +76 -0
  510. package/.vibe/skills/seven/reference/color-and-contrast.md +84 -0
  511. package/.vibe/skills/seven/reference/colorize.md +31 -0
  512. package/.vibe/skills/seven/reference/critique.md +53 -0
  513. package/.vibe/skills/seven/reference/delight.md +30 -0
  514. package/.vibe/skills/seven/reference/distill.md +30 -0
  515. package/.vibe/skills/seven/reference/doctor.md +7 -0
  516. package/.vibe/skills/seven/reference/document.md +36 -0
  517. package/.vibe/skills/seven/reference/evaluations.md +38 -0
  518. package/.vibe/skills/seven/reference/exceptions.md +7 -0
  519. package/.vibe/skills/seven/reference/extract.md +42 -0
  520. package/.vibe/skills/seven/reference/harden.md +36 -0
  521. package/.vibe/skills/seven/reference/hooks.md +11 -0
  522. package/.vibe/skills/seven/reference/init.md +38 -0
  523. package/.vibe/skills/seven/reference/layout.md +33 -0
  524. package/.vibe/skills/seven/reference/live.md +106 -0
  525. package/.vibe/skills/seven/reference/motion-design.md +71 -0
  526. package/.vibe/skills/seven/reference/onboard.md +35 -0
  527. package/.vibe/skills/seven/reference/optimize.md +34 -0
  528. package/.vibe/skills/seven/reference/overdrive.md +32 -0
  529. package/.vibe/skills/seven/reference/polish.md +55 -0
  530. package/.vibe/skills/seven/reference/product.md +43 -0
  531. package/.vibe/skills/seven/reference/quieter.md +31 -0
  532. package/.vibe/skills/seven/reference/routing.md +28 -0
  533. package/.vibe/skills/seven/reference/shape.md +85 -0
  534. package/.vibe/skills/seven/reference/spatial-design.md +60 -0
  535. package/.vibe/skills/seven/reference/typeset.md +28 -0
  536. package/.vibe/skills/seven/reference/typography.md +43 -0
  537. package/.vibe/skills/seven/reference/ux-writing.md +47 -0
  538. package/.vibe/skills/seven/reference/visual-probes.md +36 -0
  539. package/.vibe/skills/seven/scripts/context-signals.mjs +94 -0
  540. package/.vibe/skills/seven/scripts/critique-storage.mjs +155 -0
  541. package/.vibe/skills/seven/scripts/load-context.mjs +93 -0
  542. package/.vibe/skills/seven/scripts/update-check.mjs +120 -0
  543. package/README.md +51 -90
  544. package/cli/bin/seven.mjs +0 -0
  545. package/cli/engine/browser/injected/index.mjs +62 -13
  546. package/cli/engine/detect-antipatterns-browser.js +4743 -23
  547. package/cli/engine/detect-antipatterns.mjs +1 -0
  548. package/cli/engine/engines/browser/detect-url.mjs +366 -3
  549. package/cli/engine/engines/regex/detect-text.mjs +469 -1
  550. package/cli/engine/engines/static-html/detect-html.mjs +131 -0
  551. package/cli/engine/registry/seven-antipatterns.mjs +379 -4
  552. package/cli/engine/rules/checks.mjs +360 -1
  553. package/cli/engine/shared/tokens.mjs +19 -0
  554. package/cli/engine/token-data.generated.mjs +4029 -4
  555. package/docs/detector-rules.md +277 -38
  556. package/docs/upstream-parity.json +242 -0
  557. package/extension/README.md +5 -0
  558. package/extension/background/service-worker.js +134 -0
  559. package/extension/content/content-script.js +340 -0
  560. package/extension/detector/detect.js +7816 -0
  561. package/extension/devtools/devtools.html +1 -0
  562. package/extension/devtools/devtools.js +3 -0
  563. package/extension/devtools/panel.css +66 -0
  564. package/extension/devtools/panel.html +3 -0
  565. package/extension/devtools/panel.js +37 -0
  566. package/extension/manifest.json +22 -0
  567. package/extension/popup/popup.css +106 -0
  568. package/extension/popup/popup.html +27 -0
  569. package/extension/popup/popup.js +74 -0
  570. package/package.json +18 -7
@@ -21,6 +21,7 @@ import { runChecks } from '../../rules/checks.mjs'
21
21
 
22
22
  const hasRounded = (line) => /\brounded(?:-\w+)?\b/.test(line)
23
23
  const hasBorderRadius = (line) => /border-radius/i.test(line)
24
+ const isCommentLine = (line) => /^\s*(?:\/\/|\/\*|\*|\*\/)/.test(line)
24
25
  const isSafeElement = (line) =>
25
26
  /<(?:blockquote|nav[\s>]|pre[\s>]|code[\s>]|a\s|input[\s>]|span[\s>])/i.test(line)
26
27
 
@@ -53,9 +54,265 @@ const COLORED_BORDER_CLASS_RE =
53
54
  /\bborder-(?:[lrtbxy]-)?(?:(?:red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-\d{2,3}|primary|secondary|destructive|warning|success|info|accent|brand)\b/
54
55
  const hasColoredSideAccent = (line) => COLORED_BORDER_CLASS_RE.test(line)
55
56
 
57
+ function lineAtIndex(content, index) {
58
+ return content.slice(0, Math.max(0, index)).split('\n').length
59
+ }
60
+
61
+ function normalizeVisibleText(value) {
62
+ return String(value || '')
63
+ .replace(/&nbsp;/gi, ' ')
64
+ .replace(/&amp;/gi, '&')
65
+ .replace(/\s+/g, ' ')
66
+ .trim()
67
+ }
68
+
69
+ /** Extract text that can plausibly reach product chrome, excluding code and comments. */
70
+ function extractUserFacingText(content) {
71
+ const masked = String(content || '')
72
+ .replace(/\/\*[\s\S]*?\*\//g, ' ')
73
+ .replace(/(^|[^:])\/\/[^\n]*/gm, '$1 ')
74
+ .replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, ' ')
75
+ .replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, ' ')
76
+ const values = []
77
+ for (const match of masked.matchAll(/>([^<{][^<]*)</g)) {
78
+ const text = normalizeVisibleText(match[1])
79
+ if (text) values.push(text)
80
+ }
81
+ for (const match of masked.matchAll(/\b(?:aria-label|title|placeholder|label|description|helperText|emptyText)\s*=\s*(?:\{\s*)?["'`]([^"'`]{2,240})["'`]/gi)) {
82
+ const text = normalizeVisibleText(match[1])
83
+ if (text) values.push(text)
84
+ }
85
+ return values.join('\n')
86
+ }
87
+
88
+ function parseCssLengthPx(value) {
89
+ const match = String(value || '').trim().match(/^(-?[\d.]+)(px|rem|em)$/i)
90
+ if (!match) return null
91
+ const amount = Number(match[1])
92
+ if (!Number.isFinite(amount)) return null
93
+ return match[2].toLowerCase() === 'px' ? amount : amount * 16
94
+ }
95
+
96
+ function hasShellChromeOutline(attrs) {
97
+ const classValue =
98
+ String(attrs || '').match(/\bclass(?:Name)?\s*=\s*["']([^"']*)["']/i)?.[1] || ''
99
+ const utilityOutline = classValue.split(/\s+/).some((token) => {
100
+ const utility = token.split(':').at(-1) || ''
101
+ if (/^shadow(?:$|-)/.test(utility)) return utility !== 'shadow-none'
102
+ if (/^border(?:$|-[trblxy]$|-[trblxy]-(?!0$|none$)|-(?:\d+|\[[^\]]+\])$)/.test(utility)) {
103
+ return !/(?:^|-)(?:0|none)$/.test(utility)
104
+ }
105
+ return false
106
+ })
107
+ return utilityOutline || /\b(?:boxShadow|box-shadow|border(?:Top|Right|Bottom|Left)?(?:Width)?)\s*:/i.test(attrs)
108
+ }
109
+
110
+ function hasManualSidebarOffset(attrs) {
111
+ const classValue =
112
+ String(attrs || '').match(/\bclass(?:Name)?\s*=\s*["']([^"']*)["']/i)?.[1] || ''
113
+ return classValue.split(/\s+/).some((token) => {
114
+ const utility = token.split(':').at(-1) || ''
115
+ return /^(?:m[lr]|p[lr]|left|right)-/.test(utility) || /^w-\[calc\(/.test(utility)
116
+ })
117
+ }
118
+
119
+ /**
120
+ * Lightweight JSX ancestry check for Seven's application shell. Runtime DOM
121
+ * geometry is checked separately; this catches the same mistake before render.
122
+ */
123
+ function analyzeSidebarTopbarShell(content, filePath) {
124
+ if (!/\.[cm]?[jt]sx$/i.test(filePath || '')) return []
125
+ if (!/<SidebarProvider\b/.test(content) || !/<Sidebar\b/.test(content) || !/<Topbar\b/.test(content)) {
126
+ return []
127
+ }
128
+
129
+ const providerCount = [...content.matchAll(/<SidebarProvider\b/g)].length
130
+ const topbarCount = [...content.matchAll(/<Topbar\b/g)].length
131
+ const tagRe = /<(\/?)(SidebarProvider|SidebarInset|Sidebar|Topbar|SidebarTrigger)\b([^>]*?)(\/?)>/g
132
+ const stack = []
133
+ const topbars = []
134
+ const findings = []
135
+ let match
136
+
137
+ while ((match = tagRe.exec(content)) !== null) {
138
+ const closing = match[1] === '/'
139
+ const name = match[2]
140
+ const attrs = match[3] || ''
141
+ const selfClosing = match[4] === '/' || /\/\s*$/.test(attrs)
142
+
143
+ if (closing) {
144
+ const index = stack.findLastIndex((entry) => entry.name === name)
145
+ if (index >= 0) stack.splice(index, 1)
146
+ continue
147
+ }
148
+
149
+ const provider = [...stack].reverse().find((entry) => entry.name === 'SidebarProvider')
150
+ const inset = [...stack].reverse().find((entry) => entry.name === 'SidebarInset')
151
+ const entry = { name, index: match.index, attrs }
152
+
153
+ if (name === 'SidebarProvider') {
154
+ entry.hasSidebar = false
155
+ entry.staticSidebar = false
156
+ } else if (name === 'Sidebar' && provider) {
157
+ provider.hasSidebar = true
158
+ if (/\bcollapsible\s*=\s*(?:["']none["']|\{\s*["']none["']\s*\})/i.test(attrs)) {
159
+ provider.staticSidebar = true
160
+ }
161
+ } else if (name === 'SidebarInset' && provider && hasManualSidebarOffset(attrs)) {
162
+ findings.push(
163
+ finding(
164
+ 'sidebar-topbar-shell',
165
+ filePath,
166
+ 'SidebarInset uses a manual sidebar offset instead of the provider sibling layout',
167
+ lineAtIndex(content, match.index)
168
+ )
169
+ )
170
+ } else if (name === 'Topbar') {
171
+ const validAncestry = Boolean(provider && inset)
172
+ const topbar = {
173
+ index: match.index,
174
+ provider,
175
+ validAncestry,
176
+ hasTrigger: false,
177
+ }
178
+ topbars.push(topbar)
179
+ entry.topbar = topbar
180
+
181
+ if (provider && !inset) {
182
+ findings.push(
183
+ finding(
184
+ 'sidebar-topbar-shell',
185
+ filePath,
186
+ 'Topbar is inside SidebarProvider but outside SidebarInset',
187
+ lineAtIndex(content, match.index)
188
+ )
189
+ )
190
+ } else if (!provider && providerCount === 1 && topbarCount === 1) {
191
+ findings.push(
192
+ finding(
193
+ 'sidebar-topbar-shell',
194
+ filePath,
195
+ 'Topbar is outside the only SidebarProvider; the shell would be T-shaped or disconnected',
196
+ lineAtIndex(content, match.index)
197
+ )
198
+ )
199
+ }
200
+
201
+ if (validAncestry && hasShellChromeOutline(attrs)) {
202
+ findings.push(
203
+ finding(
204
+ 'sidebar-topbar-shell',
205
+ filePath,
206
+ 'Shell Topbar adds a border or shadow; Seven chrome is borderless',
207
+ lineAtIndex(content, match.index)
208
+ )
209
+ )
210
+ }
211
+ } else if (name === 'SidebarTrigger') {
212
+ const topbarEntry = [...stack].reverse().find((item) => item.name === 'Topbar')
213
+ if (topbarEntry?.topbar) topbarEntry.topbar.hasTrigger = true
214
+ }
215
+
216
+ if (!selfClosing) stack.push(entry)
217
+ }
218
+
219
+ for (const topbar of topbars) {
220
+ if (
221
+ topbar.validAncestry &&
222
+ topbar.provider?.hasSidebar &&
223
+ !topbar.provider.staticSidebar &&
224
+ !topbar.hasTrigger
225
+ ) {
226
+ findings.push(
227
+ finding(
228
+ 'sidebar-topbar-shell',
229
+ filePath,
230
+ 'Collapsible Sidebar + Topbar shell has no SidebarTrigger inside Topbar',
231
+ lineAtIndex(content, topbar.index)
232
+ )
233
+ )
234
+ }
235
+ }
236
+
237
+ return findings
238
+ }
239
+
240
+ /**
241
+ * Source contract for the dual Rail. Labels are authored data, so checking
242
+ * them before render catches the empty 200px overlay that DOM geometry alone
243
+ * cannot explain. The ancestry pass also rejects Link > button nesting.
244
+ */
245
+ function analyzeSidebarRailBehavior(content, filePath) {
246
+ if (!/\.[cm]?[jt]sx$/i.test(filePath || '')) return []
247
+ if (!/<SidebarRailContent\b/.test(content) || !/<SidebarRailButton\b/.test(content)) {
248
+ return []
249
+ }
250
+
251
+ const findings = []
252
+ const stack = []
253
+ const tagRe = /<(\/?)(SidebarRailButton|NavLink|Link|a)\b([^>]*?)(\/?)>/g
254
+ let match
255
+
256
+ while ((match = tagRe.exec(content)) !== null) {
257
+ const closing = match[1] === '/'
258
+ const name = match[2]
259
+ const attrs = match[3] || ''
260
+ const selfClosing = match[4] === '/' || /\/\s*$/.test(attrs)
261
+
262
+ if (closing) {
263
+ const index = stack.findLastIndex((entry) => entry.name === name)
264
+ if (index >= 0) stack.splice(index, 1)
265
+ continue
266
+ }
267
+
268
+ if (name === 'SidebarRailButton') {
269
+ if (!/\blabel\s*=/.test(attrs)) {
270
+ findings.push(
271
+ finding(
272
+ 'sidebar-rail-behavior',
273
+ filePath,
274
+ 'SidebarRailButton in a dual Rail has no label for the expanded overlay',
275
+ lineAtIndex(content, match.index)
276
+ )
277
+ )
278
+ }
279
+
280
+ const linkAncestor = [...stack]
281
+ .reverse()
282
+ .find((entry) => entry.name === 'Link' || entry.name === 'NavLink' || entry.name === 'a')
283
+ if (linkAncestor) {
284
+ findings.push(
285
+ finding(
286
+ 'sidebar-rail-behavior',
287
+ filePath,
288
+ `${linkAncestor.name} wraps SidebarRailButton; put asChild on SidebarRailButton and make the link its child`,
289
+ lineAtIndex(content, match.index)
290
+ )
291
+ )
292
+ }
293
+ }
294
+
295
+ if (!selfClosing) stack.push({ name })
296
+ }
297
+
298
+ return findings
299
+ }
300
+
56
301
  // Per-line matchers — each emits one Seven rule ID. `test(match, line)` gates
57
302
  // the hit; `fmt(match, line)` builds the snippet.
58
303
  const REGEX_MATCHERS = [
304
+ {
305
+ id: 'broken-image',
306
+ regex: /<img\b[^>]*?\bsrc\s*=\s*(?:""|''|"\s+"|'\s+'|"#"|'#')/gi,
307
+ test: (match, line) => !isCommentLine(line),
308
+ fmt: (match) => match[0],
309
+ },
310
+ {
311
+ id: 'broken-image',
312
+ regex: /<img\b(?:(?!\bsrc\s*=)[^>])*>/gi,
313
+ test: (match, line) => !isCommentLine(line) && !/\{\s*\.\.\./.test(match[0]),
314
+ fmt: () => '<img> without src',
315
+ },
59
316
  // --- Side-stripe border ---
60
317
  // A Tailwind side border is a stripe only when it is >=2px AND carries a
61
318
  // colored accent. A bare `border-l-2` (default/neutral color) is a
@@ -195,6 +452,200 @@ const REGEX_MATCHERS = [
195
452
  return `transition-property: ${found ? found.join(', ') : m[1].trim()}`
196
453
  },
197
454
  },
455
+ // --- Current upstream signals adapted to Seven ---
456
+ {
457
+ id: 'radial-halo',
458
+ regex: /radial-gradient\([^;{}\n]*(?:transparent|rgba\([^)]*,\s*0(?:\.0+)?\s*\))[^;{}\n]*\)/gi,
459
+ test: (m, line) => !/(?:chart|heatmap|radar|canvas|mask-image)/i.test(line),
460
+ fmt: () => 'radial-gradient color wash fading to transparent',
461
+ },
462
+ {
463
+ id: 'marquee',
464
+ regex: /<marquee\b[^>]*>|\banimate-(?:marquee|ticker|scroll)\b/gi,
465
+ test: (m, line) => !isCommentLine(line),
466
+ fmt: (m) => m[0],
467
+ },
468
+ {
469
+ id: 'blinking-cursor',
470
+ regex: /\banimate-(?:blink|cursor|caret)\b|animation(?:-name)?\s*:\s*(?:blink|cursor|caret)\b/gi,
471
+ test: (m, line, filePath) =>
472
+ !/<(?:input|textarea)\b|contenteditable/i.test(line) &&
473
+ !/(?:input-?otp|otpinput|editable)/i.test(filePath || ''),
474
+ fmt: (m) => m[0],
475
+ },
476
+ {
477
+ id: 'extreme-negative-tracking',
478
+ regex: /letter-spacing\s*:\s*(-?[\d.]+)(em|px)|\btracking-\[(-?[\d.]+)(em|px)\]/gi,
479
+ test: (m) => {
480
+ const value = Number(m[1] ?? m[3])
481
+ const unit = String(m[2] ?? m[4]).toLowerCase()
482
+ return unit === 'em' ? value < -0.075 : value < -1.2
483
+ },
484
+ fmt: (m) => m[0],
485
+ },
486
+ {
487
+ id: 'repeating-stripes-gradient',
488
+ regex: /repeating-(?:linear|radial|conic)-gradient\s*\(/gi,
489
+ test: (m, line, filePath) =>
490
+ !/(?:chart|progress|skeleton|mask-image|checkerboard|color-picker|alpha)/i.test(line) &&
491
+ !/(?:colorpicker|color-picker|colormath)/i.test(filePath || ''),
492
+ fmt: (m) => m[0],
493
+ },
494
+ {
495
+ id: 'image-hover-transform',
496
+ regex: /img\s*:\s*hover\s*\{[^}]*transform\s*:\s*(?:scale|rotate)|<img\b[^>]*\bhover:(?:scale|rotate)-[^\s"']+/gi,
497
+ test: (m, line) => !isCommentLine(line),
498
+ fmt: () => 'image scales or rotates on hover',
499
+ },
500
+ {
501
+ id: 'undersized-ui-text',
502
+ regex: /<(?:a|button|label|th|td|time|option|summary)\b[^>]*(?:text-\[(?:length:)?([\d.]+)px\]|font-size\s*:\s*([\d.]+)px)[^>]*>/gi,
503
+ test: (m) => Number(m[1] ?? m[2]) < 11,
504
+ fmt: (m) => `${Number(m[1] ?? m[2])}px functional text`,
505
+ },
506
+ ]
507
+
508
+ const SOURCE_ANALYZERS = [
509
+ analyzeSidebarTopbarShell,
510
+ analyzeSidebarRailBehavior,
511
+ // A small round element using a pulse animation. Static status dots without
512
+ // animation and real progress indicators are intentionally ignored.
513
+ (content, filePath) => {
514
+ const tagRe = /<(span|div|i)\b([^>]*)>/gi
515
+ let match
516
+ while ((match = tagRe.exec(content)) !== null) {
517
+ const attrs = match[2]
518
+ if (!/(?:animate-pulse|animation\s*:\s*[^;"']*pulse)/i.test(attrs)) continue
519
+ if (!/(?:rounded-full|border-radius\s*:\s*50%)/i.test(attrs)) continue
520
+ const tailwindSmall = /\b(?:size|w|h)-(?:1|1\.5|2|2\.5|3|3\.5|4)\b/.test(attrs)
521
+ const width = attrs.match(/width\s*:\s*([\d.]+)px/i)?.[1]
522
+ const height = attrs.match(/height\s*:\s*([\d.]+)px/i)?.[1]
523
+ const inlineSmall = width && height && Number(width) <= 16 && Number(height) <= 16
524
+ if (!tailwindSmall && !inlineSmall) continue
525
+ return [finding('pulsing-dot', filePath, 'small round element with pulse animation', lineAtIndex(content, match.index))]
526
+ }
527
+ return []
528
+ },
529
+ // Large pictorial SVG made from primitive shapes. Lucide-sized icons,
530
+ // logos, and explicit chart/data graphics stay out of scope.
531
+ (content, filePath) => {
532
+ const svgRe = /<svg\b([^>]*)>([\s\S]*?)<\/svg>/gi
533
+ let match
534
+ while ((match = svgRe.exec(content)) !== null) {
535
+ const attrs = match[1]
536
+ if (/(?:chart|graph|logo|icon|sparkline|data-viz|data-role=["']chart)/i.test(attrs)) continue
537
+ const primitives = [...match[2].matchAll(/<(?:rect|circle|ellipse|polygon|path)\b/gi)].length
538
+ const viewBox = attrs.match(/viewBox\s*=\s*["'][^"']*\s([\d.]+)\s+([\d.]+)["']/i)
539
+ const width = Number(attrs.match(/\bwidth\s*=\s*["']?([\d.]+)/i)?.[1] || viewBox?.[1] || 0)
540
+ const height = Number(attrs.match(/\bheight\s*=\s*["']?([\d.]+)/i)?.[1] || viewBox?.[2] || 0)
541
+ if (primitives < 12 || Math.max(width, height) < 200) continue
542
+ return [finding('shape-assembled-illustration', filePath, `${primitives} primitive SVG shapes in a ${width || '?'}×${height || '?'} visual`, lineAtIndex(content, match.index))]
543
+ }
544
+ return []
545
+ },
546
+ // Infinite horizontal travel. This deliberately requires both keyframe
547
+ // movement and infinite use, so finite carousel transitions are not hit.
548
+ (content, filePath) => {
549
+ const travelingNames = new Set()
550
+ for (const match of content.matchAll(/@keyframes\s+([\w-]+)\s*\{([\s\S]*?)\n?\}/gi)) {
551
+ if (/translateX\s*\(\s*-?(?:50|100)%|translate3d\s*\(\s*-?(?:50|100)%/i.test(match[2])) travelingNames.add(match[1])
552
+ }
553
+ for (const name of travelingNames) {
554
+ const use = new RegExp(`animation(?:-name)?\\s*:[^;{}]*\\b${name}\\b[^;{}]*\\binfinite\\b|animation-iteration-count\\s*:\\s*infinite`, 'i')
555
+ if (use.test(content)) return [finding('marquee', filePath, `infinite horizontal animation "${name}"`)]
556
+ }
557
+ return []
558
+ },
559
+ // Repeated rounded icon tiles directly before headings.
560
+ (content, filePath) => {
561
+ const matches = [...content.matchAll(/<(?:div|span)\b[^>]*(?:rounded(?:-\w+)?|border-radius)[^>]*>[\s\S]{0,400}?(?:<svg\b|<\w+(?:Icon|icon)\b)[\s\S]{0,500}?<h[2-5]\b/gi)]
562
+ if (matches.length < 3) return []
563
+ return [finding('icon-tile-stack', filePath, `${matches.length} rounded icon tiles stacked above headings`, lineAtIndex(content, matches[0].index || 0))]
564
+ },
565
+ // Tiny sequence labels repeated as section scaffolding.
566
+ (content, filePath) => {
567
+ const matches = [...content.matchAll(/<(?:span|small|div)\b[^>]*(?:text-(?:xs|\[(?:length:)?(?:8|9|10|11)px\])|font-size\s*:\s*(?:8|9|10|11)px)[^>]*>\s*(?:0?\d{1,2}|[IVX]{1,5})\s*<\/[^>]+>[\s\S]{0,240}?<h[2-5]\b/gi)]
568
+ if (matches.length < 3) return []
569
+ return [finding('numbered-section-labels', filePath, `${matches.length} tiny numbered section labels`, lineAtIndex(content, matches[0].index || 0))]
570
+ },
571
+ // Long display heading: the combination of copy length and scale is the
572
+ // defect, never display size alone.
573
+ (content, filePath) => {
574
+ const h1Re = /<h1\b([^>]*)>([\s\S]*?)<\/h1>/gi
575
+ let match
576
+ while ((match = h1Re.exec(content)) !== null) {
577
+ const attrs = match[1]
578
+ const text = normalizeVisibleText(match[2].replace(/<[^>]+>/g, ' '))
579
+ const tailwind = attrs.match(/\btext-(7xl|8xl|9xl)\b/i)
580
+ const inline = attrs.match(/font-size\s*:\s*([\d.]+)(px|rem|em)/i)
581
+ const px = inline ? parseCssLengthPx(`${inline[1]}${inline[2]}`) : tailwind ? { '7xl': 72, '8xl': 96, '9xl': 128 }[tailwind[1].toLowerCase()] : 0
582
+ if ((px || 0) < 64 || (text.length < 32 && text.split(/\s+/).length < 6)) continue
583
+ return [finding('oversized-h1', filePath, `${Math.round(px || 0)}px h1 with ${text.length} characters`, lineAtIndex(content, match.index))]
584
+ }
585
+ return []
586
+ },
587
+ // Hairline edge plus diffuse shadow in the same authored block or utility
588
+ // list. Borders on overlays are allowed; the card-decoration combination is not.
589
+ (content, filePath) => {
590
+ for (const match of content.matchAll(/([^{}]+)\{([^{}]+)\}/g)) {
591
+ const selector = match[1]
592
+ const body = match[2]
593
+ if (/(?:dialog|popover|menu|tooltip|overlay)/i.test(selector)) continue
594
+ if (!/(?:border(?:-width)?\s*:\s*1px|border\s*:\s*1px\s+solid)/i.test(body)) continue
595
+ const shadow = body.match(/box-shadow\s*:\s*([^;]+)/i)?.[1] || ''
596
+ const lengthSource = shadow.replace(/(?:rgb|hsl|oklch)a?\([^)]*\)/gi, '')
597
+ const lengths = [...lengthSource.matchAll(/(-?[\d.]+)px|(?<![\d.])(-?0)(?![\d.])/g)]
598
+ .map((item) => Math.abs(Number(item[1] ?? item[2])))
599
+ if (lengths.length >= 3 && lengths[2] >= 16) {
600
+ return [finding('gpt-thin-border-wide-shadow', filePath, `1px border + ${lengths[2]}px shadow blur`, lineAtIndex(content, match.index || 0))]
601
+ }
602
+ }
603
+ const utility = content.match(/class(?:Name)?\s*=\s*["'][^"']*\bborder\b[^"']*\bshadow-(?:xl|2xl)\b[^"']*["']/i)
604
+ return utility ? [finding('gpt-thin-border-wide-shadow', filePath, 'border + wide Tailwind shadow', lineAtIndex(content, utility.index || 0))] : []
605
+ },
606
+ // Two perpendicular tiled gradients form the generated-UI grid tell.
607
+ (content, filePath) => {
608
+ if (/(?:data-role=["'](?:chart|canvas|map)|blueprint|measurement)/i.test(content)) return []
609
+ const gradients = [...content.matchAll(/linear-gradient\s*\(/gi)]
610
+ if (gradients.length < 2 || !/background-size\s*:\s*\d+(?:px|rem)\s+\d+(?:px|rem)/i.test(content)) return []
611
+ if (!/(?:1px|\.5px)[^;{}]{0,160}(?:transparent|rgba\([^)]*,\s*0)/i.test(content)) return []
612
+ return [finding('codex-grid-background', filePath, 'two-axis tiled hairline gradient grid')]
613
+ },
614
+ // Copy analyzers only inspect text that can plausibly reach UI chrome.
615
+ (content, filePath) => {
616
+ const text = extractUserFacingText(content)
617
+ const match = text.match(/\b(?:streamline|empower|supercharge|world-class|enterprise-grade|next-generation|cutting-edge|seamless|revolucione|potencialize|líder de mercado|de ponta|sem atrito|nível empresarial|tudo em um)\b/i)
618
+ return match ? [finding('marketing-buzzword', filePath, `generic claim: "${match[0]}"`)] : []
619
+ },
620
+ (content, filePath) => {
621
+ const text = extractUserFacingText(content)
622
+ const patterns = [
623
+ ...(text.match(/\bnão\s+[^.!?]{2,50}[.!?]\s+(?:é|apenas|simplesmente|só)\s+[^.!?]{2,50}[.!?]/gim) || []),
624
+ ...(text.match(/\bnot\s+[^.!?]{2,50}[.!?]\s+(?:just|simply)\s+[^.!?]{2,50}[.!?]/gim) || []),
625
+ ]
626
+ return patterns.length >= 3 ? [finding('aphoristic-cadence', filePath, `${patterns.length} repeated contrast constructions`)] : []
627
+ },
628
+ (content, filePath) => {
629
+ const text = extractUserFacingText(content)
630
+ const match = text.match(/\b(?:security|innovation|compliance|productivity|growth|performance|automation|design|innovation|segurança|inovação|conformidade|produtividade|crescimento|performance|automação|design)\s+theater\b/i)
631
+ return match ? [finding('theater-slop-phrase', filePath, `"${match[0]}"`)] : []
632
+ },
633
+ ]
634
+
635
+ const SOURCE_ANALYZER_RULE_IDS = [
636
+ 'sidebar-topbar-shell',
637
+ 'sidebar-rail-behavior',
638
+ 'pulsing-dot',
639
+ 'shape-assembled-illustration',
640
+ 'marquee',
641
+ 'icon-tile-stack',
642
+ 'numbered-section-labels',
643
+ 'oversized-h1',
644
+ 'gpt-thin-border-wide-shadow',
645
+ 'codex-grid-background',
646
+ 'marketing-buzzword',
647
+ 'aphoristic-cadence',
648
+ 'theater-slop-phrase',
198
649
  ]
199
650
 
200
651
  // Whole-file analyzers — one per page-level rule. Each returns an array of
@@ -378,7 +829,7 @@ function runRegexMatchers(lines, filePath, lineOffset = 0, blockContext = null,
378
829
  const context = blockContext
379
830
  ? lines.slice(Math.max(0, i - 3), Math.min(lines.length, i + 4)).join(' ')
380
831
  : line
381
- if (matcher.test(m, context)) {
832
+ if (matcher.test(m, context, filePath)) {
382
833
  matches.push(finding(matcher.id, filePath, matcher.fmt(m, context), i + 1 + lineOffset))
383
834
  }
384
835
  }
@@ -469,6 +920,21 @@ function detectText(content, filePath, options = {}) {
469
920
  )
470
921
  }
471
922
 
923
+ // Pipeline 2b: whole-source analyzers for signals that need sibling
924
+ // declarations, repeated structures, or UI-copy context.
925
+ for (let i = 0; i < SOURCE_ANALYZERS.length; i++) {
926
+ const analyzerRuleId = SOURCE_ANALYZER_RULE_IDS[i]
927
+ if (ruleIds && !ruleIds.includes(analyzerRuleId)) continue
928
+ const analyzer = SOURCE_ANALYZERS[i]
929
+ findings.push(
930
+ ...profileFindings(
931
+ profile,
932
+ { engine: 'regex', phase: 'source-analyzer', ruleId: analyzerRuleId, target: filePath },
933
+ () => analyzer(content, filePath)
934
+ )
935
+ )
936
+ }
937
+
472
938
  // Deduplicate (same antipattern + snippet within 2 lines).
473
939
  const deduped = []
474
940
  for (const f of findings) {
@@ -501,6 +967,8 @@ export {
501
967
  REGEX_MATCHERS,
502
968
  REGEX_ANALYZERS,
503
969
  ANALYZER_RULE_IDS,
970
+ SOURCE_ANALYZERS,
971
+ SOURCE_ANALYZER_RULE_IDS,
504
972
  extractStyleBlocks,
505
973
  extractCSSinJS,
506
974
  runRegexMatchers,
@@ -21,6 +21,8 @@ import {
21
21
  checkPageLayout,
22
22
  checkPageQualityFromDoc,
23
23
  checkPageTypography,
24
+ checkSidebarRailBehavior,
25
+ checkSidebarTopbarShell,
24
26
  resolveBackground,
25
27
  } from '../../rules/checks.mjs'
26
28
  import { detectText } from '../regex/detect-text.mjs'
@@ -44,7 +46,77 @@ import {
44
46
 
45
47
  // Per-element rules: each names a selector and a check. `customPropMap` is
46
48
  // reserved for var() resolution the cascade already performs upstream.
49
+ function checkBrokenImage(element) {
50
+ const source = String(element.getAttribute('src') || '').trim()
51
+ if (!source || /^(?:#|about:blank)$|(?:placehold|placeholder|example)\./i.test(source)) {
52
+ return [{ id: 'broken-image', snippet: source ? `<img src="${source}">` : '<img> without a usable src' }]
53
+ }
54
+ return []
55
+ }
56
+
57
+ function checkClippedPositionedChild(element, style, window) {
58
+ if (!/(hidden|clip)/.test(`${style.overflow || ''} ${style.overflowX || ''} ${style.overflowY || ''}`)) return []
59
+ for (const child of element.querySelectorAll('*')) {
60
+ const childStyle = window.getComputedStyle(child)
61
+ if (childStyle.position !== 'absolute') continue
62
+ const identity = `${child.getAttribute('role') || ''} ${child.getAttribute('class') || ''} ${child.getAttribute('data-slot') || ''}`
63
+ if (!/(menu|tooltip|popover)/i.test(identity)) continue
64
+ return [{ id: 'clipped-overflow-container', snippet: `${element.tagName.toLowerCase()} clips positioned ${child.tagName.toLowerCase()}` }]
65
+ }
66
+ return []
67
+ }
68
+
69
+ function directText(element) {
70
+ return [...element.childNodes]
71
+ .filter((node) => node.nodeType === 3)
72
+ .map((node) => node.textContent || '')
73
+ .join(' ')
74
+ .replace(/\s+/g, ' ')
75
+ .trim()
76
+ }
77
+
78
+ function checkUndersizedUiText(element, style, tag) {
79
+ const identity = `${element.getAttribute('class') || ''} ${element.getAttribute('data-slot') || ''}`
80
+ if (/(?:sr-only|visually-hidden|legal|smallprint|code|terminal)/i.test(identity)) return []
81
+ if (['sup', 'sub', 'code', 'pre'].includes(tag) || element.getAttribute('aria-hidden') === 'true') return []
82
+ const text = directText(element)
83
+ const size = parseFloat(style.fontSize)
84
+ if (!text || !Number.isFinite(size) || size >= 11 || size <= 0) return []
85
+ return [{ id: 'undersized-ui-text', snippet: `${size}px functional ${tag} text "${text.slice(0, 60)}"` }]
86
+ }
87
+
88
+ function checkOversizedH1(element, style) {
89
+ const text = String(element.textContent || '').replace(/\s+/g, ' ').trim()
90
+ const size = parseFloat(style.fontSize)
91
+ if (!Number.isFinite(size) || size < 64 || (text.length < 32 && text.split(/\s+/).length < 6)) return []
92
+ return [{ id: 'oversized-h1', snippet: `${Math.round(size)}px h1 with ${text.length} characters` }]
93
+ }
94
+
95
+ function checkThinBorderWideShadow(element, style) {
96
+ const identity = `${element.getAttribute('class') || ''} ${element.getAttribute('data-slot') || ''} ${element.getAttribute('role') || ''}`
97
+ if (/(?:dialog|popover|menu|tooltip|overlay)/i.test(identity)) return []
98
+ const borders = ['Top', 'Right', 'Bottom', 'Left']
99
+ .map((side) => parseFloat(style[`border${side}Width`]) || 0)
100
+ .filter((value) => value > 0)
101
+ if (borders.length === 0 || Math.max(...borders) > 1.1) return []
102
+ const shadow = String(style.boxShadow || '')
103
+ if (!shadow || shadow === 'none') return []
104
+ const lengths = [...shadow.matchAll(/(-?[\d.]+)px/g)].map((match) => Math.abs(Number(match[1])))
105
+ if (lengths.length < 3 || lengths[2] < 16) return []
106
+ return [{ id: 'gpt-thin-border-wide-shadow', snippet: `${Math.max(...borders)}px border + ${lengths[2]}px shadow blur` }]
107
+ }
108
+
47
109
  const STATIC_ELEMENT_RULES = [
110
+ {
111
+ id: 'broken-image',
112
+ selector: 'img',
113
+ run: (el) => checkBrokenImage(el),
114
+ },
115
+ {
116
+ id: 'clipped-overflow-container',
117
+ selector: '*',
118
+ run: (el, tag, style, window) => checkClippedPositionedChild(el, style, window),
119
+ },
48
120
  {
49
121
  id: 'side-stripe-border',
50
122
  selector: '*',
@@ -86,8 +158,63 @@ const STATIC_ELEMENT_RULES = [
86
158
  selector: '*',
87
159
  run: (el, tag, style, window) => checkElementQuality(el, style, tag, window),
88
160
  },
161
+ {
162
+ id: 'undersized-ui-text',
163
+ selector: 'a,button,label,th,td,time,option,summary,[role="button"],[role="link"],[role="menuitem"],[role="tab"]',
164
+ run: (el, tag, style) => checkUndersizedUiText(el, style, tag),
165
+ },
166
+ {
167
+ id: 'oversized-h1',
168
+ selector: 'h1',
169
+ run: (el, tag, style) => checkOversizedH1(el, style),
170
+ },
171
+ {
172
+ id: 'gpt-thin-border-wide-shadow',
173
+ selector: '*',
174
+ run: (el, tag, style) => checkThinBorderWideShadow(el, style),
175
+ },
89
176
  ]
90
177
 
178
+ function checkIconTileStacks(document, window) {
179
+ let count = 0
180
+ let first = ''
181
+ for (const heading of document.querySelectorAll('h2,h3,h4,h5')) {
182
+ const tile = heading.previousElementSibling
183
+ if (!tile || !tile.querySelector('svg')) continue
184
+ const style = window.getComputedStyle(tile)
185
+ const width = parseFloat(style.width) || 0
186
+ const height = parseFloat(style.height) || 0
187
+ const radius = parseFloat(style.borderRadius) || parseFloat(style.borderTopLeftRadius) || 0
188
+ if (radius < 4 || width < 24 || height < 24 || width > 80 || height > 80) continue
189
+ count++
190
+ if (!first) first = String(heading.textContent || '').replace(/\s+/g, ' ').trim().slice(0, 60)
191
+ }
192
+ return count >= 3 ? [{ id: 'icon-tile-stack', snippet: `${count} rounded icon tiles stacked above headings${first ? `; first: "${first}"` : ''}` }] : []
193
+ }
194
+
195
+ function checkRepeatedContainerText(document) {
196
+ const findings = []
197
+ for (const container of document.querySelectorAll('article,aside,[role="region"],*')) {
198
+ const identity = `${container.getAttribute('class') || ''} ${container.getAttribute('data-slot') || ''} ${container.getAttribute('role') || ''}`
199
+ if (!/(?:card|panel|dialog|sheet|sidebar|region)/i.test(identity) && !['article', 'aside'].includes(container.tagName.toLowerCase())) continue
200
+ const occurrences = new Map()
201
+ for (const element of container.querySelectorAll('span,p,small,strong,em,label,div')) {
202
+ const text = directText(element).toLocaleLowerCase('pt-BR')
203
+ if (text.length < 2 || text.length > 80) continue
204
+ const entry = occurrences.get(text) || []
205
+ entry.push(`${element.tagName.toLowerCase()}.${String(element.getAttribute('class') || '').split(/\s+/)[0] || ''}`)
206
+ occurrences.set(text, entry)
207
+ }
208
+ for (const [text, structures] of occurrences) {
209
+ if (structures.length < 3 || new Set(structures).size < 2) continue
210
+ findings.push({ id: 'repeated-container-text', snippet: `"${text.slice(0, 60)}" appears ${structures.length} times in one container` })
211
+ break
212
+ }
213
+ if (findings.length >= 10) break
214
+ }
215
+ return findings
216
+ }
217
+
91
218
  /**
92
219
  * @param {string} filePath path to an HTML file
93
220
  * @param {{ ruleIds?: string[], profile?: object }} [options]
@@ -185,6 +312,10 @@ async function detectHtml(filePath, options = {}) {
185
312
  pushPage(runPageCheck('flat-type-hierarchy', () => checkPageTypography(document, window)))
186
313
  pushPage(runPageCheck('layout-rules', () => checkPageLayout(document, window)))
187
314
  pushPage(runPageCheck('skipped-heading', () => checkPageQualityFromDoc(document)))
315
+ pushPage(runPageCheck('sidebar-topbar-shell', () => checkSidebarTopbarShell(document)))
316
+ pushPage(runPageCheck('sidebar-rail-behavior', () => checkSidebarRailBehavior(document)))
317
+ pushPage(runPageCheck('icon-tile-stack', () => checkIconTileStacks(document, window)))
318
+ pushPage(runPageCheck('repeated-container-text', () => checkRepeatedContainerText(document)))
188
319
  pushPage(
189
320
  runPageCheck('html-patterns', () =>
190
321
  // bounce-easing and layout-transition are already covered by the regex