oh-my-opencode 5.1.51 → 5.1.55

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 (916) hide show
  1. package/dist/agents/atlas/agent.d.ts +5 -5
  2. package/dist/agents/dynamic-agent-core-sections.d.ts +0 -1
  3. package/dist/agents/dynamic-agent-prompt-builder.d.ts +1 -1
  4. package/dist/agents/gpt-apply-patch-guard.d.ts +0 -1
  5. package/dist/agents/hephaestus/agent.d.ts +3 -7
  6. package/dist/agents/hephaestus/model-support.d.ts +6 -0
  7. package/dist/agents/metis.d.ts +0 -15
  8. package/dist/agents/native-model-prompt.d.ts +9 -0
  9. package/dist/agents/native-prompt-frame.d.ts +20 -0
  10. package/dist/agents/native-tool-snippet.d.ts +6 -0
  11. package/dist/agents/sisyphus/default.d.ts +0 -1
  12. package/dist/agents/sisyphus-agent-factory.d.ts +2 -11
  13. package/dist/agents/sisyphus-junior/agent.d.ts +2 -20
  14. package/dist/agents/sisyphus-junior/index.d.ts +1 -11
  15. package/dist/agents/sisyphus-runtime-prompt-reconciler.d.ts +6 -0
  16. package/dist/agents/types.d.ts +2 -2
  17. package/dist/cli/index.js +1174 -394
  18. package/dist/cli/service-auth/credential-lock.d.ts +11 -0
  19. package/dist/cli/service-auth/credential-owner.d.ts +10 -0
  20. package/dist/cli/service-auth/index.d.ts +3 -1
  21. package/dist/cli/service-auth/keystore.d.ts +8 -1
  22. package/dist/cli/service-auth/owned-refresh.d.ts +21 -0
  23. package/dist/cli/service-auth/protocol-v2.d.ts +27 -0
  24. package/dist/cli/service-auth/protocol.d.ts +26 -2
  25. package/dist/cli/service-auth/recovery-clock.d.ts +7 -0
  26. package/dist/cli/service-auth/refresh-attempt.d.ts +34 -0
  27. package/dist/cli/service-auth/session.d.ts +9 -2
  28. package/dist/cli-node/index.js +1174 -394
  29. package/dist/config/schema/agent-overrides.d.ts +64 -0
  30. package/dist/config/schema/categories.d.ts +8 -0
  31. package/dist/config/schema/oh-my-opencode-config.d.ts +64 -0
  32. package/dist/hooks/native-edition-nudge/hook.d.ts +3 -4
  33. package/dist/index.js +15625 -8841
  34. package/dist/oh-my-opencode.schema.json +112 -0
  35. package/dist/plugin/session-tool-permissions.d.ts +10 -0
  36. package/dist/plugin/system-transform.d.ts +2 -1
  37. package/dist/plugin/tool-definition.d.ts +1 -0
  38. package/dist/shared/bun-ffi-shim.d.ts +29 -0
  39. package/dist/shared/json-file-cache-store.d.ts +11 -0
  40. package/dist/skills/browser/runtime/omowright/index.js +24 -33
  41. package/dist/skills/browser/runtime/omowright/manifest.json +3 -3
  42. package/dist/skills/frontend/ATTRIBUTION.md +104 -1
  43. package/dist/skills/frontend/SKILL.md +7 -3
  44. package/dist/skills/frontend/references/design/design-system-architecture.md +3 -3
  45. package/dist/skills/frontend/references/perfection/craft-floor.md +59 -0
  46. package/dist/skills/frontend/references/perfection/detect.md +52 -0
  47. package/dist/skills/frontend/scripts/detect/cli.ts +70 -0
  48. package/dist/skills/frontend/scripts/detect/config.test.ts +26 -0
  49. package/dist/skills/frontend/scripts/detect/config.ts +53 -0
  50. package/dist/skills/frontend/scripts/detect/core/characters.ts +2 -0
  51. package/dist/skills/frontend/scripts/detect/core/color.test.ts +29 -0
  52. package/dist/skills/frontend/scripts/detect/core/color.ts +150 -0
  53. package/dist/skills/frontend/scripts/detect/core/page.ts +84 -0
  54. package/dist/skills/frontend/scripts/detect/core/shadow.ts +40 -0
  55. package/dist/skills/frontend/scripts/detect/core/source.ts +33 -0
  56. package/dist/skills/frontend/scripts/detect/detect.ts +77 -0
  57. package/dist/skills/frontend/scripts/detect/index.ts +23 -0
  58. package/dist/skills/frontend/scripts/detect/lint.test.ts +27 -0
  59. package/dist/skills/frontend/scripts/detect/lint.ts +98 -0
  60. package/dist/skills/frontend/scripts/detect/render/probe-placement.test.ts +19 -0
  61. package/dist/skills/frontend/scripts/detect/render/probe-placement.ts +50 -0
  62. package/dist/skills/frontend/scripts/detect/render/renderer.ts +37 -0
  63. package/dist/skills/frontend/scripts/detect/render/webview.ts +71 -0
  64. package/dist/skills/frontend/scripts/detect/report.ts +29 -0
  65. package/dist/skills/frontend/scripts/detect/rule.ts +42 -0
  66. package/dist/skills/frontend/scripts/detect/rules/color/ai-color-palette.test.ts +74 -0
  67. package/dist/skills/frontend/scripts/detect/rules/color/ai-color-palette.ts +83 -0
  68. package/dist/skills/frontend/scripts/detect/rules/color/cream-palette.test.ts +24 -0
  69. package/dist/skills/frontend/scripts/detect/rules/color/cream-palette.ts +35 -0
  70. package/dist/skills/frontend/scripts/detect/rules/color/dark-glow.test.ts +47 -0
  71. package/dist/skills/frontend/scripts/detect/rules/color/dark-glow.ts +44 -0
  72. package/dist/skills/frontend/scripts/detect/rules/color/design-system-color.test.ts +26 -0
  73. package/dist/skills/frontend/scripts/detect/rules/color/design-system-color.ts +35 -0
  74. package/dist/skills/frontend/scripts/detect/rules/color/gradient-text.test.ts +24 -0
  75. package/dist/skills/frontend/scripts/detect/rules/color/gradient-text.ts +59 -0
  76. package/dist/skills/frontend/scripts/detect/rules/color/gray-on-color.test.ts +39 -0
  77. package/dist/skills/frontend/scripts/detect/rules/color/gray-on-color.ts +38 -0
  78. package/dist/skills/frontend/scripts/detect/rules/color/index.ts +15 -0
  79. package/dist/skills/frontend/scripts/detect/rules/color/low-contrast.test.ts +209 -0
  80. package/dist/skills/frontend/scripts/detect/rules/color/low-contrast.ts +57 -0
  81. package/dist/skills/frontend/scripts/detect/rules/color/placeholder-contrast.test.ts +62 -0
  82. package/dist/skills/frontend/scripts/detect/rules/color/radial-halo.test.ts +40 -0
  83. package/dist/skills/frontend/scripts/detect/rules/color/radial-halo.ts +31 -0
  84. package/dist/skills/frontend/scripts/detect/rules/color/radial-spotlight-glow.test.ts +27 -0
  85. package/dist/skills/frontend/scripts/detect/rules/color/radial-spotlight-glow.ts +33 -0
  86. package/dist/skills/frontend/scripts/detect/rules/color/support/animation-opacity.ts +78 -0
  87. package/dist/skills/frontend/scripts/detect/rules/color/support/color-path.ts +15 -0
  88. package/dist/skills/frontend/scripts/detect/rules/color/support/contrast-pairs.ts +54 -0
  89. package/dist/skills/frontend/scripts/detect/rules/color/support/contrast-role.ts +76 -0
  90. package/dist/skills/frontend/scripts/detect/rules/color/support/glow-forms.ts +56 -0
  91. package/dist/skills/frontend/scripts/detect/rules/color/support/gradient-samples.ts +134 -0
  92. package/dist/skills/frontend/scripts/detect/rules/color/support/gradients.ts +91 -0
  93. package/dist/skills/frontend/scripts/detect/rules/color/support/mockup-roots.ts +63 -0
  94. package/dist/skills/frontend/scripts/detect/rules/color/support/page-ignore.ts +7 -0
  95. package/dist/skills/frontend/scripts/detect/rules/color/support/painted-text.ts +141 -0
  96. package/dist/skills/frontend/scripts/detect/rules/color/support/palette-roles.ts +58 -0
  97. package/dist/skills/frontend/scripts/detect/rules/color/support/placeholder-contrast.ts +25 -0
  98. package/dist/skills/frontend/scripts/detect/rules/color/support/stock-accent.ts +31 -0
  99. package/dist/skills/frontend/scripts/detect/rules/color/support/text-colors.ts +80 -0
  100. package/dist/skills/frontend/scripts/detect/rules/copy/aphoristic-cadence.test.ts +18 -0
  101. package/dist/skills/frontend/scripts/detect/rules/copy/aphoristic-cadence.ts +20 -0
  102. package/dist/skills/frontend/scripts/detect/rules/copy/broken-image.test.ts +25 -0
  103. package/dist/skills/frontend/scripts/detect/rules/copy/broken-image.ts +17 -0
  104. package/dist/skills/frontend/scripts/detect/rules/copy/em-dash-overuse.test.ts +39 -0
  105. package/dist/skills/frontend/scripts/detect/rules/copy/em-dash-overuse.ts +46 -0
  106. package/dist/skills/frontend/scripts/detect/rules/copy/index.ts +15 -0
  107. package/dist/skills/frontend/scripts/detect/rules/copy/marketing-buzzword.test.ts +18 -0
  108. package/dist/skills/frontend/scripts/detect/rules/copy/marketing-buzzword.ts +33 -0
  109. package/dist/skills/frontend/scripts/detect/rules/copy/numbered-section-labels.test.ts +58 -0
  110. package/dist/skills/frontend/scripts/detect/rules/copy/numbered-section-labels.ts +34 -0
  111. package/dist/skills/frontend/scripts/detect/rules/copy/repeated-container-text.test.ts +43 -0
  112. package/dist/skills/frontend/scripts/detect/rules/copy/repeated-container-text.ts +56 -0
  113. package/dist/skills/frontend/scripts/detect/rules/copy/script-error.test.ts +48 -0
  114. package/dist/skills/frontend/scripts/detect/rules/copy/script-error.ts +38 -0
  115. package/dist/skills/frontend/scripts/detect/rules/copy/skipped-heading.test.ts +49 -0
  116. package/dist/skills/frontend/scripts/detect/rules/copy/skipped-heading.ts +81 -0
  117. package/dist/skills/frontend/scripts/detect/rules/copy/support/numbered-label.ts +94 -0
  118. package/dist/skills/frontend/scripts/detect/rules/copy/support/page-text.ts +37 -0
  119. package/dist/skills/frontend/scripts/detect/rules/copy/theater-slop-phrase.test.ts +17 -0
  120. package/dist/skills/frontend/scripts/detect/rules/copy/theater-slop-phrase.ts +21 -0
  121. package/dist/skills/frontend/scripts/detect/rules/decoration/blinking-cursor.test.ts +43 -0
  122. package/dist/skills/frontend/scripts/detect/rules/decoration/blinking-cursor.ts +48 -0
  123. package/dist/skills/frontend/scripts/detect/rules/decoration/border-accent-on-rounded.test.ts +33 -0
  124. package/dist/skills/frontend/scripts/detect/rules/decoration/border-accent-on-rounded.ts +14 -0
  125. package/dist/skills/frontend/scripts/detect/rules/decoration/bounce-easing.test.ts +72 -0
  126. package/dist/skills/frontend/scripts/detect/rules/decoration/bounce-easing.ts +83 -0
  127. package/dist/skills/frontend/scripts/detect/rules/decoration/buried-raster.test.ts +95 -0
  128. package/dist/skills/frontend/scripts/detect/rules/decoration/buried-raster.ts +72 -0
  129. package/dist/skills/frontend/scripts/detect/rules/decoration/codex-grid-background.test.ts +28 -0
  130. package/dist/skills/frontend/scripts/detect/rules/decoration/codex-grid-background.ts +34 -0
  131. package/dist/skills/frontend/scripts/detect/rules/decoration/design-system-radius.test.ts +37 -0
  132. package/dist/skills/frontend/scripts/detect/rules/decoration/design-system-radius.ts +31 -0
  133. package/dist/skills/frontend/scripts/detect/rules/decoration/gpt-thin-border-wide-shadow.test.ts +59 -0
  134. package/dist/skills/frontend/scripts/detect/rules/decoration/gpt-thin-border-wide-shadow.ts +66 -0
  135. package/dist/skills/frontend/scripts/detect/rules/decoration/hard-offset-shadow.test.ts +45 -0
  136. package/dist/skills/frontend/scripts/detect/rules/decoration/hard-offset-shadow.ts +31 -0
  137. package/dist/skills/frontend/scripts/detect/rules/decoration/hero-eyebrow-chip.test.ts +76 -0
  138. package/dist/skills/frontend/scripts/detect/rules/decoration/hero-eyebrow-chip.ts +19 -0
  139. package/dist/skills/frontend/scripts/detect/rules/decoration/icon-tile-stack.test.ts +67 -0
  140. package/dist/skills/frontend/scripts/detect/rules/decoration/icon-tile-stack.ts +92 -0
  141. package/dist/skills/frontend/scripts/detect/rules/decoration/index.ts +38 -0
  142. package/dist/skills/frontend/scripts/detect/rules/decoration/kicker-above-heading.test.ts +126 -0
  143. package/dist/skills/frontend/scripts/detect/rules/decoration/kicker-above-heading.ts +69 -0
  144. package/dist/skills/frontend/scripts/detect/rules/decoration/marquee.test.ts +63 -0
  145. package/dist/skills/frontend/scripts/detect/rules/decoration/marquee.ts +51 -0
  146. package/dist/skills/frontend/scripts/detect/rules/decoration/organic-clip-path.test.ts +67 -0
  147. package/dist/skills/frontend/scripts/detect/rules/decoration/organic-clip-path.ts +41 -0
  148. package/dist/skills/frontend/scripts/detect/rules/decoration/pulsing-dot.test.ts +58 -0
  149. package/dist/skills/frontend/scripts/detect/rules/decoration/pulsing-dot.ts +72 -0
  150. package/dist/skills/frontend/scripts/detect/rules/decoration/repeating-stripes-gradient.test.ts +26 -0
  151. package/dist/skills/frontend/scripts/detect/rules/decoration/repeating-stripes-gradient.ts +25 -0
  152. package/dist/skills/frontend/scripts/detect/rules/decoration/shape-assembled-illustration.test.ts +59 -0
  153. package/dist/skills/frontend/scripts/detect/rules/decoration/shape-assembled-illustration.ts +58 -0
  154. package/dist/skills/frontend/scripts/detect/rules/decoration/side-tab.test.ts +91 -0
  155. package/dist/skills/frontend/scripts/detect/rules/decoration/side-tab.ts +17 -0
  156. package/dist/skills/frontend/scripts/detect/rules/decoration/support/appearance.ts +110 -0
  157. package/dist/skills/frontend/scripts/detect/rules/decoration/support/assert-cases.ts +25 -0
  158. package/dist/skills/frontend/scripts/detect/rules/decoration/support/borders.ts +150 -0
  159. package/dist/skills/frontend/scripts/detect/rules/decoration/support/clip-geometry.ts +151 -0
  160. package/dist/skills/frontend/scripts/detect/rules/decoration/support/css-candidates.ts +66 -0
  161. package/dist/skills/frontend/scripts/detect/rules/decoration/support/curve-samples.ts +55 -0
  162. package/dist/skills/frontend/scripts/detect/rules/decoration/support/gradient-pattern.ts +40 -0
  163. package/dist/skills/frontend/scripts/detect/rules/decoration/support/keyframes.ts +134 -0
  164. package/dist/skills/frontend/scripts/detect/rules/decoration/support/labels.ts +85 -0
  165. package/dist/skills/frontend/scripts/detect/rules/decoration/support/raster-state.ts +51 -0
  166. package/dist/skills/frontend/scripts/detect/rules/index.ts +16 -0
  167. package/dist/skills/frontend/scripts/detect/rules/layout/body-text-viewport-edge.test.ts +64 -0
  168. package/dist/skills/frontend/scripts/detect/rules/layout/body-text-viewport-edge.ts +62 -0
  169. package/dist/skills/frontend/scripts/detect/rules/layout/clipped-overflow-container.test.ts +40 -0
  170. package/dist/skills/frontend/scripts/detect/rules/layout/clipped-overflow-container.ts +15 -0
  171. package/dist/skills/frontend/scripts/detect/rules/layout/content-hidden-at-rest.test.ts +62 -0
  172. package/dist/skills/frontend/scripts/detect/rules/layout/content-hidden-at-rest.ts +63 -0
  173. package/dist/skills/frontend/scripts/detect/rules/layout/cramped-padding.test.ts +61 -0
  174. package/dist/skills/frontend/scripts/detect/rules/layout/cramped-padding.ts +97 -0
  175. package/dist/skills/frontend/scripts/detect/rules/layout/edge-flush-cards.test.ts +43 -0
  176. package/dist/skills/frontend/scripts/detect/rules/layout/edge-flush-cards.ts +47 -0
  177. package/dist/skills/frontend/scripts/detect/rules/layout/first-viewport-column-overflow.test.ts +28 -0
  178. package/dist/skills/frontend/scripts/detect/rules/layout/first-viewport-column-overflow.ts +43 -0
  179. package/dist/skills/frontend/scripts/detect/rules/layout/heading-rhythm.test.ts +67 -0
  180. package/dist/skills/frontend/scripts/detect/rules/layout/heading-rhythm.ts +30 -0
  181. package/dist/skills/frontend/scripts/detect/rules/layout/index.ts +21 -0
  182. package/dist/skills/frontend/scripts/detect/rules/layout/monotonous-spacing.test.ts +19 -0
  183. package/dist/skills/frontend/scripts/detect/rules/layout/monotonous-spacing.ts +32 -0
  184. package/dist/skills/frontend/scripts/detect/rules/layout/nested-cards.test.ts +60 -0
  185. package/dist/skills/frontend/scripts/detect/rules/layout/nested-cards.ts +38 -0
  186. package/dist/skills/frontend/scripts/detect/rules/layout/straggler.test.ts +33 -0
  187. package/dist/skills/frontend/scripts/detect/rules/layout/straggler.ts +28 -0
  188. package/dist/skills/frontend/scripts/detect/rules/layout/support/cards.ts +114 -0
  189. package/dist/skills/frontend/scripts/detect/rules/layout/support/clipping.ts +71 -0
  190. package/dist/skills/frontend/scripts/detect/rules/layout/support/declared-mockups.ts +46 -0
  191. package/dist/skills/frontend/scripts/detect/rules/layout/support/geometry.ts +73 -0
  192. package/dist/skills/frontend/scripts/detect/rules/layout/support/hidden-interface.ts +35 -0
  193. package/dist/skills/frontend/scripts/detect/rules/layout/support/layout-cases.ts +23 -0
  194. package/dist/skills/frontend/scripts/detect/rules/layout/support/line-breaks.ts +32 -0
  195. package/dist/skills/frontend/scripts/detect/rules/layout/support/motion.ts +77 -0
  196. package/dist/skills/frontend/scripts/detect/rules/layout/support/padding.ts +93 -0
  197. package/dist/skills/frontend/scripts/detect/rules/layout/support/rhythm.ts +161 -0
  198. package/dist/skills/frontend/scripts/detect/rules/layout/text-occlusion.test.ts +37 -0
  199. package/dist/skills/frontend/scripts/detect/rules/layout/text-occlusion.ts +84 -0
  200. package/dist/skills/frontend/scripts/detect/rules/layout/text-overflow.test.ts +83 -0
  201. package/dist/skills/frontend/scripts/detect/rules/layout/text-overflow.ts +72 -0
  202. package/dist/skills/frontend/scripts/detect/rules/layout/unbalanced-heading.test.ts +22 -0
  203. package/dist/skills/frontend/scripts/detect/rules/layout/unbalanced-heading.ts +22 -0
  204. package/dist/skills/frontend/scripts/detect/rules/layout/viewport-reflow.test.ts +34 -0
  205. package/dist/skills/frontend/scripts/detect/rules/layout/viewport-reflow.ts +33 -0
  206. package/dist/skills/frontend/scripts/detect/rules/source/ai-color-palette.test.ts +13 -0
  207. package/dist/skills/frontend/scripts/detect/rules/source/ai-color-palette.ts +11 -0
  208. package/dist/skills/frontend/scripts/detect/rules/source/aphoristic-cadence.test.ts +12 -0
  209. package/dist/skills/frontend/scripts/detect/rules/source/aphoristic-cadence.ts +14 -0
  210. package/dist/skills/frontend/scripts/detect/rules/source/border-accent-on-rounded.test.ts +14 -0
  211. package/dist/skills/frontend/scripts/detect/rules/source/border-accent-on-rounded.ts +20 -0
  212. package/dist/skills/frontend/scripts/detect/rules/source/bounce-easing.test.ts +19 -0
  213. package/dist/skills/frontend/scripts/detect/rules/source/bounce-easing.ts +21 -0
  214. package/dist/skills/frontend/scripts/detect/rules/source/broken-image.test.ts +27 -0
  215. package/dist/skills/frontend/scripts/detect/rules/source/broken-image.ts +16 -0
  216. package/dist/skills/frontend/scripts/detect/rules/source/codex-grid-background.test.ts +11 -0
  217. package/dist/skills/frontend/scripts/detect/rules/source/codex-grid-background.ts +18 -0
  218. package/dist/skills/frontend/scripts/detect/rules/source/dark-glow.test.ts +15 -0
  219. package/dist/skills/frontend/scripts/detect/rules/source/dark-glow.ts +21 -0
  220. package/dist/skills/frontend/scripts/detect/rules/source/em-dash-overuse.test.ts +13 -0
  221. package/dist/skills/frontend/scripts/detect/rules/source/em-dash-overuse.ts +15 -0
  222. package/dist/skills/frontend/scripts/detect/rules/source/gradient-text.test.ts +12 -0
  223. package/dist/skills/frontend/scripts/detect/rules/source/gradient-text.ts +11 -0
  224. package/dist/skills/frontend/scripts/detect/rules/source/gray-on-color.test.ts +20 -0
  225. package/dist/skills/frontend/scripts/detect/rules/source/gray-on-color.ts +13 -0
  226. package/dist/skills/frontend/scripts/detect/rules/source/index.ts +19 -0
  227. package/dist/skills/frontend/scripts/detect/rules/source/marketing-buzzword.test.ts +12 -0
  228. package/dist/skills/frontend/scripts/detect/rules/source/marketing-buzzword.ts +17 -0
  229. package/dist/skills/frontend/scripts/detect/rules/source/marquee.test.ts +12 -0
  230. package/dist/skills/frontend/scripts/detect/rules/source/marquee.ts +12 -0
  231. package/dist/skills/frontend/scripts/detect/rules/source/monotonous-spacing.test.ts +13 -0
  232. package/dist/skills/frontend/scripts/detect/rules/source/monotonous-spacing.ts +22 -0
  233. package/dist/skills/frontend/scripts/detect/rules/source/overused-font.test.ts +21 -0
  234. package/dist/skills/frontend/scripts/detect/rules/source/overused-font.ts +16 -0
  235. package/dist/skills/frontend/scripts/detect/rules/source/radial-halo.test.ts +16 -0
  236. package/dist/skills/frontend/scripts/detect/rules/source/radial-halo.ts +14 -0
  237. package/dist/skills/frontend/scripts/detect/rules/source/side-tab.test.ts +29 -0
  238. package/dist/skills/frontend/scripts/detect/rules/source/side-tab.ts +58 -0
  239. package/dist/skills/frontend/scripts/detect/rules/source/support/accent-scans.ts +78 -0
  240. package/dist/skills/frontend/scripts/detect/rules/source/support/check-source.ts +6 -0
  241. package/dist/skills/frontend/scripts/detect/rules/source/support/corners.ts +105 -0
  242. package/dist/skills/frontend/scripts/detect/rules/source/support/css-effects.ts +81 -0
  243. package/dist/skills/frontend/scripts/detect/rules/source/support/css-scopes.ts +131 -0
  244. package/dist/skills/frontend/scripts/detect/rules/source/support/image-tags.ts +113 -0
  245. package/dist/skills/frontend/scripts/detect/rules/source/support/js-punctuation.ts +34 -0
  246. package/dist/skills/frontend/scripts/detect/rules/source/support/markup-scope.ts +44 -0
  247. package/dist/skills/frontend/scripts/detect/rules/source/support/source-color.ts +42 -0
  248. package/dist/skills/frontend/scripts/detect/rules/source/support/source-shadow.ts +15 -0
  249. package/dist/skills/frontend/scripts/detect/rules/source/support/source-text.ts +110 -0
  250. package/dist/skills/frontend/scripts/detect/rules/typography/all-caps-body.test.ts +24 -0
  251. package/dist/skills/frontend/scripts/detect/rules/typography/all-caps-body.ts +15 -0
  252. package/dist/skills/frontend/scripts/detect/rules/typography/design-system-font-size.test.ts +21 -0
  253. package/dist/skills/frontend/scripts/detect/rules/typography/design-system-font-size.ts +23 -0
  254. package/dist/skills/frontend/scripts/detect/rules/typography/design-system-font.test.ts +22 -0
  255. package/dist/skills/frontend/scripts/detect/rules/typography/design-system-font.ts +24 -0
  256. package/dist/skills/frontend/scripts/detect/rules/typography/extreme-negative-tracking.test.ts +23 -0
  257. package/dist/skills/frontend/scripts/detect/rules/typography/extreme-negative-tracking.ts +18 -0
  258. package/dist/skills/frontend/scripts/detect/rules/typography/flat-type-hierarchy.test.ts +33 -0
  259. package/dist/skills/frontend/scripts/detect/rules/typography/flat-type-hierarchy.ts +26 -0
  260. package/dist/skills/frontend/scripts/detect/rules/typography/index.ts +21 -0
  261. package/dist/skills/frontend/scripts/detect/rules/typography/italic-serif-display.test.ts +24 -0
  262. package/dist/skills/frontend/scripts/detect/rules/typography/italic-serif-display.ts +24 -0
  263. package/dist/skills/frontend/scripts/detect/rules/typography/justified-text.test.ts +31 -0
  264. package/dist/skills/frontend/scripts/detect/rules/typography/justified-text.ts +32 -0
  265. package/dist/skills/frontend/scripts/detect/rules/typography/line-length.test.ts +43 -0
  266. package/dist/skills/frontend/scripts/detect/rules/typography/line-length.ts +28 -0
  267. package/dist/skills/frontend/scripts/detect/rules/typography/oversized-h1.test.ts +26 -0
  268. package/dist/skills/frontend/scripts/detect/rules/typography/oversized-h1.ts +20 -0
  269. package/dist/skills/frontend/scripts/detect/rules/typography/overused-font.test.ts +35 -0
  270. package/dist/skills/frontend/scripts/detect/rules/typography/overused-font.ts +45 -0
  271. package/dist/skills/frontend/scripts/detect/rules/typography/support/drawn-enlargement.ts +48 -0
  272. package/dist/skills/frontend/scripts/detect/rules/typography/support/fading-text.ts +48 -0
  273. package/dist/skills/frontend/scripts/detect/rules/typography/support/flex-runs.ts +16 -0
  274. package/dist/skills/frontend/scripts/detect/rules/typography/support/font-family.ts +28 -0
  275. package/dist/skills/frontend/scripts/detect/rules/typography/support/painted-text.test.ts +63 -0
  276. package/dist/skills/frontend/scripts/detect/rules/typography/support/painted-text.ts +81 -0
  277. package/dist/skills/frontend/scripts/detect/rules/typography/support/svg-size.ts +57 -0
  278. package/dist/skills/frontend/scripts/detect/rules/typography/support/text-context.ts +112 -0
  279. package/dist/skills/frontend/scripts/detect/rules/typography/support/text-lines.ts +43 -0
  280. package/dist/skills/frontend/scripts/detect/rules/typography/support/type-hierarchy.ts +48 -0
  281. package/dist/skills/frontend/scripts/detect/rules/typography/tight-leading.test.ts +54 -0
  282. package/dist/skills/frontend/scripts/detect/rules/typography/tight-leading.ts +47 -0
  283. package/dist/skills/frontend/scripts/detect/rules/typography/tiny-text.test.ts +60 -0
  284. package/dist/skills/frontend/scripts/detect/rules/typography/tiny-text.ts +23 -0
  285. package/dist/skills/frontend/scripts/detect/rules/typography/undersized-ui-text.test.ts +98 -0
  286. package/dist/skills/frontend/scripts/detect/rules/typography/undersized-ui-text.ts +28 -0
  287. package/dist/skills/frontend/scripts/detect/rules/typography/wide-tracking.test.ts +26 -0
  288. package/dist/skills/frontend/scripts/detect/rules/typography/wide-tracking.ts +26 -0
  289. package/dist/skills/frontend/scripts/detect/snapshot/collect.ts +158 -0
  290. package/dist/skills/frontend/scripts/detect/snapshot/style-props.ts +25 -0
  291. package/dist/skills/frontend/scripts/detect/testing/build-snapshot.ts +78 -0
  292. package/dist/skills/frontend/scripts/detect/tsconfig.json +19 -0
  293. package/dist/skills/frontend/scripts/detect/types.ts +124 -0
  294. package/dist/skills/programming/SKILL.md +17 -74
  295. package/dist/skills/programming/references/go/README.md +1 -1
  296. package/dist/skills/programming/references/go/bootstrap.md +2 -2
  297. package/dist/skills/programming/references/python/README.md +4 -4
  298. package/dist/skills/programming/references/python/one-liners.md +5 -5
  299. package/dist/skills/programming/references/testing/README.md +82 -0
  300. package/dist/skills/programming/references/testing/junk-classes.md +56 -0
  301. package/dist/skills/programming/references/typescript/README.md +1 -2
  302. package/dist/skills/programming/scripts/go/new-project.ts +197 -0
  303. package/dist/skills/programming/scripts/python/new-project.ts +231 -0
  304. package/dist/skills/programming/scripts/python/new-script.ts +134 -0
  305. package/dist/skills/programming/scripts/rust/new-project.ts +215 -0
  306. package/dist/skills/programming/scripts/scaffolders.test.ts +96 -0
  307. package/dist/skills/programming/scripts/shared/run-tool.ts +19 -0
  308. package/dist/skills/programming/scripts/typescript/check-test-junk-rules.ts +140 -0
  309. package/dist/skills/programming/scripts/typescript/check-test-junk.test.ts +125 -0
  310. package/dist/skills/programming/scripts/typescript/check-test-junk.ts +148 -0
  311. package/dist/skills/programming/scripts/typescript/mutation-proof.test.ts +43 -0
  312. package/dist/skills/programming/scripts/typescript/mutation-proof.ts +179 -0
  313. package/dist/skills/remove-ai-slops/SKILL.md +32 -20
  314. package/dist/skills/ulw-research/scripts/source-commands.mjs +3 -1
  315. package/dist/skills/ulw-research/scripts/source-integrity.test.ts +39 -2
  316. package/dist/skills/visual-qa/SKILL.md +12 -1
  317. package/dist/tools/delegate-task/models-distribution.d.ts +1 -0
  318. package/dist/tui.js +142 -42
  319. package/package.json +22 -19
  320. package/packages/lsp-core/src/lsp/config-loader.ts +18 -2
  321. package/packages/lsp-core/src/lsp/host-js-runtime.test.ts +150 -0
  322. package/packages/lsp-core/src/lsp/host-js-runtime.ts +57 -0
  323. package/packages/lsp-core/src/lsp/server-definitions.ts +10 -0
  324. package/packages/lsp-core/src/lsp/server-resolution.ts +9 -1
  325. package/packages/lsp-core/src/lsp/typescript-server-defaults.test.ts +84 -0
  326. package/packages/lsp-daemon/dist/cli.js +81 -15
  327. package/packages/lsp-daemon/dist/client.js +74 -8
  328. package/packages/lsp-daemon/dist/index.js +76 -10
  329. package/packages/lsp-tools-mcp/dist/cli.js +74 -8
  330. package/packages/lsp-tools-mcp/dist/mcp.js +74 -8
  331. package/packages/lsp-tools-mcp/dist/tools.js +74 -8
  332. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  333. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +22 -4
  334. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  335. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  336. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  337. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  338. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  339. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  340. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  341. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  342. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
  343. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +77 -13
  344. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  345. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  346. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  347. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  348. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  349. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  350. package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +34 -2
  351. package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +34 -2
  352. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  353. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  354. package/packages/omo-codex/plugin/components/telemetry/test/codex-hook.test.ts +14 -1
  355. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  356. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  357. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  358. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  359. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  360. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  361. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  362. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  363. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  364. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  365. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  366. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  367. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  368. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  369. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  370. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  371. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  372. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  373. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  374. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  375. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  376. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  377. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  378. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  379. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  380. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  381. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  382. package/packages/omo-codex/plugin/package-lock.json +12 -12
  383. package/packages/omo-codex/plugin/package.json +1 -1
  384. package/packages/omo-codex/plugin/scripts/auto-update-plan.mjs +16 -1
  385. package/packages/omo-codex/plugin/skills/browser/runtime/omowright/index.js +24 -33
  386. package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +3 -3
  387. package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +104 -1
  388. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +7 -3
  389. package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +3 -3
  390. package/packages/omo-codex/plugin/skills/frontend/references/perfection/craft-floor.md +59 -0
  391. package/packages/omo-codex/plugin/skills/frontend/references/perfection/detect.md +52 -0
  392. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/cli.ts +70 -0
  393. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/config.ts +53 -0
  394. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/core/characters.ts +2 -0
  395. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/core/color.ts +150 -0
  396. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/core/page.ts +84 -0
  397. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/core/shadow.ts +40 -0
  398. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/core/source.ts +33 -0
  399. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/detect.ts +77 -0
  400. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/index.ts +23 -0
  401. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/lint.ts +98 -0
  402. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/render/probe-placement.ts +50 -0
  403. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/render/renderer.ts +37 -0
  404. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/render/webview.ts +71 -0
  405. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/report.ts +29 -0
  406. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rule.ts +42 -0
  407. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/ai-color-palette.ts +83 -0
  408. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/cream-palette.ts +35 -0
  409. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/dark-glow.ts +44 -0
  410. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/design-system-color.ts +35 -0
  411. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/gradient-text.ts +59 -0
  412. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/gray-on-color.ts +38 -0
  413. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/index.ts +15 -0
  414. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/low-contrast.ts +57 -0
  415. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/radial-halo.ts +31 -0
  416. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/radial-spotlight-glow.ts +33 -0
  417. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/animation-opacity.ts +78 -0
  418. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/color-path.ts +15 -0
  419. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/contrast-pairs.ts +54 -0
  420. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/contrast-role.ts +76 -0
  421. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/glow-forms.ts +56 -0
  422. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/gradient-samples.ts +134 -0
  423. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/gradients.ts +91 -0
  424. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/mockup-roots.ts +63 -0
  425. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/page-ignore.ts +7 -0
  426. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/painted-text.ts +141 -0
  427. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/palette-roles.ts +58 -0
  428. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/placeholder-contrast.ts +25 -0
  429. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/stock-accent.ts +31 -0
  430. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/text-colors.ts +80 -0
  431. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/aphoristic-cadence.ts +20 -0
  432. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/broken-image.ts +17 -0
  433. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/em-dash-overuse.ts +46 -0
  434. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/index.ts +15 -0
  435. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/marketing-buzzword.ts +33 -0
  436. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/numbered-section-labels.ts +34 -0
  437. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/repeated-container-text.ts +56 -0
  438. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/script-error.ts +38 -0
  439. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/skipped-heading.ts +81 -0
  440. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/support/numbered-label.ts +94 -0
  441. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/support/page-text.ts +37 -0
  442. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/theater-slop-phrase.ts +21 -0
  443. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/blinking-cursor.ts +48 -0
  444. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/border-accent-on-rounded.ts +14 -0
  445. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/bounce-easing.ts +83 -0
  446. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/buried-raster.ts +72 -0
  447. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/codex-grid-background.ts +34 -0
  448. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/design-system-radius.ts +31 -0
  449. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/gpt-thin-border-wide-shadow.ts +66 -0
  450. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/hard-offset-shadow.ts +31 -0
  451. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/hero-eyebrow-chip.ts +19 -0
  452. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/icon-tile-stack.ts +92 -0
  453. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/index.ts +38 -0
  454. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/kicker-above-heading.ts +69 -0
  455. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/marquee.ts +51 -0
  456. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/organic-clip-path.ts +41 -0
  457. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/pulsing-dot.ts +72 -0
  458. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/repeating-stripes-gradient.ts +25 -0
  459. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/shape-assembled-illustration.ts +58 -0
  460. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/side-tab.ts +17 -0
  461. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/appearance.ts +110 -0
  462. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/assert-cases.ts +25 -0
  463. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/borders.ts +150 -0
  464. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/clip-geometry.ts +151 -0
  465. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/css-candidates.ts +66 -0
  466. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/curve-samples.ts +55 -0
  467. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/gradient-pattern.ts +40 -0
  468. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/keyframes.ts +134 -0
  469. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/labels.ts +85 -0
  470. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/raster-state.ts +51 -0
  471. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/index.ts +16 -0
  472. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/body-text-viewport-edge.ts +62 -0
  473. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/clipped-overflow-container.ts +15 -0
  474. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/content-hidden-at-rest.ts +63 -0
  475. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/cramped-padding.ts +97 -0
  476. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/edge-flush-cards.ts +47 -0
  477. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/first-viewport-column-overflow.ts +43 -0
  478. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/heading-rhythm.ts +30 -0
  479. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/index.ts +21 -0
  480. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/monotonous-spacing.ts +32 -0
  481. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/nested-cards.ts +38 -0
  482. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/straggler.ts +28 -0
  483. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/cards.ts +114 -0
  484. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/clipping.ts +71 -0
  485. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/declared-mockups.ts +46 -0
  486. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/geometry.ts +73 -0
  487. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/hidden-interface.ts +35 -0
  488. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/layout-cases.ts +23 -0
  489. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/line-breaks.ts +32 -0
  490. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/motion.ts +77 -0
  491. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/padding.ts +93 -0
  492. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/rhythm.ts +161 -0
  493. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/text-occlusion.ts +84 -0
  494. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/text-overflow.ts +72 -0
  495. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/unbalanced-heading.ts +22 -0
  496. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/viewport-reflow.ts +33 -0
  497. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/ai-color-palette.ts +11 -0
  498. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/aphoristic-cadence.ts +14 -0
  499. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/border-accent-on-rounded.ts +20 -0
  500. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/bounce-easing.ts +21 -0
  501. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/broken-image.ts +16 -0
  502. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/codex-grid-background.ts +18 -0
  503. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/dark-glow.ts +21 -0
  504. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/em-dash-overuse.ts +15 -0
  505. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/gradient-text.ts +11 -0
  506. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/gray-on-color.ts +13 -0
  507. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/index.ts +19 -0
  508. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/marketing-buzzword.ts +17 -0
  509. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/marquee.ts +12 -0
  510. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/monotonous-spacing.ts +22 -0
  511. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/overused-font.ts +16 -0
  512. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/radial-halo.ts +14 -0
  513. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/side-tab.ts +58 -0
  514. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/accent-scans.ts +78 -0
  515. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/check-source.ts +6 -0
  516. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/corners.ts +105 -0
  517. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/css-effects.ts +81 -0
  518. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/css-scopes.ts +131 -0
  519. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/image-tags.ts +113 -0
  520. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/js-punctuation.ts +34 -0
  521. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/markup-scope.ts +44 -0
  522. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/source-color.ts +42 -0
  523. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/source-shadow.ts +15 -0
  524. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/source-text.ts +110 -0
  525. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/all-caps-body.ts +15 -0
  526. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/design-system-font-size.ts +23 -0
  527. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/design-system-font.ts +24 -0
  528. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/extreme-negative-tracking.ts +18 -0
  529. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/flat-type-hierarchy.ts +26 -0
  530. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/index.ts +21 -0
  531. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/italic-serif-display.ts +24 -0
  532. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/justified-text.ts +32 -0
  533. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/line-length.ts +28 -0
  534. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/oversized-h1.ts +20 -0
  535. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/overused-font.ts +45 -0
  536. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/drawn-enlargement.ts +48 -0
  537. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/fading-text.ts +48 -0
  538. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/flex-runs.ts +16 -0
  539. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/font-family.ts +28 -0
  540. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/painted-text.ts +81 -0
  541. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/svg-size.ts +57 -0
  542. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/text-context.ts +112 -0
  543. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/text-lines.ts +43 -0
  544. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/type-hierarchy.ts +48 -0
  545. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/tight-leading.ts +47 -0
  546. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/tiny-text.ts +23 -0
  547. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/undersized-ui-text.ts +28 -0
  548. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/wide-tracking.ts +26 -0
  549. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/snapshot/collect.ts +158 -0
  550. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/snapshot/style-props.ts +25 -0
  551. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/testing/build-snapshot.ts +78 -0
  552. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/tsconfig.json +19 -0
  553. package/packages/omo-codex/plugin/skills/frontend/scripts/detect/types.ts +124 -0
  554. package/packages/omo-codex/plugin/skills/programming/SKILL.md +17 -74
  555. package/packages/omo-codex/plugin/skills/programming/references/go/README.md +1 -1
  556. package/packages/omo-codex/plugin/skills/programming/references/go/bootstrap.md +2 -2
  557. package/packages/omo-codex/plugin/skills/programming/references/python/README.md +4 -4
  558. package/packages/omo-codex/plugin/skills/programming/references/python/one-liners.md +5 -5
  559. package/packages/omo-codex/plugin/skills/programming/references/testing/README.md +82 -0
  560. package/packages/omo-codex/plugin/skills/programming/references/testing/junk-classes.md +56 -0
  561. package/packages/omo-codex/plugin/skills/programming/references/typescript/README.md +1 -2
  562. package/packages/omo-codex/plugin/skills/programming/scripts/go/new-project.ts +197 -0
  563. package/packages/omo-codex/plugin/skills/programming/scripts/python/new-project.ts +231 -0
  564. package/packages/omo-codex/plugin/skills/programming/scripts/python/new-script.ts +134 -0
  565. package/packages/omo-codex/plugin/skills/programming/scripts/rust/new-project.ts +215 -0
  566. package/packages/omo-codex/plugin/skills/programming/scripts/shared/run-tool.ts +19 -0
  567. package/packages/omo-codex/plugin/skills/programming/scripts/typescript/check-test-junk-rules.ts +140 -0
  568. package/packages/omo-codex/plugin/skills/programming/scripts/typescript/check-test-junk.ts +148 -0
  569. package/packages/omo-codex/plugin/skills/programming/scripts/typescript/mutation-proof.ts +179 -0
  570. package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +32 -20
  571. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-commands.mjs +3 -1
  572. package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +12 -1
  573. package/packages/omo-codex/plugin/test/auto-update.test.mjs +62 -0
  574. package/packages/omo-codex/plugin/test/payload-equivalence.test.mjs +12 -2
  575. package/packages/omo-codex/scripts/install-dist/install-local.mjs +79 -10
  576. package/packages/shared-skills/skills/browser/runtime/omowright/index.js +24 -33
  577. package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +3 -3
  578. package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +104 -1
  579. package/packages/shared-skills/skills/frontend/SKILL.md +7 -3
  580. package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +3 -3
  581. package/packages/shared-skills/skills/frontend/references/perfection/craft-floor.md +59 -0
  582. package/packages/shared-skills/skills/frontend/references/perfection/detect.md +52 -0
  583. package/packages/shared-skills/skills/frontend/scripts/detect/cli.ts +70 -0
  584. package/packages/shared-skills/skills/frontend/scripts/detect/config.test.ts +26 -0
  585. package/packages/shared-skills/skills/frontend/scripts/detect/config.ts +53 -0
  586. package/packages/shared-skills/skills/frontend/scripts/detect/core/characters.ts +2 -0
  587. package/packages/shared-skills/skills/frontend/scripts/detect/core/color.test.ts +29 -0
  588. package/packages/shared-skills/skills/frontend/scripts/detect/core/color.ts +150 -0
  589. package/packages/shared-skills/skills/frontend/scripts/detect/core/page.ts +84 -0
  590. package/packages/shared-skills/skills/frontend/scripts/detect/core/shadow.ts +40 -0
  591. package/packages/shared-skills/skills/frontend/scripts/detect/core/source.ts +33 -0
  592. package/packages/shared-skills/skills/frontend/scripts/detect/detect.ts +77 -0
  593. package/packages/shared-skills/skills/frontend/scripts/detect/index.ts +23 -0
  594. package/packages/shared-skills/skills/frontend/scripts/detect/lint.test.ts +27 -0
  595. package/packages/shared-skills/skills/frontend/scripts/detect/lint.ts +98 -0
  596. package/packages/shared-skills/skills/frontend/scripts/detect/render/probe-placement.test.ts +19 -0
  597. package/packages/shared-skills/skills/frontend/scripts/detect/render/probe-placement.ts +50 -0
  598. package/packages/shared-skills/skills/frontend/scripts/detect/render/renderer.ts +37 -0
  599. package/packages/shared-skills/skills/frontend/scripts/detect/render/webview.ts +71 -0
  600. package/packages/shared-skills/skills/frontend/scripts/detect/report.ts +29 -0
  601. package/packages/shared-skills/skills/frontend/scripts/detect/rule.ts +42 -0
  602. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/ai-color-palette.test.ts +74 -0
  603. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/ai-color-palette.ts +83 -0
  604. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/cream-palette.test.ts +24 -0
  605. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/cream-palette.ts +35 -0
  606. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/dark-glow.test.ts +47 -0
  607. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/dark-glow.ts +44 -0
  608. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/design-system-color.test.ts +26 -0
  609. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/design-system-color.ts +35 -0
  610. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/gradient-text.test.ts +24 -0
  611. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/gradient-text.ts +59 -0
  612. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/gray-on-color.test.ts +39 -0
  613. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/gray-on-color.ts +38 -0
  614. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/index.ts +15 -0
  615. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/low-contrast.test.ts +209 -0
  616. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/low-contrast.ts +57 -0
  617. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/placeholder-contrast.test.ts +62 -0
  618. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/radial-halo.test.ts +40 -0
  619. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/radial-halo.ts +31 -0
  620. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/radial-spotlight-glow.test.ts +27 -0
  621. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/radial-spotlight-glow.ts +33 -0
  622. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/animation-opacity.ts +78 -0
  623. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/color-path.ts +15 -0
  624. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/contrast-pairs.ts +54 -0
  625. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/contrast-role.ts +76 -0
  626. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/glow-forms.ts +56 -0
  627. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/gradient-samples.ts +134 -0
  628. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/gradients.ts +91 -0
  629. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/mockup-roots.ts +63 -0
  630. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/page-ignore.ts +7 -0
  631. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/painted-text.ts +141 -0
  632. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/palette-roles.ts +58 -0
  633. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/placeholder-contrast.ts +25 -0
  634. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/stock-accent.ts +31 -0
  635. package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/text-colors.ts +80 -0
  636. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/aphoristic-cadence.test.ts +18 -0
  637. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/aphoristic-cadence.ts +20 -0
  638. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/broken-image.test.ts +25 -0
  639. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/broken-image.ts +17 -0
  640. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/em-dash-overuse.test.ts +39 -0
  641. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/em-dash-overuse.ts +46 -0
  642. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/index.ts +15 -0
  643. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/marketing-buzzword.test.ts +18 -0
  644. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/marketing-buzzword.ts +33 -0
  645. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/numbered-section-labels.test.ts +58 -0
  646. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/numbered-section-labels.ts +34 -0
  647. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/repeated-container-text.test.ts +43 -0
  648. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/repeated-container-text.ts +56 -0
  649. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/script-error.test.ts +48 -0
  650. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/script-error.ts +38 -0
  651. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/skipped-heading.test.ts +49 -0
  652. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/skipped-heading.ts +81 -0
  653. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/support/numbered-label.ts +94 -0
  654. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/support/page-text.ts +37 -0
  655. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/theater-slop-phrase.test.ts +17 -0
  656. package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/theater-slop-phrase.ts +21 -0
  657. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/blinking-cursor.test.ts +43 -0
  658. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/blinking-cursor.ts +48 -0
  659. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/border-accent-on-rounded.test.ts +33 -0
  660. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/border-accent-on-rounded.ts +14 -0
  661. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/bounce-easing.test.ts +72 -0
  662. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/bounce-easing.ts +83 -0
  663. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/buried-raster.test.ts +95 -0
  664. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/buried-raster.ts +72 -0
  665. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/codex-grid-background.test.ts +28 -0
  666. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/codex-grid-background.ts +34 -0
  667. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/design-system-radius.test.ts +37 -0
  668. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/design-system-radius.ts +31 -0
  669. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/gpt-thin-border-wide-shadow.test.ts +59 -0
  670. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/gpt-thin-border-wide-shadow.ts +66 -0
  671. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/hard-offset-shadow.test.ts +45 -0
  672. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/hard-offset-shadow.ts +31 -0
  673. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/hero-eyebrow-chip.test.ts +76 -0
  674. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/hero-eyebrow-chip.ts +19 -0
  675. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/icon-tile-stack.test.ts +67 -0
  676. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/icon-tile-stack.ts +92 -0
  677. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/index.ts +38 -0
  678. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/kicker-above-heading.test.ts +126 -0
  679. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/kicker-above-heading.ts +69 -0
  680. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/marquee.test.ts +63 -0
  681. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/marquee.ts +51 -0
  682. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/organic-clip-path.test.ts +67 -0
  683. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/organic-clip-path.ts +41 -0
  684. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/pulsing-dot.test.ts +58 -0
  685. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/pulsing-dot.ts +72 -0
  686. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/repeating-stripes-gradient.test.ts +26 -0
  687. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/repeating-stripes-gradient.ts +25 -0
  688. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/shape-assembled-illustration.test.ts +59 -0
  689. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/shape-assembled-illustration.ts +58 -0
  690. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/side-tab.test.ts +91 -0
  691. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/side-tab.ts +17 -0
  692. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/appearance.ts +110 -0
  693. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/assert-cases.ts +25 -0
  694. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/borders.ts +150 -0
  695. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/clip-geometry.ts +151 -0
  696. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/css-candidates.ts +66 -0
  697. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/curve-samples.ts +55 -0
  698. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/gradient-pattern.ts +40 -0
  699. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/keyframes.ts +134 -0
  700. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/labels.ts +85 -0
  701. package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/raster-state.ts +51 -0
  702. package/packages/shared-skills/skills/frontend/scripts/detect/rules/index.ts +16 -0
  703. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/body-text-viewport-edge.test.ts +64 -0
  704. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/body-text-viewport-edge.ts +62 -0
  705. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/clipped-overflow-container.test.ts +40 -0
  706. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/clipped-overflow-container.ts +15 -0
  707. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/content-hidden-at-rest.test.ts +62 -0
  708. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/content-hidden-at-rest.ts +63 -0
  709. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/cramped-padding.test.ts +61 -0
  710. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/cramped-padding.ts +97 -0
  711. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/edge-flush-cards.test.ts +43 -0
  712. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/edge-flush-cards.ts +47 -0
  713. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/first-viewport-column-overflow.test.ts +28 -0
  714. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/first-viewport-column-overflow.ts +43 -0
  715. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/heading-rhythm.test.ts +67 -0
  716. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/heading-rhythm.ts +30 -0
  717. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/index.ts +21 -0
  718. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/monotonous-spacing.test.ts +19 -0
  719. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/monotonous-spacing.ts +32 -0
  720. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/nested-cards.test.ts +60 -0
  721. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/nested-cards.ts +38 -0
  722. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/straggler.test.ts +33 -0
  723. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/straggler.ts +28 -0
  724. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/cards.ts +114 -0
  725. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/clipping.ts +71 -0
  726. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/declared-mockups.ts +46 -0
  727. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/geometry.ts +73 -0
  728. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/hidden-interface.ts +35 -0
  729. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/layout-cases.ts +23 -0
  730. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/line-breaks.ts +32 -0
  731. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/motion.ts +77 -0
  732. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/padding.ts +93 -0
  733. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/rhythm.ts +161 -0
  734. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/text-occlusion.test.ts +37 -0
  735. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/text-occlusion.ts +84 -0
  736. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/text-overflow.test.ts +83 -0
  737. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/text-overflow.ts +72 -0
  738. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/unbalanced-heading.test.ts +22 -0
  739. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/unbalanced-heading.ts +22 -0
  740. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/viewport-reflow.test.ts +34 -0
  741. package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/viewport-reflow.ts +33 -0
  742. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/ai-color-palette.test.ts +13 -0
  743. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/ai-color-palette.ts +11 -0
  744. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/aphoristic-cadence.test.ts +12 -0
  745. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/aphoristic-cadence.ts +14 -0
  746. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/border-accent-on-rounded.test.ts +14 -0
  747. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/border-accent-on-rounded.ts +20 -0
  748. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/bounce-easing.test.ts +19 -0
  749. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/bounce-easing.ts +21 -0
  750. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/broken-image.test.ts +27 -0
  751. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/broken-image.ts +16 -0
  752. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/codex-grid-background.test.ts +11 -0
  753. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/codex-grid-background.ts +18 -0
  754. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/dark-glow.test.ts +15 -0
  755. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/dark-glow.ts +21 -0
  756. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/em-dash-overuse.test.ts +13 -0
  757. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/em-dash-overuse.ts +15 -0
  758. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/gradient-text.test.ts +12 -0
  759. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/gradient-text.ts +11 -0
  760. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/gray-on-color.test.ts +20 -0
  761. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/gray-on-color.ts +13 -0
  762. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/index.ts +19 -0
  763. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/marketing-buzzword.test.ts +12 -0
  764. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/marketing-buzzword.ts +17 -0
  765. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/marquee.test.ts +12 -0
  766. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/marquee.ts +12 -0
  767. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/monotonous-spacing.test.ts +13 -0
  768. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/monotonous-spacing.ts +22 -0
  769. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/overused-font.test.ts +21 -0
  770. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/overused-font.ts +16 -0
  771. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/radial-halo.test.ts +16 -0
  772. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/radial-halo.ts +14 -0
  773. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/side-tab.test.ts +29 -0
  774. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/side-tab.ts +58 -0
  775. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/accent-scans.ts +78 -0
  776. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/check-source.ts +6 -0
  777. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/corners.ts +105 -0
  778. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/css-effects.ts +81 -0
  779. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/css-scopes.ts +131 -0
  780. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/image-tags.ts +113 -0
  781. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/js-punctuation.ts +34 -0
  782. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/markup-scope.ts +44 -0
  783. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/source-color.ts +42 -0
  784. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/source-shadow.ts +15 -0
  785. package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/source-text.ts +110 -0
  786. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/all-caps-body.test.ts +24 -0
  787. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/all-caps-body.ts +15 -0
  788. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/design-system-font-size.test.ts +21 -0
  789. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/design-system-font-size.ts +23 -0
  790. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/design-system-font.test.ts +22 -0
  791. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/design-system-font.ts +24 -0
  792. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/extreme-negative-tracking.test.ts +23 -0
  793. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/extreme-negative-tracking.ts +18 -0
  794. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/flat-type-hierarchy.test.ts +33 -0
  795. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/flat-type-hierarchy.ts +26 -0
  796. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/index.ts +21 -0
  797. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/italic-serif-display.test.ts +24 -0
  798. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/italic-serif-display.ts +24 -0
  799. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/justified-text.test.ts +31 -0
  800. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/justified-text.ts +32 -0
  801. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/line-length.test.ts +43 -0
  802. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/line-length.ts +28 -0
  803. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/oversized-h1.test.ts +26 -0
  804. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/oversized-h1.ts +20 -0
  805. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/overused-font.test.ts +35 -0
  806. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/overused-font.ts +45 -0
  807. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/drawn-enlargement.ts +48 -0
  808. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/fading-text.ts +48 -0
  809. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/flex-runs.ts +16 -0
  810. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/font-family.ts +28 -0
  811. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/painted-text.test.ts +63 -0
  812. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/painted-text.ts +81 -0
  813. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/svg-size.ts +57 -0
  814. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/text-context.ts +112 -0
  815. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/text-lines.ts +43 -0
  816. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/type-hierarchy.ts +48 -0
  817. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/tight-leading.test.ts +54 -0
  818. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/tight-leading.ts +47 -0
  819. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/tiny-text.test.ts +60 -0
  820. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/tiny-text.ts +23 -0
  821. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/undersized-ui-text.test.ts +98 -0
  822. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/undersized-ui-text.ts +28 -0
  823. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/wide-tracking.test.ts +26 -0
  824. package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/wide-tracking.ts +26 -0
  825. package/packages/shared-skills/skills/frontend/scripts/detect/snapshot/collect.ts +158 -0
  826. package/packages/shared-skills/skills/frontend/scripts/detect/snapshot/style-props.ts +25 -0
  827. package/packages/shared-skills/skills/frontend/scripts/detect/testing/build-snapshot.ts +78 -0
  828. package/packages/shared-skills/skills/frontend/scripts/detect/tsconfig.json +19 -0
  829. package/packages/shared-skills/skills/frontend/scripts/detect/types.ts +124 -0
  830. package/packages/shared-skills/skills/programming/SKILL.md +17 -74
  831. package/packages/shared-skills/skills/programming/references/go/README.md +1 -1
  832. package/packages/shared-skills/skills/programming/references/go/bootstrap.md +2 -2
  833. package/packages/shared-skills/skills/programming/references/python/README.md +4 -4
  834. package/packages/shared-skills/skills/programming/references/python/one-liners.md +5 -5
  835. package/packages/shared-skills/skills/programming/references/testing/README.md +82 -0
  836. package/packages/shared-skills/skills/programming/references/testing/junk-classes.md +56 -0
  837. package/packages/shared-skills/skills/programming/references/typescript/README.md +1 -2
  838. package/packages/shared-skills/skills/programming/scripts/go/new-project.ts +197 -0
  839. package/packages/shared-skills/skills/programming/scripts/python/new-project.ts +231 -0
  840. package/packages/shared-skills/skills/programming/scripts/python/new-script.ts +134 -0
  841. package/packages/shared-skills/skills/programming/scripts/rust/new-project.ts +215 -0
  842. package/packages/shared-skills/skills/programming/scripts/scaffolders.test.ts +96 -0
  843. package/packages/shared-skills/skills/programming/scripts/shared/run-tool.ts +19 -0
  844. package/packages/shared-skills/skills/programming/scripts/typescript/check-test-junk-rules.ts +140 -0
  845. package/packages/shared-skills/skills/programming/scripts/typescript/check-test-junk.test.ts +125 -0
  846. package/packages/shared-skills/skills/programming/scripts/typescript/check-test-junk.ts +148 -0
  847. package/packages/shared-skills/skills/programming/scripts/typescript/mutation-proof.test.ts +43 -0
  848. package/packages/shared-skills/skills/programming/scripts/typescript/mutation-proof.ts +179 -0
  849. package/packages/shared-skills/skills/remove-ai-slops/SKILL.md +32 -20
  850. package/packages/shared-skills/skills/ulw-research/scripts/source-commands.mjs +3 -1
  851. package/packages/shared-skills/skills/ulw-research/scripts/source-integrity.test.ts +39 -2
  852. package/packages/shared-skills/skills/visual-qa/SKILL.md +12 -1
  853. package/dist/agents/gpt-prompt-identity.d.ts +0 -3
  854. package/dist/agents/hephaestus/gpt-5-4.d.ts +0 -24
  855. package/dist/agents/hephaestus/gpt-5-5.d.ts +0 -2
  856. package/dist/agents/hephaestus/gpt-5-6.d.ts +0 -2
  857. package/dist/agents/kimi-tool-loop-guard.d.ts +0 -1
  858. package/dist/agents/sisyphus/claude-fable-5.d.ts +0 -19
  859. package/dist/agents/sisyphus/claude-opus-4-7.d.ts +0 -22
  860. package/dist/agents/sisyphus/claude-opus-4-8.d.ts +0 -19
  861. package/dist/agents/sisyphus/claude-opus-5.d.ts +0 -33
  862. package/dist/agents/sisyphus/gemini.d.ts +0 -20
  863. package/dist/agents/sisyphus/glm-5-2.d.ts +0 -4
  864. package/dist/agents/sisyphus/gpt-5-4.d.ts +0 -26
  865. package/dist/agents/sisyphus/gpt-5-5.d.ts +0 -6
  866. package/dist/agents/sisyphus/gpt-task-system-guide.d.ts +0 -1
  867. package/dist/agents/sisyphus/grok-4.d.ts +0 -21
  868. package/dist/agents/sisyphus/index.d.ts +0 -31
  869. package/dist/agents/sisyphus/kimi-k2-6.d.ts +0 -32
  870. package/dist/agents/sisyphus/kimi-k2-7.d.ts +0 -17
  871. package/dist/agents/sisyphus/kimi-k3-1.d.ts +0 -9
  872. package/dist/agents/sisyphus/kimi-k3.d.ts +0 -19
  873. package/dist/agents/sisyphus-dynamic-prompt-builder.d.ts +0 -2
  874. package/dist/agents/sisyphus-dynamic-prompt-execution.d.ts +0 -2
  875. package/dist/agents/sisyphus-dynamic-prompt-exploration.d.ts +0 -2
  876. package/dist/agents/sisyphus-dynamic-prompt-role.d.ts +0 -2
  877. package/dist/agents/sisyphus-dynamic-prompt-sections.d.ts +0 -18
  878. package/dist/agents/sisyphus-dynamic-prompt-style.d.ts +0 -2
  879. package/dist/agents/sisyphus-dynamic-prompt.d.ts +0 -3
  880. package/dist/agents/sisyphus-gemini-fallback-overrides.d.ts +0 -1
  881. package/dist/agents/sisyphus-junior/gemini.d.ts +0 -10
  882. package/dist/agents/sisyphus-junior/glm-5-2.d.ts +0 -1
  883. package/dist/agents/sisyphus-junior/gpt-5-4.d.ts +0 -11
  884. package/dist/agents/sisyphus-junior/gpt-5-5.d.ts +0 -5
  885. package/dist/agents/sisyphus-junior/gpt.d.ts +0 -9
  886. package/dist/agents/sisyphus-junior/kimi-k2-6.d.ts +0 -13
  887. package/dist/agents/sisyphus-junior/kimi-k2-7.d.ts +0 -11
  888. package/dist/agents/sisyphus-junior/kimi-k3-1.d.ts +0 -6
  889. package/dist/agents/sisyphus-junior/kimi-k3.d.ts +0 -12
  890. package/dist/features/claude-code-agent-loader/opencode-config-agents-reader.d.ts +0 -1
  891. package/dist/features/claude-code-command-loader/loader-cache.d.ts +0 -1
  892. package/dist/features/claude-code-command-loader/loader.d.ts +0 -1
  893. package/dist/features/opencode-skill-loader/config-source-discovery.d.ts +0 -1
  894. package/dist/features/opencode-skill-loader/merger/config-skill-entry-loader.d.ts +0 -1
  895. package/dist/features/opencode-skill-loader/opencode-config-skills-reader.d.ts +0 -1
  896. package/dist/features/team-mode/team-layout-tmux/resolve-caller-tmux-session.d.ts +0 -1
  897. package/dist/features/team-mode/team-registry/team-spec-input-normalizer.d.ts +0 -1
  898. package/dist/shared/git-worktree/collect-git-diff-stats.d.ts +0 -1
  899. package/dist/shared/git-worktree/parse-status-porcelain-line.d.ts +0 -1
  900. package/dist/shared/migration/agent-names.d.ts +0 -1
  901. package/dist/shared/migration/migrations-sidecar.d.ts +0 -1
  902. package/dist/shared/skill-path-resolver.d.ts +0 -1
  903. package/dist/shared/zip-entry-listing/powershell-zip-entry-listing.d.ts +0 -1
  904. package/dist/shared/zip-entry-listing/zipinfo-zip-entry-listing.d.ts +0 -1
  905. package/dist/skills/programming/scripts/go/new-project.py +0 -138
  906. package/dist/skills/programming/scripts/python/new-project.py +0 -172
  907. package/dist/skills/programming/scripts/python/new-script.py +0 -116
  908. package/dist/skills/programming/scripts/rust/new-project.py +0 -178
  909. package/packages/omo-codex/plugin/skills/programming/scripts/go/new-project.py +0 -138
  910. package/packages/omo-codex/plugin/skills/programming/scripts/python/new-project.py +0 -172
  911. package/packages/omo-codex/plugin/skills/programming/scripts/python/new-script.py +0 -116
  912. package/packages/omo-codex/plugin/skills/programming/scripts/rust/new-project.py +0 -178
  913. package/packages/shared-skills/skills/programming/scripts/go/new-project.py +0 -138
  914. package/packages/shared-skills/skills/programming/scripts/python/new-project.py +0 -172
  915. package/packages/shared-skills/skills/programming/scripts/python/new-script.py +0 -116
  916. package/packages/shared-skills/skills/programming/scripts/rust/new-project.py +0 -178
@@ -0,0 +1,40 @@
1
+ import { parseColor } from "../../../core/color"
2
+ import { splitTop } from "./appearance"
3
+ const position = (value: string): number | null => {
4
+ const token = value
5
+ .replace(/\s/g, "")
6
+ .replace(/^(?:calc\()+/, "")
7
+ .replace(/\)+$/, "")
8
+ const match = /^([-+]?[\d.]+)(%|deg|grad|turn|px)?$/.exec(token)
9
+ if (!match) return null
10
+ const n = Number(match[1])
11
+ if (n === 0) return 0
12
+ return match[2] === "%" ? n / 100 : match[2] === "deg" ? n / 360 : match[2] === "grad" ? n / 400 : match[2] === "turn" ? n : null
13
+ }
14
+ export function repeats(value: string): boolean {
15
+ for (const layer of splitTop(value)) {
16
+ const m = /^repeating-(linear|radial)-gradient\(([\s\S]*)\)$/i.exec(layer)
17
+ if (!m) continue
18
+ const stops = splitTop(m[2] ?? ""),
19
+ first = splitTop(stops[0] ?? "", /\s/),
20
+ token = first[0] ?? ""
21
+ if (token.includes("var(")) return true
22
+ const start =
23
+ parseColor(token) !== null ||
24
+ (/^(?:transparent|currentcolor|[a-z]+)$/i.test(token) && !/^(?:circle|ellipse|to|at|in|closest|farthest)/i.test(token))
25
+ ? 0
26
+ : 1
27
+ if (stops.length < start + 2) return true
28
+ if (m[1]?.toLowerCase() === "radial" && start === 1) {
29
+ const prelude = (stops[0] ?? "").split(/\bat\b|\bin\b/)[0] ?? ""
30
+ if (/closest-|farthest-side|[0-9]/.test(prelude)) return true
31
+ }
32
+ const a = splitTop(stops[start] ?? "", /\s/),
33
+ b = splitTop(stops.at(-1) ?? "", /\s/)
34
+ if (b.length === 1 && b[0]?.includes("var(")) return true
35
+ const zero = a[1] === undefined || position(a[1]) === 0,
36
+ full = b.length === 1 || position(b.at(-1) ?? "") === 1
37
+ if (!(zero && full)) return true
38
+ }
39
+ return false
40
+ }
@@ -0,0 +1,134 @@
1
+ import type { ComputedStyle, PageSnapshot } from "../../../types"
2
+ import { splitTop } from "./appearance"
3
+ export type Frame = Readonly<Record<string, string>>
4
+ export type KeyframeStep = { readonly key: string; readonly declarations: Frame }
5
+ export function keyframeSteps(s: PageSnapshot, name: string): readonly KeyframeStep[] | null {
6
+ const frames: KeyframeStep[] = []
7
+ let found = false
8
+ for (const css of s.cssText) {
9
+ const text = css.replace(/\/\*[\s\S]*?\*\//g, "")
10
+ for (const m of text.matchAll(/@(?:-webkit-)?keyframes\s+([\w-]+)\s*\{/g)) {
11
+ if (m[1] !== name) continue
12
+ found = true
13
+ let end = (m.index ?? 0) + m[0].length,
14
+ depth = 1
15
+ const start = end
16
+ while (end < text.length && depth > 0) {
17
+ if (text[end] === "{") depth++
18
+ if (text[end] === "}") depth--
19
+ end++
20
+ }
21
+ for (const step of text.slice(start, end - 1).matchAll(/([^{}]+)\{([^{}]*)\}/g)) {
22
+ const entries = (step[2] ?? "").split(";").flatMap((d) => {
23
+ const i = d.indexOf(":")
24
+ return i < 0 ? [] : [[d.slice(0, i).trim().toLowerCase(), d.slice(i + 1).trim()]]
25
+ })
26
+ frames.push({ key: (step[1] ?? "").trim(), declarations: Object.fromEntries(entries) })
27
+ }
28
+ }
29
+ }
30
+ return found ? frames : null
31
+ }
32
+ export function keyframes(s: PageSnapshot, name: string): readonly Frame[] | null {
33
+ return keyframeSteps(s, name)?.map(step => step.declarations) ?? null
34
+ }
35
+ export function infiniteNames(style: ComputedStyle): readonly string[] {
36
+ const iterations = splitTop(style["animation-iteration-count"] ?? "")
37
+ return splitTop(style["animation-name"] ?? "").filter((n, i) => n !== "none" && iterations[i % iterations.length] === "infinite")
38
+ }
39
+ export function onlyUnitPulse(frames: readonly Frame[]): boolean {
40
+ return (
41
+ frames.length > 0 &&
42
+ frames.every((f) =>
43
+ Object.entries(f).every(([p, v]) => {
44
+ if (p === "opacity") return true
45
+ if (p === "animation-timing-function") return !/linear\(|var\(/.test(v) && !overshoot(v)
46
+ if (p !== "scale" && p !== "transform") return false
47
+ if (v === "none") return true
48
+ const rest = p === "scale" ? v : v.replace(/scale(?:[XYZ]|3d)?\(([^)]*)\)/gi, "$1")
49
+ return (
50
+ /^[\s,0-9.+-]+$/.test(rest) &&
51
+ rest
52
+ .split(/[\s,]+/)
53
+ .filter(Boolean)
54
+ .every((n) => Number(n) >= 0 && Number(n) <= 1)
55
+ )
56
+ }),
57
+ )
58
+ )
59
+ }
60
+ export const overshoot = (v: string): boolean =>
61
+ [...v.matchAll(/cubic-bezier\(\s*([\d.+-]+)\s*,\s*([\d.+-]+)\s*,\s*([\d.+-]+)\s*,\s*([\d.+-]+)\s*\)/g)].some((m) =>
62
+ [Number(m[2]), Number(m[4])].some((y) => y < -0.1 || y > 1.1),
63
+ )
64
+ const scalar = (v: string): number | null => (/^[-+]?(?:\d*\.)?\d+(?:px)?$/.test(v) ? Number.parseFloat(v) : null)
65
+ const differs = (a: string | undefined, b: string | undefined): boolean => {
66
+ if (a === undefined || b === undefined) return false
67
+ const x = scalar(a),
68
+ y = scalar(b)
69
+ return x !== null && y !== null ? Math.abs(x - y) >= 4 : a.replace(/\s/g, "") !== b.replace(/\s/g, "")
70
+ }
71
+ function translation(f: Frame): readonly string[] | null {
72
+ const t = f["transform"]
73
+ if (t === undefined && f["translate"] === undefined) return null
74
+ if (t?.includes("matrix")) return []
75
+ const axes = ["0", "0", "0"]
76
+ for (const m of (t ?? "").matchAll(/translate([XYZ]|3d)?\(([^)]*)\)/gi)) {
77
+ const suffix = m[1]?.toLowerCase(),
78
+ args = (m[2] ?? "").split(/,\s*/).map((x) => x.trim())
79
+ if (suffix === "x" || suffix === "y" || suffix === "z") axes[suffix === "x" ? 0 : suffix === "y" ? 1 : 2] = args[0] ?? "0"
80
+ else
81
+ args.forEach((v, i) => {
82
+ axes[i] = v
83
+ })
84
+ }
85
+ if (f["translate"])
86
+ f["translate"].split(/\s+/).forEach((v, i) => {
87
+ axes[i] = v
88
+ })
89
+ return axes
90
+ }
91
+ export function dotPulse(frames: readonly Frame[]): boolean {
92
+ const declarations = frames.flatMap((f) => Object.entries(f))
93
+ const scales = declarations
94
+ .filter(([p]) => p === "transform")
95
+ .flatMap(([, v]) => [...v.matchAll(/scale([XY]|3d)?\(/gi)].map((m) => m[1] ?? "both"))
96
+ const oneAxis =
97
+ scales.length > 0 &&
98
+ new Set(scales).size === 1 &&
99
+ ["X", "Y", "x", "y"].includes(scales[0] ?? "") &&
100
+ !declarations.some(([p]) => p === "scale")
101
+ const signal = declarations.some(
102
+ ([p, v]) => p === "opacity" || p === "box-shadow" || p === "scale" || (p === "transform" && /scale/i.test(v) && !oneAxis),
103
+ )
104
+ if (!signal) return false
105
+ const translations = frames.map(translation).filter((t): t is readonly string[] => t !== null)
106
+ for (const a of translations)
107
+ for (const b of translations)
108
+ for (let i = 0; i < 3; i++) {
109
+ const x = a[i] ?? "0",
110
+ y = b[i] ?? "0"
111
+ if (!x.includes("%") && !y.includes("%") && differs(x, y)) return false
112
+ }
113
+ const sizes = frames.filter((f) => f["height"] !== undefined)
114
+ if (sizes.some((f) => f["height"] !== sizes[0]?.["height"]) && sizes.every((f) => f["width"] === sizes[0]?.["width"])) return false
115
+ const pairs = [
116
+ ["left", "right"],
117
+ ["top", "bottom"],
118
+ ["inset-inline-start", "inset-inline-end"],
119
+ ["inset-block-start", "inset-block-end"],
120
+ ["margin-left", "margin-right"],
121
+ ["margin-top", "margin-bottom"],
122
+ ["margin-inline-start", "margin-inline-end"],
123
+ ["margin-block-start", "margin-block-end"],
124
+ ]
125
+ for (const a of frames)
126
+ for (const b of frames) {
127
+ if (differs(a["width"], b["width"]) || differs(a["height"], b["height"])) continue
128
+ for (const [x = "", y = ""] of pairs) if (differs(a[x], b[x]) !== differs(a[y], b[y])) return false
129
+ }
130
+ return true
131
+ }
132
+ export const toggles = (frames: readonly Frame[]): boolean =>
133
+ frames.some((f) => Number(f["opacity"] ?? 1) <= 0.15 || f["visibility"] === "hidden") &&
134
+ frames.every((f) => Object.keys(f).every((p) => ["opacity", "visibility", "animation-timing-function"].includes(p)))
@@ -0,0 +1,85 @@
1
+ import { ancestors, childrenOf, descendants, fontSizePx, isHeading, parentOf, styleOf } from "../../../core/page"
2
+ import { parseColor } from "../../../core/color"
3
+ import type { ElementSnapshot, PageSnapshot } from "../../../types"
4
+ import { chroma, context, length, radii, visible } from "./appearance"
5
+ function previous(s: PageSnapshot, e: ElementSnapshot): ElementSnapshot | null {
6
+ const p = parentOf(s, e)
7
+ if (!p) return null
8
+ const siblings = childrenOf(s, p),
9
+ at = siblings.findIndex((n) => n.index === e.index)
10
+ return siblings[at - 1] ?? null
11
+ }
12
+ export function labelBefore(s: PageSnapshot, h: ElementSnapshot): { label: ElementSnapshot; levels: number } | null {
13
+ let at = h
14
+ for (let levels = 0; levels <= 4; levels++) {
15
+ const label = previous(s, at)
16
+ if (label) return { label, levels }
17
+ const p = parentOf(s, at)
18
+ if (!p || ["body", "html"].includes(p.tag)) return null
19
+ at = p
20
+ }
21
+ return null
22
+ }
23
+ export function labelType(s: PageSnapshot, e: ElementSnapshot): ElementSnapshot {
24
+ let at = e
25
+ for (let i = 0; i < 3; i++) {
26
+ if (at.ownText.trim() !== "") return at
27
+ const children = childrenOf(s, at).filter((c) => c.text.trim() !== "")
28
+ const only = children[0]
29
+ if (children.length !== 1 || !only) return at
30
+ at = only
31
+ }
32
+ return at
33
+ }
34
+ export const application = (s: PageSnapshot, e: ElementSnapshot): boolean =>
35
+ context(s, e, (a) => a.tag === "dialog" || ["tabpanel", "dialog", "application"].includes(a.attributes["role"] ?? ""))
36
+ export const caps = (e: ElementSnapshot): boolean =>
37
+ styleOf(e, "text-transform") === "uppercase" || (/[A-Z]/.test(e.text) && !/[a-z]/.test(e.text))
38
+ export function heroLabel(s: PageSnapshot, h: ElementSnapshot): ElementSnapshot | null {
39
+ if (h.tag !== "h1" || fontSizePx(h) < 48 || application(s, h) || !visible(s, h)) return null
40
+ const e = previous(s, h)
41
+ if (!e || isHeading(e) || e.text.trim().length < 2 || e.text.trim().length > 60 || !visible(s, e)) return null
42
+ const ty = labelType(s, e),
43
+ size = fontSizePx(ty),
44
+ spacing = length(styleOf(ty, "letter-spacing"))
45
+ if (size <= 0 || size > 14) return null
46
+ const dated =
47
+ (e.tag === "time" || [...descendants(s, e)].some((c) => c.tag === "time") || /\b(?:19|20)\d{2}\b/.test(e.text)) && spacing < 1.6
48
+ const tracked = caps(ty) && !dated && (spacing >= 1.6 || spacing >= size * 0.08)
49
+ const bold = Number(styleOf(ty, "font-weight")) >= 700 && chroma(styleOf(ty, "color"), 40)
50
+ const dash = [e.before, e.after].some(
51
+ (p) =>
52
+ p &&
53
+ length(p.style["width"] ?? "") >= 8 &&
54
+ length(p.style["width"] ?? "") <= 80 &&
55
+ length(p.style["height"] ?? "") >= 1 &&
56
+ length(p.style["height"] ?? "") <= 6 &&
57
+ chroma(p.style["background-color"] ?? ""),
58
+ )
59
+ return tracked || bold || dash ? e : null
60
+ }
61
+ export const headingLevel = (e: ElementSnapshot): number =>
62
+ isHeading(e) ? Number(e.tag.slice(1)) : e.attributes["role"] === "heading" ? Number(e.attributes["aria-level"] ?? 2) : 0
63
+ export function cardContext(s: PageSnapshot, h: ElementSnapshot, label: ElementSnapshot): boolean {
64
+ for (const a of ancestors(s, h)) {
65
+ if (a.tag === "body") break
66
+ if (![...descendants(s, a)].some((n) => n.index === label.index)) continue
67
+ if (["article", "li", "a", "button"].includes(a.tag) && a.rect.height <= s.viewport.height * 2) return true
68
+ if (headingLevel(h) < 3 || a.rect.height >= s.viewport.height) continue
69
+ const bg = parseColor(styleOf(a, "background-color")),
70
+ framed = radii(a).some((r) => r > 0) && bg !== null && bg.a >= 0.9
71
+ if (!framed) continue
72
+ const own = parseColor(styleOf(label, "background-color"))
73
+ const badge =
74
+ styleOf(label, "position") === "absolute" &&
75
+ (label.rect.y <= a.rect.y + 2 ||
76
+ (own !== null && own.a >= 0.9 && Math.max(Math.abs(own.r - bg.r), Math.abs(own.g - bg.g), Math.abs(own.b - bg.b)) > 3))
77
+ return fontSizePx(h) < 24 || badge
78
+ }
79
+ return false
80
+ }
81
+ export const nearAbove = (label: ElementSnapshot, h: ElementSnapshot): boolean =>
82
+ label.rect.y + label.rect.height <= h.rect.y + 4 &&
83
+ h.rect.y - label.rect.y - label.rect.height <= Math.max(64, fontSizePx(h) * 2) &&
84
+ label.rect.x < h.rect.x + h.rect.width &&
85
+ label.rect.x + label.rect.width > h.rect.x
@@ -0,0 +1,51 @@
1
+ import { ancestors, childrenOf, parentOf, styleOf } from "../../../core/page"
2
+ import type { ElementSnapshot, PageSnapshot } from "../../../types"
3
+
4
+ const tokens = (e: ElementSnapshot): readonly string[] => [...new Set((e.attributes["class"] ?? "").toLowerCase().split(/\s+/).filter(Boolean))]
5
+ const opacity = (s: PageSnapshot, e: ElementSnapshot): number =>
6
+ [e, ...ancestors(s, e)].reduce((value, n) => {
7
+ const own = Number.parseFloat(styleOf(n, "opacity"))
8
+ return value * (Number.isFinite(own) ? own : 1)
9
+ }, 1)
10
+ const transitionsOpacity = (e: ElementSnapshot): boolean => {
11
+ const times = styleOf(e, "transition-duration").split(",")
12
+ return styleOf(e, "transition-property").split(",").some((p, i) =>
13
+ ["opacity", "all"].includes(p.trim()) && Number.parseFloat(times[i % times.length] ?? "0") > 0)
14
+ }
15
+
16
+ export function pendingRaster(s: PageSnapshot, e: ElementSnapshot): boolean {
17
+ if (e.motion.includes("opacity")) return true
18
+ const chain = [e, ...ancestors(s, e)]
19
+ if (chain.slice(1).some(n => Number.parseFloat(styleOf(n, "opacity")) <= 0.02) ||
20
+ chain.some(n => styleOf(n, "display") === "none" || styleOf(n, "visibility") === "hidden")) return true
21
+ const attrs = e.attributes
22
+ if (attrs["data-loaded"]?.trim().toLowerCase() === "false" ||
23
+ (attrs["data-ll-status"] !== undefined && attrs["data-ll-status"].trim().toLowerCase() !== "loaded")) return true
24
+ if (["data-src", "data-srcset", "data-lazy", "data-lazy-src", "data-lazy-srcset", "data-original", "data-original-src"]
25
+ .some(name => attrs[name] !== undefined) && (attrs["src"] ?? "").trim() === "") return true
26
+ const parent = parentOf(s, e)
27
+ const classes = [e, ...(parent ? [parent] : [])].flatMap(tokens)
28
+ if (classes.some(t => t.includes("lazy")) && !classes.some(t => t.includes("loaded")) &&
29
+ (opacity(s, e) <= 0.02 || /(?:^|;)\s*opacity\s*:/i.test(attrs["style"] ?? ""))) return true
30
+ if (parent && opacity(s, e) <= 0.02) {
31
+ const videoOver = (n: ElementSnapshot, depth: number): boolean => {
32
+ const w = Math.min(e.rect.x + e.rect.width, n.rect.x + n.rect.width) - Math.max(e.rect.x, n.rect.x)
33
+ const h = Math.min(e.rect.y + e.rect.height, n.rect.y + n.rect.height) - Math.max(e.rect.y, n.rect.y)
34
+ if (n.tag === "video" && opacity(s, n) > 0.02 && [n, ...ancestors(s, n)].every(a =>
35
+ styleOf(a, "display") !== "none" && styleOf(a, "visibility") !== "hidden") &&
36
+ w > 0 && h > 0 && w * h >= e.rect.width * e.rect.height * 0.5) return true
37
+ return depth > 0 && childrenOf(s, n).some(child => videoOver(child, depth - 1))
38
+ }
39
+ if (parent.tag === "video" || childrenOf(s, parent).some(n => n.index !== e.index && videoOver(n, 3))) return true
40
+ }
41
+ if (e.tag !== "img" || opacity(s, e) > 0.02) return false
42
+ const own = tokens(e)
43
+ const peers = s.elements.filter(other => {
44
+ if (other.index === e.index || other.tag !== "img" || Number.parseFloat(styleOf(other, "opacity")) < 0.5 ||
45
+ opacity(s, other) <= 0.02 || !transitionsOpacity(other)) return false
46
+ const theirs = tokens(other)
47
+ const shared = own.filter(t => theirs.includes(t)).length
48
+ return shared > 0 && own.length - shared <= 1 && theirs.filter(t => !own.includes(t)).length === 1
49
+ })
50
+ return peers.length >= 2
51
+ }
@@ -0,0 +1,16 @@
1
+ import type { Rule } from "../rule"
2
+ import { COLOR_RULES } from "./color"
3
+ import { TYPOGRAPHY_RULES } from "./typography"
4
+ import { LAYOUT_RULES } from "./layout"
5
+ import { DECORATION_RULES } from "./decoration"
6
+ import { COPY_RULES } from "./copy"
7
+ import { SOURCE_RULES } from "./source"
8
+
9
+ export const ALL_RULES: readonly Rule[] = [
10
+ ...COLOR_RULES,
11
+ ...TYPOGRAPHY_RULES,
12
+ ...LAYOUT_RULES,
13
+ ...DECORATION_RULES,
14
+ ...COPY_RULES,
15
+ ...SOURCE_RULES,
16
+ ]
@@ -0,0 +1,64 @@
1
+ import { expect, test } from "bun:test"
2
+ import type { NodeSpec } from "../../testing/build-snapshot"
3
+ import { bodyTextViewportEdge } from "./body-text-viewport-edge"
4
+ import { lines, marked } from "./support/layout-cases"
5
+
6
+ const prose = "This paragraph contains substantial reading text that needs a gutter at either side of the page."
7
+
8
+ test("#given full width prose with and without a gutter #then only edge touching text reports", () => {
9
+ expect(marked(bodyTextViewportEdge, [
10
+ { id: "flush", tag: "p", text: prose, rect: { width: 1280, height: 80 }, lineRects: lines([1280, 100], 0, 0) },
11
+ { id: "inset", tag: "p", text: prose, rect: { width: 1280, height: 80 }, lineRects: lines([1200], 40, 100) },
12
+ ])).toEqual(["#flush"])
13
+ })
14
+
15
+ test("#given a phone gutter of twelve pixels #then phone and desktop floors differ", () => {
16
+ const node = { id: "copy", tag: "p", text: prose, rect: { x: 12, width: 296 }, lineRects: lines([296], 12, 0) }
17
+ expect(marked(bodyTextViewportEdge, [node], { viewport: { width: 320, height: 800 } })).toEqual([])
18
+ expect(marked(bodyTextViewportEdge, [{ ...node, rect: { x: 12, width: 1256 }, lineRects: lines([1256], 12, 0) }])).toEqual(["#copy"])
19
+ })
20
+
21
+ test("#given navigation and scrollable tracks beside body content #then only body content keeps the gutter requirement", () => {
22
+ const node = { id: "copy", tag: "p", text: prose, rect: { width: 1280 }, lineRects: lines([1280], 0, 0) }
23
+ expect(marked(bodyTextViewportEdge, [node])).toEqual(["#copy"])
24
+ expect(marked(bodyTextViewportEdge, [{ tag: "nav", children: [node] }])).toEqual([])
25
+ expect(marked(bodyTextViewportEdge, [{ style: { "overflow-x": "auto" }, children: [node] }])).toEqual([])
26
+ })
27
+
28
+ test("#given body text past the window #then overflow is reported once at page level", () => {
29
+ const node = { tag: "p", text: prose, rect: { x: 40, width: 1600 }, lineRects: lines([1600], 40, 0) }
30
+ expect(marked(bodyTextViewportEdge, [node, node])).toEqual(["page"])
31
+ expect(marked(bodyTextViewportEdge, [{ ...node, rect: { x: 1400, width: 1600 }, lineRects: lines([1600], 1400, 0) }])).toEqual([])
32
+ })
33
+
34
+ test("#given overflow on one side and a narrow gutter opposite #then both forms report", () => {
35
+ const node = { id: "copy", tag: "p", text: prose, rect: { x: 8, width: 1400 }, lineRects: lines([1400], 8, 0) }
36
+ expect(marked(bodyTextViewportEdge, [node])).toEqual(["#copy", "page"])
37
+ })
38
+
39
+ test("#given prose inside a whole card link #then its label is not body reading text", () => {
40
+ const node = { id: "copy", text: prose, rect: { width: 1280 }, lineRects: lines([1280], 0, 0) }
41
+ expect(marked(bodyTextViewportEdge, [{ tag: "a", children: [node] }])).toEqual([])
42
+ })
43
+
44
+ test("#given a genuinely running endless row #then its current text position is not a page gutter", () => {
45
+ const css = "@keyframes slide { from { transform: translateX(0) } to { transform: translateX(-50%) } }"
46
+ const track = (motion: readonly string[], state = "running", name = "slide", count = "infinite"): NodeSpec => ({
47
+ style: { transform: "matrix(1, 0, 0, 1, -1, 0)", "animation-name": name, "animation-iteration-count": count, "animation-play-state": state },
48
+ motion, rect: { x: -1, y: 0, width: 2560, height: 100 }, scroll: { scrollWidth: 2560, clientWidth: 2560 },
49
+ children: [
50
+ { rect: { x: -1, y: 0, width: 1280, height: 100 }, children: [{ id: "copy", tag: "p", text: prose,
51
+ rect: { x: 8, y: 0, width: 1260, height: 48 }, lineRects: lines([1200, 800], 8, 0) }] },
52
+ { rect: { x: 1279, y: 0, width: 1280, height: 100 } },
53
+ ],
54
+ })
55
+ const host = (node: NodeSpec): NodeSpec => ({ style: { "overflow-x": "hidden" },
56
+ rect: { width: 1280, height: 100 }, scroll: { clientWidth: 1280 }, children: [node] })
57
+ expect(marked(bodyTextViewportEdge, [host(track(["transform"]))], { cssText: [css] })).toEqual([])
58
+ expect(marked(bodyTextViewportEdge, [host(track([], "paused"))], { cssText: [css] })).toEqual(["#copy"])
59
+ const scale = "@keyframes pulse { from { transform: scale(.9) } to { transform: scale(1) } }"
60
+ expect(marked(bodyTextViewportEdge, [host(track(["transform"], "running", "pulse"))], { cssText: [scale] })).toEqual(["#copy"])
61
+ const fade = "@keyframes fade { from { opacity: 0 } to { opacity: 1 } }"
62
+ expect(marked(bodyTextViewportEdge, [host(track(["opacity", "transform"], "running, running", "fade, slide", "infinite, 1"))],
63
+ { cssText: [fade, css] })).toEqual(["#copy"])
64
+ })
@@ -0,0 +1,62 @@
1
+ import { childrenOf, fontSizePx, isIgnored, shortSnippet, styleOf } from "../../core/page"
2
+ import type { PageHit, PageRule } from "../../rule"
3
+ import { alpha, bounds, chain, clipsX, length, outOfFlow, painted, right, scrollsX, textLines } from "./support/geometry"
4
+ import { trackCuts } from "./support/clipping"
5
+ import { ridesRunningTrack } from "./support/motion"
6
+
7
+ export const bodyTextViewportEdge: PageRule = {
8
+ meta: {
9
+ id: "body-text-viewport-edge", name: "Body text touching viewport edge", category: "quality", severity: "warning", engine: "page",
10
+ description: "Reading text touches the viewport edge without a usable gutter.",
11
+ fixHint: "Keep at least 12px of horizontal space on phones and 16px on wider screens; constrain overflowing columns.",
12
+ },
13
+ check: ({ snapshot }) => {
14
+ const width = snapshot.viewport.width
15
+ const floor = width <= 480 ? 12 : 16
16
+ const hits: PageHit[] = []
17
+ let overflow = false
18
+ for (const el of snapshot.elements) {
19
+ if (isIgnored(snapshot, el, "body-text-viewport-edge")) continue
20
+ const prose = ["p", "li"].includes(el.tag)
21
+ const generic = ["div", "section", "article", "aside", "main"].includes(el.tag) &&
22
+ el.ownText !== "" && fontSizePx(el) < 28 && ["block", "flow-root"].includes(styleOf(el, "display")) &&
23
+ childrenOf(snapshot, el).every((c) => styleOf(c, "display") === "inline")
24
+ if (!(prose || generic) || el.text.length <= 40 || !painted(snapshot, el) || outOfFlow(el) ||
25
+ el.rect.width <= width * 0.5 || alpha(el, "background-color") > 0) continue
26
+ if (ridesRunningTrack(snapshot, el)) continue
27
+ const path = chain(snapshot, el)
28
+ if (generic && path.some((n) => /^(a|button|label|summary|select|textarea)$/.test(n.tag) ||
29
+ /^(button|link|tab|menuitem|option)$/.test(n.attributes["role"] ?? "") || n.attributes["contenteditable"] !== undefined)) continue
30
+ if (path.some((n) => n.tag === "nav" || n.tag === "header" && n.rect.height <= snapshot.viewport.height ||
31
+ scrollsX(n) || /^(pre|pre-wrap)$/.test(styleOf(n, "white-space")))) continue
32
+ const lines = textLines(snapshot, el)
33
+ const text = bounds(lines)
34
+ if (!text && generic) continue
35
+ if (text && trackCuts(snapshot, el, text)) continue
36
+ let left = text?.x ?? el.rect.x
37
+ let end = text ? right(text) : right(el.rect)
38
+ if (clipsX(el) && !["", "clip"].includes(styleOf(el, "text-overflow"))) {
39
+ left = Math.max(left, el.rect.x)
40
+ end = Math.min(end, right(el.rect))
41
+ }
42
+ const contentLeft = el.rect.x + length(el, "padding-left") + length(el, "border-left-width")
43
+ const contentEnd = right(el.rect) - length(el, "padding-right") - length(el, "border-right-width")
44
+ if (text && lines.length >= 2 && text.width >= (contentEnd - contentLeft) * 0.9 &&
45
+ !(styleOf(el, "text-align") !== "justify" && left >= 16 && end <= width - 16)) {
46
+ left = contentLeft
47
+ end = contentEnd
48
+ } else if (styleOf(el, "display") === "list-item") {
49
+ left = Math.min(left, contentLeft)
50
+ }
51
+ if (end <= 0 || left >= width) continue
52
+ if (path.slice(1).some((n) => styleOf(n, "position") === "fixed" && n.rect.height < snapshot.viewport.height / 2) && Math.min(left, width - end) >= 4) continue
53
+ if (Math.round(-left) > 0 || Math.round(end - width) > 0) overflow = true
54
+ if (Math.round(left) >= 0 && left < floor || Math.round(width - end) >= 0 && width - end < floor) hits.push({ element: el, message: `Body copy keeps less than ${floor}px from the viewport edge.`, snippet: shortSnippet(el) })
55
+ }
56
+ if (overflow) {
57
+ const widest = snapshot.elements.filter((el) => painted(snapshot, el) && !chain(snapshot, el).some(scrollsX)).sort((a, b) => right(b.rect) - right(a.rect))[0]
58
+ hits.push({ element: null, message: `Body text runs outside the viewport${widest ? `; widest element ${widest.selector} ends at ${right(widest.rect)}px` : ""}.`, snippet: widest ? shortSnippet(widest) : "Page overflow" })
59
+ }
60
+ return hits
61
+ },
62
+ }
@@ -0,0 +1,40 @@
1
+ import { expect, test } from "bun:test"
2
+ import type { NodeSpec } from "../../testing/build-snapshot"
3
+ import { clippedOverflowContainer } from "./clipped-overflow-container"
4
+ import { marked } from "./support/layout-cases"
5
+
6
+ const popup: NodeSpec = { id: "popup", attributes: { role: "menu" }, style: { position: "absolute" }, rect: { x: 30, y: 160, width: 200, height: 80 }, text: "Menu contents" }
7
+ const host = (child: NodeSpec, style = "hidden"): NodeSpec => ({
8
+ id: "host", style: { position: "relative", "overflow-x": style, "overflow-y": style }, rect: { x: 20, y: 20, width: 200, height: 120 }, children: [child],
9
+ })
10
+
11
+ test("#given escaped popup layers and decorative crops #then only popup clipping reports", () => {
12
+ expect(marked(clippedOverflowContainer, [host(popup)])).toEqual(["#host"])
13
+ expect(marked(clippedOverflowContainer, [host({ ...popup, attributes: { "aria-hidden": "true" }, text: "", id: "crop" })])).toEqual([])
14
+ expect(marked(clippedOverflowContainer, [host(popup, "auto")])).toEqual([])
15
+ })
16
+
17
+ test("#given nested clipping hosts #then the nearest clipping box owns the popup", () => {
18
+ const inner = { ...host(popup), id: "inner" }
19
+ expect(marked(clippedOverflowContainer, [host(inner)])).toEqual(["#inner"])
20
+ expect(marked(clippedOverflowContainer, [host({ ...popup, rect: { x: 30, y: 30, width: 100, height: 60 } })])).toEqual([])
21
+ })
22
+
23
+ test("#given fixed popups without and with transformed containment #then only the trapped fixed layer reports", () => {
24
+ const fixed = { ...popup, style: { position: "fixed" } }
25
+ expect(marked(clippedOverflowContainer, [host(fixed)])).toEqual([])
26
+ const transformed = { ...host(fixed), style: { position: "relative", transform: "matrix(1, 0, 0, 1, 0, 0)", "overflow-x": "hidden", "overflow-y": "hidden" } }
27
+ expect(marked(clippedOverflowContainer, [transformed])).toEqual(["#host"])
28
+ })
29
+
30
+ test("#given class named dropdowns and camel case slider tracks #then neither is an escaping popup", () => {
31
+ expect(marked(clippedOverflowContainer, [host({ ...popup, attributes: { class: "dropdown-panel" } })])).toEqual([])
32
+ expect(marked(clippedOverflowContainer, [{ ...host(popup), attributes: { class: "slickViewport" } }])).toEqual([])
33
+ expect(marked(clippedOverflowContainer, [host({ ...popup, attributes: { role: "menu", "aria-hidden": "true" } })])).toEqual([])
34
+ })
35
+
36
+ test("#given modal and nonmodal open dialogs #then only the nonmodal dialog can be trapped by a clip", () => {
37
+ const dialog = { ...popup, tag: "dialog", attributes: { open: "" }, modal: true }
38
+ expect(marked(clippedOverflowContainer, [host(dialog)])).toEqual([])
39
+ expect(marked(clippedOverflowContainer, [host({ ...dialog, modal: false })])).toEqual(["#host"])
40
+ })
@@ -0,0 +1,15 @@
1
+ import { shortSnippet } from "../../core/page"
2
+ import type { PageRule } from "../../rule"
3
+ import { clippedChild } from "./support/clipping"
4
+
5
+ export const clippedOverflowContainer: PageRule = {
6
+ meta: {
7
+ id: "clipped-overflow-container", name: "Positioned child clipped by overflow container", category: "quality", severity: "advisory", engine: "page",
8
+ description: "A container cuts off a positioned menu, tooltip, or dialog that needs to escape it.",
9
+ fixHint: "Render the popup outside the clipping box or remove the clip from its containing block.",
10
+ },
11
+ check: ({ snapshot }) => snapshot.elements.flatMap((el) => {
12
+ const child = clippedChild(snapshot, el)
13
+ return child ? [{ element: el, message: `${el.selector} clips positioned popup ${child.selector}.`, snippet: shortSnippet(el) }] : []
14
+ }),
15
+ }
@@ -0,0 +1,62 @@
1
+ import { expect, test } from "bun:test"
2
+ import { contentHiddenAtRest } from "./content-hidden-at-rest"
3
+ import { marked } from "./support/layout-cases"
4
+
5
+ const hidden = { id: "reveal", style: { opacity: "0" }, text: "Invisible main content. ".repeat(10) }
6
+ const visible = { tag: "p", text: "Visible copy. ".repeat(10) }
7
+
8
+ test("#given a failed reveal and visible content #then the page fails the hidden share threshold", () => {
9
+ expect(marked(contentHiddenAtRest, [hidden, visible])).toEqual(["page"])
10
+ expect(marked(contentHiddenAtRest, [{ ...hidden, style: { opacity: "1" } }, visible])).toEqual([])
11
+ })
12
+
13
+ test("#given closed dialogs menus and panels #then their text is excluded from the hidden share", () => {
14
+ expect(marked(contentHiddenAtRest, [hidden, visible])).toEqual(["page"])
15
+ for (const role of ["dialog", "tabpanel", "menu"]) {
16
+ expect(marked(contentHiddenAtRest, [{ ...hidden, attributes: { role } }, visible])).toEqual([])
17
+ }
18
+ expect(marked(contentHiddenAtRest, [{ tag: "nav", children: [hidden] }, visible])).toEqual([])
19
+ })
20
+
21
+ test("#given a selected tab panel whose reveal failed #then it counts as expected content", () => {
22
+ const panel = { ...hidden, attributes: { role: "tabpanel" } }
23
+ expect(marked(contentHiddenAtRest, [{ tag: "button", attributes: { "aria-controls": "reveal", "aria-selected": "true" } }, panel, visible])).toEqual(["page"])
24
+ expect(marked(contentHiddenAtRest, [{ tag: "button", attributes: { "aria-controls": "reveal", "aria-selected": "false" } }, panel, visible])).toEqual([])
25
+ })
26
+
27
+ test("#given the character and share boundaries #then only substantial hidden content fails", () => {
28
+ expect(marked(contentHiddenAtRest, [{ ...hidden, text: "x".repeat(150) }, { text: "v".repeat(50) }])).toEqual(["page"])
29
+ expect(marked(contentHiddenAtRest, [{ ...hidden, text: "x".repeat(149) }, { text: "v".repeat(51) }])).toEqual([])
30
+ expect(marked(contentHiddenAtRest, [{ ...hidden, text: "x".repeat(150) }, { text: "v".repeat(350) }])).toEqual([])
31
+ })
32
+
33
+ test("#given a hidden viewport overlay and a fixed app shell #then only the app shell is page content", () => {
34
+ const layer = { ...hidden, style: { position: "fixed", visibility: "hidden" }, rect: { x: 0, y: 0, width: 1280, height: 800 } }
35
+ const page = { ...visible, text: "Visible copy. ".repeat(60) }
36
+ expect(marked(contentHiddenAtRest, [layer, page])).toEqual([])
37
+ expect(marked(contentHiddenAtRest, [{ ...layer, text: "Hidden application text. ".repeat(40), children: [{ tag: "main" }] }, page])).toEqual(["page"])
38
+ })
39
+
40
+ test("#given sliders with no visible slide and with a visible current slide #then only waiting slides of the started slider count", () => {
41
+ const slide = { ...hidden, tag: "p" }
42
+ const slider = { attributes: { class: "swiper" }, children: [slide] }
43
+ expect(marked(contentHiddenAtRest, [slider, visible])).toEqual([])
44
+ expect(marked(contentHiddenAtRest, [{ ...slider, children: [slide, { tag: "p", text: "Current offer" }] }, visible])).toEqual(["page"])
45
+ })
46
+
47
+ test("#given an aria labelled selected tab #then a failed reveal remains hidden content", () => {
48
+ const tab = { id: "tab", tag: "button", attributes: { "aria-selected": "true" } }
49
+ const panel = { ...hidden, attributes: { role: "tabpanel", "aria-labelledby": "tab" } }
50
+ expect(marked(contentHiddenAtRest, [tab, panel, visible])).toEqual(["page"])
51
+ })
52
+
53
+ test("#given a long overlay on a larger page #then capped snippets do not decide its share", () => {
54
+ const layer = { text: "Hidden menu text. ".repeat(70), style: { position: "fixed", visibility: "hidden" },
55
+ rect: { x: 0, y: 0, width: 1280, height: 800 } }
56
+ expect(marked(contentHiddenAtRest, [layer, { text: "Visible page text. ".repeat(170) }])).toEqual([])
57
+ })
58
+
59
+ test("#given unrelated tab and content class tokens #then they do not name a closed tab panel", () => {
60
+ expect(marked(contentHiddenAtRest, [{ ...hidden, attributes: { class: "tab content" } }, visible])).toEqual(["page"])
61
+ expect(marked(contentHiddenAtRest, [{ ...hidden, attributes: { class: "tab-content" } }, visible])).toEqual([])
62
+ })
@@ -0,0 +1,63 @@
1
+ import { childrenOf, descendants, styleOf } from "../../core/page"
2
+ import type { PageRule } from "../../rule"
3
+ import type { ElementSnapshot, PageSnapshot } from "../../types"
4
+ import { bottom, chain, hasRole, right } from "./support/geometry"
5
+ import { classWords, closedClass, unstartedSlider } from "./support/hidden-interface"
6
+
7
+ function closed(s: PageSnapshot, el: ElementSnapshot): boolean {
8
+ const controls = s.elements.filter((n) => (n.attributes["aria-controls"] ?? "").split(/\s+/).includes(el.attributes["id"] ?? "\u0000"))
9
+ const labels = (el.attributes["aria-labelledby"] ?? "").split(/\s+/)
10
+ const selected = (hasRole(el, ["tabpanel"]) || classWords(el).some((word) => ["tab", "tabs", "tabpanel", "tabpane"].includes(word))) &&
11
+ (controls.some((n) => n.attributes["aria-selected"] === "true" || n.attributes["aria-expanded"] === "true") ||
12
+ s.elements.some((n) => labels.includes(n.attributes["id"] ?? "\u0000") && n.attributes["aria-selected"] === "true"))
13
+ if (!selected && controls.some((n) => n.attributes["aria-selected"] === "false" || n.attributes["aria-expanded"] === "false")) return true
14
+ if (!selected && (hasRole(el, ["dialog", "alertdialog", "tabpanel"]) || closedClass(el))) return true
15
+ if (styleOf(el, "position") === "fixed" && (right(el.rect) <= 0 || el.rect.x >= s.viewport.width)) return true
16
+ const path = chain(s, el)
17
+ if (path.some((n) => n.attributes["inert"] !== undefined || n.tag === "nav" || hasRole(n, ["navigation", "menu", "menubar"]))) return true
18
+ if (styleOf(el, "position") === "fixed" && /^(hidden|collapse)$/.test(styleOf(el, "visibility")) &&
19
+ el.rect.x <= 1 && el.rect.y <= 1 && right(el.rect) >= s.viewport.width - 1 && bottom(el.rect) >= s.viewport.height - 1) {
20
+ const nodes = [el, ...descendants(s, el)]
21
+ const chars = nodes.reduce((sum, n) => sum + n.ownText.length, 0)
22
+ const pageChars = s.elements.reduce((sum, n) => sum + n.ownText.length, 0)
23
+ if (chars * 2 < pageChars && !nodes.some((n) => n.tag === "main" || n.tag === "h1" || hasRole(n, ["main"]))) return true
24
+ }
25
+ if (path.some((n) => /^(absolute|fixed)$/.test(styleOf(n, "position")) &&
26
+ !["", "none", "matrix(1, 0, 0, 1, 0, 0)"].includes(styleOf(n, "transform")) &&
27
+ /\b(?:transform|all)\b/.test(styleOf(n, "transition-property")) &&
28
+ (right(n.rect) <= 0 || n.rect.x >= s.viewport.width))) return true
29
+ const p = el.parent === null ? undefined : s.elements[el.parent]
30
+ const siblings = p ? childrenOf(s, p) : []
31
+ const previous = siblings[siblings.indexOf(el) - 1]
32
+ if (previous && (previous.attributes["aria-expanded"] === "false" ||
33
+ childrenOf(s, previous).length === 1 && childrenOf(s, previous)[0]?.attributes["aria-expanded"] === "false")) return true
34
+ return path.slice(1).some((n) => {
35
+ const triggers = s.elements.filter((t) => (t.attributes["aria-controls"] ?? "").split(/\s+/).includes(n.attributes["id"] ?? "\u0000"))
36
+ return triggers.some((t) => t.attributes["aria-expanded"] === "false" || t.attributes["aria-selected"] === "false") &&
37
+ !triggers.some((t) => t.attributes["aria-expanded"] === "true" || t.attributes["aria-selected"] === "true")
38
+ })
39
+ }
40
+
41
+ export const contentHiddenAtRest: PageRule = {
42
+ meta: {
43
+ id: "content-hidden-at-rest", name: "Content invisible at rest", category: "quality", severity: "error", engine: "page",
44
+ description: "A large share of page text remains transparent or hidden instead of appearing as content.",
45
+ fixHint: "Show content by default and enhance its entrance without making visibility depend on a reveal script.",
46
+ },
47
+ check: ({ snapshot }) => {
48
+ let total = 0
49
+ let hidden = 0
50
+ for (const el of snapshot.elements) {
51
+ if (el.ownText === "") continue
52
+ const path = chain(snapshot, el)
53
+ if (path.some((n) => /^(script|style|noscript|template|title|head|meta|link|option|optgroup|select|datalist|dialog)$/.test(n.tag) ||
54
+ n.attributes["hidden"] !== undefined || n.attributes["aria-hidden"] === "true" || styleOf(n, "display") === "none")) continue
55
+ const invisible = [...path].reverse().find((n) => Number.parseFloat(styleOf(n, "opacity")) <= 0.02 || /^(hidden|collapse)$/.test(styleOf(n, "visibility")))
56
+ if (invisible && (closed(snapshot, invisible) || unstartedSlider(snapshot, invisible))) continue
57
+ total += el.ownText.length
58
+ if (invisible) hidden += el.ownText.length
59
+ }
60
+ if (total < 200 || hidden < 150 || hidden / total <= 0.3) return []
61
+ return [{ element: null, message: `${hidden} of ${total} characters (${Math.round(hidden / total * 100)}%) remain hidden.`, snippet: `${hidden}/${total} hidden characters` }]
62
+ },
63
+ }