@polishd/next 0.2.0 → 0.2.1-dev.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/CHANGELOG.md +35 -0
- package/README.md +37 -1
- package/dist/ai/actions.d.ts +7 -1
- package/dist/ai/actions.d.ts.map +1 -1
- package/dist/ai/actions.js +10 -0
- package/dist/ai/actions.js.map +1 -1
- package/dist/ai/design.d.ts +28 -0
- package/dist/ai/design.d.ts.map +1 -0
- package/dist/ai/design.js +245 -0
- package/dist/ai/design.js.map +1 -0
- package/dist/ai/types.d.ts +47 -0
- package/dist/ai/types.d.ts.map +1 -1
- package/dist/client/design-scan.d.ts +37 -0
- package/dist/client/design-scan.d.ts.map +1 -0
- package/dist/client/design-scan.js +319 -0
- package/dist/client/design-scan.js.map +1 -0
- package/dist/client/init.d.ts.map +1 -1
- package/dist/client/init.js +16 -0
- package/dist/client/init.js.map +1 -1
- package/dist/dashboard/design-review-card.d.ts +15 -0
- package/dist/dashboard/design-review-card.d.ts.map +1 -0
- package/dist/dashboard/design-review-card.js +82 -0
- package/dist/dashboard/design-review-card.js.map +1 -0
- package/dist/dashboard/design.d.ts +10 -0
- package/dist/dashboard/design.d.ts.map +1 -0
- package/dist/dashboard/design.js +83 -0
- package/dist/dashboard/design.js.map +1 -0
- package/dist/dashboard/index.d.ts +1 -0
- package/dist/dashboard/index.d.ts.map +1 -1
- package/dist/dashboard/index.js +34 -4
- package/dist/dashboard/index.js.map +1 -1
- package/dist/dashboard/journeys.d.ts.map +1 -1
- package/dist/dashboard/journeys.js +1 -0
- package/dist/dashboard/journeys.js.map +1 -1
- package/dist/dashboard.css +139 -0
- package/dist/server/design.d.ts +93 -0
- package/dist/server/design.d.ts.map +1 -0
- package/dist/server/design.js +430 -0
- package/dist/server/design.js.map +1 -0
- package/dist/server/ingest.d.ts.map +1 -1
- package/dist/server/ingest.js +9 -1
- package/dist/server/ingest.js.map +1 -1
- package/dist/shared/types.d.ts +31 -1
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/shared/types.js +1 -0
- package/dist/shared/types.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
### Design review — a new dashboard tab
|
|
6
|
+
|
|
7
|
+
The dashboard now has a sidebar with two tabs: **Analytics** (everything it
|
|
8
|
+
showed before) and **Design**, a new aesthetic layer. The Design tab renders
|
|
9
|
+
your site's brand guideline *reverse-engineered from the rendered pages*:
|
|
10
|
+
|
|
11
|
+
- **Typography** — every font family / size / weight combination actually in
|
|
12
|
+
use, shown as specimens with real text sampled from the site.
|
|
13
|
+
- **Color palette** — the colors your pages paint, laid out like a brand
|
|
14
|
+
palette and weighted by how much of the UI they cover, split by role
|
|
15
|
+
(text / background / border).
|
|
16
|
+
- **Contrast** — every text-on-background pairing measured against WCAG AA,
|
|
17
|
+
failures shown with live samples.
|
|
18
|
+
- **Corner radii and spacing** — the rounding and padding scales in use.
|
|
19
|
+
|
|
20
|
+
Each section flags what breaks the system deterministically — no model
|
|
21
|
+
involved: font-size sprawl (16 sizes is not a type scale), extra families,
|
|
22
|
+
near-duplicate colors (`#fefefe` next to `#ffffff`), contrast failures,
|
|
23
|
+
one-off values that appear on a single page, and padding that drifts off a
|
|
24
|
+
4px grid.
|
|
25
|
+
|
|
26
|
+
On top of the measured metrics, an **Aesthetic review** card asks the same
|
|
27
|
+
model you configured for the analytics summary how coherent the design reads
|
|
28
|
+
— strengths, and evidence-cited issues with concrete fixes. Like the summary,
|
|
29
|
+
it is fingerprint-cached: reopening the tab is free, and regenerating with
|
|
30
|
+
unchanged metrics never spends tokens. Refresh buttons for both the metrics
|
|
31
|
+
and the analysis sit on the tab.
|
|
32
|
+
|
|
33
|
+
Nothing new to wire up: pages measure their own rendered design once per
|
|
34
|
+
visitor session (a compact few-KB tally, sampled after the page settles) and
|
|
35
|
+
the data flows through the existing ingest route and store. The dashboard
|
|
36
|
+
itself is never scanned. Existing installs only need the new package version.
|
|
37
|
+
|
|
3
38
|
## 0.2.0
|
|
4
39
|
|
|
5
40
|
Everything in this release came out of the first real third-party integration of
|
package/README.md
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
Drop-in **product analytics** for Next.js (App Router). Capture real user
|
|
6
6
|
behavioral signals — rage clicks, dead clicks, scroll depth, JS errors, web
|
|
7
7
|
vitals, component engagement — and explore them on a built-in, Vercel-style
|
|
8
|
-
dashboard at `/polishd`.
|
|
8
|
+
dashboard at `/polishd`. A second **Design** tab reverse-engineers your site's
|
|
9
|
+
design system from the rendered pages — typography, palette, radii, spacing —
|
|
10
|
+
and flags what breaks it.
|
|
9
11
|
|
|
10
12
|
No third-party service. Events go to your own database: **SQLite in dev**
|
|
11
13
|
(zero-config, built into Node), **Postgres in production**. Anonymous by design —
|
|
@@ -360,6 +362,40 @@ authoritative context, so:
|
|
|
360
362
|
> provide. Your source is read only during an explicit scan (or a targeted
|
|
361
363
|
> gap-fill), and always under strict size budgets.
|
|
362
364
|
|
|
365
|
+
## Design review
|
|
366
|
+
|
|
367
|
+
The dashboard's **Design** tab (in the sidebar) is your site's brand guideline
|
|
368
|
+
reverse-engineered from what actually shipped. Every page measures its own
|
|
369
|
+
rendered design once per visitor session — the computed typography, colors,
|
|
370
|
+
corner radii and padding, reduced to a compact tally of a few KB — and the tab
|
|
371
|
+
assembles the site-wide picture:
|
|
372
|
+
|
|
373
|
+
- **Typography** — every font family / size / weight combination in use,
|
|
374
|
+
rendered as specimens with real text from your pages.
|
|
375
|
+
- **Color palette** — swatches weighted by how much of the UI each color
|
|
376
|
+
covers, split by role (text / background / border).
|
|
377
|
+
- **Contrast** — each text-on-background pairing checked against WCAG AA.
|
|
378
|
+
- **Corner radii & spacing** — the rounding and padding scales in use.
|
|
379
|
+
|
|
380
|
+
The first layer of review is **deterministic** — rule-based checks, no model:
|
|
381
|
+
too many font sizes to be a type scale, extra font families, near-duplicate
|
|
382
|
+
colors (`#fefefe` living next to `#ffffff`), contrast failures with the exact
|
|
383
|
+
ratio, one-off values that appear on a single page, padding off the 4px grid.
|
|
384
|
+
|
|
385
|
+
The second layer is the **Aesthetic review** card: the same model you
|
|
386
|
+
configured for the analytics summary reads the measured tokens and findings
|
|
387
|
+
and answers the real question — does this read as one deliberate design, or an
|
|
388
|
+
accumulation of one-off decisions? Issues it raises must cite a token that
|
|
389
|
+
actually appears in the metrics (a hex value, a px size, a page path), and each
|
|
390
|
+
comes with a concrete fix. It follows the summary's token-thrift rules: the
|
|
391
|
+
model sees a few hundred tokens of aggregated metrics, the result is cached and
|
|
392
|
+
fingerprinted, and regenerating over unchanged metrics is free. Refresh buttons
|
|
393
|
+
for both the metrics and the analysis are on the tab.
|
|
394
|
+
|
|
395
|
+
Nothing extra to install or wire: the scan ships with the existing client,
|
|
396
|
+
flows through the existing ingest route, and the dashboard itself is never
|
|
397
|
+
scanned.
|
|
398
|
+
|
|
363
399
|
## Component-level tracking
|
|
364
400
|
|
|
365
401
|
Wrap any element to track it explicitly. Interactive controls get hover + click
|
package/dist/ai/actions.d.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { type ListModelsInput, type SaveAISettingsInput } from "./settings";
|
|
2
|
-
import type { PolishdAISettingsPublic, PolishdLossItem, CreateIssueResult, GenerateProfileResult, GenerateSummaryResult, ListModelsResult, VerifyGithubResult } from "./types";
|
|
2
|
+
import type { PolishdAISettingsPublic, PolishdLossItem, CreateIssueResult, GenerateDesignReviewResult, GenerateProfileResult, GenerateSummaryResult, ListModelsResult, VerifyGithubResult } from "./types";
|
|
3
3
|
/** Generate or refresh the narrative. `force` re-asks the model even if data is unchanged. */
|
|
4
4
|
export declare function generateSummaryAction(force?: boolean): Promise<GenerateSummaryResult>;
|
|
5
|
+
/**
|
|
6
|
+
* Generate or refresh the aesthetic design review (the Design tab). Uses the
|
|
7
|
+
* same configured provider/model as the summary. `force` re-asks the model
|
|
8
|
+
* even when the design metrics haven't changed.
|
|
9
|
+
*/
|
|
10
|
+
export declare function generateDesignReviewAction(force?: boolean): Promise<GenerateDesignReviewResult>;
|
|
5
11
|
/** Persist provider/model/key/instructions/context; returns the no-secret view. */
|
|
6
12
|
export declare function saveAISettingsAction(input: SaveAISettingsInput): Promise<PolishdAISettingsPublic>;
|
|
7
13
|
/**
|
package/dist/ai/actions.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/ai/actions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/ai/actions.ts"],"names":[],"mappings":"AAqBA,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACzB,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EACV,uBAAuB,EACvB,eAAe,EACf,iBAAiB,EACjB,0BAA0B,EAC1B,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,SAAS,CAAC;AAEjB,8FAA8F;AAC9F,wBAAsB,qBAAqB,CAAC,KAAK,UAAQ,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAGzF;AAED;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC9C,KAAK,UAAQ,GACZ,OAAO,CAAC,0BAA0B,CAAC,CAGrC;AAED,mFAAmF;AACnF,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,mBAAmB,GACzB,OAAO,CAAC,uBAAuB,CAAC,CAGlC;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAI5E;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAGxF;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAGtE;AAED;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,OAAO,GAAG,UAAU,GAAG,UAAU,CAAC,GAC7D,OAAO,CAAC,iBAAiB,CAAC,CAG5B"}
|
package/dist/ai/actions.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* re-runs that same callback against the caller's cookies on every call.
|
|
14
14
|
*/
|
|
15
15
|
import { requirePolishdAuth } from "./guard";
|
|
16
|
+
import { generateDesignReview } from "./design";
|
|
16
17
|
import { verifyGithubConnection } from "./github";
|
|
17
18
|
import { createIssueFromLoss } from "./issues";
|
|
18
19
|
import { generateProjectProfile } from "./profile";
|
|
@@ -24,6 +25,15 @@ export async function generateSummaryAction(force = false) {
|
|
|
24
25
|
await requirePolishdAuth();
|
|
25
26
|
return generateSummary({ force });
|
|
26
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Generate or refresh the aesthetic design review (the Design tab). Uses the
|
|
30
|
+
* same configured provider/model as the summary. `force` re-asks the model
|
|
31
|
+
* even when the design metrics haven't changed.
|
|
32
|
+
*/
|
|
33
|
+
export async function generateDesignReviewAction(force = false) {
|
|
34
|
+
await requirePolishdAuth();
|
|
35
|
+
return generateDesignReview({ force });
|
|
36
|
+
}
|
|
27
37
|
/** Persist provider/model/key/instructions/context; returns the no-secret view. */
|
|
28
38
|
export async function saveAISettingsAction(input) {
|
|
29
39
|
await requirePolishdAuth();
|
package/dist/ai/actions.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.js","sourceRoot":"","sources":["../../src/ai/actions.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EACL,qBAAqB,EACrB,cAAc,GAGf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"actions.js","sourceRoot":"","sources":["../../src/ai/actions.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EACL,qBAAqB,EACrB,cAAc,GAGf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAY5C,8FAA8F;AAC9F,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,KAAK,GAAG,KAAK;IACvD,MAAM,kBAAkB,EAAE,CAAC;IAC3B,OAAO,eAAe,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AACpC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,KAAK,GAAG,KAAK;IAEb,MAAM,kBAAkB,EAAE,CAAC;IAC3B,OAAO,oBAAoB,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AACzC,CAAC;AAED,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,KAA0B;IAE1B,MAAM,kBAAkB,EAAE,CAAC;IAC3B,OAAO,cAAc,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,kBAAkB,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,MAAM,wBAAwB,EAAE,CAAC;IAC9C,OAAO,sBAAsB,CAAC,IAAI,CAAC,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAsB;IAC3D,MAAM,kBAAkB,EAAE,CAAC;IAC3B,OAAO,qBAAqB,CAAC,KAAK,CAAC,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,kBAAkB,EAAE,CAAC;IAC3B,OAAO,sBAAsB,EAAE,CAAC;AAClC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,IAA8D;IAE9D,MAAM,kBAAkB,EAAE,CAAC;IAC3B,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type PolishdDesignData } from "../server/design";
|
|
2
|
+
import type { GenerateDesignReviewResult, PolishdDesignReview } from "./types";
|
|
3
|
+
/** The last generated review, or null. Read-only — never calls a model. */
|
|
4
|
+
export declare function loadDesignReview(): Promise<PolishdDesignReview | null>;
|
|
5
|
+
/**
|
|
6
|
+
* Render the aggregated design data as a terse, model-readable brief.
|
|
7
|
+
* Sections are omitted when empty so the prompt only carries real signal.
|
|
8
|
+
*/
|
|
9
|
+
export declare function buildDesignDigest(data: PolishdDesignData, context?: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Generate (or reuse) the design review.
|
|
12
|
+
*
|
|
13
|
+
* @param force When false (default), a review whose fingerprint matches the
|
|
14
|
+
* current metrics is returned as-is — no model call. When true,
|
|
15
|
+
* always re-asks the model.
|
|
16
|
+
*/
|
|
17
|
+
export declare function generateDesignReview(opts?: {
|
|
18
|
+
force?: boolean;
|
|
19
|
+
}): Promise<GenerateDesignReviewResult>;
|
|
20
|
+
/**
|
|
21
|
+
* For the Design tab's first render: the cached review plus whether the live
|
|
22
|
+
* metrics have drifted from it. Only reads the store; never calls a model.
|
|
23
|
+
*/
|
|
24
|
+
export declare function loadDesignReviewState(preloaded?: PolishdDesignData): Promise<{
|
|
25
|
+
review: PolishdDesignReview | null;
|
|
26
|
+
stale: boolean;
|
|
27
|
+
}>;
|
|
28
|
+
//# sourceMappingURL=design.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design.d.ts","sourceRoot":"","sources":["../../src/ai/design.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAiB,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAIzE,OAAO,KAAK,EACV,0BAA0B,EAE1B,mBAAmB,EACpB,MAAM,SAAS,CAAC;AAIjB,2EAA2E;AAC3E,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAQ5E;AAsBD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,iBAAiB,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAmEnF;AAgED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC7B,OAAO,CAAC,0BAA0B,CAAC,CAgErC;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,SAAS,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC;IAClF,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACnC,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC,CASD"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Polishd — AI design review orchestration (server only).
|
|
3
|
+
*
|
|
4
|
+
* The Design tab's second layer. The first layer is deterministic
|
|
5
|
+
* (server/design.ts): measured typography, palette, radii, spacing, and
|
|
6
|
+
* rule-based flags. This module renders those metrics as a compact digest and
|
|
7
|
+
* asks the owner's configured model — the same provider, model, and key the
|
|
8
|
+
* analytics summary uses — for an aesthetic read: how coherent the design is,
|
|
9
|
+
* what works, and what specifically breaks the system.
|
|
10
|
+
*
|
|
11
|
+
* Token thrift mirrors summary.ts: the model sees aggregated tokens (a few
|
|
12
|
+
* hundred tokens for the whole site), never raw scans; the digest is
|
|
13
|
+
* fingerprinted and the review cached, so reopening the tab is free and a
|
|
14
|
+
* regenerate with unchanged metrics returns the cached text without a call.
|
|
15
|
+
*/
|
|
16
|
+
import { getMeta, setMeta } from "../server/store";
|
|
17
|
+
import { getDesignData } from "../server/design";
|
|
18
|
+
import { fingerprintDigest } from "./digest";
|
|
19
|
+
import { callModel } from "./providers";
|
|
20
|
+
import { resolveSettings } from "./settings";
|
|
21
|
+
const DESIGN_REVIEW_KEY = "ai_design_review";
|
|
22
|
+
/** The last generated review, or null. Read-only — never calls a model. */
|
|
23
|
+
export async function loadDesignReview() {
|
|
24
|
+
const raw = await getMeta(DESIGN_REVIEW_KEY);
|
|
25
|
+
if (!raw)
|
|
26
|
+
return null;
|
|
27
|
+
try {
|
|
28
|
+
return JSON.parse(raw);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const SYSTEM_PROMPT = "You are a senior brand and product designer reviewing a shipped website. " +
|
|
35
|
+
"You receive design tokens reverse-engineered from the rendered pages — the " +
|
|
36
|
+
"typography, color palette, corner radii and spacing actually in use, plus " +
|
|
37
|
+
"deterministic findings from rule-based checks. You never see screenshots; " +
|
|
38
|
+
"judge coherence from the system the numbers describe.\n\n" +
|
|
39
|
+
"Respond with ONLY a JSON object (no markdown fences, no preamble):\n" +
|
|
40
|
+
'{ "assessment": string, "strengths": string[], "issues": [{ "issue": string, "evidence": string, "suggestion": string }] }\n\n' +
|
|
41
|
+
"assessment: one tight paragraph (3-5 sentences) on how coherent and " +
|
|
42
|
+
"tasteful the design system reads — does it feel like one deliberate brand, " +
|
|
43
|
+
"or an accumulation of one-off decisions? Name the strongest and weakest " +
|
|
44
|
+
"aspects. If the data covers too few pages to be confident, say so.\n" +
|
|
45
|
+
"strengths: 2-4 things the design gets right (a disciplined palette, a " +
|
|
46
|
+
"clear type hierarchy, consistent radii…).\n" +
|
|
47
|
+
"issues: 0-5 specific aesthetic problems, worst first. Each issue must be " +
|
|
48
|
+
"concrete, evidence must be an exact token copied verbatim from the metrics " +
|
|
49
|
+
"(a hex color, a px value, a page path), and suggestion must be an " +
|
|
50
|
+
"actionable fix (e.g. 'collapse 15px and 17px into the 16px body size'). " +
|
|
51
|
+
"Never invent an issue: if the system is genuinely coherent, return fewer.";
|
|
52
|
+
/**
|
|
53
|
+
* Render the aggregated design data as a terse, model-readable brief.
|
|
54
|
+
* Sections are omitted when empty so the prompt only carries real signal.
|
|
55
|
+
*/
|
|
56
|
+
export function buildDesignDigest(data, context) {
|
|
57
|
+
const lines = [];
|
|
58
|
+
if (context && context.trim())
|
|
59
|
+
lines.push(`SITE: ${context.trim()}`);
|
|
60
|
+
lines.push(`SCANNED: ${data.pages.length} pages (${data.pages
|
|
61
|
+
.slice(0, 10)
|
|
62
|
+
.map((p) => p.path)
|
|
63
|
+
.join(", ")}${data.pages.length > 10 ? ", …" : ""}).`);
|
|
64
|
+
if (data.families.length) {
|
|
65
|
+
lines.push("FONT FAMILIES: " + data.families.map((f) => `${f.family} (${f.count} uses)`).join(", "));
|
|
66
|
+
}
|
|
67
|
+
if (data.fonts.length) {
|
|
68
|
+
lines.push("TYPE STYLES (family size/weight — uses, tags):");
|
|
69
|
+
for (const f of data.fonts.slice(0, 20)) {
|
|
70
|
+
lines.push(` - ${f.family} ${f.sizePx}px/${f.weight}: ${f.count} uses, ${f.pages.length} pages` +
|
|
71
|
+
`${f.tags.length ? ` (${f.tags.join(",")})` : ""}${f.outlier ? " [one-off]" : ""}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (data.colors.length) {
|
|
75
|
+
lines.push("PALETTE (share of all color usage):");
|
|
76
|
+
for (const c of data.colors.slice(0, 20)) {
|
|
77
|
+
const roles = Object.entries(c.roles)
|
|
78
|
+
.filter(([, n]) => n > 0)
|
|
79
|
+
.map(([r]) => r)
|
|
80
|
+
.join("/");
|
|
81
|
+
lines.push(` - ${c.hex}: ${c.pct}% (${roles})${c.outlier ? " [one-off]" : ""}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const failing = data.contrast.filter((p) => !p.passes);
|
|
85
|
+
if (failing.length) {
|
|
86
|
+
lines.push("CONTRAST FAILURES (WCAG AA):");
|
|
87
|
+
for (const p of failing.slice(0, 6)) {
|
|
88
|
+
lines.push(` - ${p.fg} on ${p.bg}: ${p.ratio}:1 at ${p.minSizePx}px (needs ${p.required}:1)`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (data.radii.length) {
|
|
92
|
+
lines.push("CORNER RADII: " + data.radii.map((r) => `${r.value} ×${r.count}${r.outlier ? " [one-off]" : ""}`).join(", "));
|
|
93
|
+
}
|
|
94
|
+
if (data.spacing.length) {
|
|
95
|
+
lines.push("PADDING VALUES (px ×uses): " +
|
|
96
|
+
data.spacing
|
|
97
|
+
.slice(0, 18)
|
|
98
|
+
.map((s) => `${s.px} ×${s.count}${s.offGrid ? "*" : ""}`)
|
|
99
|
+
.join(", ") +
|
|
100
|
+
" (* = off the 4px grid)");
|
|
101
|
+
}
|
|
102
|
+
if (data.flags.length) {
|
|
103
|
+
lines.push("RULE-BASED FINDINGS:");
|
|
104
|
+
for (const f of data.flags)
|
|
105
|
+
lines.push(` - [${f.section}] ${f.message}`);
|
|
106
|
+
}
|
|
107
|
+
return lines.join("\n");
|
|
108
|
+
}
|
|
109
|
+
/** Parse the model's JSON, tolerating fences/prose; fall back to plain text. */
|
|
110
|
+
function parseStructured(text) {
|
|
111
|
+
let t = text.trim();
|
|
112
|
+
const fence = t.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
113
|
+
if (fence)
|
|
114
|
+
t = fence[1].trim();
|
|
115
|
+
const start = t.indexOf("{");
|
|
116
|
+
const end = t.lastIndexOf("}");
|
|
117
|
+
if (start >= 0 && end > start) {
|
|
118
|
+
try {
|
|
119
|
+
const obj = JSON.parse(t.slice(start, end + 1));
|
|
120
|
+
const assessment = typeof obj.assessment === "string" ? obj.assessment.trim() : "";
|
|
121
|
+
if (assessment) {
|
|
122
|
+
const strengths = Array.isArray(obj.strengths)
|
|
123
|
+
? obj.strengths.filter((s) => typeof s === "string" && s.trim().length > 0).slice(0, 4)
|
|
124
|
+
: [];
|
|
125
|
+
const issues = Array.isArray(obj.issues) ? obj.issues.slice(0, 8) : [];
|
|
126
|
+
return { assessment, strengths, issues };
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
/* fall through */
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return { assessment: text.trim(), strengths: [], issues: [] };
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Hold issues to their evidence bar: the citation must literally appear in
|
|
137
|
+
* the digest we sent, so the model can't critique a color that isn't there.
|
|
138
|
+
*/
|
|
139
|
+
function verifyIssues(raw, digest) {
|
|
140
|
+
const hay = digest.toLowerCase();
|
|
141
|
+
const out = [];
|
|
142
|
+
for (const r of raw) {
|
|
143
|
+
if (typeof r.issue !== "string" || !r.issue.trim())
|
|
144
|
+
continue;
|
|
145
|
+
const evidence = typeof r.evidence === "string" ? r.evidence.trim() : "";
|
|
146
|
+
if (!evidence)
|
|
147
|
+
continue;
|
|
148
|
+
const tokens = evidence
|
|
149
|
+
.toLowerCase()
|
|
150
|
+
.split(/[^\w#/.-]+/)
|
|
151
|
+
.filter((t) => t.length >= 3);
|
|
152
|
+
if (!tokens.length || !tokens.some((t) => hay.includes(t)))
|
|
153
|
+
continue;
|
|
154
|
+
out.push({
|
|
155
|
+
issue: r.issue.trim(),
|
|
156
|
+
evidence,
|
|
157
|
+
suggestion: typeof r.suggestion === "string" && r.suggestion.trim() ? r.suggestion.trim() : undefined,
|
|
158
|
+
});
|
|
159
|
+
if (out.length >= 5)
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
return out;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Generate (or reuse) the design review.
|
|
166
|
+
*
|
|
167
|
+
* @param force When false (default), a review whose fingerprint matches the
|
|
168
|
+
* current metrics is returned as-is — no model call. When true,
|
|
169
|
+
* always re-asks the model.
|
|
170
|
+
*/
|
|
171
|
+
export async function generateDesignReview(opts = {}) {
|
|
172
|
+
const { settings } = await resolveSettings();
|
|
173
|
+
if (!settings.apiKey) {
|
|
174
|
+
return { ok: false, error: "no-key", message: "No API key configured." };
|
|
175
|
+
}
|
|
176
|
+
const data = await getDesignData();
|
|
177
|
+
if (!data.ready || data.pages.length === 0) {
|
|
178
|
+
return {
|
|
179
|
+
ok: false,
|
|
180
|
+
error: "no-data",
|
|
181
|
+
message: "No pages scanned yet — browse the site, then refresh.",
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
const digest = buildDesignDigest(data, settings.context);
|
|
185
|
+
const fingerprint = fingerprintDigest(digest);
|
|
186
|
+
if (!opts.force) {
|
|
187
|
+
const cached = await loadDesignReview();
|
|
188
|
+
if (cached && cached.fingerprint === fingerprint) {
|
|
189
|
+
return { ok: true, review: cached, regenerated: false };
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const system = settings.instructions
|
|
193
|
+
? `${SYSTEM_PROMPT}\n\nAdditional instructions from the site owner: ${settings.instructions}`
|
|
194
|
+
: SYSTEM_PROMPT;
|
|
195
|
+
let reply;
|
|
196
|
+
try {
|
|
197
|
+
reply = await callModel(settings, system, digest);
|
|
198
|
+
}
|
|
199
|
+
catch (err) {
|
|
200
|
+
return {
|
|
201
|
+
ok: false,
|
|
202
|
+
error: "provider-error",
|
|
203
|
+
message: err instanceof Error ? err.message : "The model request failed.",
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
if (!reply.text) {
|
|
207
|
+
return { ok: false, error: "provider-error", message: "The model returned an empty response." };
|
|
208
|
+
}
|
|
209
|
+
if (reply.truncated) {
|
|
210
|
+
return {
|
|
211
|
+
ok: false,
|
|
212
|
+
error: "provider-error",
|
|
213
|
+
message: "The model's response was cut off at the output limit, twice. Try a model that reasons less, or regenerate.",
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
const parsed = parseStructured(reply.text);
|
|
217
|
+
const review = {
|
|
218
|
+
text: parsed.assessment,
|
|
219
|
+
strengths: parsed.strengths,
|
|
220
|
+
issues: verifyIssues(parsed.issues, digest),
|
|
221
|
+
provider: settings.provider,
|
|
222
|
+
model: settings.model,
|
|
223
|
+
generatedAt: Date.now(),
|
|
224
|
+
fingerprint,
|
|
225
|
+
usage: reply.usage,
|
|
226
|
+
};
|
|
227
|
+
await setMeta(DESIGN_REVIEW_KEY, JSON.stringify(review));
|
|
228
|
+
return { ok: true, review, regenerated: true };
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* For the Design tab's first render: the cached review plus whether the live
|
|
232
|
+
* metrics have drifted from it. Only reads the store; never calls a model.
|
|
233
|
+
*/
|
|
234
|
+
export async function loadDesignReviewState(preloaded) {
|
|
235
|
+
const [review, data] = await Promise.all([
|
|
236
|
+
loadDesignReview(),
|
|
237
|
+
preloaded ? Promise.resolve(preloaded) : getDesignData(),
|
|
238
|
+
]);
|
|
239
|
+
if (!data.ready || data.pages.length === 0)
|
|
240
|
+
return { review, stale: false };
|
|
241
|
+
const { settings } = await resolveSettings();
|
|
242
|
+
const fingerprint = fingerprintDigest(buildDesignDigest(data, settings.context));
|
|
243
|
+
return { review, stale: review !== null && review.fingerprint !== fingerprint };
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=design.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design.js","sourceRoot":"","sources":["../../src/ai/design.ts"],"names":[],"mappings":"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"}
|
package/dist/ai/types.d.ts
CHANGED
|
@@ -151,6 +151,53 @@ export type GenerateSummaryResult = {
|
|
|
151
151
|
message: string;
|
|
152
152
|
};
|
|
153
153
|
export type GenerateSummaryError = "no-key" | "no-data" | "provider-error";
|
|
154
|
+
/**
|
|
155
|
+
* One aesthetic problem the model called out. `evidence` must be a concrete
|
|
156
|
+
* token from the design digest (a hex color, a px value, a page path) — the
|
|
157
|
+
* same citation bar the summary's losses are held to, so a review can't
|
|
158
|
+
* invent a color the site never renders.
|
|
159
|
+
*/
|
|
160
|
+
export interface PolishdDesignIssue {
|
|
161
|
+
/** The problem, in plain English. */
|
|
162
|
+
issue: string;
|
|
163
|
+
/** The token from the metrics that shows it (hex, px value, page path). */
|
|
164
|
+
evidence: string;
|
|
165
|
+
/** A concrete fix, when the model offered one. */
|
|
166
|
+
suggestion?: string;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* The model's aesthetic read of the deterministic design metrics — generated
|
|
170
|
+
* by the same provider/model the owner configured for the analytics summary,
|
|
171
|
+
* cached in the store, and refreshed only on demand or when the metrics change.
|
|
172
|
+
*/
|
|
173
|
+
export interface PolishdDesignReview {
|
|
174
|
+
/** The overall assessment — how coherent and tasteful the design reads. */
|
|
175
|
+
text: string;
|
|
176
|
+
/** What the design gets right. */
|
|
177
|
+
strengths?: string[];
|
|
178
|
+
/** Specific, evidence-cited aesthetic problems. */
|
|
179
|
+
issues?: PolishdDesignIssue[];
|
|
180
|
+
provider: PolishdAIProvider;
|
|
181
|
+
model: string;
|
|
182
|
+
generatedAt: number;
|
|
183
|
+
/** Hash of the design digest it was generated from — drives staleness. */
|
|
184
|
+
fingerprint: string;
|
|
185
|
+
usage?: {
|
|
186
|
+
inputTokens?: number;
|
|
187
|
+
outputTokens?: number;
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/** Result of a design review attempt, returned to the dashboard. */
|
|
191
|
+
export type GenerateDesignReviewResult = {
|
|
192
|
+
ok: true;
|
|
193
|
+
review: PolishdDesignReview;
|
|
194
|
+
regenerated: boolean;
|
|
195
|
+
} | {
|
|
196
|
+
ok: false;
|
|
197
|
+
error: GenerateDesignReviewError;
|
|
198
|
+
message: string;
|
|
199
|
+
};
|
|
200
|
+
export type GenerateDesignReviewError = "no-key" | "no-data" | "provider-error";
|
|
154
201
|
/**
|
|
155
202
|
* What the configured token can actually do against the configured repo,
|
|
156
203
|
* checked live during onboarding. `contents` (read) powers source reading;
|
package/dist/ai/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ai/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ai/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Polishd — client design scanner.
|
|
3
|
+
*
|
|
4
|
+
* Samples the *rendered* page — computed styles, not source CSS — and reduces
|
|
5
|
+
* it to compact tallies: which font family/size/weight combinations actually
|
|
6
|
+
* appear, which colors paint text/backgrounds/borders, which text-on-background
|
|
7
|
+
* pairs exist (for contrast checking), and which radii and paddings the page
|
|
8
|
+
* really uses. This is the deterministic half of the dashboard's Design tab:
|
|
9
|
+
* reverse-engineering the design system out of the built site.
|
|
10
|
+
*
|
|
11
|
+
* Deliberately tally-based: a page emits one `design_scan` event of a few KB,
|
|
12
|
+
* never per-element rows. Scanning runs once per session per path, after the
|
|
13
|
+
* page has settled, and only when the tab is visible (a background prerender
|
|
14
|
+
* has no layout worth measuring).
|
|
15
|
+
*/
|
|
16
|
+
import type { PolishdDesignScanPayload } from "../shared/types";
|
|
17
|
+
/**
|
|
18
|
+
* Parse a computed color into `#rrggbb` / `#rrggbbaa`, or null when fully
|
|
19
|
+
* transparent or in a syntax we don't recognize (rare wide-gamut outputs are
|
|
20
|
+
* skipped rather than guessed at).
|
|
21
|
+
*/
|
|
22
|
+
export declare function normalizeColor(value: string): string | null;
|
|
23
|
+
/**
|
|
24
|
+
* Walk the page and reduce it to design tallies. Pure DOM reads — call it when
|
|
25
|
+
* the page has settled. Returns null when there is nothing measurable.
|
|
26
|
+
*/
|
|
27
|
+
export declare function collectDesignScan(root?: Element): PolishdDesignScanPayload | null;
|
|
28
|
+
/** Serialize, shrinking the longest lists if a pathological page overflows. */
|
|
29
|
+
export declare function serializeDesignScan(payload: PolishdDesignScanPayload): string;
|
|
30
|
+
/**
|
|
31
|
+
* Scan `path` once per session, after the page settles, and hand the payload
|
|
32
|
+
* to `emit`. Skips silently when the tab is hidden at fire time (layout of a
|
|
33
|
+
* backgrounded prerender isn't the design anyone sees) — a later visit to the
|
|
34
|
+
* same path in this session will still be un-scanned and retry.
|
|
35
|
+
*/
|
|
36
|
+
export declare function scheduleDesignScan(path: string, emit: (payloadJson: string, elements: number) => void, delayMs?: number): void;
|
|
37
|
+
//# sourceMappingURL=design-scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design-scan.d.ts","sourceRoot":"","sources":["../../src/client/design-scan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAMV,wBAAwB,EACzB,MAAM,iBAAiB,CAAC;AA0BzB;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAiB3D;AAyCD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,OAAuB,GAAG,wBAAwB,GAAG,IAAI,CAqKhG;AAED,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CAe7E;AAID;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,EACrD,OAAO,SAAO,GACb,IAAI,CAyCN"}
|