quiver-cli 0.1.0
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/README.md +188 -0
- package/bin/quiver-cli.mjs +2 -0
- package/dist/cli.js +3074 -0
- package/package.json +55 -0
- package/template/.agents/AGENTS.md +25 -0
- package/template/.agents/commands/cp.md +116 -0
- package/template/.agents/commands/next-setup.md +1064 -0
- package/template/.agents/commands/tf-readme.md +38 -0
- package/template/.agents/config.json +60 -0
- package/template/.agents/skills/agent-browser/SKILL.md +55 -0
- package/template/.agents/skills/apps/skybridge/SKILL.md +46 -0
- package/template/.agents/skills/apps/skybridge/references/architecture.md +175 -0
- package/template/.agents/skills/apps/skybridge/references/copy-template.md +24 -0
- package/template/.agents/skills/apps/skybridge/references/csp.md +33 -0
- package/template/.agents/skills/apps/skybridge/references/deploy.md +33 -0
- package/template/.agents/skills/apps/skybridge/references/discover.md +84 -0
- package/template/.agents/skills/apps/skybridge/references/download-file.md +77 -0
- package/template/.agents/skills/apps/skybridge/references/fetch-and-render-data.md +151 -0
- package/template/.agents/skills/apps/skybridge/references/oauth.md +115 -0
- package/template/.agents/skills/apps/skybridge/references/open-external-links.md +71 -0
- package/template/.agents/skills/apps/skybridge/references/prompt-llm.md +20 -0
- package/template/.agents/skills/apps/skybridge/references/publish.md +19 -0
- package/template/.agents/skills/apps/skybridge/references/run-locally.md +51 -0
- package/template/.agents/skills/apps/skybridge/references/state-and-context.md +151 -0
- package/template/.agents/skills/apps/skybridge/references/ui-guidelines.md +205 -0
- package/template/.agents/skills/code/cleanup/SKILL.md +26 -0
- package/template/.agents/skills/code/vercel-react-best-practices/AGENTS.md +3810 -0
- package/template/.agents/skills/code/vercel-react-best-practices/README.md +123 -0
- package/template/.agents/skills/code/vercel-react-best-practices/SKILL.md +149 -0
- package/template/.agents/skills/code/vercel-react-best-practices/metadata.json +15 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/_sections.md +46 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/_template.md +28 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/advanced-effect-event-deps.md +56 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-api-routes.md +38 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-cheap-condition-before-await.md +37 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-defer-await.md +82 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-dependencies.md +51 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-parallel.md +28 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-analyzable-paths.md +63 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-barrel-imports.md +60 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-preload.md +50 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-early-exit.md +50 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-flatmap-filter.md +60 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-index-maps.md +37 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-request-idle-callback.md +105 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-activity.md +26 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-resource-hints.md +85 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-script-defer-async.md +68 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-memo.md +44 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-no-inline-components.md +82 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-use-deferred-value.md +59 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-cache-react.md +76 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-hoist-static-io.md +149 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-no-shared-module-state.md +50 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-parallel-nested-fetching.md +34 -0
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-serialization.md +38 -0
- package/template/.agents/skills/data/prisma-cli/SKILL.md +247 -0
- package/template/.agents/skills/data/prisma-cli/references/db-execute.md +78 -0
- package/template/.agents/skills/data/prisma-cli/references/db-pull.md +185 -0
- package/template/.agents/skills/data/prisma-cli/references/db-push.md +148 -0
- package/template/.agents/skills/data/prisma-cli/references/db-seed.md +188 -0
- package/template/.agents/skills/data/prisma-cli/references/debug.md +46 -0
- package/template/.agents/skills/data/prisma-cli/references/dev.md +157 -0
- package/template/.agents/skills/data/prisma-cli/references/format.md +48 -0
- package/template/.agents/skills/data/prisma-cli/references/generate.md +173 -0
- package/template/.agents/skills/data/prisma-cli/references/init.md +136 -0
- package/template/.agents/skills/data/prisma-cli/references/mcp.md +38 -0
- package/template/.agents/skills/data/prisma-cli/references/migrate-deploy.md +127 -0
- package/template/.agents/skills/data/prisma-cli/references/migrate-dev.md +145 -0
- package/template/.agents/skills/data/prisma-cli/references/migrate-diff.md +89 -0
- package/template/.agents/skills/data/prisma-cli/references/migrate-reset.md +78 -0
- package/template/.agents/skills/data/prisma-cli/references/migrate-resolve.md +57 -0
- package/template/.agents/skills/data/prisma-cli/references/migrate-status.md +65 -0
- package/template/.agents/skills/data/prisma-cli/references/studio.md +137 -0
- package/template/.agents/skills/data/prisma-cli/references/validate.md +53 -0
- package/template/.agents/skills/data/prisma-client-api/SKILL.md +216 -0
- package/template/.agents/skills/data/prisma-client-api/references/client-methods.md +223 -0
- package/template/.agents/skills/data/prisma-client-api/references/constructor.md +208 -0
- package/template/.agents/skills/data/prisma-client-api/references/filters.md +256 -0
- package/template/.agents/skills/data/prisma-client-api/references/model-queries.md +281 -0
- package/template/.agents/skills/data/prisma-client-api/references/query-options.md +276 -0
- package/template/.agents/skills/data/prisma-client-api/references/raw-queries.md +194 -0
- package/template/.agents/skills/data/prisma-client-api/references/relations.md +308 -0
- package/template/.agents/skills/data/prisma-client-api/references/transactions.md +184 -0
- package/template/.agents/skills/design/impeccable/SKILL.md +176 -0
- package/template/.agents/skills/design/impeccable/reference/adapt.md +311 -0
- package/template/.agents/skills/design/impeccable/reference/animate.md +201 -0
- package/template/.agents/skills/design/impeccable/reference/audit.md +133 -0
- package/template/.agents/skills/design/impeccable/reference/bolder.md +113 -0
- package/template/.agents/skills/design/impeccable/reference/brand.md +108 -0
- package/template/.agents/skills/design/impeccable/reference/clarify.md +288 -0
- package/template/.agents/skills/design/impeccable/reference/codex.md +105 -0
- package/template/.agents/skills/design/impeccable/reference/colorize.md +257 -0
- package/template/.agents/skills/design/impeccable/reference/craft.md +123 -0
- package/template/.agents/skills/design/impeccable/reference/critique.md +767 -0
- package/template/.agents/skills/design/impeccable/reference/delight.md +302 -0
- package/template/.agents/skills/design/impeccable/reference/distill.md +111 -0
- package/template/.agents/skills/design/impeccable/reference/document.md +429 -0
- package/template/.agents/skills/design/impeccable/reference/extract.md +69 -0
- package/template/.agents/skills/design/impeccable/reference/harden.md +347 -0
- package/template/.agents/skills/design/impeccable/reference/init.md +172 -0
- package/template/.agents/skills/design/impeccable/reference/interaction-design.md +189 -0
- package/template/.agents/skills/design/impeccable/reference/layout.md +161 -0
- package/template/.agents/skills/design/impeccable/reference/live.md +718 -0
- package/template/.agents/skills/design/impeccable/reference/onboard.md +234 -0
- package/template/.agents/skills/design/impeccable/reference/optimize.md +258 -0
- package/template/.agents/skills/design/impeccable/reference/overdrive.md +130 -0
- package/template/.agents/skills/design/impeccable/reference/polish.md +241 -0
- package/template/.agents/skills/design/impeccable/reference/product.md +60 -0
- package/template/.agents/skills/design/impeccable/reference/quieter.md +99 -0
- package/template/.agents/skills/design/impeccable/reference/shape.md +165 -0
- package/template/.agents/skills/design/impeccable/reference/typeset.md +279 -0
- package/template/.agents/skills/design/impeccable/scripts/cleanup-deprecated.mjs +284 -0
- package/template/.agents/skills/design/impeccable/scripts/command-metadata.json +94 -0
- package/template/.agents/skills/design/impeccable/scripts/context-signals.mjs +225 -0
- package/template/.agents/skills/design/impeccable/scripts/context.mjs +270 -0
- package/template/.agents/skills/design/impeccable/scripts/critique-storage.mjs +242 -0
- package/template/.agents/skills/design/impeccable/scripts/design-parser.mjs +835 -0
- package/template/.agents/skills/design/impeccable/scripts/detect-csp.mjs +198 -0
- package/template/.agents/skills/design/impeccable/scripts/detect.mjs +21 -0
- package/template/.agents/skills/design/impeccable/scripts/detector/browser/injected/index.mjs +1733 -0
- package/template/.agents/skills/design/impeccable/scripts/detector/cli/main.mjs +244 -0
- package/template/.agents/skills/design/impeccable/scripts/detector/detect-antipatterns-browser.js +4551 -0
- package/template/.agents/skills/design/impeccable/scripts/detector/detect-antipatterns.mjs +43 -0
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/browser/detect-url.mjs +252 -0
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/regex/detect-text.mjs +535 -0
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +986 -0
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/static-html/detect-html.mjs +208 -0
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/visual/screenshot-contrast.mjs +189 -0
- package/template/.agents/skills/design/impeccable/scripts/detector/findings.mjs +12 -0
- package/template/.agents/skills/design/impeccable/scripts/detector/node/file-system.mjs +198 -0
- package/template/.agents/skills/design/impeccable/scripts/detector/profile/profiler.mjs +166 -0
- package/template/.agents/skills/design/impeccable/scripts/detector/registry/antipatterns.mjs +419 -0
- package/template/.agents/skills/design/impeccable/scripts/detector/rules/checks.mjs +2316 -0
- package/template/.agents/skills/design/impeccable/scripts/detector/shared/color.mjs +124 -0
- package/template/.agents/skills/design/impeccable/scripts/detector/shared/constants.mjs +101 -0
- package/template/.agents/skills/design/impeccable/scripts/detector/shared/page.mjs +7 -0
- package/template/.agents/skills/design/impeccable/scripts/impeccable-paths.mjs +126 -0
- package/template/.agents/skills/design/impeccable/scripts/is-generated.mjs +69 -0
- package/template/.agents/skills/design/impeccable/scripts/live-accept.mjs +812 -0
- package/template/.agents/skills/design/impeccable/scripts/live-browser-session.js +123 -0
- package/template/.agents/skills/design/impeccable/scripts/live-browser.js +10316 -0
- package/template/.agents/skills/design/impeccable/scripts/live-commit-manual-edits.mjs +1241 -0
- package/template/.agents/skills/design/impeccable/scripts/live-complete.mjs +75 -0
- package/template/.agents/skills/design/impeccable/scripts/live-completion.mjs +19 -0
- package/template/.agents/skills/design/impeccable/scripts/live-copy-edit-agent.mjs +683 -0
- package/template/.agents/skills/design/impeccable/scripts/live-discard-manual-edits.mjs +51 -0
- package/template/.agents/skills/design/impeccable/scripts/live-event-validation.mjs +136 -0
- package/template/.agents/skills/design/impeccable/scripts/live-inject.mjs +557 -0
- package/template/.agents/skills/design/impeccable/scripts/live-insert-ui.mjs +458 -0
- package/template/.agents/skills/design/impeccable/scripts/live-insert.mjs +272 -0
- package/template/.agents/skills/design/impeccable/scripts/live-manual-edit-evidence.mjs +363 -0
- package/template/.agents/skills/design/impeccable/scripts/live-manual-edits-buffer.mjs +152 -0
- package/template/.agents/skills/design/impeccable/scripts/live-poll.mjs +379 -0
- package/template/.agents/skills/design/impeccable/scripts/live-resume.mjs +94 -0
- package/template/.agents/skills/design/impeccable/scripts/live-server.mjs +2322 -0
- package/template/.agents/skills/design/impeccable/scripts/live-session-store.mjs +289 -0
- package/template/.agents/skills/design/impeccable/scripts/live-status.mjs +61 -0
- package/template/.agents/skills/design/impeccable/scripts/live-svelte-component.mjs +826 -0
- package/template/.agents/skills/design/impeccable/scripts/live-sveltekit-adapter.mjs +274 -0
- package/template/.agents/skills/design/impeccable/scripts/live-ui-core.mjs +179 -0
- package/template/.agents/skills/design/impeccable/scripts/live-wrap.mjs +894 -0
- package/template/.agents/skills/design/impeccable/scripts/live.mjs +246 -0
- package/template/.agents/skills/design/impeccable/scripts/modern-screenshot.umd.js +14 -0
- package/template/.agents/skills/design/impeccable/scripts/palette.mjs +633 -0
- package/template/.agents/skills/design/impeccable/scripts/pin.mjs +214 -0
- package/template/.agents/skills/design/shadcn/SKILL.md +242 -0
- package/template/.agents/skills/design/shadcn/agents/openai.yml +5 -0
- package/template/.agents/skills/design/shadcn/assets/shadcn-small.png +0 -0
- package/template/.agents/skills/design/shadcn/assets/shadcn.png +0 -0
- package/template/.agents/skills/design/shadcn/cli.md +257 -0
- package/template/.agents/skills/design/shadcn/customization.md +202 -0
- package/template/.agents/skills/design/shadcn/evals/evals.json +47 -0
- package/template/.agents/skills/design/shadcn/mcp.md +94 -0
- package/template/.agents/skills/design/shadcn/rules/base-vs-radix.md +306 -0
- package/template/.agents/skills/design/shadcn/rules/composition.md +195 -0
- package/template/.agents/skills/design/shadcn/rules/forms.md +192 -0
- package/template/.agents/skills/design/shadcn/rules/icons.md +101 -0
- package/template/.agents/skills/design/shadcn/rules/styling.md +162 -0
- package/template/.agents/skills/find-skills/SKILL.md +142 -0
- package/template/.agents/skills/integrations/langfuse/SKILL.md +142 -0
- package/template/.agents/skills/integrations/langfuse/references/cli.md +52 -0
- package/template/.agents/skills/integrations/langfuse/references/error-analysis.md +100 -0
- package/template/.agents/skills/integrations/langfuse/references/instrumentation.md +134 -0
- package/template/.agents/skills/integrations/langfuse/references/judge-calibration.md +288 -0
- package/template/.agents/skills/integrations/langfuse/references/prompt-migration.md +234 -0
- package/template/.agents/skills/integrations/langfuse/references/sdk-upgrade.md +175 -0
- package/template/.agents/skills/integrations/langfuse/references/skill-feedback.md +52 -0
- package/template/.agents/skills/integrations/langfuse/references/user-feedback.md +88 -0
- package/template/.agents/skills/integrations/posthog/SKILL.md +102 -0
- package/template/.agents/skills/integrations/posthog/references/error-tracking-alerts.md +63 -0
- package/template/.agents/skills/integrations/posthog/references/error-tracking-assigning-issues.md +77 -0
- package/template/.agents/skills/integrations/posthog/references/error-tracking-fingerprints.md +57 -0
- package/template/.agents/skills/integrations/posthog/references/error-tracking-monitoring.md +140 -0
- package/template/.agents/skills/integrations/posthog/references/error-tracking-nextjs.md +490 -0
- package/template/.agents/skills/integrations/posthog/references/error-tracking-source-maps.md +45 -0
- package/template/.agents/skills/integrations/posthog/references/feature-flags-best-practices.md +139 -0
- package/template/.agents/skills/integrations/posthog/references/feature-flags-react.md +302 -0
- package/template/.agents/skills/integrations/posthog/references/identify-users.md +202 -0
- package/template/.agents/skills/integrations/posthog/references/integration-example.md +706 -0
- package/template/.agents/skills/integrations/posthog/references/integration-nextjs.md +385 -0
- package/template/.agents/skills/integrations/posthog/references/integration-step-1-begin.md +43 -0
- package/template/.agents/skills/integrations/posthog/references/integration-step-2-edit.md +37 -0
- package/template/.agents/skills/integrations/posthog/references/integration-step-3-revise.md +22 -0
- package/template/.agents/skills/integrations/posthog/references/integration-step-4-conclude.md +38 -0
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-anthropic.md +200 -0
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-basics.md +62 -0
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-costs.md +197 -0
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-manual-capture.md +397 -0
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-traces.md +98 -0
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-vercel-ai.md +120 -0
- package/template/.agents/skills/repo/repo-ci/SKILL.md +265 -0
- package/template/.agents/skills/repo/repo-init-next-js/SKILL.md +129 -0
- package/template/.agents/skills/repo/repo-init-next-js/references/file-contents.md +800 -0
- package/template/.agents/skills/repo/repo-init-next-js/scripts/setup.sh +47 -0
- package/template/.agents/skills/repo/repo-init-node/SKILL.md +196 -0
- package/template/.agents/skills/skill-creator/LICENSE.txt +202 -0
- package/template/.agents/skills/skill-creator/SKILL.md +485 -0
- package/template/.agents/skills/skill-creator/agents/analyzer.md +274 -0
- package/template/.agents/skills/skill-creator/agents/comparator.md +202 -0
- package/template/.agents/skills/skill-creator/agents/grader.md +223 -0
- package/template/.agents/skills/skill-creator/assets/eval_review.html +146 -0
- package/template/.agents/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/template/.agents/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/template/.agents/skills/skill-creator/references/schemas.md +430 -0
- package/template/.agents/skills/skill-creator/scripts/__init__.py +0 -0
- package/template/.agents/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/template/.agents/skills/skill-creator/scripts/generate_report.py +326 -0
- package/template/.agents/skills/skill-creator/scripts/improve_description.py +247 -0
- package/template/.agents/skills/skill-creator/scripts/package_skill.py +136 -0
- package/template/.agents/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/template/.agents/skills/skill-creator/scripts/run_eval.py +310 -0
- package/template/.agents/skills/skill-creator/scripts/run_loop.py +328 -0
- package/template/.agents/skills/skill-creator/scripts/utils.py +47 -0
- package/template/.agents/upstreams.json +80 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
function profileNow() {
|
|
2
|
+
return typeof performance !== 'undefined' && performance.now
|
|
3
|
+
? performance.now()
|
|
4
|
+
: Date.now();
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function createDetectorProfile() {
|
|
8
|
+
return { events: [] };
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function recordProfileEvent(profile, event) {
|
|
12
|
+
if (!profile) return;
|
|
13
|
+
const normalized = {
|
|
14
|
+
engine: event.engine || 'unknown',
|
|
15
|
+
phase: event.phase || 'unknown',
|
|
16
|
+
ruleId: event.ruleId || 'unknown',
|
|
17
|
+
target: event.target || '',
|
|
18
|
+
ms: Number.isFinite(event.ms) ? event.ms : 0,
|
|
19
|
+
findings: Number.isFinite(event.findings) ? event.findings : 0,
|
|
20
|
+
};
|
|
21
|
+
if (event.detail) normalized.detail = event.detail;
|
|
22
|
+
if (Array.isArray(event.findingIds) && event.findingIds.length) {
|
|
23
|
+
normalized.findingIds = event.findingIds;
|
|
24
|
+
}
|
|
25
|
+
if (typeof profile === 'function') {
|
|
26
|
+
profile(normalized);
|
|
27
|
+
} else if (typeof profile.record === 'function') {
|
|
28
|
+
profile.record(normalized);
|
|
29
|
+
} else if (Array.isArray(profile.events)) {
|
|
30
|
+
profile.events.push(normalized);
|
|
31
|
+
} else if (Array.isArray(profile)) {
|
|
32
|
+
profile.push(normalized);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function extractFindingIds(findings) {
|
|
37
|
+
if (!Array.isArray(findings) || findings.length === 0) return [];
|
|
38
|
+
return [...new Set(findings.map(f => f?.id || f?.type || f?.antipattern).filter(Boolean))];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function profileFindings(profile, meta, callback) {
|
|
42
|
+
if (!profile) return callback();
|
|
43
|
+
const started = profileNow();
|
|
44
|
+
const findings = callback();
|
|
45
|
+
recordProfileEvent(profile, {
|
|
46
|
+
...meta,
|
|
47
|
+
ms: profileNow() - started,
|
|
48
|
+
findings: Array.isArray(findings) ? findings.length : 0,
|
|
49
|
+
findingIds: extractFindingIds(findings),
|
|
50
|
+
});
|
|
51
|
+
return findings;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function profileStep(profile, meta, callback) {
|
|
55
|
+
if (!profile) return callback();
|
|
56
|
+
const started = profileNow();
|
|
57
|
+
try {
|
|
58
|
+
return callback();
|
|
59
|
+
} finally {
|
|
60
|
+
recordProfileEvent(profile, {
|
|
61
|
+
...meta,
|
|
62
|
+
ms: profileNow() - started,
|
|
63
|
+
findings: 0,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function profileFindingsAsync(profile, meta, callback) {
|
|
69
|
+
if (!profile) return callback();
|
|
70
|
+
const started = profileNow();
|
|
71
|
+
const findings = await callback();
|
|
72
|
+
recordProfileEvent(profile, {
|
|
73
|
+
...meta,
|
|
74
|
+
ms: profileNow() - started,
|
|
75
|
+
findings: Array.isArray(findings) ? findings.length : 0,
|
|
76
|
+
findingIds: extractFindingIds(findings),
|
|
77
|
+
});
|
|
78
|
+
return findings;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function profileStepAsync(profile, meta, callback) {
|
|
82
|
+
if (!profile) return callback();
|
|
83
|
+
const started = profileNow();
|
|
84
|
+
try {
|
|
85
|
+
return await callback();
|
|
86
|
+
} finally {
|
|
87
|
+
recordProfileEvent(profile, {
|
|
88
|
+
...meta,
|
|
89
|
+
ms: profileNow() - started,
|
|
90
|
+
findings: 0,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function percentile(sortedValues, pct) {
|
|
96
|
+
if (!sortedValues.length) return 0;
|
|
97
|
+
const idx = Math.min(
|
|
98
|
+
sortedValues.length - 1,
|
|
99
|
+
Math.max(0, Math.ceil((pct / 100) * sortedValues.length) - 1),
|
|
100
|
+
);
|
|
101
|
+
return sortedValues[idx];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function summarizeDetectorProfile(profile) {
|
|
105
|
+
const events = Array.isArray(profile)
|
|
106
|
+
? profile
|
|
107
|
+
: (Array.isArray(profile?.events) ? profile.events : []);
|
|
108
|
+
const groups = new Map();
|
|
109
|
+
for (const event of events) {
|
|
110
|
+
const key = [
|
|
111
|
+
event.engine || 'unknown',
|
|
112
|
+
event.phase || 'unknown',
|
|
113
|
+
event.ruleId || 'unknown',
|
|
114
|
+
event.target || '',
|
|
115
|
+
].join('\u0000');
|
|
116
|
+
let group = groups.get(key);
|
|
117
|
+
if (!group) {
|
|
118
|
+
group = {
|
|
119
|
+
engine: event.engine || 'unknown',
|
|
120
|
+
phase: event.phase || 'unknown',
|
|
121
|
+
ruleId: event.ruleId || 'unknown',
|
|
122
|
+
target: event.target || '',
|
|
123
|
+
calls: 0,
|
|
124
|
+
totalMs: 0,
|
|
125
|
+
findings: 0,
|
|
126
|
+
samples: [],
|
|
127
|
+
};
|
|
128
|
+
groups.set(key, group);
|
|
129
|
+
}
|
|
130
|
+
const ms = Number.isFinite(event.ms) ? event.ms : 0;
|
|
131
|
+
group.calls += 1;
|
|
132
|
+
group.totalMs += ms;
|
|
133
|
+
group.findings += Number.isFinite(event.findings) ? event.findings : 0;
|
|
134
|
+
group.samples.push(ms);
|
|
135
|
+
}
|
|
136
|
+
return [...groups.values()]
|
|
137
|
+
.map(group => {
|
|
138
|
+
const samples = group.samples.sort((a, b) => a - b);
|
|
139
|
+
return {
|
|
140
|
+
engine: group.engine,
|
|
141
|
+
phase: group.phase,
|
|
142
|
+
ruleId: group.ruleId,
|
|
143
|
+
target: group.target,
|
|
144
|
+
calls: group.calls,
|
|
145
|
+
totalMs: Number(group.totalMs.toFixed(3)),
|
|
146
|
+
avgMs: Number((group.totalMs / group.calls).toFixed(3)),
|
|
147
|
+
p50: Number(percentile(samples, 50).toFixed(3)),
|
|
148
|
+
p95: Number(percentile(samples, 95).toFixed(3)),
|
|
149
|
+
findings: group.findings,
|
|
150
|
+
};
|
|
151
|
+
})
|
|
152
|
+
.sort((a, b) => b.totalMs - a.totalMs);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export {
|
|
156
|
+
profileNow,
|
|
157
|
+
createDetectorProfile,
|
|
158
|
+
recordProfileEvent,
|
|
159
|
+
extractFindingIds,
|
|
160
|
+
profileFindings,
|
|
161
|
+
profileStep,
|
|
162
|
+
profileFindingsAsync,
|
|
163
|
+
profileStepAsync,
|
|
164
|
+
percentile,
|
|
165
|
+
summarizeDetectorProfile,
|
|
166
|
+
};
|
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
const ANTIPATTERNS = [
|
|
2
|
+
// ── AI slop: tells that something was AI-generated ──
|
|
3
|
+
{
|
|
4
|
+
id: 'side-tab',
|
|
5
|
+
category: 'slop',
|
|
6
|
+
name: 'Side-tab accent border',
|
|
7
|
+
description:
|
|
8
|
+
'Thick colored border on one side of a card — the most recognizable tell of AI-generated UIs. Use a subtler accent or remove it entirely.',
|
|
9
|
+
skillSection: 'Visual Details',
|
|
10
|
+
skillGuideline: 'colored accent stripe',
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
id: 'border-accent-on-rounded',
|
|
14
|
+
category: 'slop',
|
|
15
|
+
name: 'Border accent on rounded element',
|
|
16
|
+
description:
|
|
17
|
+
'Thick accent border on a rounded card — the border clashes with the rounded corners. Remove the border or the border-radius.',
|
|
18
|
+
skillSection: 'Visual Details',
|
|
19
|
+
skillGuideline: 'colored accent stripe',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: 'overused-font',
|
|
23
|
+
category: 'slop',
|
|
24
|
+
name: 'Overused font',
|
|
25
|
+
description:
|
|
26
|
+
'Inter, Roboto, Fraunces, Geist, Plus Jakarta Sans, and Space Grotesk are used on so many sites they no longer feel distinctive. Each new wave of AI-generated UIs converges on the same handful of faces. Choose a face that gives your interface personality.',
|
|
27
|
+
skillSection: 'Typography',
|
|
28
|
+
skillGuideline: 'overused fonts like Inter',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: 'single-font',
|
|
32
|
+
category: 'slop',
|
|
33
|
+
name: 'Single font for everything',
|
|
34
|
+
description:
|
|
35
|
+
'Only one font family is used for the entire page. Pair a distinctive display font with a refined body font to create typographic hierarchy.',
|
|
36
|
+
skillSection: 'Typography',
|
|
37
|
+
skillGuideline: 'only one font family for the entire page',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: 'flat-type-hierarchy',
|
|
41
|
+
category: 'slop',
|
|
42
|
+
name: 'Flat type hierarchy',
|
|
43
|
+
description:
|
|
44
|
+
'Font sizes are too close together — no clear visual hierarchy. Use fewer sizes with more contrast (aim for at least a 1.25 ratio between steps).',
|
|
45
|
+
skillSection: 'Typography',
|
|
46
|
+
skillGuideline: 'flat type hierarchy',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: 'gradient-text',
|
|
50
|
+
category: 'slop',
|
|
51
|
+
name: 'Gradient text',
|
|
52
|
+
description:
|
|
53
|
+
'Gradient text is decorative rather than meaningful — a common AI tell, especially on headings and metrics. Use solid colors for text.',
|
|
54
|
+
skillSection: 'Color & Contrast',
|
|
55
|
+
skillGuideline: 'gradient text for',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: 'ai-color-palette',
|
|
59
|
+
category: 'slop',
|
|
60
|
+
name: 'AI color palette',
|
|
61
|
+
description:
|
|
62
|
+
'Purple/violet gradients and cyan-on-dark are the most recognizable tells of AI-generated UIs. Choose a distinctive, intentional palette.',
|
|
63
|
+
skillSection: 'Color & Contrast',
|
|
64
|
+
skillGuideline: 'AI color palette',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: 'cream-palette',
|
|
68
|
+
category: 'slop',
|
|
69
|
+
name: 'Cream / beige palette',
|
|
70
|
+
description:
|
|
71
|
+
'A warm cream or beige page background has become the default "tasteful" AI surface, reached for by reflex. Choose a background that comes from a deliberate palette, not the safe warm off-white.',
|
|
72
|
+
skillSection: 'Color & Contrast',
|
|
73
|
+
skillGuideline: 'cream and beige as the default surface',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
id: 'nested-cards',
|
|
77
|
+
category: 'slop',
|
|
78
|
+
name: 'Nested cards',
|
|
79
|
+
description:
|
|
80
|
+
'Cards inside cards create visual noise and excessive depth. Flatten the hierarchy — use spacing, typography, and dividers instead of nesting containers.',
|
|
81
|
+
skillSection: 'Layout & Space',
|
|
82
|
+
skillGuideline: 'Nest cards inside cards',
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: 'monotonous-spacing',
|
|
86
|
+
category: 'slop',
|
|
87
|
+
name: 'Monotonous spacing',
|
|
88
|
+
description:
|
|
89
|
+
'The same spacing value used everywhere — no rhythm, no variation. Use tight groupings for related items and generous separations between sections.',
|
|
90
|
+
skillSection: 'Layout & Space',
|
|
91
|
+
skillGuideline: 'same spacing everywhere',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: 'bounce-easing',
|
|
95
|
+
category: 'slop',
|
|
96
|
+
name: 'Bounce or elastic easing',
|
|
97
|
+
description:
|
|
98
|
+
'Bounce and elastic easing feel dated and tacky. Real objects decelerate smoothly — use exponential easing (ease-out-quart/quint/expo) instead.',
|
|
99
|
+
skillSection: 'Motion',
|
|
100
|
+
skillGuideline: 'bounce or elastic easing',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
id: 'dark-glow',
|
|
104
|
+
category: 'slop',
|
|
105
|
+
name: 'Dark mode with glowing accents',
|
|
106
|
+
description:
|
|
107
|
+
'Dark backgrounds with colored box-shadow glows are the default "cool" look of AI-generated UIs. Use subtle, purposeful lighting instead — or skip the dark theme entirely.',
|
|
108
|
+
skillSection: 'Color & Contrast',
|
|
109
|
+
skillGuideline: 'dark mode with glowing accents',
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
id: 'icon-tile-stack',
|
|
113
|
+
category: 'slop',
|
|
114
|
+
name: 'Icon tile stacked above heading',
|
|
115
|
+
description:
|
|
116
|
+
'A small rounded-square icon container above a heading is the universal AI feature-card template — every generator outputs this exact shape. Try a side-by-side icon and heading, or let the icon sit in flow without its own container.',
|
|
117
|
+
skillSection: 'Typography',
|
|
118
|
+
skillGuideline: 'large icons with rounded corners above every heading',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: 'italic-serif-display',
|
|
122
|
+
category: 'slop',
|
|
123
|
+
name: 'Italic serif display headline',
|
|
124
|
+
description:
|
|
125
|
+
'Oversized italic serif (Fraunces, Recoleta, Playfair, Newsreader-italic) as the primary hero headline reads as taste in isolation but has become the universal AI-startup landing page hero. Set roman, or move to a non-serif display face. Editorial / magazine register may legitimately want this — judge by context.',
|
|
126
|
+
skillSection: 'Typography',
|
|
127
|
+
skillGuideline: 'oversized italic serif as the hero headline',
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
id: 'hero-eyebrow-chip',
|
|
131
|
+
category: 'slop',
|
|
132
|
+
name: 'Hero eyebrow / pill chip',
|
|
133
|
+
description:
|
|
134
|
+
'A tiny uppercase letter-spaced label sitting immediately above an oversized hero headline — or the same shape rendered as a pill chip — is now the default AI SaaS hero. Drop the eyebrow, integrate the kicker into the headline, or run it as a navigation breadcrumb instead.',
|
|
135
|
+
skillSection: 'Typography',
|
|
136
|
+
skillGuideline: 'tiny uppercase tracked label above the hero headline',
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
id: 'repeated-section-kickers',
|
|
140
|
+
category: 'slop',
|
|
141
|
+
severity: 'advisory',
|
|
142
|
+
name: 'Repeated section kicker labels',
|
|
143
|
+
description:
|
|
144
|
+
'Repeating tiny uppercase tracked labels above section headings turns a brand page into AI editorial scaffolding. Replace them with stronger structure, artifacts, imagery, or a deliberate brand system.',
|
|
145
|
+
skillSection: 'Typography',
|
|
146
|
+
skillGuideline: 'repeated eyebrow or kicker labels as section scaffolding',
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
id: 'numbered-section-markers',
|
|
150
|
+
category: 'slop',
|
|
151
|
+
severity: 'advisory',
|
|
152
|
+
name: 'Numbered section markers (01 / 02 / 03)',
|
|
153
|
+
description:
|
|
154
|
+
'Numbered display markers as section labels (01, 02, 03) are the AI editorial scaffold one tier deeper than tracked eyebrow chips. If you find yourself reaching for them, choose a different section cadence.',
|
|
155
|
+
skillSection: 'Layout & Space',
|
|
156
|
+
skillGuideline: 'numbered section markers',
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
id: 'em-dash-overuse',
|
|
160
|
+
category: 'slop',
|
|
161
|
+
name: 'Em-dash overuse',
|
|
162
|
+
description:
|
|
163
|
+
'More than two em-dashes (— or --) in body copy is an AI cadence tell. Use commas, colons, periods, or parentheses instead.',
|
|
164
|
+
skillSection: 'Copy',
|
|
165
|
+
skillGuideline: 'no em dashes',
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
id: 'marketing-buzzword',
|
|
169
|
+
category: 'slop',
|
|
170
|
+
name: 'Marketing buzzword',
|
|
171
|
+
description:
|
|
172
|
+
'Generic SaaS phrases (streamline / empower / supercharge / world-class / enterprise-grade / next-generation / cutting-edge / etc) are instant AI tells. Pick a specific verb and noun that says what the product literally does.',
|
|
173
|
+
skillSection: 'Copy',
|
|
174
|
+
skillGuideline: 'marketing buzzwords',
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
id: 'aphoristic-cadence',
|
|
178
|
+
category: 'slop',
|
|
179
|
+
name: 'Aphoristic-cadence copy',
|
|
180
|
+
description:
|
|
181
|
+
'Three or more sections landing on a short rebuttal sentence ("X. No Y." / "X. Just Y.") or a manufactured-contrast aphorism ("Not a feature. A platform.") reads as AI cadence, not voice. Once is fine; the pattern is the tell.',
|
|
182
|
+
skillSection: 'Copy',
|
|
183
|
+
skillGuideline: 'aphoristic cadence',
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
id: 'oversized-h1',
|
|
187
|
+
category: 'slop',
|
|
188
|
+
name: 'Oversized hero headline',
|
|
189
|
+
description:
|
|
190
|
+
'A full-sentence headline set at display size ends up dominating the viewport, leaving no room for anything else above the fold. A punchy one- or two-word headline at that size is fine — the problem is a long headline blown up too large. Set long headlines smaller, or tighten the copy.',
|
|
191
|
+
skillSection: 'Typography',
|
|
192
|
+
skillGuideline: 'long headline set at display size',
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
id: 'extreme-negative-tracking',
|
|
196
|
+
category: 'slop',
|
|
197
|
+
name: 'Crushed letter spacing',
|
|
198
|
+
description:
|
|
199
|
+
'Letter-spacing pulled tighter than the point where characters keep their own shapes costs legibility. Tighten display type optically, not destructively.',
|
|
200
|
+
skillSection: 'Typography',
|
|
201
|
+
skillGuideline: 'letter spacing crushed past legibility',
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
id: 'broken-image',
|
|
205
|
+
category: 'quality',
|
|
206
|
+
name: 'Broken or placeholder image',
|
|
207
|
+
description:
|
|
208
|
+
'<img> tags with empty src, missing src, or placeholder values ship as broken-image boxes. Use real images, generated assets, or remove the tag.',
|
|
209
|
+
skillSection: 'Imagery',
|
|
210
|
+
skillGuideline: 'broken image references',
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
// ── Quality: general design and accessibility issues ──
|
|
214
|
+
{
|
|
215
|
+
id: 'gray-on-color',
|
|
216
|
+
category: 'quality',
|
|
217
|
+
name: 'Gray text on colored background',
|
|
218
|
+
description:
|
|
219
|
+
'Gray text looks washed out on colored backgrounds. Use a darker shade of the background color instead, or white/near-white for contrast.',
|
|
220
|
+
skillSection: 'Color & Contrast',
|
|
221
|
+
skillGuideline: 'gray text on colored backgrounds',
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
id: 'low-contrast',
|
|
225
|
+
category: 'quality',
|
|
226
|
+
name: 'Low contrast text',
|
|
227
|
+
description:
|
|
228
|
+
'Text does not meet WCAG AA contrast requirements (4.5:1 for body, 3:1 for large text). Increase the contrast between text and background.',
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
id: 'layout-transition',
|
|
232
|
+
category: 'quality',
|
|
233
|
+
name: 'Layout property animation',
|
|
234
|
+
description:
|
|
235
|
+
'Animating width, height, padding, or margin causes layout thrash and janky performance. Use transform and opacity instead, or grid-template-rows for height animations.',
|
|
236
|
+
skillSection: 'Motion',
|
|
237
|
+
skillGuideline: 'Animate layout properties',
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
id: 'line-length',
|
|
241
|
+
category: 'quality',
|
|
242
|
+
name: 'Line length too long',
|
|
243
|
+
description:
|
|
244
|
+
'Text lines wider than ~80 characters are hard to read. The eye loses its place tracking back to the start of the next line. Add a max-width (65ch to 75ch) to text containers.',
|
|
245
|
+
skillSection: 'Layout & Space',
|
|
246
|
+
skillGuideline: 'wrap beyond ~80 characters',
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
id: 'cramped-padding',
|
|
250
|
+
category: 'quality',
|
|
251
|
+
name: 'Cramped padding',
|
|
252
|
+
description:
|
|
253
|
+
'Text is too close to the edge of its container. Two shapes: (1) an element with its own text where the padding is too low for the font size, and (2) a wrapper with text-bearing children and near-zero padding against a visible boundary (border, outline, or non-transparent background) — children land flush against the boundary line. Add at least 8px (ideally 12–16px) of padding inside bordered, outlined, or colored containers.',
|
|
254
|
+
skillSection: 'Layout & Space',
|
|
255
|
+
skillGuideline: 'inside bordered or colored containers',
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
id: 'body-text-viewport-edge',
|
|
259
|
+
category: 'quality',
|
|
260
|
+
name: 'Body text touching viewport edge',
|
|
261
|
+
description:
|
|
262
|
+
'Body paragraphs render flush against the left or right viewport edge with no container providing horizontal padding. Wrap content in a container with at least 16px (ideally 24-32px) of horizontal padding, or apply max-width with mx-auto.',
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
id: 'tight-leading',
|
|
266
|
+
category: 'quality',
|
|
267
|
+
name: 'Tight line height',
|
|
268
|
+
description:
|
|
269
|
+
'Line height below 1.3x the font size makes multi-line text hard to read. Use 1.5 to 1.7 for body text so lines have room to breathe.',
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
id: 'skipped-heading',
|
|
273
|
+
category: 'quality',
|
|
274
|
+
name: 'Skipped heading level',
|
|
275
|
+
description:
|
|
276
|
+
'Heading levels should not skip (e.g. h1 then h3 with no h2). Screen readers use heading hierarchy for navigation. Skipping levels breaks the document outline.',
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
id: 'justified-text',
|
|
280
|
+
category: 'quality',
|
|
281
|
+
name: 'Justified text',
|
|
282
|
+
description:
|
|
283
|
+
'Justified text without hyphenation creates uneven word spacing ("rivers of white"). Use text-align: left for body text, or enable hyphens: auto if you must justify.',
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
id: 'tiny-text',
|
|
287
|
+
category: 'quality',
|
|
288
|
+
name: 'Tiny body text',
|
|
289
|
+
description:
|
|
290
|
+
'Body text below 12px is hard to read, especially on high-DPI screens. Use at least 14px for body content, 16px is ideal.',
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
id: 'all-caps-body',
|
|
294
|
+
category: 'quality',
|
|
295
|
+
name: 'All-caps body text',
|
|
296
|
+
description:
|
|
297
|
+
'Long passages in uppercase are hard to read. We recognize words by shape (ascenders and descenders), which all-caps removes. Reserve uppercase for short labels and headings.',
|
|
298
|
+
skillSection: 'Typography',
|
|
299
|
+
skillGuideline: 'long body passages in uppercase',
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
id: 'wide-tracking',
|
|
303
|
+
category: 'quality',
|
|
304
|
+
name: 'Wide letter spacing on body text',
|
|
305
|
+
description:
|
|
306
|
+
'Letter spacing above 0.05em on body text disrupts natural character groupings and slows reading. Reserve wide tracking for short uppercase labels only.',
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
id: 'text-overflow',
|
|
310
|
+
category: 'quality',
|
|
311
|
+
name: 'Content overflowing its container',
|
|
312
|
+
description:
|
|
313
|
+
'Content renders wider than its container, spilling out or forcing a horizontal scrollbar. Let text wrap, constrain widths, or give the region a deliberate scroll affordance.',
|
|
314
|
+
skillSection: 'Layout & Space',
|
|
315
|
+
skillGuideline: 'content wider than its container',
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
id: 'clipped-overflow-container',
|
|
319
|
+
category: 'quality',
|
|
320
|
+
name: 'Positioned child clipped by overflow container',
|
|
321
|
+
description:
|
|
322
|
+
'A clipping container (overflow hidden or clip) wrapping an absolutely-positioned child cuts off tooltips, menus, and popovers that need to escape. Let the overflow be visible, or move the positioned layer out of the clip.',
|
|
323
|
+
skillSection: 'Layout & Space',
|
|
324
|
+
skillGuideline: 'overflow container clipping positioned children',
|
|
325
|
+
},
|
|
326
|
+
|
|
327
|
+
// ── Provider tells: opt-in via --gpt / --gemini (gated off by default) ──
|
|
328
|
+
{
|
|
329
|
+
id: 'gpt-thin-border-wide-shadow',
|
|
330
|
+
category: 'slop',
|
|
331
|
+
severity: 'advisory',
|
|
332
|
+
gated: 'gpt',
|
|
333
|
+
name: 'Hairline border with wide shadow',
|
|
334
|
+
description:
|
|
335
|
+
'A hairline border paired with a wide, diffuse shadow is a recurring generated-UI signature. Commit to one — a defined edge or a soft elevation — rather than both at once.',
|
|
336
|
+
skillSection: 'Visual Details',
|
|
337
|
+
skillGuideline: 'hairline border plus wide diffuse shadow',
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
id: 'repeating-stripes-gradient',
|
|
341
|
+
category: 'slop',
|
|
342
|
+
severity: 'advisory',
|
|
343
|
+
gated: 'gpt',
|
|
344
|
+
name: 'Repeating-gradient stripes',
|
|
345
|
+
description:
|
|
346
|
+
'Repeating-gradient stripes used as surface decoration are a recurring generated-UI signature. Reach for a deliberate texture or leave the surface plain.',
|
|
347
|
+
skillSection: 'Visual Details',
|
|
348
|
+
skillGuideline: 'repeating-gradient decorative stripes',
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
id: 'theater-slop-phrase',
|
|
352
|
+
category: 'slop',
|
|
353
|
+
severity: 'advisory',
|
|
354
|
+
gated: 'gpt',
|
|
355
|
+
name: 'Theater framing copy',
|
|
356
|
+
description:
|
|
357
|
+
'Dismissing something as "theater" is a recurring generated-copy tic. Say plainly what the thing does or does not do.',
|
|
358
|
+
skillSection: 'Copy',
|
|
359
|
+
skillGuideline: 'theater framing copy',
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
id: 'image-hover-transform',
|
|
363
|
+
category: 'slop',
|
|
364
|
+
severity: 'advisory',
|
|
365
|
+
gated: 'gemini',
|
|
366
|
+
name: 'Image hover transform',
|
|
367
|
+
description:
|
|
368
|
+
'Scaling or rotating an image on hover is a recurring generated-UI signature. Let imagery sit still, or use a subtler, purposeful interaction.',
|
|
369
|
+
skillSection: 'Motion',
|
|
370
|
+
skillGuideline: 'image scale or rotate on hover',
|
|
371
|
+
},
|
|
372
|
+
];
|
|
373
|
+
|
|
374
|
+
const RULE_ENGINE_SUPPORT = {
|
|
375
|
+
regex: new Set(['source', 'page-analyzer']),
|
|
376
|
+
'static-html': new Set(['element', 'page']),
|
|
377
|
+
browser: new Set(['element', 'page', 'layout']),
|
|
378
|
+
visual: new Set(['visual-contrast']),
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
function getAntipattern(id) {
|
|
382
|
+
return ANTIPATTERNS.find(rule => rule.id === id);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function getRulesForCategory(category) {
|
|
386
|
+
return ANTIPATTERNS.filter(rule => rule.category === category);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function getRuleEngineSupport(engine) {
|
|
390
|
+
return RULE_ENGINE_SUPPORT[engine] || new Set();
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// Set of provider tags that gate rules off by default (e.g. 'gpt', 'gemini').
|
|
394
|
+
const GATED_PROVIDERS = new Set(
|
|
395
|
+
ANTIPATTERNS.map(rule => rule.gated).filter(Boolean),
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
// Drop findings for rules gated behind a provider tag unless that provider
|
|
399
|
+
// was explicitly enabled (CLI --gpt / --gemini). Non-gated findings always
|
|
400
|
+
// pass through. `findings` carry the rule id on `.antipattern`.
|
|
401
|
+
function filterByProviders(findings, providers = []) {
|
|
402
|
+
const enabled = new Set(providers || []);
|
|
403
|
+
if (!GATED_PROVIDERS.size) return findings;
|
|
404
|
+
return findings.filter(f => {
|
|
405
|
+
const rule = getAntipattern(f.antipattern);
|
|
406
|
+
if (!rule || !rule.gated) return true;
|
|
407
|
+
return enabled.has(rule.gated);
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
export {
|
|
412
|
+
ANTIPATTERNS,
|
|
413
|
+
RULE_ENGINE_SUPPORT,
|
|
414
|
+
GATED_PROVIDERS,
|
|
415
|
+
getAntipattern,
|
|
416
|
+
getRulesForCategory,
|
|
417
|
+
getRuleEngineSupport,
|
|
418
|
+
filterByProviders,
|
|
419
|
+
};
|