synthesisui 0.16.471 → 0.16.473
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/add.js +2 -0
- package/dist/commands/hook.js +5 -0
- package/dist/commands/import.js +15 -3
- package/dist/commands/login.js +18 -2
- package/dist/commands/sync.js +4 -1
- package/dist/doctor/scan.js +44 -1
- package/dist/fonts.js +19 -1
- package/dist/install-marks.js +26 -3
- package/dist/not-expressed.js +4 -1
- package/dist/what-grew.js +64 -3
- package/package.json +1 -1
package/dist/commands/add.js
CHANGED
|
@@ -48,6 +48,8 @@ const IGNORED = [
|
|
|
48
48
|
".ledger-sent",
|
|
49
49
|
/** O que a última medição viu, para a próxima dizer o que mudou - descreve ESTE clone. */
|
|
50
50
|
".last-sync.json",
|
|
51
|
+
/** O que o sync destacado mandou, esperando o fim do turno seguinte dizer - ver `what-grew.ts` (28/09). */
|
|
52
|
+
".last-growth.json",
|
|
51
53
|
"not-expressed.md",
|
|
52
54
|
/**
|
|
53
55
|
* O RELATÓRIO QUE O `inspect` ESCREVE - a leitura inteira com forma, para ele abrir no navegador.
|
package/dist/commands/hook.js
CHANGED
|
@@ -11,6 +11,7 @@ import { governs, ungovernedIn } from "../governed.js";
|
|
|
11
11
|
import { readMode } from "../mode.js";
|
|
12
12
|
import { namesRemoved, previousText, rulesTouchedBy, } from "../rule-touched.js";
|
|
13
13
|
import { loadSystem } from "./doctor.js";
|
|
14
|
+
import { takeGrowthNote } from "../what-grew.js";
|
|
14
15
|
const pass = () => ({ continue: true });
|
|
15
16
|
const speak = (context) => ({
|
|
16
17
|
continue: true,
|
|
@@ -664,6 +665,10 @@ async function endOfTurn(root, input) {
|
|
|
664
665
|
const { said } = changed.length > 0
|
|
665
666
|
? await checkChanged(root, changed, mode, "turn")
|
|
666
667
|
: { said: [] };
|
|
668
|
+
/** O que o sync destacado do turno anterior mandou para o rascunho - dito uma vez (re-rodada, 28/09). */
|
|
669
|
+
const grown = await takeGrowthNote(root).catch(() => null);
|
|
670
|
+
if (grown)
|
|
671
|
+
said.push(grown);
|
|
667
672
|
await moveTurnClock(root);
|
|
668
673
|
out(said.length === 0
|
|
669
674
|
? pass()
|
package/dist/commands/import.js
CHANGED
|
@@ -4648,6 +4648,16 @@ quiet = false) {
|
|
|
4648
4648
|
say(body(n));
|
|
4649
4649
|
}
|
|
4650
4650
|
}
|
|
4651
|
+
/**
|
|
4652
|
+
* A FRASE DO NASCIMENTO - e ela depende de o código dele nomear alguma coisa. Bateria, 28/09 (b2): num projeto sem
|
|
4653
|
+
* token nenhum o sistema inteiro é a semente, e "v1 is your tokens" levava ao contrário. Ver
|
|
4654
|
+
* `nao-espelha-o-que-nao-existe.spec.ts`.
|
|
4655
|
+
*/
|
|
4656
|
+
export function birthLine(name, declared) {
|
|
4657
|
+
return declared === 0
|
|
4658
|
+
? `${name} - your code names no token yet, so this system is our starting point, with your colours and sizes measured next to it (listed in the report).`
|
|
4659
|
+
: `${name} - v1 is your tokens, nothing improved yet; where your code names nothing, it keeps the starting point's value (listed in the report).`;
|
|
4660
|
+
}
|
|
4651
4661
|
export async function runImport(opts) {
|
|
4652
4662
|
const root = opts.root ?? process.cwd();
|
|
4653
4663
|
/**
|
|
@@ -4983,8 +4993,10 @@ export async function runImport(opts) {
|
|
|
4983
4993
|
census.scheme = scheme;
|
|
4984
4994
|
if (!scheme && mustNotGuessPolarity(census)) {
|
|
4985
4995
|
console.log("");
|
|
4986
|
-
console.log(body(
|
|
4987
|
-
|
|
4996
|
+
console.log(body(
|
|
4997
|
+
/** Desde a "(b)" do dono (28/09): as cores entram como a face única, e a escolha é um clique na tela. */
|
|
4998
|
+
"Your stylesheet does not say which face this project opens in, and nothing here declares a light or a dark scheme on its own. Nothing was guessed: your colours came in as the system's one face."));
|
|
4999
|
+
console.log(body(`Next, if you like: say light or dark on the system's page - one click - or run this with ${paint.strong("--scheme dark")} or ${paint.strong("--scheme light")}.`));
|
|
4988
5000
|
}
|
|
4989
5001
|
// The file on disk has to say what we sent, or the next person to read it is
|
|
4990
5002
|
// reading a different import than the one that happened.
|
|
@@ -5139,7 +5151,7 @@ export async function runImport(opts) {
|
|
|
5139
5151
|
* NÃO "ESPELHA EXATAMENTE" - rodadas 11 e 13, 28/09: a v1 trazia um `display` de 4rem e uma mono JetBrains que
|
|
5140
5152
|
* o projeto nunca declarou, e a frase dizia o contrário. As fundações vêm da semente onde ele não nomeia nada.
|
|
5141
5153
|
*/
|
|
5142
|
-
|
|
5154
|
+
birthLine(paint.strong(payload?.name ?? "Your system"), Object.keys(census.declared ?? {}).length)));
|
|
5143
5155
|
/**
|
|
5144
5156
|
* ONDE ELE NASCEU, dito pela plataforma e não pelo que foi pedido.
|
|
5145
5157
|
*
|
package/dist/commands/login.js
CHANGED
|
@@ -50,9 +50,25 @@ export async function login(opts) {
|
|
|
50
50
|
*/
|
|
51
51
|
if (!opts.force) {
|
|
52
52
|
const existing = await readCredentials();
|
|
53
|
-
|
|
53
|
+
/**
|
|
54
|
+
* E DIZ QUEM - bateria, 28/09 (b11). O passo Install da galeria acabou de dizer que a CONTA importa ("the
|
|
55
|
+
* account that owns <slug>"), e esta linha dizia só o host. A mesma pergunta que o `status` já faz (#1630).
|
|
56
|
+
* Um token que a plataforma responde e não aceita mais não é "já entrou": segue para o login de verdade.
|
|
57
|
+
* Sem resposta nenhuma, vale o que a máquina tem - offline não é motivo para abrir um browser.
|
|
58
|
+
*/
|
|
59
|
+
const who = existing && sameRegistry(existing.registry, base)
|
|
60
|
+
? await fetch(`${base}/api/auth/get-session`, {
|
|
61
|
+
headers: { Authorization: `Bearer ${existing.token}` },
|
|
62
|
+
})
|
|
63
|
+
.then(async (r) => r.ok ? (await r.json()) : null)
|
|
64
|
+
.then((j) => ({ reached: true, email: j?.user?.email ?? null }))
|
|
65
|
+
.catch(() => ({ reached: false, email: null }))
|
|
66
|
+
: null;
|
|
67
|
+
if (who && (who.email || !who.reached)) {
|
|
54
68
|
console.log("");
|
|
55
|
-
console.log(
|
|
69
|
+
console.log(who.email
|
|
70
|
+
? `✓ Already signed in as ${who.email} on ${base}.`
|
|
71
|
+
: `✓ Already signed in to ${base} on this machine (the account could not be confirmed - the registry did not answer).`);
|
|
56
72
|
console.log(" Run `synthesisui login --force` to sign in as someone else,");
|
|
57
73
|
console.log(" or `synthesisui logout` to sign out of this machine.");
|
|
58
74
|
return;
|
package/dist/commands/sync.js
CHANGED
|
@@ -13,7 +13,7 @@ import { measuredScope, rememberScope } from "../measured-scope.js";
|
|
|
13
13
|
import { fromCensus } from "../memory/observation.js";
|
|
14
14
|
import { reportMeasurement } from "../memory/report.js";
|
|
15
15
|
import { mergeCensus } from "../merge-census.js";
|
|
16
|
-
import { describeGrowth, whatGrew } from "../what-grew.js";
|
|
16
|
+
import { describeGrowth, recordGrowthForTurn, whatGrew } from "../what-grew.js";
|
|
17
17
|
import { body, paint, section, snippet } from "../output.js";
|
|
18
18
|
import { repoStateOf } from "../repo-state.js";
|
|
19
19
|
import { reportWhatIsLeft } from "./align.js";
|
|
@@ -617,6 +617,9 @@ export async function remeasure(args) {
|
|
|
617
617
|
console.log(section("What your code grew"));
|
|
618
618
|
for (const l of growth)
|
|
619
619
|
console.log(body(l));
|
|
620
|
+
/** Sem terminal (o fim do turno), a lista fica para o turno seguinte dizer - ver `recordGrowthForTurn`. */
|
|
621
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
622
|
+
await recordGrowthForTurn(root, growth);
|
|
620
623
|
if (!(await askToSendGrowth())) {
|
|
621
624
|
console.log(body("Nothing was sent. Your draft is untouched - run `npx synthesisui sync` again when you want them in."));
|
|
622
625
|
return null;
|
package/dist/doctor/scan.js
CHANGED
|
@@ -490,6 +490,44 @@ export function scanSource(file, source, table) {
|
|
|
490
490
|
}
|
|
491
491
|
return scanCore(file, source, table);
|
|
492
492
|
}
|
|
493
|
+
/**
|
|
494
|
+
* OS SELETORES QUE DECLARAM VOCABULÁRIO - `@theme`, `:root` e a redefinição por tema (bateria, 28/09: b5 escreve
|
|
495
|
+
* `[data-theme="dark"] { --c-bg: #0f172a; ... }`). Dentro deles uma `--x: valor` é a definição, não um uso.
|
|
496
|
+
*/
|
|
497
|
+
const TOKEN_SELECTOR_PART = /^(@theme\b.*|:root(\[[^\]]*\])?|html(\[[^\]]*\]|\.[\w-]+)?|\[data-(theme|mode|scheme|color-scheme)(=[^\]]*)?\]|\.(dark|light))$/;
|
|
498
|
+
/**
|
|
499
|
+
* O SELETOR INTEIRO precisa ser a raiz do tema - `html.dark .shell { --shell-fill: … }` é uma variável de UM
|
|
500
|
+
* componente redefinida por tema, e essa continua sendo acusada (o corpus `css-global-custom-property`).
|
|
501
|
+
*/
|
|
502
|
+
function isTokenSelector(selector) {
|
|
503
|
+
const parts = selector.split(",").map((p) => p.trim());
|
|
504
|
+
return parts.length > 0 && parts.every((p) => TOKEN_SELECTOR_PART.test(p));
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* ONDE ESTÃO OS VALORES QUE ESTA LINHA ATRIBUI A UMA VARIÁVEL, dentro de um bloco de vocabulário - bateria, 28/09.
|
|
508
|
+
*
|
|
509
|
+
* A guarda de `scanCore` lia `--x:` só no COMEÇO da linha, e `:root { --q-stone: #44403c; ... }` numa linha só
|
|
510
|
+
* voltava como quatro "replace now" (b8). Trocar `#44403c` por `var(--q-stone)` na própria declaração faz o token
|
|
511
|
+
* apontar para si mesmo: o navegador descarta o valor e toda cor do app some. O seletor que governa cada
|
|
512
|
+
* declaração é o do último `{` antes dela na linha; sem `{` antes, vale o bloco multilinha em que a linha está.
|
|
513
|
+
*/
|
|
514
|
+
function declarationSpans(line, inBlock) {
|
|
515
|
+
const out = [];
|
|
516
|
+
for (const m of line.matchAll(DECLARES_ALL)) {
|
|
517
|
+
const start = m.index ?? 0;
|
|
518
|
+
const open = line.lastIndexOf("{", start + 1);
|
|
519
|
+
const governed = open < 0
|
|
520
|
+
? inBlock
|
|
521
|
+
: line.lastIndexOf("}", start) < open &&
|
|
522
|
+
isTokenSelector(line.slice(line.lastIndexOf("}", open) + 1, open).trim());
|
|
523
|
+
if (!governed)
|
|
524
|
+
continue;
|
|
525
|
+
const colon = m[0].indexOf(":");
|
|
526
|
+
const valueAt = start + m[0].indexOf(m[2], colon);
|
|
527
|
+
out.push([valueAt, valueAt + m[2].length]);
|
|
528
|
+
}
|
|
529
|
+
return out;
|
|
530
|
+
}
|
|
493
531
|
/** `--color-ocean-500: #059aed;` - uma declaração de custom property no CSS dele. */
|
|
494
532
|
/** Cada declaração `--x: valor;` da linha, quantas houver - ver o laço em `scanCore`. */
|
|
495
533
|
const DECLARES_ALL = /(?:^|[\s{;])(--[a-z0-9-]+)\s*:\s*([^;{}]+);/gi;
|
|
@@ -558,7 +596,7 @@ function scanCore(file, source, table) {
|
|
|
558
596
|
const indent = line ? raw.indexOf(line) : 0;
|
|
559
597
|
const at = i + 1;
|
|
560
598
|
const depthBefore = braceDepth;
|
|
561
|
-
const opensTokenBlock =
|
|
599
|
+
const opensTokenBlock = line.includes("{") && isTokenSelector(line.slice(0, line.indexOf("{")).trim());
|
|
562
600
|
if (opensTokenBlock && tokenBlockDepth === 0)
|
|
563
601
|
tokenBlockDepth = depthBefore + 1;
|
|
564
602
|
const inTokenBlock = tokenBlockDepth > 0 && (opensTokenBlock || depthBefore >= tokenBlockDepth);
|
|
@@ -639,6 +677,8 @@ function scanCore(file, source, table) {
|
|
|
639
677
|
// written by hand - flagging it would be telling someone to tokenize a
|
|
640
678
|
// variable. And the same literal twice in one declaration (a two-stop
|
|
641
679
|
// shadow) is one decision, so it is reported once.
|
|
680
|
+
const declared = declarationSpans(line, inTokenBlock && !opensTokenBlock);
|
|
681
|
+
const inDeclaration = (at) => declared.some(([a, b]) => at >= a && at < b);
|
|
642
682
|
const spans = fallbackSpans(line, table);
|
|
643
683
|
const inFallback = (at) => spans.some(([a, b]) => at >= a && at <= b);
|
|
644
684
|
/** Ver `markupTextSpans`: HTML montado como texto sai do alcance da folha do app. */
|
|
@@ -653,6 +693,9 @@ function scanCore(file, source, table) {
|
|
|
653
693
|
const push = (kind, literal, col = -1) => {
|
|
654
694
|
if (literal.includes("$") || literal.includes("{"))
|
|
655
695
|
return;
|
|
696
|
+
/** A definição do token não é drift - ver `declarationSpans`. */
|
|
697
|
+
if (col >= 0 && inDeclaration(col))
|
|
698
|
+
return;
|
|
656
699
|
if (col >= 0 && inFallback(col)) {
|
|
657
700
|
setAside("a token's own fallback");
|
|
658
701
|
return;
|
package/dist/fonts.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { subsetsToEmit, weightsToEmit, } from "./next-font-weights.js";
|
|
2
|
-
// Fallbacks genéricos do CSS -
|
|
2
|
+
// Fallbacks genéricos do CSS e as famílias de sistema - nenhuma delas é webfont para baixar.
|
|
3
3
|
const GENERIC_FAMILIES = new Set([
|
|
4
4
|
"sans-serif",
|
|
5
5
|
"serif",
|
|
@@ -12,6 +12,24 @@ const GENERIC_FAMILIES = new Set([
|
|
|
12
12
|
"fantasy",
|
|
13
13
|
"inherit",
|
|
14
14
|
"initial",
|
|
15
|
+
/**
|
|
16
|
+
* AS FAMÍLIAS QUE JÁ ESTÃO EM TODA MÁQUINA - bateria, 28/09. Georgia, Arial e Verdana não se baixam de lugar
|
|
17
|
+
* nenhum, e pedi-las ao Google Fonts gerava um `<link>` para o que ele não tem, logo abaixo da frase que dizia isso.
|
|
18
|
+
*/
|
|
19
|
+
"arial",
|
|
20
|
+
"helvetica",
|
|
21
|
+
"helvetica neue",
|
|
22
|
+
"georgia",
|
|
23
|
+
"verdana",
|
|
24
|
+
"tahoma",
|
|
25
|
+
"trebuchet ms",
|
|
26
|
+
"times new roman",
|
|
27
|
+
"times",
|
|
28
|
+
"courier new",
|
|
29
|
+
"courier",
|
|
30
|
+
"segoe ui",
|
|
31
|
+
"-apple-system",
|
|
32
|
+
"blinkmacsystemfont",
|
|
15
33
|
]);
|
|
16
34
|
/**
|
|
17
35
|
* A PRIMEIRA FAMÍLIA DE UMA PILHA - `"Geist Mono", ui-monospace, monospace` é `Geist Mono`.
|
package/dist/install-marks.js
CHANGED
|
@@ -295,7 +295,16 @@
|
|
|
295
295
|
* escrita como a função dele (`color("brand")`), nunca `$semantic-brand` (rodada 14 do refinamento). Um
|
|
296
296
|
* componente escrito antes num projeto desses está sem estilo.
|
|
297
297
|
*/
|
|
298
|
-
|
|
298
|
+
/**
|
|
299
|
+
* 0.16.471 -> 0.16.472 em 28/09, e o passo 1 dá **SIM**: o `.gitignore` da pasta passa a cobrir `.last-growth.json`, o que
|
|
300
|
+
* o sync destacado deixa para o fim do turno dizer (re-rodada depois do #1631). Uma pasta escrita antes deixaria esse
|
|
301
|
+
* arquivo local entrar num commit.
|
|
302
|
+
*/
|
|
303
|
+
/**
|
|
304
|
+
* 0.16.472 -> 0.16.473 em 28/09, e o passo 1 dá **SIM** (a bateria): as famílias de sistema (Georgia, Arial, Verdana)
|
|
305
|
+
* deixam de virar `<link>` do Google Fonts, e a webfont ao lado delas ganha o `fonts.ts` que antes não saía.
|
|
306
|
+
*/
|
|
307
|
+
export const MATERIALISER_SINCE = "0.16.473";
|
|
299
308
|
/**
|
|
300
309
|
* A ÚLTIMA VERSÃO EM QUE O QUE O HOOK RODA MUDOU.
|
|
301
310
|
*
|
|
@@ -467,7 +476,16 @@ export const COUNTED_DIFFERENTLY = "this run counts a value as named only when Y
|
|
|
467
476
|
* (`$palette`, `color("brand")`) - rodada 14 do refinamento. Um hook anterior acusa como valor à mão toda cor
|
|
468
477
|
* que o projeto guarda num mapa.
|
|
469
478
|
*/
|
|
470
|
-
|
|
479
|
+
/**
|
|
480
|
+
* 0.16.471 -> 0.16.472 em 28/09, e o passo 1 dá **SIM**: o fim do turno entrega ao agente o que o sync destacado do turno
|
|
481
|
+
* anterior mandou para o rascunho (re-rodada, f12). Um hook anterior deixa esses componentes entrarem calados.
|
|
482
|
+
*/
|
|
483
|
+
/**
|
|
484
|
+
* 0.16.472 -> 0.16.473 em 28/09, e o passo 1 dá **SIM** (a bateria, b8): o hook deixa de acusar o valor que um
|
|
485
|
+
* `:root { --q-stone: #44403c; … }` de uma linha atribui ao token. Um hook anterior manda trocar a definição pelo
|
|
486
|
+
* próprio nome, e quem obedece apaga a cor.
|
|
487
|
+
*/
|
|
488
|
+
export const CHECKER_SINCE = "0.16.473";
|
|
471
489
|
/**
|
|
472
490
|
* A ÚLTIMA VERSÃO EM QUE OS LEITORES PASSARAM A PRODUZIR UM CENSO DIFERENTE.
|
|
473
491
|
*
|
|
@@ -932,7 +950,12 @@ export const CHECKER_SINCE = "0.16.471";
|
|
|
932
950
|
* não põe no sistema a peça do framework (`StrictMode`, `next/link`) nem a raiz do Vite (`src/App.tsx`); e o que
|
|
933
951
|
* mora na pasta compartilhada de componentes nunca vira "feature". Um censo lido antes guardou tudo isso errado.
|
|
934
952
|
*/
|
|
935
|
-
|
|
953
|
+
/**
|
|
954
|
+
* 0.16.471 -> 0.16.473 em 28/09, e o passo 1 dá **SIM** (a bateria, b3, b5, b8): a varredura deixa de contar como valor à
|
|
955
|
+
* mão o que um `:root { --a: x; }` ou um `[data-theme="dark"] { … }` de UMA linha atribui a uma variável - a definição do
|
|
956
|
+
* token. Quatro apps do corpus moveram. Um censo lido antes guardou essas declarações como drift.
|
|
957
|
+
*/
|
|
958
|
+
export const READER_SINCE = "0.16.473";
|
|
936
959
|
/**
|
|
937
960
|
* O QUE ESTÁ INSTALADO AQUI FICOU PARA TRÁS - e as DUAS condições que fazem isso ser verdade.
|
|
938
961
|
*
|
package/dist/not-expressed.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SKIP_LABEL } from "./doctor/component-gate.js";
|
|
1
2
|
/**
|
|
2
3
|
* O QUE ESTA LEITURA NÃO CONSEGUIU SEGURAR, escrito pela esteira e não pedido a ninguém.
|
|
3
4
|
*
|
|
@@ -69,7 +70,9 @@ export function notExpressed(census) {
|
|
|
69
70
|
" a reading to correct - and the reason below is the one to argue with.");
|
|
70
71
|
out.push("");
|
|
71
72
|
for (const s of skipped)
|
|
72
|
-
out.push(
|
|
73
|
+
out.push(
|
|
74
|
+
/** `because` é opcional; sem ele, o rótulo do `why` - nunca `undefined` (bateria, 28/09). */
|
|
75
|
+
` ${s.name}${s.file ? ` (${s.file})` : ""}\n ${s.because ?? SKIP_LABEL[s.why] ?? s.why}`);
|
|
73
76
|
}
|
|
74
77
|
out.push("");
|
|
75
78
|
return `${out.join("\n")}\n`;
|
package/dist/what-grew.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
|
-
import { join, relative } from "node:path";
|
|
2
|
+
import { dirname, join, relative } from "node:path";
|
|
3
|
+
import { readStyleSheet } from "./doctor/scss-lens.js";
|
|
3
4
|
import { loadSystem, walkAll } from "./commands/doctor.js";
|
|
4
5
|
import { diagnose, scanSource } from "./doctor/scan.js";
|
|
5
6
|
export async function whatGrew(root, census,
|
|
@@ -26,6 +27,9 @@ before) {
|
|
|
26
27
|
context.push(report);
|
|
27
28
|
}
|
|
28
29
|
}
|
|
30
|
+
/** Os componentes dele que um arquivo monta, cada um uma vez - fora ele mesmo. */
|
|
31
|
+
const own = new Set(now.filter((c) => typeof c.api?.file === "string").map((c) => c.name));
|
|
32
|
+
const composed = (src, self) => new Set([...src.matchAll(/<([A-Z][A-Za-z0-9]*)\b/g)].map((m) => m[1]).filter((n) => n !== self && own.has(n))).size;
|
|
29
33
|
const born = [];
|
|
30
34
|
for (const c of fresh) {
|
|
31
35
|
const file = c.api?.file;
|
|
@@ -34,13 +38,29 @@ before) {
|
|
|
34
38
|
born.push({ name: c.name, file, fromSystem: 0, of: 0, byHand: [] });
|
|
35
39
|
continue;
|
|
36
40
|
}
|
|
37
|
-
|
|
41
|
+
/**
|
|
42
|
+
* E A FOLHA QUE ELE IMPORTA - relato 15, 28/09: "Landing - no colour or spacing of its own to measure", com os
|
|
43
|
+
* valores no `Landing.module.css` ao lado. O componente é o `.tsx` MAIS o estilo que ele puxa.
|
|
44
|
+
*/
|
|
45
|
+
const reports = [scanSource(file, src, table)];
|
|
46
|
+
for (const m of src.matchAll(/^\s*import\s+(?:[\w{}\s,*]+\s+from\s+)?["'](\.{1,2}\/[^"']+\.(?:css|scss|sass|less))["']/gm)) {
|
|
47
|
+
const sheet = join(dirname(file), m[1]);
|
|
48
|
+
const css = await readStyleSheet(join(root, sheet)).catch(() => "");
|
|
49
|
+
if (css)
|
|
50
|
+
reports.push(scanSource(sheet, css, table));
|
|
51
|
+
}
|
|
52
|
+
const d = diagnose(reports, context);
|
|
53
|
+
/** Classes utilitárias numa string qualquer do arquivo - `className="…"`, `cn("…")`, `cva("…")` (f11, 28/09). */
|
|
54
|
+
const utilities = !d.reach.measured &&
|
|
55
|
+
/["'`][^"'`\n]*(?<![\w-])(bg|text|border|p[xytrbl]?|m[xytrbl]?|gap|rounded|shadow)-[a-z0-9][^"'`\n]*["'`]/.test(src);
|
|
38
56
|
born.push({
|
|
39
57
|
name: c.name,
|
|
40
58
|
file,
|
|
41
59
|
fromSystem: d.reach.measured ? d.reach.uses : 0,
|
|
42
60
|
of: d.reach.measured ? d.reach.of : 0,
|
|
43
61
|
byHand: [...new Set(d.findings.map((f) => f.literal))],
|
|
62
|
+
...(utilities ? { utilities: true } : {}),
|
|
63
|
+
...(composed(src, c.name) >= 3 ? { composes: composed(src, c.name) } : {}),
|
|
44
64
|
});
|
|
45
65
|
}
|
|
46
66
|
return { born, gone };
|
|
@@ -50,9 +70,50 @@ export function describeGrowth(grown) {
|
|
|
50
70
|
const out = [];
|
|
51
71
|
for (const b of grown.born)
|
|
52
72
|
out.push(b.of === 0
|
|
53
|
-
?
|
|
73
|
+
? b.utilities
|
|
74
|
+
? `${b.name} (${b.file}) - styled with utility classes; \`npx synthesisui doctor\` measures those`
|
|
75
|
+
: `${b.name} (${b.file}) - no colour or spacing of its own to measure`
|
|
54
76
|
: `${b.name} (${b.file}) - ${b.fromSystem} of ${b.of} values from your system${b.byHand.length > 0 ? `; by hand: ${b.byHand.slice(0, 4).join(", ")}${b.byHand.length > 4 ? ", …" : ""}` : ""}`);
|
|
77
|
+
/** A tela que mora na pasta de componentes: a linha pergunta, e quem responde decide. */
|
|
78
|
+
for (const [i, b] of grown.born.entries())
|
|
79
|
+
if (b.composes)
|
|
80
|
+
out[i] = `${out[i]} - it composes ${b.composes} of your components - a screen?`;
|
|
55
81
|
for (const g of grown.gone)
|
|
56
82
|
out.push(`${g} is no longer in your code - it leaves the draft with this send`);
|
|
57
83
|
return out;
|
|
58
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* O QUE O SYNC DESTACADO MANDOU, PARA O FIM DO TURNO SEGUINTE DIZER - re-rodada, f12 (28/09).
|
|
87
|
+
*
|
|
88
|
+
* Pelo agente, o `sync` roda destacado do fim do turno (`auto-sync.ts`), com a saída descartada: o bloco "What your
|
|
89
|
+
* code grew" não chegava a ninguém, e o componente entrava no rascunho calado - o contrário da decisão do dono. A
|
|
90
|
+
* lista fica ao lado, e o fim do turno seguinte a entrega ao agente UMA vez, para ele contar à pessoa.
|
|
91
|
+
*/
|
|
92
|
+
const GROWTH_FILE = ".last-growth.json";
|
|
93
|
+
export async function recordGrowthForTurn(root, lines) {
|
|
94
|
+
if (lines.length === 0)
|
|
95
|
+
return;
|
|
96
|
+
const { writeFile } = await import("node:fs/promises");
|
|
97
|
+
await writeFile(join(root, "_synthesisui", GROWTH_FILE), JSON.stringify({ at: new Date().toISOString(), lines }), "utf8").catch(() => { });
|
|
98
|
+
}
|
|
99
|
+
export async function takeGrowthNote(root) {
|
|
100
|
+
const { rm } = await import("node:fs/promises");
|
|
101
|
+
const path = join(root, "_synthesisui", GROWTH_FILE);
|
|
102
|
+
const raw = await readFile(path, "utf8").catch(() => null);
|
|
103
|
+
if (raw == null)
|
|
104
|
+
return null;
|
|
105
|
+
await rm(path, { force: true }).catch(() => { });
|
|
106
|
+
try {
|
|
107
|
+
const { lines } = JSON.parse(raw);
|
|
108
|
+
if (!lines?.length)
|
|
109
|
+
return null;
|
|
110
|
+
return [
|
|
111
|
+
"The last sync sent to your system's draft (the person has not seen this yet - tell the person, in one line each):",
|
|
112
|
+
...lines.map((l) => ` ${l}`),
|
|
113
|
+
"Each one can stay out of the system on its page before the draft is published.",
|
|
114
|
+
].join("\n");
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
}
|
package/package.json
CHANGED