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.
- package/dist/agents/atlas/agent.d.ts +5 -5
- package/dist/agents/dynamic-agent-core-sections.d.ts +0 -1
- package/dist/agents/dynamic-agent-prompt-builder.d.ts +1 -1
- package/dist/agents/gpt-apply-patch-guard.d.ts +0 -1
- package/dist/agents/hephaestus/agent.d.ts +3 -7
- package/dist/agents/hephaestus/model-support.d.ts +6 -0
- package/dist/agents/metis.d.ts +0 -15
- package/dist/agents/native-model-prompt.d.ts +9 -0
- package/dist/agents/native-prompt-frame.d.ts +20 -0
- package/dist/agents/native-tool-snippet.d.ts +6 -0
- package/dist/agents/sisyphus/default.d.ts +0 -1
- package/dist/agents/sisyphus-agent-factory.d.ts +2 -11
- package/dist/agents/sisyphus-junior/agent.d.ts +2 -20
- package/dist/agents/sisyphus-junior/index.d.ts +1 -11
- package/dist/agents/sisyphus-runtime-prompt-reconciler.d.ts +6 -0
- package/dist/agents/types.d.ts +2 -2
- package/dist/cli/index.js +1174 -394
- package/dist/cli/service-auth/credential-lock.d.ts +11 -0
- package/dist/cli/service-auth/credential-owner.d.ts +10 -0
- package/dist/cli/service-auth/index.d.ts +3 -1
- package/dist/cli/service-auth/keystore.d.ts +8 -1
- package/dist/cli/service-auth/owned-refresh.d.ts +21 -0
- package/dist/cli/service-auth/protocol-v2.d.ts +27 -0
- package/dist/cli/service-auth/protocol.d.ts +26 -2
- package/dist/cli/service-auth/recovery-clock.d.ts +7 -0
- package/dist/cli/service-auth/refresh-attempt.d.ts +34 -0
- package/dist/cli/service-auth/session.d.ts +9 -2
- package/dist/cli-node/index.js +1174 -394
- package/dist/config/schema/agent-overrides.d.ts +64 -0
- package/dist/config/schema/categories.d.ts +8 -0
- package/dist/config/schema/oh-my-opencode-config.d.ts +64 -0
- package/dist/hooks/native-edition-nudge/hook.d.ts +3 -4
- package/dist/index.js +15625 -8841
- package/dist/oh-my-opencode.schema.json +112 -0
- package/dist/plugin/session-tool-permissions.d.ts +10 -0
- package/dist/plugin/system-transform.d.ts +2 -1
- package/dist/plugin/tool-definition.d.ts +1 -0
- package/dist/shared/bun-ffi-shim.d.ts +29 -0
- package/dist/shared/json-file-cache-store.d.ts +11 -0
- package/dist/skills/browser/runtime/omowright/index.js +24 -33
- package/dist/skills/browser/runtime/omowright/manifest.json +3 -3
- package/dist/skills/frontend/ATTRIBUTION.md +104 -1
- package/dist/skills/frontend/SKILL.md +7 -3
- package/dist/skills/frontend/references/design/design-system-architecture.md +3 -3
- package/dist/skills/frontend/references/perfection/craft-floor.md +59 -0
- package/dist/skills/frontend/references/perfection/detect.md +52 -0
- package/dist/skills/frontend/scripts/detect/cli.ts +70 -0
- package/dist/skills/frontend/scripts/detect/config.test.ts +26 -0
- package/dist/skills/frontend/scripts/detect/config.ts +53 -0
- package/dist/skills/frontend/scripts/detect/core/characters.ts +2 -0
- package/dist/skills/frontend/scripts/detect/core/color.test.ts +29 -0
- package/dist/skills/frontend/scripts/detect/core/color.ts +150 -0
- package/dist/skills/frontend/scripts/detect/core/page.ts +84 -0
- package/dist/skills/frontend/scripts/detect/core/shadow.ts +40 -0
- package/dist/skills/frontend/scripts/detect/core/source.ts +33 -0
- package/dist/skills/frontend/scripts/detect/detect.ts +77 -0
- package/dist/skills/frontend/scripts/detect/index.ts +23 -0
- package/dist/skills/frontend/scripts/detect/lint.test.ts +27 -0
- package/dist/skills/frontend/scripts/detect/lint.ts +98 -0
- package/dist/skills/frontend/scripts/detect/render/probe-placement.test.ts +19 -0
- package/dist/skills/frontend/scripts/detect/render/probe-placement.ts +50 -0
- package/dist/skills/frontend/scripts/detect/render/renderer.ts +37 -0
- package/dist/skills/frontend/scripts/detect/render/webview.ts +71 -0
- package/dist/skills/frontend/scripts/detect/report.ts +29 -0
- package/dist/skills/frontend/scripts/detect/rule.ts +42 -0
- package/dist/skills/frontend/scripts/detect/rules/color/ai-color-palette.test.ts +74 -0
- package/dist/skills/frontend/scripts/detect/rules/color/ai-color-palette.ts +83 -0
- package/dist/skills/frontend/scripts/detect/rules/color/cream-palette.test.ts +24 -0
- package/dist/skills/frontend/scripts/detect/rules/color/cream-palette.ts +35 -0
- package/dist/skills/frontend/scripts/detect/rules/color/dark-glow.test.ts +47 -0
- package/dist/skills/frontend/scripts/detect/rules/color/dark-glow.ts +44 -0
- package/dist/skills/frontend/scripts/detect/rules/color/design-system-color.test.ts +26 -0
- package/dist/skills/frontend/scripts/detect/rules/color/design-system-color.ts +35 -0
- package/dist/skills/frontend/scripts/detect/rules/color/gradient-text.test.ts +24 -0
- package/dist/skills/frontend/scripts/detect/rules/color/gradient-text.ts +59 -0
- package/dist/skills/frontend/scripts/detect/rules/color/gray-on-color.test.ts +39 -0
- package/dist/skills/frontend/scripts/detect/rules/color/gray-on-color.ts +38 -0
- package/dist/skills/frontend/scripts/detect/rules/color/index.ts +15 -0
- package/dist/skills/frontend/scripts/detect/rules/color/low-contrast.test.ts +209 -0
- package/dist/skills/frontend/scripts/detect/rules/color/low-contrast.ts +57 -0
- package/dist/skills/frontend/scripts/detect/rules/color/placeholder-contrast.test.ts +62 -0
- package/dist/skills/frontend/scripts/detect/rules/color/radial-halo.test.ts +40 -0
- package/dist/skills/frontend/scripts/detect/rules/color/radial-halo.ts +31 -0
- package/dist/skills/frontend/scripts/detect/rules/color/radial-spotlight-glow.test.ts +27 -0
- package/dist/skills/frontend/scripts/detect/rules/color/radial-spotlight-glow.ts +33 -0
- package/dist/skills/frontend/scripts/detect/rules/color/support/animation-opacity.ts +78 -0
- package/dist/skills/frontend/scripts/detect/rules/color/support/color-path.ts +15 -0
- package/dist/skills/frontend/scripts/detect/rules/color/support/contrast-pairs.ts +54 -0
- package/dist/skills/frontend/scripts/detect/rules/color/support/contrast-role.ts +76 -0
- package/dist/skills/frontend/scripts/detect/rules/color/support/glow-forms.ts +56 -0
- package/dist/skills/frontend/scripts/detect/rules/color/support/gradient-samples.ts +134 -0
- package/dist/skills/frontend/scripts/detect/rules/color/support/gradients.ts +91 -0
- package/dist/skills/frontend/scripts/detect/rules/color/support/mockup-roots.ts +63 -0
- package/dist/skills/frontend/scripts/detect/rules/color/support/page-ignore.ts +7 -0
- package/dist/skills/frontend/scripts/detect/rules/color/support/painted-text.ts +141 -0
- package/dist/skills/frontend/scripts/detect/rules/color/support/palette-roles.ts +58 -0
- package/dist/skills/frontend/scripts/detect/rules/color/support/placeholder-contrast.ts +25 -0
- package/dist/skills/frontend/scripts/detect/rules/color/support/stock-accent.ts +31 -0
- package/dist/skills/frontend/scripts/detect/rules/color/support/text-colors.ts +80 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/aphoristic-cadence.test.ts +18 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/aphoristic-cadence.ts +20 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/broken-image.test.ts +25 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/broken-image.ts +17 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/em-dash-overuse.test.ts +39 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/em-dash-overuse.ts +46 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/index.ts +15 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/marketing-buzzword.test.ts +18 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/marketing-buzzword.ts +33 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/numbered-section-labels.test.ts +58 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/numbered-section-labels.ts +34 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/repeated-container-text.test.ts +43 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/repeated-container-text.ts +56 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/script-error.test.ts +48 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/script-error.ts +38 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/skipped-heading.test.ts +49 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/skipped-heading.ts +81 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/support/numbered-label.ts +94 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/support/page-text.ts +37 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/theater-slop-phrase.test.ts +17 -0
- package/dist/skills/frontend/scripts/detect/rules/copy/theater-slop-phrase.ts +21 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/blinking-cursor.test.ts +43 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/blinking-cursor.ts +48 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/border-accent-on-rounded.test.ts +33 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/border-accent-on-rounded.ts +14 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/bounce-easing.test.ts +72 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/bounce-easing.ts +83 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/buried-raster.test.ts +95 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/buried-raster.ts +72 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/codex-grid-background.test.ts +28 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/codex-grid-background.ts +34 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/design-system-radius.test.ts +37 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/design-system-radius.ts +31 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/gpt-thin-border-wide-shadow.test.ts +59 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/gpt-thin-border-wide-shadow.ts +66 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/hard-offset-shadow.test.ts +45 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/hard-offset-shadow.ts +31 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/hero-eyebrow-chip.test.ts +76 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/hero-eyebrow-chip.ts +19 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/icon-tile-stack.test.ts +67 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/icon-tile-stack.ts +92 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/index.ts +38 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/kicker-above-heading.test.ts +126 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/kicker-above-heading.ts +69 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/marquee.test.ts +63 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/marquee.ts +51 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/organic-clip-path.test.ts +67 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/organic-clip-path.ts +41 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/pulsing-dot.test.ts +58 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/pulsing-dot.ts +72 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/repeating-stripes-gradient.test.ts +26 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/repeating-stripes-gradient.ts +25 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/shape-assembled-illustration.test.ts +59 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/shape-assembled-illustration.ts +58 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/side-tab.test.ts +91 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/side-tab.ts +17 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/support/appearance.ts +110 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/support/assert-cases.ts +25 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/support/borders.ts +150 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/support/clip-geometry.ts +151 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/support/css-candidates.ts +66 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/support/curve-samples.ts +55 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/support/gradient-pattern.ts +40 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/support/keyframes.ts +134 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/support/labels.ts +85 -0
- package/dist/skills/frontend/scripts/detect/rules/decoration/support/raster-state.ts +51 -0
- package/dist/skills/frontend/scripts/detect/rules/index.ts +16 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/body-text-viewport-edge.test.ts +64 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/body-text-viewport-edge.ts +62 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/clipped-overflow-container.test.ts +40 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/clipped-overflow-container.ts +15 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/content-hidden-at-rest.test.ts +62 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/content-hidden-at-rest.ts +63 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/cramped-padding.test.ts +61 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/cramped-padding.ts +97 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/edge-flush-cards.test.ts +43 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/edge-flush-cards.ts +47 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/first-viewport-column-overflow.test.ts +28 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/first-viewport-column-overflow.ts +43 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/heading-rhythm.test.ts +67 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/heading-rhythm.ts +30 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/index.ts +21 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/monotonous-spacing.test.ts +19 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/monotonous-spacing.ts +32 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/nested-cards.test.ts +60 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/nested-cards.ts +38 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/straggler.test.ts +33 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/straggler.ts +28 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/support/cards.ts +114 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/support/clipping.ts +71 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/support/declared-mockups.ts +46 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/support/geometry.ts +73 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/support/hidden-interface.ts +35 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/support/layout-cases.ts +23 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/support/line-breaks.ts +32 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/support/motion.ts +77 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/support/padding.ts +93 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/support/rhythm.ts +161 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/text-occlusion.test.ts +37 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/text-occlusion.ts +84 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/text-overflow.test.ts +83 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/text-overflow.ts +72 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/unbalanced-heading.test.ts +22 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/unbalanced-heading.ts +22 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/viewport-reflow.test.ts +34 -0
- package/dist/skills/frontend/scripts/detect/rules/layout/viewport-reflow.ts +33 -0
- package/dist/skills/frontend/scripts/detect/rules/source/ai-color-palette.test.ts +13 -0
- package/dist/skills/frontend/scripts/detect/rules/source/ai-color-palette.ts +11 -0
- package/dist/skills/frontend/scripts/detect/rules/source/aphoristic-cadence.test.ts +12 -0
- package/dist/skills/frontend/scripts/detect/rules/source/aphoristic-cadence.ts +14 -0
- package/dist/skills/frontend/scripts/detect/rules/source/border-accent-on-rounded.test.ts +14 -0
- package/dist/skills/frontend/scripts/detect/rules/source/border-accent-on-rounded.ts +20 -0
- package/dist/skills/frontend/scripts/detect/rules/source/bounce-easing.test.ts +19 -0
- package/dist/skills/frontend/scripts/detect/rules/source/bounce-easing.ts +21 -0
- package/dist/skills/frontend/scripts/detect/rules/source/broken-image.test.ts +27 -0
- package/dist/skills/frontend/scripts/detect/rules/source/broken-image.ts +16 -0
- package/dist/skills/frontend/scripts/detect/rules/source/codex-grid-background.test.ts +11 -0
- package/dist/skills/frontend/scripts/detect/rules/source/codex-grid-background.ts +18 -0
- package/dist/skills/frontend/scripts/detect/rules/source/dark-glow.test.ts +15 -0
- package/dist/skills/frontend/scripts/detect/rules/source/dark-glow.ts +21 -0
- package/dist/skills/frontend/scripts/detect/rules/source/em-dash-overuse.test.ts +13 -0
- package/dist/skills/frontend/scripts/detect/rules/source/em-dash-overuse.ts +15 -0
- package/dist/skills/frontend/scripts/detect/rules/source/gradient-text.test.ts +12 -0
- package/dist/skills/frontend/scripts/detect/rules/source/gradient-text.ts +11 -0
- package/dist/skills/frontend/scripts/detect/rules/source/gray-on-color.test.ts +20 -0
- package/dist/skills/frontend/scripts/detect/rules/source/gray-on-color.ts +13 -0
- package/dist/skills/frontend/scripts/detect/rules/source/index.ts +19 -0
- package/dist/skills/frontend/scripts/detect/rules/source/marketing-buzzword.test.ts +12 -0
- package/dist/skills/frontend/scripts/detect/rules/source/marketing-buzzword.ts +17 -0
- package/dist/skills/frontend/scripts/detect/rules/source/marquee.test.ts +12 -0
- package/dist/skills/frontend/scripts/detect/rules/source/marquee.ts +12 -0
- package/dist/skills/frontend/scripts/detect/rules/source/monotonous-spacing.test.ts +13 -0
- package/dist/skills/frontend/scripts/detect/rules/source/monotonous-spacing.ts +22 -0
- package/dist/skills/frontend/scripts/detect/rules/source/overused-font.test.ts +21 -0
- package/dist/skills/frontend/scripts/detect/rules/source/overused-font.ts +16 -0
- package/dist/skills/frontend/scripts/detect/rules/source/radial-halo.test.ts +16 -0
- package/dist/skills/frontend/scripts/detect/rules/source/radial-halo.ts +14 -0
- package/dist/skills/frontend/scripts/detect/rules/source/side-tab.test.ts +29 -0
- package/dist/skills/frontend/scripts/detect/rules/source/side-tab.ts +58 -0
- package/dist/skills/frontend/scripts/detect/rules/source/support/accent-scans.ts +78 -0
- package/dist/skills/frontend/scripts/detect/rules/source/support/check-source.ts +6 -0
- package/dist/skills/frontend/scripts/detect/rules/source/support/corners.ts +105 -0
- package/dist/skills/frontend/scripts/detect/rules/source/support/css-effects.ts +81 -0
- package/dist/skills/frontend/scripts/detect/rules/source/support/css-scopes.ts +131 -0
- package/dist/skills/frontend/scripts/detect/rules/source/support/image-tags.ts +113 -0
- package/dist/skills/frontend/scripts/detect/rules/source/support/js-punctuation.ts +34 -0
- package/dist/skills/frontend/scripts/detect/rules/source/support/markup-scope.ts +44 -0
- package/dist/skills/frontend/scripts/detect/rules/source/support/source-color.ts +42 -0
- package/dist/skills/frontend/scripts/detect/rules/source/support/source-shadow.ts +15 -0
- package/dist/skills/frontend/scripts/detect/rules/source/support/source-text.ts +110 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/all-caps-body.test.ts +24 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/all-caps-body.ts +15 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/design-system-font-size.test.ts +21 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/design-system-font-size.ts +23 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/design-system-font.test.ts +22 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/design-system-font.ts +24 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/extreme-negative-tracking.test.ts +23 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/extreme-negative-tracking.ts +18 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/flat-type-hierarchy.test.ts +33 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/flat-type-hierarchy.ts +26 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/index.ts +21 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/italic-serif-display.test.ts +24 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/italic-serif-display.ts +24 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/justified-text.test.ts +31 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/justified-text.ts +32 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/line-length.test.ts +43 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/line-length.ts +28 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/oversized-h1.test.ts +26 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/oversized-h1.ts +20 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/overused-font.test.ts +35 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/overused-font.ts +45 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/support/drawn-enlargement.ts +48 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/support/fading-text.ts +48 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/support/flex-runs.ts +16 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/support/font-family.ts +28 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/support/painted-text.test.ts +63 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/support/painted-text.ts +81 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/support/svg-size.ts +57 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/support/text-context.ts +112 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/support/text-lines.ts +43 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/support/type-hierarchy.ts +48 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/tight-leading.test.ts +54 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/tight-leading.ts +47 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/tiny-text.test.ts +60 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/tiny-text.ts +23 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/undersized-ui-text.test.ts +98 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/undersized-ui-text.ts +28 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/wide-tracking.test.ts +26 -0
- package/dist/skills/frontend/scripts/detect/rules/typography/wide-tracking.ts +26 -0
- package/dist/skills/frontend/scripts/detect/snapshot/collect.ts +158 -0
- package/dist/skills/frontend/scripts/detect/snapshot/style-props.ts +25 -0
- package/dist/skills/frontend/scripts/detect/testing/build-snapshot.ts +78 -0
- package/dist/skills/frontend/scripts/detect/tsconfig.json +19 -0
- package/dist/skills/frontend/scripts/detect/types.ts +124 -0
- package/dist/skills/programming/SKILL.md +17 -74
- package/dist/skills/programming/references/go/README.md +1 -1
- package/dist/skills/programming/references/go/bootstrap.md +2 -2
- package/dist/skills/programming/references/python/README.md +4 -4
- package/dist/skills/programming/references/python/one-liners.md +5 -5
- package/dist/skills/programming/references/testing/README.md +82 -0
- package/dist/skills/programming/references/testing/junk-classes.md +56 -0
- package/dist/skills/programming/references/typescript/README.md +1 -2
- package/dist/skills/programming/scripts/go/new-project.ts +197 -0
- package/dist/skills/programming/scripts/python/new-project.ts +231 -0
- package/dist/skills/programming/scripts/python/new-script.ts +134 -0
- package/dist/skills/programming/scripts/rust/new-project.ts +215 -0
- package/dist/skills/programming/scripts/scaffolders.test.ts +96 -0
- package/dist/skills/programming/scripts/shared/run-tool.ts +19 -0
- package/dist/skills/programming/scripts/typescript/check-test-junk-rules.ts +140 -0
- package/dist/skills/programming/scripts/typescript/check-test-junk.test.ts +125 -0
- package/dist/skills/programming/scripts/typescript/check-test-junk.ts +148 -0
- package/dist/skills/programming/scripts/typescript/mutation-proof.test.ts +43 -0
- package/dist/skills/programming/scripts/typescript/mutation-proof.ts +179 -0
- package/dist/skills/remove-ai-slops/SKILL.md +32 -20
- package/dist/skills/ulw-research/scripts/source-commands.mjs +3 -1
- package/dist/skills/ulw-research/scripts/source-integrity.test.ts +39 -2
- package/dist/skills/visual-qa/SKILL.md +12 -1
- package/dist/tools/delegate-task/models-distribution.d.ts +1 -0
- package/dist/tui.js +142 -42
- package/package.json +22 -19
- package/packages/lsp-core/src/lsp/config-loader.ts +18 -2
- package/packages/lsp-core/src/lsp/host-js-runtime.test.ts +150 -0
- package/packages/lsp-core/src/lsp/host-js-runtime.ts +57 -0
- package/packages/lsp-core/src/lsp/server-definitions.ts +10 -0
- package/packages/lsp-core/src/lsp/server-resolution.ts +9 -1
- package/packages/lsp-core/src/lsp/typescript-server-defaults.test.ts +84 -0
- package/packages/lsp-daemon/dist/cli.js +81 -15
- package/packages/lsp-daemon/dist/client.js +74 -8
- package/packages/lsp-daemon/dist/index.js +76 -10
- package/packages/lsp-tools-mcp/dist/cli.js +74 -8
- package/packages/lsp-tools-mcp/dist/mcp.js +74 -8
- package/packages/lsp-tools-mcp/dist/tools.js +74 -8
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +22 -4
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
- package/packages/omo-codex/plugin/components/lsp/dist/cli.js +77 -13
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +34 -2
- package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +34 -2
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/test/codex-hook.test.ts +14 -1
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +12 -12
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/auto-update-plan.mjs +16 -1
- package/packages/omo-codex/plugin/skills/browser/runtime/omowright/index.js +24 -33
- package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +3 -3
- package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +104 -1
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +7 -3
- package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +3 -3
- package/packages/omo-codex/plugin/skills/frontend/references/perfection/craft-floor.md +59 -0
- package/packages/omo-codex/plugin/skills/frontend/references/perfection/detect.md +52 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/cli.ts +70 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/config.ts +53 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/core/characters.ts +2 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/core/color.ts +150 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/core/page.ts +84 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/core/shadow.ts +40 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/core/source.ts +33 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/detect.ts +77 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/index.ts +23 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/lint.ts +98 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/render/probe-placement.ts +50 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/render/renderer.ts +37 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/render/webview.ts +71 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/report.ts +29 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rule.ts +42 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/ai-color-palette.ts +83 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/cream-palette.ts +35 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/dark-glow.ts +44 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/design-system-color.ts +35 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/gradient-text.ts +59 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/gray-on-color.ts +38 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/index.ts +15 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/low-contrast.ts +57 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/radial-halo.ts +31 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/radial-spotlight-glow.ts +33 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/animation-opacity.ts +78 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/color-path.ts +15 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/contrast-pairs.ts +54 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/contrast-role.ts +76 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/glow-forms.ts +56 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/gradient-samples.ts +134 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/gradients.ts +91 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/mockup-roots.ts +63 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/page-ignore.ts +7 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/painted-text.ts +141 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/palette-roles.ts +58 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/placeholder-contrast.ts +25 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/stock-accent.ts +31 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/color/support/text-colors.ts +80 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/aphoristic-cadence.ts +20 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/broken-image.ts +17 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/em-dash-overuse.ts +46 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/index.ts +15 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/marketing-buzzword.ts +33 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/numbered-section-labels.ts +34 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/repeated-container-text.ts +56 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/script-error.ts +38 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/skipped-heading.ts +81 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/support/numbered-label.ts +94 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/support/page-text.ts +37 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/copy/theater-slop-phrase.ts +21 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/blinking-cursor.ts +48 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/border-accent-on-rounded.ts +14 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/bounce-easing.ts +83 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/buried-raster.ts +72 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/codex-grid-background.ts +34 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/design-system-radius.ts +31 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/gpt-thin-border-wide-shadow.ts +66 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/hard-offset-shadow.ts +31 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/hero-eyebrow-chip.ts +19 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/icon-tile-stack.ts +92 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/index.ts +38 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/kicker-above-heading.ts +69 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/marquee.ts +51 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/organic-clip-path.ts +41 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/pulsing-dot.ts +72 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/repeating-stripes-gradient.ts +25 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/shape-assembled-illustration.ts +58 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/side-tab.ts +17 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/appearance.ts +110 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/assert-cases.ts +25 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/borders.ts +150 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/clip-geometry.ts +151 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/css-candidates.ts +66 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/curve-samples.ts +55 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/gradient-pattern.ts +40 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/keyframes.ts +134 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/labels.ts +85 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/decoration/support/raster-state.ts +51 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/index.ts +16 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/body-text-viewport-edge.ts +62 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/clipped-overflow-container.ts +15 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/content-hidden-at-rest.ts +63 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/cramped-padding.ts +97 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/edge-flush-cards.ts +47 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/first-viewport-column-overflow.ts +43 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/heading-rhythm.ts +30 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/index.ts +21 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/monotonous-spacing.ts +32 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/nested-cards.ts +38 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/straggler.ts +28 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/cards.ts +114 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/clipping.ts +71 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/declared-mockups.ts +46 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/geometry.ts +73 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/hidden-interface.ts +35 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/layout-cases.ts +23 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/line-breaks.ts +32 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/motion.ts +77 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/padding.ts +93 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/support/rhythm.ts +161 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/text-occlusion.ts +84 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/text-overflow.ts +72 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/unbalanced-heading.ts +22 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/layout/viewport-reflow.ts +33 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/ai-color-palette.ts +11 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/aphoristic-cadence.ts +14 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/border-accent-on-rounded.ts +20 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/bounce-easing.ts +21 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/broken-image.ts +16 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/codex-grid-background.ts +18 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/dark-glow.ts +21 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/em-dash-overuse.ts +15 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/gradient-text.ts +11 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/gray-on-color.ts +13 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/index.ts +19 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/marketing-buzzword.ts +17 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/marquee.ts +12 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/monotonous-spacing.ts +22 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/overused-font.ts +16 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/radial-halo.ts +14 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/side-tab.ts +58 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/accent-scans.ts +78 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/check-source.ts +6 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/corners.ts +105 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/css-effects.ts +81 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/css-scopes.ts +131 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/image-tags.ts +113 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/js-punctuation.ts +34 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/markup-scope.ts +44 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/source-color.ts +42 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/source-shadow.ts +15 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/source/support/source-text.ts +110 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/all-caps-body.ts +15 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/design-system-font-size.ts +23 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/design-system-font.ts +24 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/extreme-negative-tracking.ts +18 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/flat-type-hierarchy.ts +26 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/index.ts +21 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/italic-serif-display.ts +24 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/justified-text.ts +32 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/line-length.ts +28 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/oversized-h1.ts +20 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/overused-font.ts +45 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/drawn-enlargement.ts +48 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/fading-text.ts +48 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/flex-runs.ts +16 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/font-family.ts +28 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/painted-text.ts +81 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/svg-size.ts +57 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/text-context.ts +112 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/text-lines.ts +43 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/support/type-hierarchy.ts +48 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/tight-leading.ts +47 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/tiny-text.ts +23 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/undersized-ui-text.ts +28 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/rules/typography/wide-tracking.ts +26 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/snapshot/collect.ts +158 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/snapshot/style-props.ts +25 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/testing/build-snapshot.ts +78 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/tsconfig.json +19 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/detect/types.ts +124 -0
- package/packages/omo-codex/plugin/skills/programming/SKILL.md +17 -74
- package/packages/omo-codex/plugin/skills/programming/references/go/README.md +1 -1
- package/packages/omo-codex/plugin/skills/programming/references/go/bootstrap.md +2 -2
- package/packages/omo-codex/plugin/skills/programming/references/python/README.md +4 -4
- package/packages/omo-codex/plugin/skills/programming/references/python/one-liners.md +5 -5
- package/packages/omo-codex/plugin/skills/programming/references/testing/README.md +82 -0
- package/packages/omo-codex/plugin/skills/programming/references/testing/junk-classes.md +56 -0
- package/packages/omo-codex/plugin/skills/programming/references/typescript/README.md +1 -2
- package/packages/omo-codex/plugin/skills/programming/scripts/go/new-project.ts +197 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/python/new-project.ts +231 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/python/new-script.ts +134 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/rust/new-project.ts +215 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/shared/run-tool.ts +19 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/check-test-junk-rules.ts +140 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/check-test-junk.ts +148 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/mutation-proof.ts +179 -0
- package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +32 -20
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-commands.mjs +3 -1
- package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +12 -1
- package/packages/omo-codex/plugin/test/auto-update.test.mjs +62 -0
- package/packages/omo-codex/plugin/test/payload-equivalence.test.mjs +12 -2
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +79 -10
- package/packages/shared-skills/skills/browser/runtime/omowright/index.js +24 -33
- package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +3 -3
- package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +104 -1
- package/packages/shared-skills/skills/frontend/SKILL.md +7 -3
- package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +3 -3
- package/packages/shared-skills/skills/frontend/references/perfection/craft-floor.md +59 -0
- package/packages/shared-skills/skills/frontend/references/perfection/detect.md +52 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/cli.ts +70 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/config.test.ts +26 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/config.ts +53 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/core/characters.ts +2 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/core/color.test.ts +29 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/core/color.ts +150 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/core/page.ts +84 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/core/shadow.ts +40 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/core/source.ts +33 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/detect.ts +77 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/index.ts +23 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/lint.test.ts +27 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/lint.ts +98 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/render/probe-placement.test.ts +19 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/render/probe-placement.ts +50 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/render/renderer.ts +37 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/render/webview.ts +71 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/report.ts +29 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rule.ts +42 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/ai-color-palette.test.ts +74 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/ai-color-palette.ts +83 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/cream-palette.test.ts +24 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/cream-palette.ts +35 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/dark-glow.test.ts +47 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/dark-glow.ts +44 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/design-system-color.test.ts +26 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/design-system-color.ts +35 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/gradient-text.test.ts +24 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/gradient-text.ts +59 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/gray-on-color.test.ts +39 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/gray-on-color.ts +38 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/index.ts +15 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/low-contrast.test.ts +209 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/low-contrast.ts +57 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/placeholder-contrast.test.ts +62 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/radial-halo.test.ts +40 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/radial-halo.ts +31 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/radial-spotlight-glow.test.ts +27 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/radial-spotlight-glow.ts +33 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/animation-opacity.ts +78 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/color-path.ts +15 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/contrast-pairs.ts +54 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/contrast-role.ts +76 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/glow-forms.ts +56 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/gradient-samples.ts +134 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/gradients.ts +91 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/mockup-roots.ts +63 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/page-ignore.ts +7 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/painted-text.ts +141 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/palette-roles.ts +58 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/placeholder-contrast.ts +25 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/stock-accent.ts +31 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/color/support/text-colors.ts +80 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/aphoristic-cadence.test.ts +18 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/aphoristic-cadence.ts +20 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/broken-image.test.ts +25 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/broken-image.ts +17 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/em-dash-overuse.test.ts +39 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/em-dash-overuse.ts +46 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/index.ts +15 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/marketing-buzzword.test.ts +18 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/marketing-buzzword.ts +33 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/numbered-section-labels.test.ts +58 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/numbered-section-labels.ts +34 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/repeated-container-text.test.ts +43 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/repeated-container-text.ts +56 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/script-error.test.ts +48 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/script-error.ts +38 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/skipped-heading.test.ts +49 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/skipped-heading.ts +81 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/support/numbered-label.ts +94 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/support/page-text.ts +37 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/theater-slop-phrase.test.ts +17 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/copy/theater-slop-phrase.ts +21 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/blinking-cursor.test.ts +43 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/blinking-cursor.ts +48 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/border-accent-on-rounded.test.ts +33 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/border-accent-on-rounded.ts +14 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/bounce-easing.test.ts +72 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/bounce-easing.ts +83 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/buried-raster.test.ts +95 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/buried-raster.ts +72 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/codex-grid-background.test.ts +28 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/codex-grid-background.ts +34 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/design-system-radius.test.ts +37 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/design-system-radius.ts +31 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/gpt-thin-border-wide-shadow.test.ts +59 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/gpt-thin-border-wide-shadow.ts +66 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/hard-offset-shadow.test.ts +45 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/hard-offset-shadow.ts +31 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/hero-eyebrow-chip.test.ts +76 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/hero-eyebrow-chip.ts +19 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/icon-tile-stack.test.ts +67 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/icon-tile-stack.ts +92 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/index.ts +38 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/kicker-above-heading.test.ts +126 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/kicker-above-heading.ts +69 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/marquee.test.ts +63 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/marquee.ts +51 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/organic-clip-path.test.ts +67 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/organic-clip-path.ts +41 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/pulsing-dot.test.ts +58 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/pulsing-dot.ts +72 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/repeating-stripes-gradient.test.ts +26 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/repeating-stripes-gradient.ts +25 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/shape-assembled-illustration.test.ts +59 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/shape-assembled-illustration.ts +58 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/side-tab.test.ts +91 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/side-tab.ts +17 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/appearance.ts +110 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/assert-cases.ts +25 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/borders.ts +150 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/clip-geometry.ts +151 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/css-candidates.ts +66 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/curve-samples.ts +55 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/gradient-pattern.ts +40 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/keyframes.ts +134 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/labels.ts +85 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/decoration/support/raster-state.ts +51 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/index.ts +16 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/body-text-viewport-edge.test.ts +64 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/body-text-viewport-edge.ts +62 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/clipped-overflow-container.test.ts +40 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/clipped-overflow-container.ts +15 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/content-hidden-at-rest.test.ts +62 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/content-hidden-at-rest.ts +63 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/cramped-padding.test.ts +61 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/cramped-padding.ts +97 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/edge-flush-cards.test.ts +43 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/edge-flush-cards.ts +47 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/first-viewport-column-overflow.test.ts +28 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/first-viewport-column-overflow.ts +43 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/heading-rhythm.test.ts +67 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/heading-rhythm.ts +30 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/index.ts +21 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/monotonous-spacing.test.ts +19 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/monotonous-spacing.ts +32 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/nested-cards.test.ts +60 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/nested-cards.ts +38 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/straggler.test.ts +33 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/straggler.ts +28 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/cards.ts +114 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/clipping.ts +71 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/declared-mockups.ts +46 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/geometry.ts +73 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/hidden-interface.ts +35 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/layout-cases.ts +23 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/line-breaks.ts +32 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/motion.ts +77 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/padding.ts +93 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/support/rhythm.ts +161 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/text-occlusion.test.ts +37 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/text-occlusion.ts +84 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/text-overflow.test.ts +83 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/text-overflow.ts +72 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/unbalanced-heading.test.ts +22 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/unbalanced-heading.ts +22 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/viewport-reflow.test.ts +34 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/layout/viewport-reflow.ts +33 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/ai-color-palette.test.ts +13 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/ai-color-palette.ts +11 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/aphoristic-cadence.test.ts +12 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/aphoristic-cadence.ts +14 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/border-accent-on-rounded.test.ts +14 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/border-accent-on-rounded.ts +20 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/bounce-easing.test.ts +19 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/bounce-easing.ts +21 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/broken-image.test.ts +27 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/broken-image.ts +16 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/codex-grid-background.test.ts +11 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/codex-grid-background.ts +18 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/dark-glow.test.ts +15 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/dark-glow.ts +21 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/em-dash-overuse.test.ts +13 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/em-dash-overuse.ts +15 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/gradient-text.test.ts +12 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/gradient-text.ts +11 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/gray-on-color.test.ts +20 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/gray-on-color.ts +13 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/index.ts +19 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/marketing-buzzword.test.ts +12 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/marketing-buzzword.ts +17 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/marquee.test.ts +12 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/marquee.ts +12 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/monotonous-spacing.test.ts +13 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/monotonous-spacing.ts +22 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/overused-font.test.ts +21 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/overused-font.ts +16 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/radial-halo.test.ts +16 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/radial-halo.ts +14 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/side-tab.test.ts +29 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/side-tab.ts +58 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/accent-scans.ts +78 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/check-source.ts +6 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/corners.ts +105 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/css-effects.ts +81 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/css-scopes.ts +131 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/image-tags.ts +113 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/js-punctuation.ts +34 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/markup-scope.ts +44 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/source-color.ts +42 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/source-shadow.ts +15 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/source/support/source-text.ts +110 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/all-caps-body.test.ts +24 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/all-caps-body.ts +15 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/design-system-font-size.test.ts +21 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/design-system-font-size.ts +23 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/design-system-font.test.ts +22 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/design-system-font.ts +24 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/extreme-negative-tracking.test.ts +23 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/extreme-negative-tracking.ts +18 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/flat-type-hierarchy.test.ts +33 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/flat-type-hierarchy.ts +26 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/index.ts +21 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/italic-serif-display.test.ts +24 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/italic-serif-display.ts +24 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/justified-text.test.ts +31 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/justified-text.ts +32 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/line-length.test.ts +43 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/line-length.ts +28 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/oversized-h1.test.ts +26 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/oversized-h1.ts +20 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/overused-font.test.ts +35 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/overused-font.ts +45 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/drawn-enlargement.ts +48 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/fading-text.ts +48 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/flex-runs.ts +16 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/font-family.ts +28 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/painted-text.test.ts +63 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/painted-text.ts +81 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/svg-size.ts +57 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/text-context.ts +112 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/text-lines.ts +43 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/support/type-hierarchy.ts +48 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/tight-leading.test.ts +54 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/tight-leading.ts +47 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/tiny-text.test.ts +60 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/tiny-text.ts +23 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/undersized-ui-text.test.ts +98 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/undersized-ui-text.ts +28 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/wide-tracking.test.ts +26 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/rules/typography/wide-tracking.ts +26 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/snapshot/collect.ts +158 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/snapshot/style-props.ts +25 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/testing/build-snapshot.ts +78 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/tsconfig.json +19 -0
- package/packages/shared-skills/skills/frontend/scripts/detect/types.ts +124 -0
- package/packages/shared-skills/skills/programming/SKILL.md +17 -74
- package/packages/shared-skills/skills/programming/references/go/README.md +1 -1
- package/packages/shared-skills/skills/programming/references/go/bootstrap.md +2 -2
- package/packages/shared-skills/skills/programming/references/python/README.md +4 -4
- package/packages/shared-skills/skills/programming/references/python/one-liners.md +5 -5
- package/packages/shared-skills/skills/programming/references/testing/README.md +82 -0
- package/packages/shared-skills/skills/programming/references/testing/junk-classes.md +56 -0
- package/packages/shared-skills/skills/programming/references/typescript/README.md +1 -2
- package/packages/shared-skills/skills/programming/scripts/go/new-project.ts +197 -0
- package/packages/shared-skills/skills/programming/scripts/python/new-project.ts +231 -0
- package/packages/shared-skills/skills/programming/scripts/python/new-script.ts +134 -0
- package/packages/shared-skills/skills/programming/scripts/rust/new-project.ts +215 -0
- package/packages/shared-skills/skills/programming/scripts/scaffolders.test.ts +96 -0
- package/packages/shared-skills/skills/programming/scripts/shared/run-tool.ts +19 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/check-test-junk-rules.ts +140 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/check-test-junk.test.ts +125 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/check-test-junk.ts +148 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/mutation-proof.test.ts +43 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/mutation-proof.ts +179 -0
- package/packages/shared-skills/skills/remove-ai-slops/SKILL.md +32 -20
- package/packages/shared-skills/skills/ulw-research/scripts/source-commands.mjs +3 -1
- package/packages/shared-skills/skills/ulw-research/scripts/source-integrity.test.ts +39 -2
- package/packages/shared-skills/skills/visual-qa/SKILL.md +12 -1
- package/dist/agents/gpt-prompt-identity.d.ts +0 -3
- package/dist/agents/hephaestus/gpt-5-4.d.ts +0 -24
- package/dist/agents/hephaestus/gpt-5-5.d.ts +0 -2
- package/dist/agents/hephaestus/gpt-5-6.d.ts +0 -2
- package/dist/agents/kimi-tool-loop-guard.d.ts +0 -1
- package/dist/agents/sisyphus/claude-fable-5.d.ts +0 -19
- package/dist/agents/sisyphus/claude-opus-4-7.d.ts +0 -22
- package/dist/agents/sisyphus/claude-opus-4-8.d.ts +0 -19
- package/dist/agents/sisyphus/claude-opus-5.d.ts +0 -33
- package/dist/agents/sisyphus/gemini.d.ts +0 -20
- package/dist/agents/sisyphus/glm-5-2.d.ts +0 -4
- package/dist/agents/sisyphus/gpt-5-4.d.ts +0 -26
- package/dist/agents/sisyphus/gpt-5-5.d.ts +0 -6
- package/dist/agents/sisyphus/gpt-task-system-guide.d.ts +0 -1
- package/dist/agents/sisyphus/grok-4.d.ts +0 -21
- package/dist/agents/sisyphus/index.d.ts +0 -31
- package/dist/agents/sisyphus/kimi-k2-6.d.ts +0 -32
- package/dist/agents/sisyphus/kimi-k2-7.d.ts +0 -17
- package/dist/agents/sisyphus/kimi-k3-1.d.ts +0 -9
- package/dist/agents/sisyphus/kimi-k3.d.ts +0 -19
- package/dist/agents/sisyphus-dynamic-prompt-builder.d.ts +0 -2
- package/dist/agents/sisyphus-dynamic-prompt-execution.d.ts +0 -2
- package/dist/agents/sisyphus-dynamic-prompt-exploration.d.ts +0 -2
- package/dist/agents/sisyphus-dynamic-prompt-role.d.ts +0 -2
- package/dist/agents/sisyphus-dynamic-prompt-sections.d.ts +0 -18
- package/dist/agents/sisyphus-dynamic-prompt-style.d.ts +0 -2
- package/dist/agents/sisyphus-dynamic-prompt.d.ts +0 -3
- package/dist/agents/sisyphus-gemini-fallback-overrides.d.ts +0 -1
- package/dist/agents/sisyphus-junior/gemini.d.ts +0 -10
- package/dist/agents/sisyphus-junior/glm-5-2.d.ts +0 -1
- package/dist/agents/sisyphus-junior/gpt-5-4.d.ts +0 -11
- package/dist/agents/sisyphus-junior/gpt-5-5.d.ts +0 -5
- package/dist/agents/sisyphus-junior/gpt.d.ts +0 -9
- package/dist/agents/sisyphus-junior/kimi-k2-6.d.ts +0 -13
- package/dist/agents/sisyphus-junior/kimi-k2-7.d.ts +0 -11
- package/dist/agents/sisyphus-junior/kimi-k3-1.d.ts +0 -6
- package/dist/agents/sisyphus-junior/kimi-k3.d.ts +0 -12
- package/dist/features/claude-code-agent-loader/opencode-config-agents-reader.d.ts +0 -1
- package/dist/features/claude-code-command-loader/loader-cache.d.ts +0 -1
- package/dist/features/claude-code-command-loader/loader.d.ts +0 -1
- package/dist/features/opencode-skill-loader/config-source-discovery.d.ts +0 -1
- package/dist/features/opencode-skill-loader/merger/config-skill-entry-loader.d.ts +0 -1
- package/dist/features/opencode-skill-loader/opencode-config-skills-reader.d.ts +0 -1
- package/dist/features/team-mode/team-layout-tmux/resolve-caller-tmux-session.d.ts +0 -1
- package/dist/features/team-mode/team-registry/team-spec-input-normalizer.d.ts +0 -1
- package/dist/shared/git-worktree/collect-git-diff-stats.d.ts +0 -1
- package/dist/shared/git-worktree/parse-status-porcelain-line.d.ts +0 -1
- package/dist/shared/migration/agent-names.d.ts +0 -1
- package/dist/shared/migration/migrations-sidecar.d.ts +0 -1
- package/dist/shared/skill-path-resolver.d.ts +0 -1
- package/dist/shared/zip-entry-listing/powershell-zip-entry-listing.d.ts +0 -1
- package/dist/shared/zip-entry-listing/zipinfo-zip-entry-listing.d.ts +0 -1
- package/dist/skills/programming/scripts/go/new-project.py +0 -138
- package/dist/skills/programming/scripts/python/new-project.py +0 -172
- package/dist/skills/programming/scripts/python/new-script.py +0 -116
- package/dist/skills/programming/scripts/rust/new-project.py +0 -178
- package/packages/omo-codex/plugin/skills/programming/scripts/go/new-project.py +0 -138
- package/packages/omo-codex/plugin/skills/programming/scripts/python/new-project.py +0 -172
- package/packages/omo-codex/plugin/skills/programming/scripts/python/new-script.py +0 -116
- package/packages/omo-codex/plugin/skills/programming/scripts/rust/new-project.py +0 -178
- package/packages/shared-skills/skills/programming/scripts/go/new-project.py +0 -138
- package/packages/shared-skills/skills/programming/scripts/python/new-project.py +0 -172
- package/packages/shared-skills/skills/programming/scripts/python/new-script.py +0 -116
- 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
|
+
}
|