quiver-cli 1.3.1 → 2.0.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 +197 -239
- package/dist/cli.js +3163 -2040
- package/package.json +10 -11
- package/template/.agents/AGENTS.md +0 -26
- package/template/.agents/commands/cp.md +0 -108
- package/template/.agents/commands/next-setup.md +0 -1064
- package/template/.agents/commands/review.md +0 -68
- package/template/.agents/commands/terraform-readme.md +0 -38
- package/template/.agents/config.json +0 -80
- package/template/.agents/plugins/opencode/rtk.ts +0 -34
- package/template/.agents/skills/agent-browser/SKILL.md +0 -52
- package/template/.agents/skills/apps/skybridge/SKILL.md +0 -52
- package/template/.agents/skills/code/cleanup/SKILL.md +0 -26
- package/template/.agents/skills/code/improve/SKILL.md +0 -122
- package/template/.agents/skills/code/improve/references/audit-playbook.md +0 -130
- package/template/.agents/skills/code/improve/references/closing-the-loop.md +0 -96
- package/template/.agents/skills/code/improve/references/plan-template.md +0 -197
- package/template/.agents/skills/code/vercel-react-best-practices/AGENTS.md +0 -3810
- package/template/.agents/skills/code/vercel-react-best-practices/README.md +0 -123
- package/template/.agents/skills/code/vercel-react-best-practices/SKILL.md +0 -149
- package/template/.agents/skills/code/vercel-react-best-practices/metadata.json +0 -15
- package/template/.agents/skills/code/vercel-react-best-practices/rules/_sections.md +0 -46
- package/template/.agents/skills/code/vercel-react-best-practices/rules/_template.md +0 -28
- package/template/.agents/skills/code/vercel-react-best-practices/rules/advanced-effect-event-deps.md +0 -56
- package/template/.agents/skills/code/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -55
- package/template/.agents/skills/code/vercel-react-best-practices/rules/advanced-init-once.md +0 -42
- package/template/.agents/skills/code/vercel-react-best-practices/rules/advanced-use-latest.md +0 -39
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-api-routes.md +0 -38
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-cheap-condition-before-await.md +0 -37
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-defer-await.md +0 -82
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-dependencies.md +0 -51
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-parallel.md +0 -28
- package/template/.agents/skills/code/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -99
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-analyzable-paths.md +0 -63
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -60
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-conditional.md +0 -31
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -49
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -35
- package/template/.agents/skills/code/vercel-react-best-practices/rules/bundle-preload.md +0 -50
- package/template/.agents/skills/code/vercel-react-best-practices/rules/client-event-listeners.md +0 -74
- package/template/.agents/skills/code/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -71
- package/template/.agents/skills/code/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -48
- package/template/.agents/skills/code/vercel-react-best-practices/rules/client-swr-dedup.md +0 -56
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -107
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-cache-function-results.md +0 -80
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-cache-property-access.md +0 -28
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-cache-storage.md +0 -70
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-combine-iterations.md +0 -32
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-early-exit.md +0 -50
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-flatmap-filter.md +0 -60
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -45
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-index-maps.md +0 -37
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-length-check-first.md +0 -49
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-min-max-loop.md +0 -82
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-request-idle-callback.md +0 -105
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -24
- package/template/.agents/skills/code/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -57
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-activity.md +0 -26
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -47
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -40
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -38
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -46
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -82
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +0 -30
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-resource-hints.md +0 -85
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-script-defer-async.md +0 -68
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -28
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rendering-usetransition-loading.md +0 -75
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -39
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-dependencies.md +0 -45
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +0 -40
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-derived-state.md +0 -29
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -74
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -58
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +0 -38
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-memo.md +0 -44
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +0 -45
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-no-inline-components.md +0 -82
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +0 -35
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +0 -64
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-transitions.md +0 -40
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-use-deferred-value.md +0 -59
- package/template/.agents/skills/code/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +0 -73
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -73
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-auth-actions.md +0 -96
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-cache-lru.md +0 -41
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-cache-react.md +0 -76
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-dedup-props.md +0 -65
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-hoist-static-io.md +0 -149
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-no-shared-module-state.md +0 -50
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -83
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-parallel-nested-fetching.md +0 -34
- package/template/.agents/skills/code/vercel-react-best-practices/rules/server-serialization.md +0 -38
- package/template/.agents/skills/data/prisma-cli/SKILL.md +0 -265
- package/template/.agents/skills/data/prisma-cli/references/agent-safety.md +0 -27
- package/template/.agents/skills/data/prisma-cli/references/complete.md +0 -22
- package/template/.agents/skills/data/prisma-cli/references/db-execute.md +0 -78
- package/template/.agents/skills/data/prisma-cli/references/db-pull.md +0 -185
- package/template/.agents/skills/data/prisma-cli/references/db-push.md +0 -150
- package/template/.agents/skills/data/prisma-cli/references/db-seed.md +0 -188
- package/template/.agents/skills/data/prisma-cli/references/debug.md +0 -46
- package/template/.agents/skills/data/prisma-cli/references/dev.md +0 -157
- package/template/.agents/skills/data/prisma-cli/references/format.md +0 -48
- package/template/.agents/skills/data/prisma-cli/references/generate.md +0 -173
- package/template/.agents/skills/data/prisma-cli/references/init.md +0 -139
- package/template/.agents/skills/data/prisma-cli/references/mcp.md +0 -39
- package/template/.agents/skills/data/prisma-cli/references/migrate-deploy.md +0 -127
- package/template/.agents/skills/data/prisma-cli/references/migrate-dev.md +0 -145
- package/template/.agents/skills/data/prisma-cli/references/migrate-diff.md +0 -89
- package/template/.agents/skills/data/prisma-cli/references/migrate-reset.md +0 -80
- package/template/.agents/skills/data/prisma-cli/references/migrate-resolve.md +0 -57
- package/template/.agents/skills/data/prisma-cli/references/migrate-status.md +0 -65
- package/template/.agents/skills/data/prisma-cli/references/studio.md +0 -137
- package/template/.agents/skills/data/prisma-cli/references/validate.md +0 -53
- package/template/.agents/skills/data/prisma-client-api/SKILL.md +0 -216
- package/template/.agents/skills/data/prisma-client-api/references/client-methods.md +0 -223
- package/template/.agents/skills/data/prisma-client-api/references/constructor.md +0 -221
- package/template/.agents/skills/data/prisma-client-api/references/filters.md +0 -256
- package/template/.agents/skills/data/prisma-client-api/references/model-queries.md +0 -281
- package/template/.agents/skills/data/prisma-client-api/references/query-options.md +0 -276
- package/template/.agents/skills/data/prisma-client-api/references/raw-queries.md +0 -198
- package/template/.agents/skills/data/prisma-client-api/references/relations.md +0 -308
- package/template/.agents/skills/data/prisma-client-api/references/transactions.md +0 -184
- package/template/.agents/skills/design/impeccable/SKILL.md +0 -84
- package/template/.agents/skills/design/impeccable/reference/adapt.md +0 -312
- package/template/.agents/skills/design/impeccable/reference/adapt.native.md +0 -58
- package/template/.agents/skills/design/impeccable/reference/android.md +0 -46
- package/template/.agents/skills/design/impeccable/reference/animate.md +0 -89
- package/template/.agents/skills/design/impeccable/reference/audit.md +0 -136
- package/template/.agents/skills/design/impeccable/reference/audit.native.md +0 -139
- package/template/.agents/skills/design/impeccable/reference/bolder.md +0 -33
- package/template/.agents/skills/design/impeccable/reference/clarify.md +0 -94
- package/template/.agents/skills/design/impeccable/reference/colorize.md +0 -86
- package/template/.agents/skills/design/impeccable/reference/craft-floor.md +0 -44
- package/template/.agents/skills/design/impeccable/reference/craft.md +0 -5
- package/template/.agents/skills/design/impeccable/reference/critique.md +0 -806
- package/template/.agents/skills/design/impeccable/reference/degraded/asset-producer.md +0 -37
- package/template/.agents/skills/design/impeccable/reference/degraded/documenter.md +0 -24
- package/template/.agents/skills/design/impeccable/reference/degraded/finish-reviewer.md +0 -38
- package/template/.agents/skills/design/impeccable/reference/degraded/manual-edit-applier.md +0 -92
- package/template/.agents/skills/design/impeccable/reference/delight.md +0 -70
- package/template/.agents/skills/design/impeccable/reference/distill.md +0 -111
- package/template/.agents/skills/design/impeccable/reference/doctor.md +0 -54
- package/template/.agents/skills/design/impeccable/reference/document.md +0 -416
- package/template/.agents/skills/design/impeccable/reference/extract.md +0 -69
- package/template/.agents/skills/design/impeccable/reference/harden.md +0 -336
- package/template/.agents/skills/design/impeccable/reference/hooks.md +0 -111
- package/template/.agents/skills/design/impeccable/reference/init.md +0 -131
- package/template/.agents/skills/design/impeccable/reference/ios.md +0 -51
- package/template/.agents/skills/design/impeccable/reference/layout.md +0 -84
- package/template/.agents/skills/design/impeccable/reference/live-setup.md +0 -102
- package/template/.agents/skills/design/impeccable/reference/live.md +0 -323
- package/template/.agents/skills/design/impeccable/reference/new-work.md +0 -145
- package/template/.agents/skills/design/impeccable/reference/onboard.md +0 -234
- package/template/.agents/skills/design/impeccable/reference/operate.md +0 -61
- package/template/.agents/skills/design/impeccable/reference/optimize.md +0 -258
- package/template/.agents/skills/design/impeccable/reference/overdrive.md +0 -127
- package/template/.agents/skills/design/impeccable/reference/polish.md +0 -105
- package/template/.agents/skills/design/impeccable/reference/quieter.md +0 -99
- package/template/.agents/skills/design/impeccable/reference/routing.md +0 -18
- package/template/.agents/skills/design/impeccable/reference/shape.md +0 -59
- package/template/.agents/skills/design/impeccable/reference/typeset.md +0 -80
- package/template/.agents/skills/design/impeccable/reference/visualize.md +0 -46
- package/template/.agents/skills/design/impeccable/scripts/build-phase.mjs +0 -1022
- package/template/.agents/skills/design/impeccable/scripts/command-metadata.json +0 -94
- package/template/.agents/skills/design/impeccable/scripts/comp-diff.mjs +0 -391
- package/template/.agents/skills/design/impeccable/scripts/comp-spec.mjs +0 -513
- package/template/.agents/skills/design/impeccable/scripts/concept-seed.mjs +0 -814
- package/template/.agents/skills/design/impeccable/scripts/context-signals.mjs +0 -325
- package/template/.agents/skills/design/impeccable/scripts/context.mjs +0 -1565
- package/template/.agents/skills/design/impeccable/scripts/critique-storage.mjs +0 -473
- package/template/.agents/skills/design/impeccable/scripts/data/font-index-failures.json +0 -121
- package/template/.agents/skills/design/impeccable/scripts/data/font-index.json +0 -1
- package/template/.agents/skills/design/impeccable/scripts/detect-csp.mjs +0 -198
- package/template/.agents/skills/design/impeccable/scripts/detect.mjs +0 -30
- package/template/.agents/skills/design/impeccable/scripts/detector/browser/injected/index.mjs +0 -2204
- package/template/.agents/skills/design/impeccable/scripts/detector/cli/main.mjs +0 -432
- package/template/.agents/skills/design/impeccable/scripts/detector/design-system.mjs +0 -1311
- package/template/.agents/skills/design/impeccable/scripts/detector/detect-antipatterns-browser.js +0 -9043
- package/template/.agents/skills/design/impeccable/scripts/detector/detect-antipatterns.mjs +0 -51
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/browser/detect-url.mjs +0 -434
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/regex/detect-text.mjs +0 -1319
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +0 -1241
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/static-html/detect-html.mjs +0 -288
- package/template/.agents/skills/design/impeccable/scripts/detector/engines/visual/screenshot-contrast.mjs +0 -189
- package/template/.agents/skills/design/impeccable/scripts/detector/findings.mjs +0 -18
- package/template/.agents/skills/design/impeccable/scripts/detector/node/file-system.mjs +0 -213
- package/template/.agents/skills/design/impeccable/scripts/detector/profile/profiler.mjs +0 -166
- package/template/.agents/skills/design/impeccable/scripts/detector/registry/antipatterns.mjs +0 -635
- package/template/.agents/skills/design/impeccable/scripts/detector/rules/checks.mjs +0 -5681
- package/template/.agents/skills/design/impeccable/scripts/detector/shared/color.mjs +0 -596
- package/template/.agents/skills/design/impeccable/scripts/detector/shared/constants.mjs +0 -127
- package/template/.agents/skills/design/impeccable/scripts/detector/shared/fonts.mjs +0 -30
- package/template/.agents/skills/design/impeccable/scripts/detector/shared/inline-ignores.mjs +0 -148
- package/template/.agents/skills/design/impeccable/scripts/detector/shared/page.mjs +0 -7
- package/template/.agents/skills/design/impeccable/scripts/doctor.mjs +0 -329
- package/template/.agents/skills/design/impeccable/scripts/embed-prompt.mjs +0 -166
- package/template/.agents/skills/design/impeccable/scripts/font-match.mjs +0 -457
- package/template/.agents/skills/design/impeccable/scripts/generate-image.mjs +0 -447
- package/template/.agents/skills/design/impeccable/scripts/hook-admin.mjs +0 -819
- package/template/.agents/skills/design/impeccable/scripts/hook-before-edit.mjs +0 -538
- package/template/.agents/skills/design/impeccable/scripts/hook-lib.mjs +0 -2490
- package/template/.agents/skills/design/impeccable/scripts/hook.mjs +0 -79
- package/template/.agents/skills/design/impeccable/scripts/lib/artifact-schema.mjs +0 -93
- package/template/.agents/skills/design/impeccable/scripts/lib/composition-catalog.mjs +0 -200
- package/template/.agents/skills/design/impeccable/scripts/lib/concept-catalog.mjs +0 -396
- package/template/.agents/skills/design/impeccable/scripts/lib/design-parser.mjs +0 -880
- package/template/.agents/skills/design/impeccable/scripts/lib/font-fingerprint.mjs +0 -564
- package/template/.agents/skills/design/impeccable/scripts/lib/font-index.mjs +0 -130
- package/template/.agents/skills/design/impeccable/scripts/lib/hero-checks.mjs +0 -246
- package/template/.agents/skills/design/impeccable/scripts/lib/image-metrics.mjs +0 -306
- package/template/.agents/skills/design/impeccable/scripts/lib/impeccable-config.mjs +0 -640
- package/template/.agents/skills/design/impeccable/scripts/lib/impeccable-paths.mjs +0 -137
- package/template/.agents/skills/design/impeccable/scripts/lib/is-generated.mjs +0 -72
- package/template/.agents/skills/design/impeccable/scripts/lib/live-path-globs.mjs +0 -37
- package/template/.agents/skills/design/impeccable/scripts/lib/open-system-browser.mjs +0 -26
- package/template/.agents/skills/design/impeccable/scripts/lib/png.mjs +0 -281
- package/template/.agents/skills/design/impeccable/scripts/lib/provider.mjs +0 -5
- package/template/.agents/skills/design/impeccable/scripts/lib/raster.mjs +0 -194
- package/template/.agents/skills/design/impeccable/scripts/lib/roll-selection.mjs +0 -369
- package/template/.agents/skills/design/impeccable/scripts/lib/staleness-deep.mjs +0 -485
- package/template/.agents/skills/design/impeccable/scripts/lib/staleness-notice.mjs +0 -169
- package/template/.agents/skills/design/impeccable/scripts/lib/staleness.mjs +0 -533
- package/template/.agents/skills/design/impeccable/scripts/lib/surface-briefs.mjs +0 -149
- package/template/.agents/skills/design/impeccable/scripts/lib/target-args.mjs +0 -42
- package/template/.agents/skills/design/impeccable/scripts/lib/target-slug.mjs +0 -33
- package/template/.agents/skills/design/impeccable/scripts/lib/template-extensions.mjs +0 -146
- package/template/.agents/skills/design/impeccable/scripts/live/accept-css.mjs +0 -617
- package/template/.agents/skills/design/impeccable/scripts/live/accept-verify.mjs +0 -60
- package/template/.agents/skills/design/impeccable/scripts/live/browser-script-parts.mjs +0 -84
- package/template/.agents/skills/design/impeccable/scripts/live/completion.mjs +0 -28
- package/template/.agents/skills/design/impeccable/scripts/live/event-validation.mjs +0 -199
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/astro.mjs +0 -47
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/detect-utils.mjs +0 -73
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/index.mjs +0 -143
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/journal.mjs +0 -197
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/nextjs.mjs +0 -49
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/nuxt.mjs +0 -161
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/script-src.mjs +0 -17
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/static-html.mjs +0 -26
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/sveltekit.mjs +0 -71
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/tag-strategy.mjs +0 -247
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/tanstack-start.mjs +0 -70
- package/template/.agents/skills/design/impeccable/scripts/live/frameworks/vite-generic.mjs +0 -42
- package/template/.agents/skills/design/impeccable/scripts/live/generation-preflight.mjs +0 -149
- package/template/.agents/skills/design/impeccable/scripts/live/insert-ui.mjs +0 -458
- package/template/.agents/skills/design/impeccable/scripts/live/instructions.mjs +0 -142
- package/template/.agents/skills/design/impeccable/scripts/live/manual-apply.mjs +0 -939
- package/template/.agents/skills/design/impeccable/scripts/live/manual-edit-routes.mjs +0 -357
- package/template/.agents/skills/design/impeccable/scripts/live/manual-edits-buffer.mjs +0 -152
- package/template/.agents/skills/design/impeccable/scripts/live/poll-lanes.mjs +0 -14
- package/template/.agents/skills/design/impeccable/scripts/live/project-ignores.mjs +0 -139
- package/template/.agents/skills/design/impeccable/scripts/live/roots.mjs +0 -508
- package/template/.agents/skills/design/impeccable/scripts/live/session-store.mjs +0 -563
- package/template/.agents/skills/design/impeccable/scripts/live/source-lock.mjs +0 -105
- package/template/.agents/skills/design/impeccable/scripts/live/source-search.mjs +0 -105
- package/template/.agents/skills/design/impeccable/scripts/live/svelte-ast.mjs +0 -969
- package/template/.agents/skills/design/impeccable/scripts/live/svelte-component.mjs +0 -1366
- package/template/.agents/skills/design/impeccable/scripts/live/sveltekit-adapter.mjs +0 -304
- package/template/.agents/skills/design/impeccable/scripts/live/tanstack-adapter.mjs +0 -259
- package/template/.agents/skills/design/impeccable/scripts/live/ui-surfaces.mjs +0 -75
- package/template/.agents/skills/design/impeccable/scripts/live/vocabulary.mjs +0 -171
- package/template/.agents/skills/design/impeccable/scripts/live-accept.mjs +0 -938
- package/template/.agents/skills/design/impeccable/scripts/live-browser-dom.js +0 -146
- package/template/.agents/skills/design/impeccable/scripts/live-browser-ignores.js +0 -242
- package/template/.agents/skills/design/impeccable/scripts/live-browser-session.js +0 -123
- package/template/.agents/skills/design/impeccable/scripts/live-browser.js +0 -12551
- package/template/.agents/skills/design/impeccable/scripts/live-commit-manual-edits.mjs +0 -1200
- package/template/.agents/skills/design/impeccable/scripts/live-complete.mjs +0 -107
- package/template/.agents/skills/design/impeccable/scripts/live-copy-edit-agent.mjs +0 -800
- package/template/.agents/skills/design/impeccable/scripts/live-discard-manual-edits.mjs +0 -51
- package/template/.agents/skills/design/impeccable/scripts/live-inject.mjs +0 -463
- package/template/.agents/skills/design/impeccable/scripts/live-insert.mjs +0 -292
- package/template/.agents/skills/design/impeccable/scripts/live-manual-edit-evidence.mjs +0 -368
- package/template/.agents/skills/design/impeccable/scripts/live-poll.mjs +0 -430
- package/template/.agents/skills/design/impeccable/scripts/live-resume.mjs +0 -123
- package/template/.agents/skills/design/impeccable/scripts/live-server.mjs +0 -1698
- package/template/.agents/skills/design/impeccable/scripts/live-status.mjs +0 -71
- package/template/.agents/skills/design/impeccable/scripts/live-target.mjs +0 -30
- package/template/.agents/skills/design/impeccable/scripts/live-wrap.mjs +0 -927
- package/template/.agents/skills/design/impeccable/scripts/live.mjs +0 -334
- package/template/.agents/skills/design/impeccable/scripts/modern-screenshot.umd.js +0 -14
- package/template/.agents/skills/design/impeccable/scripts/palette.mjs +0 -628
- package/template/.agents/skills/design/impeccable/scripts/pin.mjs +0 -224
- package/template/.agents/skills/design/impeccable/scripts/serve-question.mjs +0 -1783
- package/template/.agents/skills/design/impeccable/scripts/surface-brief.mjs +0 -74
- package/template/.agents/skills/design/shadcn/SKILL.md +0 -277
- package/template/.agents/skills/design/shadcn/agents/openai.yml +0 -5
- 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 +0 -290
- package/template/.agents/skills/design/shadcn/customization.md +0 -209
- package/template/.agents/skills/design/shadcn/evals/evals.json +0 -77
- package/template/.agents/skills/design/shadcn/mcp.md +0 -105
- package/template/.agents/skills/design/shadcn/registry.md +0 -277
- package/template/.agents/skills/design/shadcn/rules/base-vs-radix.md +0 -306
- package/template/.agents/skills/design/shadcn/rules/chat.md +0 -250
- package/template/.agents/skills/design/shadcn/rules/composition.md +0 -213
- package/template/.agents/skills/design/shadcn/rules/forms.md +0 -192
- package/template/.agents/skills/design/shadcn/rules/icons.md +0 -101
- package/template/.agents/skills/design/shadcn/rules/styling.md +0 -185
- package/template/.agents/skills/find-skills/SKILL.md +0 -141
- package/template/.agents/skills/hono/SKILL.md +0 -593
- package/template/.agents/skills/integrations/langfuse/SKILL.md +0 -150
- package/template/.agents/skills/integrations/langfuse/references/ci-cd.md +0 -41
- package/template/.agents/skills/integrations/langfuse/references/cli.md +0 -60
- package/template/.agents/skills/integrations/langfuse/references/create-dataset.md +0 -35
- package/template/.agents/skills/integrations/langfuse/references/error-analysis.md +0 -87
- package/template/.agents/skills/integrations/langfuse/references/instrumentation.md +0 -121
- package/template/.agents/skills/integrations/langfuse/references/judge-calibration.md +0 -293
- package/template/.agents/skills/integrations/langfuse/references/prompt-engineering.md +0 -35
- package/template/.agents/skills/integrations/langfuse/references/prompt-migration.md +0 -79
- package/template/.agents/skills/integrations/langfuse/references/sdk-upgrade.md +0 -34
- package/template/.agents/skills/integrations/langfuse/references/setting-up-evals.md +0 -65
- package/template/.agents/skills/integrations/langfuse/references/skill-feedback.md +0 -35
- package/template/.agents/skills/integrations/langfuse/references/trace-evaluator-upgrade.md +0 -76
- package/template/.agents/skills/integrations/langfuse/references/user-feedback.md +0 -66
- package/template/.agents/skills/integrations/langfuse/references/v4-project-migration.md +0 -75
- package/template/.agents/skills/integrations/posthog/SKILL.md +0 -102
- package/template/.agents/skills/integrations/posthog/references/error-tracking-alerts.md +0 -63
- package/template/.agents/skills/integrations/posthog/references/error-tracking-assigning-issues.md +0 -77
- package/template/.agents/skills/integrations/posthog/references/error-tracking-fingerprints.md +0 -57
- package/template/.agents/skills/integrations/posthog/references/error-tracking-monitoring.md +0 -140
- package/template/.agents/skills/integrations/posthog/references/error-tracking-nextjs.md +0 -490
- package/template/.agents/skills/integrations/posthog/references/error-tracking-source-maps.md +0 -45
- package/template/.agents/skills/integrations/posthog/references/feature-flags-best-practices.md +0 -139
- package/template/.agents/skills/integrations/posthog/references/feature-flags-react.md +0 -302
- package/template/.agents/skills/integrations/posthog/references/identify-users.md +0 -202
- package/template/.agents/skills/integrations/posthog/references/integration-example.md +0 -706
- package/template/.agents/skills/integrations/posthog/references/integration-nextjs.md +0 -385
- package/template/.agents/skills/integrations/posthog/references/integration-step-1-begin.md +0 -43
- package/template/.agents/skills/integrations/posthog/references/integration-step-2-edit.md +0 -37
- package/template/.agents/skills/integrations/posthog/references/integration-step-3-revise.md +0 -22
- package/template/.agents/skills/integrations/posthog/references/integration-step-4-conclude.md +0 -38
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-anthropic.md +0 -200
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-basics.md +0 -62
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-costs.md +0 -197
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-manual-capture.md +0 -397
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-traces.md +0 -98
- package/template/.agents/skills/integrations/posthog/references/llm-analytics-vercel-ai.md +0 -120
- package/template/.agents/skills/repo/repo-ci/SKILL.md +0 -265
- package/template/.agents/skills/repo/repo-init-next-js/SKILL.md +0 -129
- package/template/.agents/skills/repo/repo-init-next-js/references/file-contents.md +0 -800
- package/template/.agents/skills/repo/repo-init-next-js/scripts/setup.sh +0 -47
- package/template/.agents/skills/repo/repo-init-node/SKILL.md +0 -196
- package/template/.agents/skills/skill-creator/LICENSE.txt +0 -202
- package/template/.agents/skills/skill-creator/SKILL.md +0 -485
- package/template/.agents/skills/skill-creator/agents/analyzer.md +0 -274
- package/template/.agents/skills/skill-creator/agents/comparator.md +0 -202
- package/template/.agents/skills/skill-creator/agents/grader.md +0 -223
- package/template/.agents/skills/skill-creator/assets/eval_review.html +0 -146
- package/template/.agents/skills/skill-creator/eval-viewer/generate_review.py +0 -471
- package/template/.agents/skills/skill-creator/eval-viewer/viewer.html +0 -1325
- package/template/.agents/skills/skill-creator/references/schemas.md +0 -430
- package/template/.agents/skills/skill-creator/scripts/__init__.py +0 -0
- package/template/.agents/skills/skill-creator/scripts/aggregate_benchmark.py +0 -401
- package/template/.agents/skills/skill-creator/scripts/generate_report.py +0 -326
- package/template/.agents/skills/skill-creator/scripts/improve_description.py +0 -247
- package/template/.agents/skills/skill-creator/scripts/package_skill.py +0 -136
- package/template/.agents/skills/skill-creator/scripts/quick_validate.py +0 -103
- package/template/.agents/skills/skill-creator/scripts/run_eval.py +0 -310
- package/template/.agents/skills/skill-creator/scripts/run_loop.py +0 -328
- package/template/.agents/skills/skill-creator/scripts/utils.py +0 -47
- package/template/.agents/skills/supabase/CHANGELOG.md +0 -78
- package/template/.agents/skills/supabase/SKILL.md +0 -149
- package/template/.agents/skills/supabase/assets/feedback-issue-template.md +0 -17
- package/template/.agents/skills/supabase/references/skill-feedback.md +0 -17
- package/template/.agents/skills/supabase-postgres-best-practices/CHANGELOG.md +0 -73
- package/template/.agents/skills/supabase-postgres-best-practices/SKILL.md +0 -64
- package/template/.agents/skills/supabase-postgres-best-practices/references/_contributing.md +0 -170
- package/template/.agents/skills/supabase-postgres-best-practices/references/_sections.md +0 -39
- package/template/.agents/skills/supabase-postgres-best-practices/references/_template.md +0 -34
- package/template/.agents/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +0 -55
- package/template/.agents/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +0 -49
- package/template/.agents/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +0 -46
- package/template/.agents/skills/supabase-postgres-best-practices/references/conn-limits.md +0 -44
- package/template/.agents/skills/supabase-postgres-best-practices/references/conn-pooling.md +0 -41
- package/template/.agents/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +0 -46
- package/template/.agents/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +0 -54
- package/template/.agents/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +0 -53
- package/template/.agents/skills/supabase-postgres-best-practices/references/data-pagination.md +0 -50
- package/template/.agents/skills/supabase-postgres-best-practices/references/data-upsert.md +0 -50
- package/template/.agents/skills/supabase-postgres-best-practices/references/lock-advisory.md +0 -56
- package/template/.agents/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +0 -68
- package/template/.agents/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +0 -50
- package/template/.agents/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +0 -54
- package/template/.agents/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +0 -45
- package/template/.agents/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +0 -55
- package/template/.agents/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +0 -55
- package/template/.agents/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +0 -44
- package/template/.agents/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +0 -40
- package/template/.agents/skills/supabase-postgres-best-practices/references/query-index-types.md +0 -48
- package/template/.agents/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +0 -43
- package/template/.agents/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +0 -45
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-constraints.md +0 -80
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-data-types.md +0 -46
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +0 -59
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +0 -55
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-partitioning.md +0 -55
- package/template/.agents/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +0 -61
- package/template/.agents/skills/supabase-postgres-best-practices/references/security-privileges.md +0 -54
- package/template/.agents/skills/supabase-postgres-best-practices/references/security-rls-basics.md +0 -50
- package/template/.agents/skills/supabase-postgres-best-practices/references/security-rls-performance.md +0 -63
- package/template/.agents/skills/writing/humanizer/LICENSE +0 -21
- package/template/.agents/skills/writing/humanizer/README.md +0 -209
- package/template/.agents/skills/writing/humanizer/SKILL.md +0 -456
- package/template/.agents/upstreams.json +0 -115
|
@@ -1,447 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* API image generation fallback: renders a mock or world board with the
|
|
4
|
-
* user's own OpenAI key when the harness has no native image generation.
|
|
5
|
-
*
|
|
6
|
-
* context.mjs reports availability (it checks OPENAI_API_KEY); harness-native
|
|
7
|
-
* generation always wins when present. This uses gpt-image-2 and spends the
|
|
8
|
-
* user's API credit (roughly $0.05-0.25 per image at default quality), so the
|
|
9
|
-
* skill states that before the first call in a session.
|
|
10
|
-
*
|
|
11
|
-
* node generate-image.mjs --prompt "..." --out mock.png [--size 1536x1024] [--quality medium]
|
|
12
|
-
* node generate-image.mjs --prompt-file prompt.txt --out mock.png
|
|
13
|
-
* node generate-image.mjs --prompt "..." --out mock.png --ref screenshot.png [--ref more.png]
|
|
14
|
-
*
|
|
15
|
-
* --ref anchors generation on input image(s) via the edits endpoint: pass a
|
|
16
|
-
* captured screenshot of a representative existing page when comping a new
|
|
17
|
-
* surface for an established world, so the identity comes from the real UI.
|
|
18
|
-
*
|
|
19
|
-
* node generate-image.mjs --plate <region-id> [--spec .impeccable/build/spec.json] [--quality high]
|
|
20
|
-
*
|
|
21
|
-
* --plate produces a shipping raster for one raster region of the measured
|
|
22
|
-
* comp spec (comp-spec.mjs): it crops the region from the approved comp,
|
|
23
|
-
* sends the crop as the reference with the spec's plate prompt (plus any
|
|
24
|
-
* --prompt you add), picks the closest supported output size to the region's
|
|
25
|
-
* aspect, writes the result to the region's `plate` path, embeds the prompt,
|
|
26
|
-
* and scores the plate against the comp crop with comp-diff so a plate that
|
|
27
|
-
* does not read as the region is reported (and, with --min, refused) here,
|
|
28
|
-
* before it lands on the page. In IMPECCABLE_IMAGE_GEN_FAKE mode the plate is
|
|
29
|
-
* the crop itself at 2x, so offline pipelines can walk the plate gate.
|
|
30
|
-
*/
|
|
31
|
-
import fs from 'node:fs';
|
|
32
|
-
import path from 'node:path';
|
|
33
|
-
import { fileURLToPath } from 'node:url';
|
|
34
|
-
import zlib from 'node:zlib';
|
|
35
|
-
|
|
36
|
-
function arg(name, fallback = null) {
|
|
37
|
-
const i = process.argv.indexOf(`--${name}`);
|
|
38
|
-
if (i === -1) return fallback;
|
|
39
|
-
const v = process.argv[i + 1];
|
|
40
|
-
return v && !v.startsWith('--') ? v : fallback;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// ---------------------------------------------------------------------------
|
|
44
|
-
// Fake mode (IMPECCABLE_IMAGE_GEN_FAKE=1)
|
|
45
|
-
//
|
|
46
|
-
// Deterministic offline stand-in for the OpenAI call: same prompt -> identical
|
|
47
|
-
// bytes, no network, no key, cost line reads $0.00. Used by the new-work smoke
|
|
48
|
-
// suite so the concept/serve-question/image chain can run without spend. The
|
|
49
|
-
// output renders the prompt over a 2-3 color palette hashed from the prompt,
|
|
50
|
-
// plus a "SYNTHETIC COMP" corner label. SVG carries the readable text; the
|
|
51
|
-
// raster (.png/.webp/.jpg) fallback carries palette stripes and stows the
|
|
52
|
-
// prompt + marker in a PNG tEXt chunk so downstream stays a valid image.
|
|
53
|
-
// ---------------------------------------------------------------------------
|
|
54
|
-
|
|
55
|
-
// FNV-1a 32-bit: tiny, dependency-free, stable across runs and platforms.
|
|
56
|
-
function hash32(str) {
|
|
57
|
-
let h = 0x811c9dc5;
|
|
58
|
-
for (let i = 0; i < str.length; i++) {
|
|
59
|
-
h ^= str.charCodeAt(i);
|
|
60
|
-
h = Math.imul(h, 0x01000193);
|
|
61
|
-
}
|
|
62
|
-
return h >>> 0;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function hslToRgb(hDeg, s, l) {
|
|
66
|
-
const h = ((hDeg % 360) + 360) % 360 / 360;
|
|
67
|
-
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
68
|
-
const p = 2 * l - q;
|
|
69
|
-
const hue = (t) => {
|
|
70
|
-
let tt = t;
|
|
71
|
-
if (tt < 0) tt += 1;
|
|
72
|
-
if (tt > 1) tt -= 1;
|
|
73
|
-
if (tt < 1 / 6) return p + (q - p) * 6 * tt;
|
|
74
|
-
if (tt < 1 / 2) return q;
|
|
75
|
-
if (tt < 2 / 3) return p + (q - p) * (2 / 3 - tt) * 6;
|
|
76
|
-
return p;
|
|
77
|
-
};
|
|
78
|
-
return [hue(h + 1 / 3), hue(h), hue(h - 1 / 3)].map((c) => Math.round(c * 255));
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const toHex = ([r, g, b]) =>
|
|
82
|
-
'#' + [r, g, b].map((c) => c.toString(16).padStart(2, '0')).join('');
|
|
83
|
-
|
|
84
|
-
// Two or three deterministic swatches derived from the prompt hash. The band
|
|
85
|
-
// count itself is prompt-derived, so different prompts differ in palette.
|
|
86
|
-
function palette(prompt) {
|
|
87
|
-
const h = hash32(prompt);
|
|
88
|
-
const base = h % 360;
|
|
89
|
-
const bands = 2 + (h >>> 9) % 2; // 2 or 3
|
|
90
|
-
const spread = 40 + (h >>> 3) % 120;
|
|
91
|
-
const out = [];
|
|
92
|
-
for (let i = 0; i < bands; i++) {
|
|
93
|
-
const hue = base + i * spread;
|
|
94
|
-
const light = 0.32 + ((h >>> (i * 5)) % 40) / 100; // 0.32 - 0.71
|
|
95
|
-
out.push(hslToRgb(hue, 0.55, light));
|
|
96
|
-
}
|
|
97
|
-
return out;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function svgFake(prompt, [w, h]) {
|
|
101
|
-
const colors = palette(prompt).map(toHex);
|
|
102
|
-
const stops = colors
|
|
103
|
-
.map((c, i) => `<stop offset="${Math.round((i / (colors.length - 1)) * 100)}%" stop-color="${c}"/>`)
|
|
104
|
-
.join('');
|
|
105
|
-
// Greedy word wrap tuned to the canvas width so the prompt stays legible.
|
|
106
|
-
const perLine = Math.max(12, Math.floor(w / 26));
|
|
107
|
-
const words = String(prompt).replace(/\s+/g, ' ').trim().split(' ');
|
|
108
|
-
const lines = [];
|
|
109
|
-
let cur = '';
|
|
110
|
-
for (const word of words) {
|
|
111
|
-
if ((cur + ' ' + word).trim().length > perLine) {
|
|
112
|
-
if (cur) lines.push(cur);
|
|
113
|
-
cur = word;
|
|
114
|
-
} else {
|
|
115
|
-
cur = (cur + ' ' + word).trim();
|
|
116
|
-
}
|
|
117
|
-
if (lines.length >= 10) break;
|
|
118
|
-
}
|
|
119
|
-
if (cur && lines.length < 11) lines.push(cur);
|
|
120
|
-
const escape = (s) => String(s).replace(/[&<>]/g, (c) => ({ '&': '&', '<': '<', '>': '>' }[c]));
|
|
121
|
-
const fontSize = Math.round(w / 24);
|
|
122
|
-
const startY = h / 2 - ((lines.length - 1) * fontSize * 1.3) / 2;
|
|
123
|
-
const text = lines
|
|
124
|
-
.map((line, i) => `<text x="${w / 2}" y="${Math.round(startY + i * fontSize * 1.3)}" font-family="Helvetica, Arial, sans-serif" font-size="${fontSize}" fill="#ffffff" text-anchor="middle" dominant-baseline="middle">${escape(line)}</text>`)
|
|
125
|
-
.join('');
|
|
126
|
-
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
127
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}" viewBox="0 0 ${w} ${h}">
|
|
128
|
-
<defs><linearGradient id="g" x1="0" y1="0" x2="1" y2="1">${stops}</linearGradient></defs>
|
|
129
|
-
<rect width="${w}" height="${h}" fill="url(#g)"/>
|
|
130
|
-
<rect x="0" y="0" width="${w}" height="${h}" fill="#000000" fill-opacity="0.22"/>
|
|
131
|
-
${text}
|
|
132
|
-
<rect x="${w - Math.round(w / 4.2)}" y="${h - Math.round(h / 16)}" width="${Math.round(w / 4.2)}" height="${Math.round(h / 16)}" fill="#000000" fill-opacity="0.55"/>
|
|
133
|
-
<text x="${w - Math.round(w / 8.4)}" y="${h - Math.round(h / 32)}" font-family="Helvetica, Arial, sans-serif" font-size="${Math.round(w / 60)}" letter-spacing="2" fill="#ffffff" text-anchor="middle" dominant-baseline="middle">SYNTHETIC COMP</text>
|
|
134
|
-
</svg>
|
|
135
|
-
`;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Minimal valid PNG: palette stripes plus a tEXt chunk carrying the marker and
|
|
139
|
-
// prompt, so a .png/.webp fake stays a decodable image and still contains the
|
|
140
|
-
// "SYNTHETIC" bytes downstream tools look for.
|
|
141
|
-
function crc32(buf) {
|
|
142
|
-
let c = 0xffffffff;
|
|
143
|
-
for (let i = 0; i < buf.length; i++) {
|
|
144
|
-
c ^= buf[i];
|
|
145
|
-
for (let k = 0; k < 8; k++) c = (c & 1) ? (0xedb88320 ^ (c >>> 1)) : (c >>> 1);
|
|
146
|
-
}
|
|
147
|
-
return (c ^ 0xffffffff) >>> 0;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function pngChunk(type, data) {
|
|
151
|
-
const typeBuf = Buffer.from(type, 'latin1');
|
|
152
|
-
const body = Buffer.concat([typeBuf, data]);
|
|
153
|
-
const len = Buffer.alloc(4);
|
|
154
|
-
len.writeUInt32BE(data.length, 0);
|
|
155
|
-
const crc = Buffer.alloc(4);
|
|
156
|
-
crc.writeUInt32BE(crc32(body), 0);
|
|
157
|
-
return Buffer.concat([len, body, crc]);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function pngFake(prompt, [w, h]) {
|
|
161
|
-
const colors = palette(prompt); // [[r,g,b], ...]
|
|
162
|
-
const bandH = Math.ceil(h / colors.length);
|
|
163
|
-
// Raw image: each scanline prefixed with a 0 filter byte, RGB pixels.
|
|
164
|
-
const stride = w * 3;
|
|
165
|
-
const raw = Buffer.alloc(h * (stride + 1));
|
|
166
|
-
for (let y = 0; y < h; y++) {
|
|
167
|
-
const rowStart = y * (stride + 1);
|
|
168
|
-
raw[rowStart] = 0;
|
|
169
|
-
const [r, g, b] = colors[Math.min(colors.length - 1, Math.floor(y / bandH))];
|
|
170
|
-
for (let x = 0; x < w; x++) {
|
|
171
|
-
const p = rowStart + 1 + x * 3;
|
|
172
|
-
raw[p] = r;
|
|
173
|
-
raw[p + 1] = g;
|
|
174
|
-
raw[p + 2] = b;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
const ihdr = Buffer.alloc(13);
|
|
178
|
-
ihdr.writeUInt32BE(w, 0);
|
|
179
|
-
ihdr.writeUInt32BE(h, 4);
|
|
180
|
-
ihdr[8] = 8; // bit depth
|
|
181
|
-
ihdr[9] = 2; // color type: truecolor RGB
|
|
182
|
-
const idat = zlib.deflateSync(raw, { level: 9 });
|
|
183
|
-
const textData = Buffer.concat([
|
|
184
|
-
Buffer.from('Comment', 'latin1'),
|
|
185
|
-
Buffer.from([0]),
|
|
186
|
-
Buffer.from(`SYNTHETIC COMP: ${String(prompt).replace(/\s+/g, ' ').trim()}`, 'latin1'),
|
|
187
|
-
]);
|
|
188
|
-
return Buffer.concat([
|
|
189
|
-
Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]),
|
|
190
|
-
pngChunk('IHDR', ihdr),
|
|
191
|
-
pngChunk('tEXt', textData),
|
|
192
|
-
pngChunk('IDAT', idat),
|
|
193
|
-
pngChunk('IEND', Buffer.alloc(0)),
|
|
194
|
-
]);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
function parseSize(sizeStr) {
|
|
198
|
-
const m = String(sizeStr).match(/^(\d+)x(\d+)$/);
|
|
199
|
-
if (!m) return [1536, 1024];
|
|
200
|
-
return [Number(m[1]), Number(m[2])];
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// ---------------------------------------------------------------------------
|
|
204
|
-
// Plate mode: one raster region of the measured spec -> a shipping plate.
|
|
205
|
-
// ---------------------------------------------------------------------------
|
|
206
|
-
const plateId = arg('plate');
|
|
207
|
-
let plateCtx = null;
|
|
208
|
-
if (plateId) {
|
|
209
|
-
const { loadSpec, platePrompt, plateReference, SPEC_PATH } = await import('./comp-spec.mjs');
|
|
210
|
-
const { decodePng, encodePng, loadRaster } = await import('./lib/png.mjs');
|
|
211
|
-
const { crop, resize } = await import('./lib/raster.mjs');
|
|
212
|
-
const specPath = arg('spec', SPEC_PATH);
|
|
213
|
-
const spec = loadSpec(specPath);
|
|
214
|
-
if (!spec) { console.error(`generate-image: no spec at ${specPath}; run comp-spec.mjs first`); process.exit(1); }
|
|
215
|
-
const region = spec.regions.find((r) => r.id === plateId);
|
|
216
|
-
if (!region) { console.error(`generate-image: no region ${plateId} in ${specPath}; ids: ${spec.regions.map((r) => r.id).join(', ')}`); process.exit(1); }
|
|
217
|
-
if (region.medium !== 'raster') { console.error(`generate-image: region ${plateId} is ${region.medium}, not a plate; set its kind to plate|image|texture in the regions file`); process.exit(1); }
|
|
218
|
-
let comp;
|
|
219
|
-
try { comp = loadRaster(spec.comp).image; } catch (e) { console.error(`generate-image: cannot read comp ${spec.comp}: ${e.message}`); process.exit(1); }
|
|
220
|
-
const ref = plateReference(comp, spec, region);
|
|
221
|
-
const refPath = path.join(path.dirname(specPath), 'crops', `${region.id}.png`);
|
|
222
|
-
fs.mkdirSync(path.dirname(refPath), { recursive: true });
|
|
223
|
-
fs.writeFileSync(refPath, encodePng(ref, { text: { 'impeccable:crop-of': `${spec.comp}#${region.id}` } }));
|
|
224
|
-
const out = arg('out', region.plate);
|
|
225
|
-
fs.mkdirSync(path.dirname(out), { recursive: true });
|
|
226
|
-
// Closest supported size to the region's aspect; the page crops the rest
|
|
227
|
-
// with object-fit. The plates gate demands >= 1.5x the region's width
|
|
228
|
-
// (capped at 1536), so a square region wider than 682px cannot ship from
|
|
229
|
-
// 1024x1024: take the 1536-wide landscape frame instead and let cover crop.
|
|
230
|
-
const aspect = region.px.w / region.px.h;
|
|
231
|
-
const needW = Math.min(1536, Math.ceil(region.px.w * 1.5));
|
|
232
|
-
let size = arg('size');
|
|
233
|
-
if (!size) {
|
|
234
|
-
if (aspect > 1.2) size = '1536x1024';
|
|
235
|
-
else if (aspect < 0.83) size = needW > 1024 ? '1536x1024' : '1024x1536';
|
|
236
|
-
else size = needW > 1024 ? '1536x1024' : '1024x1024';
|
|
237
|
-
}
|
|
238
|
-
const extra = arg('prompt') || (arg('prompt-file') ? fs.readFileSync(arg('prompt-file'), 'utf8') : '');
|
|
239
|
-
// Chroma: an ink-on-ground plate (a line drawing, a figure on flat ground)
|
|
240
|
-
// is generated on a flat key color and keyed to alpha, so the page's own
|
|
241
|
-
// ground shows through instead of a second, mismatched paper. Default on
|
|
242
|
-
// for kind plate when the comp region reads as ink over one flat ground;
|
|
243
|
-
// --chroma / --no-chroma force it.
|
|
244
|
-
const wantsChroma = process.argv.includes('--chroma') ? true : process.argv.includes('--no-chroma') ? false : (region.kind === 'plate' && inkOnGround(region));
|
|
245
|
-
const chromaColor = '#00ff00';
|
|
246
|
-
const chromaLine = wantsChroma ? ` Render the artwork on a perfectly flat, uniform bright green background (${chromaColor}) that fills every pixel not covered by the artwork; no paper texture, no vignette, no shadow on the green; the green will be removed and the artwork composited onto the page's own surface.` : '';
|
|
247
|
-
const prompt = [platePrompt(spec, region), extra, chromaLine].filter(Boolean).join(' ');
|
|
248
|
-
plateCtx = { spec, specPath, region, ref, refPath, out, size, prompt, comp, encodePng, resize, chroma: wantsChroma ? chromaColor : null };
|
|
249
|
-
if (process.env.IMPECCABLE_IMAGE_GEN_FAKE) {
|
|
250
|
-
const up = resize(ref, ref.width * 2, ref.height * 2);
|
|
251
|
-
fs.writeFileSync(out, encodePng(up, { text: { 'impeccable:prompt': prompt, 'impeccable:fake': '1' } }));
|
|
252
|
-
fs.writeFileSync(`${out}.json`, JSON.stringify({ prompt, createdAt: new Date().toISOString(), tool: 'generate-image.mjs', model: 'fake', plate: region.id, refs: [refPath] }, null, 2));
|
|
253
|
-
console.log(`PLATE: ${out} (${up.width}x${up.height}, fake 2x crop of region ${region.id}, $0.00, no API call)`);
|
|
254
|
-
process.exit(0);
|
|
255
|
-
}
|
|
256
|
-
// fall through to the real call below with the crop as the single --ref
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/** A region whose crop is dominated by one ground color with a dark second: ink on ground. */
|
|
260
|
-
function inkOnGround(region) {
|
|
261
|
-
const pal = region.palette || [];
|
|
262
|
-
if (pal.length < 2) return false;
|
|
263
|
-
return pal[0].coverage >= 0.55;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
function hexRgb(h) { const m = /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(h); return m ? [parseInt(m[1], 16), parseInt(m[2], 16), parseInt(m[3], 16)] : [0, 255, 0]; }
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* Key a flat color to alpha with a soft edge: pixels within `hard` of the key
|
|
270
|
-
* go fully transparent, within `soft` fade, and green spill on edge pixels is
|
|
271
|
-
* pulled toward the ink color. Writes back in place. Returns keyed fraction.
|
|
272
|
-
*/
|
|
273
|
-
async function keyChroma(file, keyHex) {
|
|
274
|
-
const { decodePng, encodePng } = await import('./lib/png.mjs');
|
|
275
|
-
const img = decodePng(fs.readFileSync(file));
|
|
276
|
-
const [kr, kg, kb] = hexRgb(keyHex);
|
|
277
|
-
// sample the actual key from the corners: generators shift the green
|
|
278
|
-
const corners = [[2, 2], [img.width - 3, 2], [2, img.height - 3], [img.width - 3, img.height - 3]];
|
|
279
|
-
let sr = 0, sg = 0, sb = 0;
|
|
280
|
-
for (const [x, y] of corners) { const p = (y * img.width + x) * 4; sr += img.data[p]; sg += img.data[p + 1]; sb += img.data[p + 2]; }
|
|
281
|
-
const key = [sr / 4, sg / 4, sb / 4];
|
|
282
|
-
const isGreenish = key[1] > 120 && key[1] > key[0] * 1.4 && key[1] > key[2] * 1.4;
|
|
283
|
-
const K = isGreenish ? key : [kr, kg, kb];
|
|
284
|
-
const hard = 60, soft = 120;
|
|
285
|
-
let keyed = 0;
|
|
286
|
-
for (let i = 0; i < img.data.length; i += 4) {
|
|
287
|
-
const r = img.data[i], g = img.data[i + 1], b = img.data[i + 2];
|
|
288
|
-
const d = Math.sqrt((r - K[0]) ** 2 + (g - K[1]) ** 2 + (b - K[2]) ** 2);
|
|
289
|
-
// also treat "greener than both other channels by a margin" as key, for gradients the generator adds
|
|
290
|
-
const greenDom = g > 150 && g - Math.max(r, b) > 60;
|
|
291
|
-
if (d < hard || greenDom) { img.data[i + 3] = 0; keyed++; continue; }
|
|
292
|
-
if (d < soft) {
|
|
293
|
-
const a = (d - hard) / (soft - hard);
|
|
294
|
-
img.data[i + 3] = Math.round(img.data[i + 3] * a);
|
|
295
|
-
// despill: pull green down to the mean of the others on the fringe
|
|
296
|
-
const m = (r + b) / 2; img.data[i + 1] = Math.round(g * a + m * (1 - a));
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
// keep the tEXt chunks (the embedded prompt written before keying)
|
|
300
|
-
fs.writeFileSync(file, encodePng(img, { text: img.text && Object.keys(img.text).length ? img.text : null }));
|
|
301
|
-
return keyed / (img.data.length / 4);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
async function scorePlate(ctx, outFile) {
|
|
305
|
-
try {
|
|
306
|
-
const { compare } = await import('./comp-diff.mjs');
|
|
307
|
-
const { decodePng } = await import('./lib/png.mjs');
|
|
308
|
-
let plate = decodePng(fs.readFileSync(outFile));
|
|
309
|
-
// a keyed plate ships over the page ground: composite it over the region's
|
|
310
|
-
// sampled ground before scoring, the way it will show
|
|
311
|
-
if (ctx.chroma) {
|
|
312
|
-
const { createImage, blit } = await import('./lib/raster.mjs');
|
|
313
|
-
const g = (ctx.region.palette && ctx.region.palette[0] && ctx.region.palette[0].hex) || '#ffffff';
|
|
314
|
-
const m = /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(g);
|
|
315
|
-
const ground = m ? [parseInt(m[1], 16), parseInt(m[2], 16), parseInt(m[3], 16), 255] : [255, 255, 255, 255];
|
|
316
|
-
const over = createImage(plate.width, plate.height, ground);
|
|
317
|
-
blit(over, plate, 0, 0);
|
|
318
|
-
plate = over;
|
|
319
|
-
}
|
|
320
|
-
// a plate ships under object-fit: cover, so score it the way it will show
|
|
321
|
-
const res = compare({ comp: ctx.ref, build: plate, align: 'cover', kind: ctx.region.kind });
|
|
322
|
-
const s = res.whole;
|
|
323
|
-
const min = arg('min') ? parseFloat(arg('min')) : null;
|
|
324
|
-
const line = `PLATE-SCORE ${ctx.region.id} ${(s.overall * 100).toFixed(0)}% against the comp region (structure ${(s.structure * 100).toFixed(0)}%, color ${(s.color * 100).toFixed(0)}%, detail ${(s.detail * 100).toFixed(0)}%)`;
|
|
325
|
-
console.log(line);
|
|
326
|
-
const { plateVerdict } = await import('./build-phase.mjs');
|
|
327
|
-
const v = plateVerdict(ctx.region, s);
|
|
328
|
-
if (!v.ok) console.log(`PLATE-WARN the plate does not read as region ${ctx.region.id}: ${v.reasons.join('; ')}. Open ${outFile} beside ${ctx.refPath} and regenerate before building on it; the plates gate refuses it as it stands.`);
|
|
329
|
-
if (min != null && s.overall < min) { console.log(`PLATE-REJECTED below --min ${(min * 100).toFixed(0)}%`); process.exit(3); }
|
|
330
|
-
} catch (e) {
|
|
331
|
-
console.log(`PLATE-SCORE unavailable: ${e.message}`);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// A comp written into .impeccable/mocks/ while a direction is dealt but the
|
|
336
|
-
// build phases never started is a comp round happening outside the state
|
|
337
|
-
// file, and every session cut after it resumes with no state to follow. The
|
|
338
|
-
// roll writes .impeccable/build/pending.json; build-phase.mjs start clears
|
|
339
|
-
// it. Refuse mock output until start has run (or --force-mock).
|
|
340
|
-
{
|
|
341
|
-
const outArg = arg('out') || (plateCtx && plateCtx.out) || '';
|
|
342
|
-
const intoMocks = /(^|[\\/])\.impeccable[\\/]mocks[\\/]/.test(outArg) && !/[\\/]decision[\\/]/.test(outArg);
|
|
343
|
-
const pending = fs.existsSync(path.join('.impeccable', 'build', 'pending.json'));
|
|
344
|
-
const state = fs.existsSync(path.join('.impeccable', 'build', 'state.json'));
|
|
345
|
-
if (intoMocks && pending && !state && !process.argv.includes('--force-mock')) {
|
|
346
|
-
console.error(`generate-image: a direction was chosen (concept-seed rolled) but build-phase.mjs start has not run, so this comp would be generated outside the build's state. Run: node ${path.dirname(fileURLToPath(import.meta.url))}/build-phase.mjs start --direction <seed key> --kind <assigned|pick|challenger|canon> first (it opens the comps phase), then generate. --force-mock overrides.`);
|
|
347
|
-
process.exit(4);
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
if (process.env.IMPECCABLE_IMAGE_GEN_FAKE) {
|
|
352
|
-
const fakePromptFile = arg('prompt-file');
|
|
353
|
-
const fakePrompt = fakePromptFile ? fs.readFileSync(fakePromptFile, 'utf8') : arg('prompt');
|
|
354
|
-
const fakeOut = arg('out');
|
|
355
|
-
if (!fakePrompt || !fakeOut) {
|
|
356
|
-
console.error('generate-image: --prompt (or --prompt-file) and --out are required.');
|
|
357
|
-
process.exit(1);
|
|
358
|
-
}
|
|
359
|
-
const dims = parseSize(arg('size', '1536x1024'));
|
|
360
|
-
const bytes = fakeOut.endsWith('.svg')
|
|
361
|
-
? Buffer.from(svgFake(fakePrompt, dims), 'utf8')
|
|
362
|
-
: pngFake(fakePrompt, dims);
|
|
363
|
-
fs.writeFileSync(fakeOut, bytes);
|
|
364
|
-
console.log(`IMAGE: ${fakeOut} (${dims[0]}x${dims[1]}, fake synthetic comp, $0.00, no API call)`);
|
|
365
|
-
process.exit(0);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
const key = process.env.OPENAI_API_KEY;
|
|
369
|
-
if (!key) {
|
|
370
|
-
console.error('generate-image: OPENAI_API_KEY is not set; use the harness-native image tool instead.');
|
|
371
|
-
process.exit(1);
|
|
372
|
-
}
|
|
373
|
-
const promptFile = arg('prompt-file');
|
|
374
|
-
const prompt = plateCtx ? plateCtx.prompt : (promptFile ? fs.readFileSync(promptFile, 'utf8') : arg('prompt'));
|
|
375
|
-
const out = plateCtx ? plateCtx.out : arg('out');
|
|
376
|
-
if (!prompt || !out) {
|
|
377
|
-
console.error('generate-image: --prompt (or --prompt-file) and --out are required.');
|
|
378
|
-
process.exit(1);
|
|
379
|
-
}
|
|
380
|
-
const size = plateCtx ? plateCtx.size : arg('size', '1536x1024');
|
|
381
|
-
const quality = arg('quality', plateCtx ? 'high' : 'medium');
|
|
382
|
-
// Reference images (--ref, repeatable): route through the edits endpoint,
|
|
383
|
-
// which accepts input images. This is how a comp for an established world
|
|
384
|
-
// inherits the real UI's identity from a captured screenshot instead of a
|
|
385
|
-
// prose paraphrase of it; the prompt then describes the NEW surface and the
|
|
386
|
-
// reference carries palette, type, and component character.
|
|
387
|
-
const refs = (() => {
|
|
388
|
-
const found = plateCtx ? [plateCtx.refPath] : [];
|
|
389
|
-
for (let i = 0; i < process.argv.length; i += 1) {
|
|
390
|
-
if (process.argv[i] === '--ref' && process.argv[i + 1] && !process.argv[i + 1].startsWith('--')) found.push(process.argv[i + 1]);
|
|
391
|
-
}
|
|
392
|
-
return found;
|
|
393
|
-
})();
|
|
394
|
-
|
|
395
|
-
let response;
|
|
396
|
-
if (refs.length) {
|
|
397
|
-
const form = new FormData();
|
|
398
|
-
form.append('model', 'gpt-image-2');
|
|
399
|
-
form.append('prompt', prompt);
|
|
400
|
-
form.append('size', size);
|
|
401
|
-
form.append('quality', quality);
|
|
402
|
-
form.append('n', '1');
|
|
403
|
-
for (const ref of refs) {
|
|
404
|
-
const bytes = fs.readFileSync(ref);
|
|
405
|
-
const type = ref.endsWith('.png') ? 'image/png' : ref.endsWith('.webp') ? 'image/webp' : 'image/jpeg';
|
|
406
|
-
form.append('image[]', new Blob([bytes], { type }), ref.split('/').pop());
|
|
407
|
-
}
|
|
408
|
-
response = await fetch('https://api.openai.com/v1/images/edits', {
|
|
409
|
-
method: 'POST',
|
|
410
|
-
headers: { Authorization: `Bearer ${key}` },
|
|
411
|
-
body: form,
|
|
412
|
-
});
|
|
413
|
-
} else {
|
|
414
|
-
response = await fetch('https://api.openai.com/v1/images/generations', {
|
|
415
|
-
method: 'POST',
|
|
416
|
-
headers: { Authorization: `Bearer ${key}`, 'content-type': 'application/json' },
|
|
417
|
-
body: JSON.stringify({ model: 'gpt-image-2', prompt, size, quality, n: 1 }),
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
if (!response.ok) {
|
|
421
|
-
console.error(`generate-image: API error ${response.status}: ${(await response.text()).slice(0, 300)}`);
|
|
422
|
-
process.exit(1);
|
|
423
|
-
}
|
|
424
|
-
const json = await response.json();
|
|
425
|
-
const b64 = json?.data?.[0]?.b64_json;
|
|
426
|
-
if (!b64) {
|
|
427
|
-
console.error('generate-image: no image in response');
|
|
428
|
-
process.exit(1);
|
|
429
|
-
}
|
|
430
|
-
fs.writeFileSync(out, Buffer.from(b64, 'base64'));
|
|
431
|
-
// The prompt travels with the asset: embedded in the file itself (EXIF-class
|
|
432
|
-
// metadata via embed-prompt.mjs) so intent survives copies across harnesses,
|
|
433
|
-
// plus a sidecar for anything that indexes rather than opens the image.
|
|
434
|
-
let embedded = false;
|
|
435
|
-
try {
|
|
436
|
-
const { spawnSync } = await import('node:child_process');
|
|
437
|
-
const result = spawnSync(process.execPath, [fileURLToPath(new URL('./embed-prompt.mjs', import.meta.url)), out, '--prompt', prompt], { stdio: 'ignore' });
|
|
438
|
-
embedded = !result.error && result.status === 0;
|
|
439
|
-
if (!embedded) console.warn('generate-image: failed to embed prompt in the image');
|
|
440
|
-
fs.writeFileSync(`${out}.json`, JSON.stringify({ prompt, createdAt: new Date().toISOString(), tool: 'generate-image.mjs', model: 'gpt-image-2', ...(refs.length ? { refs } : {}) }, null, 2));
|
|
441
|
-
} catch { /* embedding is best-effort */ }
|
|
442
|
-
console.log(`IMAGE: ${out} (${size}, ${quality}, gpt-image-2, billed to your OpenAI key); ${embedded ? 'prompt embedded + sidecar' : 'sidecar'} at ${out}.json`);
|
|
443
|
-
if (plateCtx && plateCtx.chroma) {
|
|
444
|
-
const frac = await keyChroma(out, plateCtx.chroma);
|
|
445
|
-
console.log(`PLATE-CHROMA keyed ${(frac * 100).toFixed(0)}% of pixels to alpha (${plateCtx.chroma}); place with a plain <img> over the page's own ground, no background on the plate. If the keyed fraction is under 20% the generator ignored the key: regenerate with --no-chroma and use mix-blend-mode: multiply instead.`);
|
|
446
|
-
}
|
|
447
|
-
if (plateCtx) await scorePlate(plateCtx, out);
|