synthesisui 0.16.504 → 0.16.505
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/read.js +8 -45
- package/dist/reading/read-page.js +93 -0
- package/dist/reading/reread.js +2 -1
- package/package.json +1 -1
package/dist/commands/read.js
CHANGED
|
@@ -5,10 +5,8 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, wri
|
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
import { homedir } from "node:os";
|
|
7
7
|
import { join, relative } from "node:path";
|
|
8
|
-
import {
|
|
9
|
-
import { PAGE_SCRIPT } from "../reading/page-script.js";
|
|
8
|
+
import { readSite } from "../reading/read-page.js";
|
|
10
9
|
import { headingsOf } from "../reading/reread.js";
|
|
11
|
-
import { decodePng } from "../reading/png.js";
|
|
12
10
|
import { PENDING, globalClassOf, loadRoleRules, globalStyles, moduleClassName, pxOf, readPending } from "../role-rules.js";
|
|
13
11
|
import { agentsToMaintain } from "../agents-chosen.js";
|
|
14
12
|
import { syncClaudeMd } from "../claude-md.js";
|
|
@@ -29,10 +27,7 @@ import { projectRootFrom } from "./hook.js";
|
|
|
29
27
|
*/
|
|
30
28
|
const READER_VERSION = "1.58.2";
|
|
31
29
|
const READER_DIR = join(homedir(), ".synthesisui", "reader");
|
|
32
|
-
export
|
|
33
|
-
["desktop", 1440, 900],
|
|
34
|
-
["celular", 390, 844],
|
|
35
|
-
];
|
|
30
|
+
export { VIEWPORTS, confirmByPixels } from "../reading/read-page.js";
|
|
36
31
|
/** `download: false` é o fim do turno: ele nunca baixa nada sozinho - sem o leitor na máquina, não relê (E01, fase 3). */
|
|
37
32
|
export function loadReader(say, download = true) {
|
|
38
33
|
const override = process.env.SYNTHESISUI_PLAYWRIGHT;
|
|
@@ -93,26 +88,6 @@ export async function findServer(url, root, waitMs = 4000) {
|
|
|
93
88
|
}
|
|
94
89
|
return null;
|
|
95
90
|
}
|
|
96
|
-
/**
|
|
97
|
-
* CADA CONTRASTE BAIXO CONFERIDO PELOS PIXELS: sem tinta é texto não pintado; acima do alvo, o DOM errou o fundo. A mesma
|
|
98
|
-
* conferência na leitura e no fim do turno (E01 da fase 3) - duas cópias divergiriam no primeiro conserto.
|
|
99
|
-
*/
|
|
100
|
-
export async function confirmByPixels(found, pageOf) {
|
|
101
|
-
const confirmed = [];
|
|
102
|
-
for (const f of found) {
|
|
103
|
-
const page = pageOf(f.sample);
|
|
104
|
-
let px = null;
|
|
105
|
-
if (page && f.sample.w >= 2 && f.sample.h >= 2) {
|
|
106
|
-
const png = await page.screenshot({ fullPage: true, clip: { x: Math.max(0, f.sample.x), y: Math.max(0, f.sample.y), width: f.sample.w, height: f.sample.h } }).catch(() => null);
|
|
107
|
-
const rgba = png ? decodePng(png) : null;
|
|
108
|
-
px = rgba ? pixelRatio(rgba) : null;
|
|
109
|
-
}
|
|
110
|
-
if (px !== null && (px < 1.2 || px >= f.alvo))
|
|
111
|
-
continue;
|
|
112
|
-
confirmed.push({ ...f, pixels: px });
|
|
113
|
-
}
|
|
114
|
-
return confirmed;
|
|
115
|
-
}
|
|
116
91
|
/** O maior tamanho entre as classes de um texto (o do desktop), sem o prefixo de tela - a mesma escolha da checagem. */
|
|
117
92
|
function sizeClassOf(cls) {
|
|
118
93
|
const toks = cls.match(/(?:[a-z0-9]+:)?text-(?:\[(?:clamp\([^\]\s]+\)|[\d.]+(?:rem|px|em))\]|xs|sm|base|lg|[2-9]?xl)(?=\s|$|\|)/g) ?? [];
|
|
@@ -372,23 +347,12 @@ export async function read(opts) {
|
|
|
372
347
|
const routes = opts.routes?.length ? opts.routes : ["/"];
|
|
373
348
|
const pw = loadReader(say);
|
|
374
349
|
const browser = (await launch(pw, say));
|
|
375
|
-
const
|
|
376
|
-
|
|
350
|
+
const site = await readSite(browser, base, routes).catch(async (e) => {
|
|
351
|
+
await browser.close().catch(() => { });
|
|
352
|
+
throw e;
|
|
353
|
+
});
|
|
354
|
+
const { reading, seen } = site;
|
|
377
355
|
try {
|
|
378
|
-
for (const rota of routes) {
|
|
379
|
-
for (const [disp, w, h] of VIEWPORTS) {
|
|
380
|
-
const ctx = await browser.newContext({ viewport: { width: w, height: h }, reducedMotion: "reduce" });
|
|
381
|
-
const page = await ctx.newPage();
|
|
382
|
-
await page.goto(new URL(rota, base).href, { waitUntil: "networkidle", timeout: 90_000 });
|
|
383
|
-
await page.waitForTimeout(800);
|
|
384
|
-
const textos = (await page.evaluate(PAGE_SCRIPT));
|
|
385
|
-
for (const t of textos)
|
|
386
|
-
seen.push({ ...t, rota, disp });
|
|
387
|
-
pages.set(`${rota}|${disp}`, { page, ctx });
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
const reading = classify(seen);
|
|
391
|
-
reading.contraste = await confirmByPixels(reading.contraste, (t) => pages.get(`${t.rota}|${t.disp}`)?.page);
|
|
392
356
|
const files = sources(root);
|
|
393
357
|
const home = (t) => homeOf(root, files, t);
|
|
394
358
|
const out = {
|
|
@@ -436,8 +400,7 @@ export async function read(opts) {
|
|
|
436
400
|
say(`\n Written to _synthesisui/reading.json. Nothing in your code changed.`);
|
|
437
401
|
}
|
|
438
402
|
finally {
|
|
439
|
-
|
|
440
|
-
await ctx.close().catch(() => { });
|
|
403
|
+
await site.close();
|
|
441
404
|
await browser.close().catch(() => { });
|
|
442
405
|
}
|
|
443
406
|
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { classify, pixelRatio, } from "./classify.js";
|
|
2
|
+
import { PAGE_SCRIPT } from "./page-script.js";
|
|
3
|
+
import { decodePng } from "./png.js";
|
|
4
|
+
export const VIEWPORTS = [
|
|
5
|
+
["desktop", 1440, 900],
|
|
6
|
+
["celular", 390, 844],
|
|
7
|
+
];
|
|
8
|
+
/**
|
|
9
|
+
* CADA CONTRASTE BAIXO CONFERIDO PELOS PIXELS: sem tinta é texto não pintado; acima do alvo, o DOM errou o fundo. A mesma
|
|
10
|
+
* conferência na leitura e no fim do turno (E01 da fase 3) - duas cópias divergiriam no primeiro conserto.
|
|
11
|
+
*/
|
|
12
|
+
export async function confirmByPixels(found, pageOf) {
|
|
13
|
+
const confirmed = [];
|
|
14
|
+
for (const f of found) {
|
|
15
|
+
const page = pageOf(f.sample);
|
|
16
|
+
let px = null;
|
|
17
|
+
if (page && f.sample.w >= 2 && f.sample.h >= 2) {
|
|
18
|
+
const png = await page
|
|
19
|
+
.screenshot({
|
|
20
|
+
fullPage: true,
|
|
21
|
+
clip: {
|
|
22
|
+
x: Math.max(0, f.sample.x),
|
|
23
|
+
y: Math.max(0, f.sample.y),
|
|
24
|
+
width: f.sample.w,
|
|
25
|
+
height: f.sample.h,
|
|
26
|
+
},
|
|
27
|
+
})
|
|
28
|
+
.catch(() => null);
|
|
29
|
+
const rgba = png ? decodePng(png) : null;
|
|
30
|
+
px = rgba ? pixelRatio(rgba) : null;
|
|
31
|
+
}
|
|
32
|
+
if (px !== null && (px < 1.2 || px >= f.alvo))
|
|
33
|
+
continue;
|
|
34
|
+
confirmed.push({ ...f, pixels: px });
|
|
35
|
+
}
|
|
36
|
+
return confirmed;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Mede `routes` de `base` nas duas larguras, classifica e confere o contraste pelos pixels. Quem chama fecha (`close`).
|
|
40
|
+
* As duas larguras abrem AO MESMO TEMPO (medido em 21/10: resend.com levava 46 s em sequência), e os textos entram na
|
|
41
|
+
* ordem de `VIEWPORTS`, a mesma de antes - a classificação não muda.
|
|
42
|
+
*/
|
|
43
|
+
export async function readSite(browser, base, routes, opts = {}) {
|
|
44
|
+
const seen = [];
|
|
45
|
+
const pages = new Map();
|
|
46
|
+
const statuses = new Map();
|
|
47
|
+
const ctxs = [];
|
|
48
|
+
const close = async () => {
|
|
49
|
+
for (const ctx of ctxs)
|
|
50
|
+
await ctx.close().catch(() => { });
|
|
51
|
+
};
|
|
52
|
+
const open = async (rota, disp, w, h) => {
|
|
53
|
+
const ctx = await browser.newContext({
|
|
54
|
+
...opts.context,
|
|
55
|
+
viewport: { width: w, height: h },
|
|
56
|
+
reducedMotion: "reduce",
|
|
57
|
+
});
|
|
58
|
+
ctxs.push(ctx);
|
|
59
|
+
if (opts.prepare)
|
|
60
|
+
await opts.prepare(ctx);
|
|
61
|
+
const page = await ctx.newPage();
|
|
62
|
+
const href = new URL(rota, base).href;
|
|
63
|
+
const res = opts.settleMs === undefined
|
|
64
|
+
? await page.goto(href, { waitUntil: "networkidle", timeout: 90_000 })
|
|
65
|
+
: await page
|
|
66
|
+
.goto(href, { waitUntil: "networkidle", timeout: opts.settleMs })
|
|
67
|
+
.catch((e) => {
|
|
68
|
+
if (!/timeout/i.test(e.message))
|
|
69
|
+
throw e;
|
|
70
|
+
return null;
|
|
71
|
+
});
|
|
72
|
+
const code = res?.status?.();
|
|
73
|
+
statuses.set(`${rota}|${disp}`, typeof code === "number" ? code : null);
|
|
74
|
+
await page.waitForTimeout(800);
|
|
75
|
+
const textos = (await page.evaluate(PAGE_SCRIPT));
|
|
76
|
+
pages.set(`${rota}|${disp}`, page);
|
|
77
|
+
return textos.map((t) => ({ ...t, rota, disp }));
|
|
78
|
+
};
|
|
79
|
+
try {
|
|
80
|
+
for (const rota of routes) {
|
|
81
|
+
const byWidth = await Promise.all(VIEWPORTS.map(([disp, w, h]) => open(rota, disp, w, h)));
|
|
82
|
+
for (const textos of byWidth)
|
|
83
|
+
seen.push(...textos);
|
|
84
|
+
}
|
|
85
|
+
const reading = classify(seen);
|
|
86
|
+
reading.contraste = await confirmByPixels(reading.contraste, (t) => pages.get(`${t.rota}|${t.disp}`));
|
|
87
|
+
return { reading, seen, pages, statuses, close };
|
|
88
|
+
}
|
|
89
|
+
catch (e) {
|
|
90
|
+
await close();
|
|
91
|
+
throw e;
|
|
92
|
+
}
|
|
93
|
+
}
|
package/dist/reading/reread.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
2
2
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import { basename, extname, join, relative, sep } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { declaredPort, findServer, homeOf, launch, loadReader, sources } from "../commands/read.js";
|
|
5
|
+
import { confirmByPixels } from "./read-page.js";
|
|
5
6
|
import { loadRoleRules } from "../role-rules.js";
|
|
6
7
|
import { classify } from "./classify.js";
|
|
7
8
|
import { PAGE_SCRIPT } from "./page-script.js";
|
package/package.json
CHANGED