synthesisui 0.16.249 → 0.16.251
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/absorb-plan.js +14 -3
- package/dist/cli-flags.js +79 -0
- package/dist/commands/absorb.js +32 -10
- package/dist/commands/doctor.js +76 -11
- package/dist/commands/login.js +2 -1
- package/dist/commands/logout.js +26 -0
- package/dist/commands/mcp.js +42 -2
- package/dist/commands/status.js +14 -0
- package/dist/config.js +25 -1
- package/dist/doctor/their-names.js +2 -11
- package/dist/doctor/tokens.js +47 -1
- package/dist/index.js +15 -59
- package/dist/install-marks.js +1 -1
- package/package.json +1 -1
package/dist/absorb-plan.js
CHANGED
|
@@ -170,15 +170,26 @@ export function describeAbsorb(plan) {
|
|
|
170
170
|
return [
|
|
171
171
|
"Nothing to absorb: every repeated value your code writes by hand already has a name in the system.",
|
|
172
172
|
];
|
|
173
|
-
|
|
173
|
+
/**
|
|
174
|
+
* A SEÇÃO DOS QUE JÁ TÊM NOME SÓ EXISTE SE ALGUM TIVER - e no dia 1 nenhum tem.
|
|
175
|
+
*
|
|
176
|
+
* Quem começa do zero não declarou um token ainda, então isto abria com "0 of 4 values
|
|
177
|
+
* already have a name" e uma lista vazia: a primeira frase do comando dizendo um zero que
|
|
178
|
+
* não é notícia nenhuma, antes da única seção que importa para ela.
|
|
179
|
+
*/
|
|
180
|
+
if (ready.length > 0)
|
|
181
|
+
lines.push(`${ready.length} of ${plan.entries.length} values already have a name in YOUR vocabulary - those travel as they are:`);
|
|
174
182
|
for (const e of ready.slice(0, 8))
|
|
175
183
|
lines.push(` ${e.value.padEnd(24)} ${e.path.padEnd(28)} ${e.files} file${e.files === 1 ? "" : "s"}${e.theirName ? ` · your ${e.theirName}` : ""}`);
|
|
176
184
|
if (ready.length > 8)
|
|
177
185
|
lines.push(` (${ready.length - 8} more)`);
|
|
178
186
|
if (pending.length > 0) {
|
|
179
187
|
const close = pending.filter((e) => e.near);
|
|
180
|
-
|
|
181
|
-
|
|
188
|
+
if (ready.length > 0)
|
|
189
|
+
lines.push("");
|
|
190
|
+
lines.push(ready.length > 0
|
|
191
|
+
? `${pending.length} nobody names yet. Naming is a design decision, so those wait for a word from you:`
|
|
192
|
+
: `${pending.length} repeated values, and none of them has a name yet. Naming is a design decision, so each waits for a word from you:`);
|
|
182
193
|
for (const e of pending.slice(0, 8))
|
|
183
194
|
lines.push(` ${e.value.padEnd(24)} ${`<${e.kind}, ${e.files} file${e.files === 1 ? "" : "s"}>`.padEnd(28)} ${e.near ? `≈ your ${e.near.name} (${e.near.away})` : 'path: ""'}`);
|
|
184
195
|
if (pending.length > 8)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A LINHA DE COMANDO, DESMONTADA - e o único lugar que sabe fazer isso.
|
|
3
|
+
*
|
|
4
|
+
* Este parser vivia dentro do `index.ts`, privado, e por isso nunca foi
|
|
5
|
+
* exercido por um teste. O custo apareceu inteiro num defeito: `login --force`
|
|
6
|
+
* era lido de `args` - a lista de POSICIONAIS, de onde este parser já tirou
|
|
7
|
+
* toda `--flag` - então a flag anunciada no help nunca chegou ao comando, e a
|
|
8
|
+
* resposta era sugerir o comando que a pessoa acabou de rodar.
|
|
9
|
+
*
|
|
10
|
+
* Separado, ele é testável, e `boolFlag` fecha a porta: quem lê uma flag
|
|
11
|
+
* booleana pede pelo NOME dela a quem tem a resposta, e não procura a string
|
|
12
|
+
* numa lista que por construção não a contém.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* A REPEATED FLAG ACCUMULATES rather than overwriting.
|
|
16
|
+
*
|
|
17
|
+
* `--usage apps/web --usage apps/admin` is the natural way to say two, and keeping
|
|
18
|
+
* only the last would drop one silently - which is the failure mode this codebase
|
|
19
|
+
* refuses everywhere else. Every existing flag is passed once and still arrives as
|
|
20
|
+
* a string, so nothing that reads `typeof flags.x === "string"` changes.
|
|
21
|
+
*/
|
|
22
|
+
export function parseFlags(argv) {
|
|
23
|
+
const positionals = [];
|
|
24
|
+
const flags = {};
|
|
25
|
+
const put = (key, value) => {
|
|
26
|
+
const had = flags[key];
|
|
27
|
+
if (had === undefined) {
|
|
28
|
+
flags[key] = value;
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (typeof value !== "string")
|
|
32
|
+
return;
|
|
33
|
+
flags[key] = [
|
|
34
|
+
...(Array.isArray(had) ? had : typeof had === "string" ? [had] : []),
|
|
35
|
+
value,
|
|
36
|
+
];
|
|
37
|
+
};
|
|
38
|
+
for (let i = 0; i < argv.length; i++) {
|
|
39
|
+
const arg = argv[i];
|
|
40
|
+
if (arg === "-h" || arg === "--help") {
|
|
41
|
+
flags.help = true;
|
|
42
|
+
}
|
|
43
|
+
else if (arg.startsWith("--")) {
|
|
44
|
+
const body = arg.slice(2);
|
|
45
|
+
const eq = body.indexOf("=");
|
|
46
|
+
if (eq !== -1) {
|
|
47
|
+
// `--key=value` form (e.g. --out=templates/page.tsx)
|
|
48
|
+
put(body.slice(0, eq), body.slice(eq + 1));
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
// `--key value` form
|
|
52
|
+
const next = argv[i + 1];
|
|
53
|
+
if (next !== undefined && !next.startsWith("--")) {
|
|
54
|
+
put(body, next);
|
|
55
|
+
i++;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
put(body, true);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
positionals.push(arg);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return { positionals, flags };
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* UMA FLAG BOOLEANA, LIDA PELO NOME - `true` só quando ela está mesmo lá.
|
|
70
|
+
*
|
|
71
|
+
* `--yes` sozinha chega como `true`; `--yes` seguida de um posicional chega
|
|
72
|
+
* como a string daquele posicional, porque o parser não sabe quais flags levam
|
|
73
|
+
* valor. Nos dois casos a pessoa DISSE a flag, e é isso que um booleano
|
|
74
|
+
* responde - tratar `--yes algo` como não-dito seria obedecer pela metade.
|
|
75
|
+
*/
|
|
76
|
+
export function boolFlag(flags, name) {
|
|
77
|
+
const v = flags[name];
|
|
78
|
+
return v === true || typeof v === "string" || Array.isArray(v);
|
|
79
|
+
}
|
package/dist/commands/absorb.js
CHANGED
|
@@ -32,11 +32,23 @@ export async function absorb(opts) {
|
|
|
32
32
|
if (opts.send)
|
|
33
33
|
return sendProposal(root, path, opts.registry);
|
|
34
34
|
const installed = await loadSystem(root);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
/**
|
|
36
|
+
* SEM SISTEMA INSTALADO ISTO CONTINUA VALENDO - e recusar aqui fechava o dia 1.
|
|
37
|
+
*
|
|
38
|
+
* Este comando recusava com "não há nada para absorver PARA DENTRO", o que confundia o
|
|
39
|
+
* DESTINO com o TRABALHO. O trabalho é ler os valores que ela escreveu à mão e propor um
|
|
40
|
+
* nome para cada um; ele não depende de sistema nenhum, e as quatro coisas de que ele
|
|
41
|
+
* precisa já funcionam sem um: a tabela vem vazia (nada tem nome, então tudo é candidato),
|
|
42
|
+
* o vocabulário lido é o DELA, e a fundação existente é um conjunto vazio.
|
|
43
|
+
*
|
|
44
|
+
* Quem começa do zero era justamente quem mais precisava disto e quem menos podia rodar:
|
|
45
|
+
* ela escreve o primeiro componente, o doctor diz "9 valores à mão, nenhum tem nome", e o
|
|
46
|
+
* comando que dá nome respondia que não. Caminhado num projeto em branco em 18/08.
|
|
47
|
+
*
|
|
48
|
+
* O DESTINO É QUE MUDA, e ele se resolve sozinho: sem sistema, os tokens pertencem ao CSS
|
|
49
|
+
* dela - o mesmo caminho que `absorb: "code"` já servia a quem escolheu. Ver `sendProposal`.
|
|
50
|
+
*/
|
|
51
|
+
const hasSystem = Boolean(installed.table.slug);
|
|
40
52
|
const measured = await measuredScope(root);
|
|
41
53
|
const rel = scopePaths(measured);
|
|
42
54
|
const roots = rel.length > 0 ? rel.map((s) => resolve(root, s)) : [root];
|
|
@@ -61,7 +73,9 @@ export async function absorb(opts) {
|
|
|
61
73
|
reports.push(scanSource(file.slice(root.length + 1), source, installed.table));
|
|
62
74
|
}
|
|
63
75
|
const plan = absorbPlan(diagnose(reports), theirs, pathsInSystem(installed.documents), opts.cap ?? 40);
|
|
64
|
-
console.log(section(
|
|
76
|
+
console.log(section(hasSystem
|
|
77
|
+
? "What the system could absorb"
|
|
78
|
+
: "Name what you wrote by hand"));
|
|
65
79
|
console.log(body(paint.dim(`read from ${rel.length > 0 ? rel.join(", ") : "this project"} · your own vocabulary read from the root`)));
|
|
66
80
|
console.log("");
|
|
67
81
|
for (const line of describeAbsorb(plan))
|
|
@@ -69,7 +83,7 @@ export async function absorb(opts) {
|
|
|
69
83
|
if (plan.entries.length === 0)
|
|
70
84
|
return;
|
|
71
85
|
const proposal = {
|
|
72
|
-
slug: installed.table.slug,
|
|
86
|
+
slug: installed.table.slug ?? null,
|
|
73
87
|
at: new Date().toISOString(),
|
|
74
88
|
scope: rel,
|
|
75
89
|
entries: plan.entries,
|
|
@@ -146,17 +160,25 @@ async function sendProposal(root, path, registry) {
|
|
|
146
160
|
* colar. Nunca escrevemos no arquivo do cliente - e o import seguinte lê os tokens de volta, o que faz
|
|
147
161
|
* o caminho fechar sem nós tocarmos em nada.
|
|
148
162
|
*/
|
|
149
|
-
|
|
163
|
+
/**
|
|
164
|
+
* E SEM SISTEMA O DESTINO NÃO É UMA PREFERÊNCIA, é a única resposta que existe: os tokens
|
|
165
|
+
* pertencem ao CSS dela, porque não há outro lugar. Um `system` configurado aqui apontaria
|
|
166
|
+
* para um slug nulo e a chamada morreria num 404 depois de ela ter nomeado tudo à mão.
|
|
167
|
+
*/
|
|
168
|
+
const configured = (await readProjectConfig(root)).absorb ?? "system";
|
|
169
|
+
const target = proposal.slug ? configured : "code";
|
|
150
170
|
if (target === "code") {
|
|
151
171
|
console.log(section("Paste this into your own vocabulary"));
|
|
152
|
-
console.log(body(paint.dim(
|
|
172
|
+
console.log(body(paint.dim(proposal.slug
|
|
173
|
+
? "Your config says absorbed values belong in your CSS, so nothing was sent."
|
|
174
|
+
: "You have no system yet, so these belong in your own CSS - nothing was sent, and nothing needed an account.")));
|
|
153
175
|
console.log("");
|
|
154
176
|
console.log(" :root {");
|
|
155
177
|
for (const e of ready)
|
|
156
178
|
console.log(` --${e.path.replace(/\./g, "-")}: ${e.value};`);
|
|
157
179
|
console.log(" }");
|
|
158
180
|
console.log("");
|
|
159
|
-
console.log(body("The next import or `sync` reads these back as tokens you declared, and from then on the doctor
|
|
181
|
+
console.log(body("The next import or `sync` reads these back as tokens you declared, and from then on the doctor holds your code to them by your own names."));
|
|
160
182
|
return;
|
|
161
183
|
}
|
|
162
184
|
const token = await readToken();
|
package/dist/commands/doctor.js
CHANGED
|
@@ -401,6 +401,18 @@ function verdict(d, hasSystem, overruled, conflicts) {
|
|
|
401
401
|
body("installed. Nothing to fix, and nothing to compare against."),
|
|
402
402
|
];
|
|
403
403
|
}
|
|
404
|
+
/**
|
|
405
|
+
* O DIA ZERO - e o comando que serve a ele não era dito em lugar nenhum.
|
|
406
|
+
*
|
|
407
|
+
* "Dê um nome a eles" seguido de `init --ds <slug>` e o link da galeria oferece UMA saída, e
|
|
408
|
+
* ela é adotar o vocabulário de outra pessoa. A outra saída existe, faz exatamente o que a
|
|
409
|
+
* frase promete, e roda aqui mesmo sem conta e sem rede: `absorb` lê os valores repetidos e
|
|
410
|
+
* pede um nome para cada um. Ele passou a rodar sem sistema instalado neste mesmo PR, e uma
|
|
411
|
+
* capacidade que a pessoa precisa adivinhar não existe.
|
|
412
|
+
*
|
|
413
|
+
* A ordem é a da decisão dela: nomear o que ela já escreveu vem antes de escolher o de
|
|
414
|
+
* alguém, porque o primeiro é sobre o código que está na tela dela agora.
|
|
415
|
+
*/
|
|
404
416
|
if (!hasSystem) {
|
|
405
417
|
const distinct = new Set(d.findings.map((f) => f.literal.toLowerCase()));
|
|
406
418
|
return [
|
|
@@ -408,7 +420,10 @@ function verdict(d, hasSystem, overruled, conflicts) {
|
|
|
408
420
|
body(`${distinct.size} distinct design values are written by hand here.`),
|
|
409
421
|
body("No design system is installed, so none of them has a name yet."),
|
|
410
422
|
"",
|
|
411
|
-
body("
|
|
423
|
+
body("Name them yourself - this reads them and asks you for the words:"),
|
|
424
|
+
snippet(["npx synthesisui@latest absorb"]),
|
|
425
|
+
"",
|
|
426
|
+
body("Or start from a system somebody already published:"),
|
|
412
427
|
snippet(["npx synthesisui@latest init --ds <slug>"]),
|
|
413
428
|
body("Browse systems at https://www.synthesisui.com/gallery"),
|
|
414
429
|
];
|
|
@@ -784,7 +799,19 @@ export async function doctor(opts) {
|
|
|
784
799
|
* na mesma tela (dono: "fiquei perdido"). Ou o número não significa nada, ou existe uma lista de
|
|
785
800
|
* prioridades; as duas não cabem juntas.
|
|
786
801
|
*/
|
|
787
|
-
|
|
802
|
+
/**
|
|
803
|
+
* A FIAÇÃO SÓ EXISTE PARA UM SISTEMA NOSSO - e usar "tem nomes" no lugar disso recusava o
|
|
804
|
+
* `--fix` a quem nunca instalou nada (medido em 18/08, no caminho de quem começa do zero).
|
|
805
|
+
*
|
|
806
|
+
* Ela escreve os tokens dela no próprio `:root`, o doctor passa a dizer "7 dos seus valores
|
|
807
|
+
* têm nome", e o `--fix` respondia "trocar agora apontaria para variáveis que o navegador não
|
|
808
|
+
* resolve". Ele resolve: o CSS é dela e já está na página. A frase era literalmente falsa, e
|
|
809
|
+
* ela aparece no primeiro comando que promete adotar.
|
|
810
|
+
*
|
|
811
|
+
* `table.source` é a distinção certa e ela já estava aqui, uma linha abaixo, em `unwired`:
|
|
812
|
+
* `"yours"` e `"adopted"` são o vocabulário dela, e não há duas linhas para ligar.
|
|
813
|
+
*/
|
|
814
|
+
const blocked = table.source === "installed" && (!wiring.imported || !wiring.scoped);
|
|
788
815
|
const unwired = table.source === "installed" &&
|
|
789
816
|
(!wiring.imported || !wiring.scoped || fontsPending);
|
|
790
817
|
if (unwired) {
|
|
@@ -897,7 +924,15 @@ export async function doctor(opts) {
|
|
|
897
924
|
if (hasSystem && measurable) {
|
|
898
925
|
console.log("");
|
|
899
926
|
console.log(body(`Token coverage ${meter(d.coverage)} ${paint.strong(`${String(d.coverage).padStart(3)}%`)}`));
|
|
900
|
-
console.log(body(paint.dim(
|
|
927
|
+
console.log(body(paint.dim(
|
|
928
|
+
/**
|
|
929
|
+
* DE QUEM É O VOCABULÁRIO, dito na própria linha.
|
|
930
|
+
*
|
|
931
|
+
* `systemName` cai em "this system" quando não há um instalado - e aí a tabela é a DELA,
|
|
932
|
+
* lida das folhas dela. "8 from this system" lê como se existisse um sistema nosso no
|
|
933
|
+
* projeto, e não existe: são os tokens que ela mesma declarou, usados no código dela.
|
|
934
|
+
*/
|
|
935
|
+
` ${d.tokenUses} ${table.source === "installed" ? `from ${systemName}` : "through your own tokens"}${d.ownUses > 0 ? `, ${d.ownUses} from your own tokens` : ""}, ${d.findings.length} by hand${d.phantomUses > 0 ? `, ${d.phantomUses} naming nothing` : ""}`)));
|
|
901
936
|
/**
|
|
902
937
|
* A CAMADA DE TOKEN DELE, CONTADA - e a decisão é do dono, em 13/08.
|
|
903
938
|
*
|
|
@@ -911,7 +946,22 @@ export async function doctor(opts) {
|
|
|
911
946
|
* `--ds-*` também segura. Apontar uma para a outra é uma linha por variável, num arquivo só - e
|
|
912
947
|
* os 122 usos seguem o sistema sem tocar em um componente sequer.
|
|
913
948
|
*/
|
|
914
|
-
|
|
949
|
+
/**
|
|
950
|
+
* E ESTE BLOCO SÓ EXISTE CONTRA UM SISTEMA NOSSO - ele estava se comparando consigo mesmo.
|
|
951
|
+
*
|
|
952
|
+
* `mirrored` marca um token dela quando a tabela segura aquele valor. Quando a tabela É a
|
|
953
|
+
* dela, ela foi construída a partir daquelas mesmas declarações, então TODO token dela sai
|
|
954
|
+
* espelhado por construção - 4 de 4 no projeto que caminhei em 18/08. E a linha seguinte
|
|
955
|
+
* mandava apontá-los para `--ds-*` num projeto que não tem um único `--ds-*`: um conselho
|
|
956
|
+
* impossível de seguir, no primeiro relatório que ela lê.
|
|
957
|
+
*
|
|
958
|
+
* O `used 0x` era falso pelo mesmo motivo: os usos dos tokens dela foram contados na linha
|
|
959
|
+
* de cima, porque contra a tabela dela eles SÃO o vocabulário conhecido.
|
|
960
|
+
*
|
|
961
|
+
* Quando não há sistema nosso, "os seus tokens" e "o sistema" são a mesma coisa, e não há
|
|
962
|
+
* nada a apontar - a linha de cima já disse tudo o que é verdade.
|
|
963
|
+
*/
|
|
964
|
+
if (d.ownTokens > 0 && table.source === "installed") {
|
|
915
965
|
console.log(body(paint.dim(` ${d.ownTokens} token${d.ownTokens === 1 ? "" : "s"} of your own, used ${d.ownUses}x${d.ownMirrored > 0 ? ` - ${d.ownMirrored} hold a value ${systemName} also names` : ""}`)));
|
|
916
966
|
if (d.ownMirrored > 0)
|
|
917
967
|
console.log(body(paint.dim(` point those at the \`--ds-*\` that holds it: ${d.ownMirrored} lines, one file`)));
|
|
@@ -1671,16 +1721,31 @@ export async function doctor(opts) {
|
|
|
1671
1721
|
*/
|
|
1672
1722
|
if (table.source === "yours") {
|
|
1673
1723
|
console.log("");
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1724
|
+
/**
|
|
1725
|
+
* E O COMANDO OFERECIDO É O QUE FAZ O SISTEMA DELA.
|
|
1726
|
+
*
|
|
1727
|
+
* O comentário que estava aqui já dizia a coisa certa - *"este leitor JÁ TEM um design
|
|
1728
|
+
* system, então 'instale o nosso' significaria substituir o dele, e um CTA que finge o
|
|
1729
|
+
* contrário é o tipo de exagero confiante que custa confiança"* - e a linha logo abaixo
|
|
1730
|
+
* oferecia `init --ds <slug>` mais a galeria, que é literalmente instalar o de outra
|
|
1731
|
+
* pessoa. O diagnóstico estava escrito e o conserto não (medido em 18/08).
|
|
1732
|
+
*
|
|
1733
|
+
* O comando que serve a ela existe e é outro: `import` lê o repositório DELA e devolve
|
|
1734
|
+
* um sistema com o vocabulário dela dentro. Caminhado num projeto em branco: quatro
|
|
1735
|
+
* tokens próprios e um componente saíram como "1 of 1 components came out with a
|
|
1736
|
+
* blueprint - 100%".
|
|
1737
|
+
*
|
|
1738
|
+
* A galeria continua dita, uma linha abaixo e em voz baixa: forkar um sistema pronto é
|
|
1739
|
+
* uma escolha legítima, só não é a primeira coisa a oferecer a quem já tem o dela.
|
|
1740
|
+
*/
|
|
1679
1741
|
console.log(body("Your tokens exist. What your agent is missing is a contract:"));
|
|
1680
1742
|
console.log(body("rules it reads BEFORE writing UI, and a manifest of what exists."));
|
|
1681
1743
|
console.log("");
|
|
1682
|
-
console.log(paint.blue(snippet(["npx synthesisui@latest
|
|
1683
|
-
console.log(body(paint.dim("
|
|
1744
|
+
console.log(paint.blue(snippet(["npx synthesisui@latest import --dry"])));
|
|
1745
|
+
console.log(body(paint.dim("reads THIS repo and turns your own vocabulary into that contract -")));
|
|
1746
|
+
console.log(body(paint.dim("local, free, and it writes nothing but the measurement.")));
|
|
1747
|
+
console.log("");
|
|
1748
|
+
console.log(body(paint.dim("Or start from a system somebody already published, if you would rather:")));
|
|
1684
1749
|
console.log(body(paint.blue("https://www.synthesisui.com/gallery")));
|
|
1685
1750
|
}
|
|
1686
1751
|
console.log("");
|
package/dist/commands/login.js
CHANGED
|
@@ -53,7 +53,8 @@ export async function login(opts) {
|
|
|
53
53
|
if (existing && sameRegistry(existing.registry, base)) {
|
|
54
54
|
console.log("");
|
|
55
55
|
console.log(`✓ Already signed in to ${base} on this machine.`);
|
|
56
|
-
console.log(" Run `synthesisui login --force` to sign in as someone else
|
|
56
|
+
console.log(" Run `synthesisui login --force` to sign in as someone else,");
|
|
57
|
+
console.log(" or `synthesisui logout` to sign out of this machine.");
|
|
57
58
|
return;
|
|
58
59
|
}
|
|
59
60
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { clearCredentials, credentialsPath, readCredentials, } from "../config.js";
|
|
2
|
+
/**
|
|
3
|
+
* SAIR DA CONTA NESTA MÁQUINA - o comando que faltava do par.
|
|
4
|
+
*
|
|
5
|
+
* O CLI sabia entrar e não sabia sair. Quem precisava trocar de conta era
|
|
6
|
+
* mandado apagar `~/.synthesisui/credentials.json` na mão - e uma instrução que
|
|
7
|
+
* termina em `rm` num diretório de configuração é a que faz alguém apagar a
|
|
8
|
+
* pasta errada.
|
|
9
|
+
*
|
|
10
|
+
* Ele diz de QUAL host saiu, porque a credencial guarda o registry que a
|
|
11
|
+
* emitiu: sair de um localhost e achar que saiu da produção é o mesmo mal
|
|
12
|
+
* entendido que fez o token de dev ser enviado para o site em 31/07.
|
|
13
|
+
*/
|
|
14
|
+
export async function logout() {
|
|
15
|
+
const existing = await readCredentials();
|
|
16
|
+
const had = await clearCredentials();
|
|
17
|
+
console.log("");
|
|
18
|
+
if (!had) {
|
|
19
|
+
console.log("✓ You are not signed in on this machine - nothing to do.");
|
|
20
|
+
console.log(" Run `synthesisui login` to connect the CLI to an account.");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
console.log(`✓ Signed out${existing?.registry ? ` of ${existing.registry}` : ""} on this machine.`);
|
|
24
|
+
console.log(` Removed ${credentialsPath}`);
|
|
25
|
+
console.log(" Run `synthesisui login` to sign in as someone else.");
|
|
26
|
+
}
|
package/dist/commands/mcp.js
CHANGED
|
@@ -1147,6 +1147,45 @@ const BY_COMPONENT = {
|
|
|
1147
1147
|
describe_component: "describe",
|
|
1148
1148
|
add_component: "add",
|
|
1149
1149
|
};
|
|
1150
|
+
/**
|
|
1151
|
+
* QUAL ARGUMENTO CARREGA O ASSUNTO DE CADA CHAMADA - e sem isto a medição não responde nada.
|
|
1152
|
+
*
|
|
1153
|
+
* Medido em 18/08: 2 das 15 ferramentas gravavam O QUE foi pedido; as outras 13 gravavam o
|
|
1154
|
+
* próprio nome. `compose_context` estava entre as 13 - e ela é a ÚNICA que emite `composed`,
|
|
1155
|
+
* que é o sinal inteiro de "aqui faltou uma receita". O banco acumulava "compose_context: 47"
|
|
1156
|
+
* e nunca "a família `field`: 12", e é o segundo número que abre uma candidata a receita.
|
|
1157
|
+
*
|
|
1158
|
+
* Esperar volume não consertaria isso: o dado que estava sendo guardado não responde a
|
|
1159
|
+
* pergunta, então o relógio da espera não estava correndo.
|
|
1160
|
+
*
|
|
1161
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
1162
|
+
* O QUE ENTRA, E O QUE NÃO ENTRA DE PROPÓSITO
|
|
1163
|
+
*
|
|
1164
|
+
* Entra o que é um NOME - do vocabulário dela ou do nosso. Ficam de fora, e não por
|
|
1165
|
+
* esquecimento:
|
|
1166
|
+
*
|
|
1167
|
+
* find_token `value` é um valor do repositório dele (`#4f46e5`)
|
|
1168
|
+
* check_file `path` é um caminho do repositório dele
|
|
1169
|
+
* playbook `section` é navegação nossa, e não diz nada sobre o sistema dele
|
|
1170
|
+
*
|
|
1171
|
+
* Os dois primeiros são dado DELE, e a nossa tabela de contadores não é lugar para eles. O
|
|
1172
|
+
* `SLUG` do outro lado já os rejeitaria em silêncio; não mandar é dizer a mesma coisa em voz
|
|
1173
|
+
* alta. `list_components`, `system_doctrine`, `recipe_vocabulary` e `refresh_system` não têm
|
|
1174
|
+
* assunto nenhum - a pergunta É o sistema inteiro.
|
|
1175
|
+
*
|
|
1176
|
+
* `validate_recipes` no plural é um LOTE, e um lote não tem um assunto só.
|
|
1177
|
+
*/
|
|
1178
|
+
const SUBJECT_ARG = {
|
|
1179
|
+
describe_component: "name",
|
|
1180
|
+
add_component: "name",
|
|
1181
|
+
/** A família pedida - o sinal que o A1 precisa e que não estava sendo guardado. */
|
|
1182
|
+
compose_context: "family",
|
|
1183
|
+
/** O que ela pediu e o sistema não tinha: a lacuna, com nome. */
|
|
1184
|
+
request_component: "name",
|
|
1185
|
+
request_rule: "name",
|
|
1186
|
+
request_token: "name",
|
|
1187
|
+
validate_recipe: "name",
|
|
1188
|
+
};
|
|
1150
1189
|
/**
|
|
1151
1190
|
* O ÚNICO PONTO DE INSTRUMENTAÇÃO - e é isto que o dono pediu (18/08): *"vira
|
|
1152
1191
|
* comportamento padrão e não depende de disciplina futura."*
|
|
@@ -1163,8 +1202,9 @@ async function callTool(root, name, args,
|
|
|
1163
1202
|
cli) {
|
|
1164
1203
|
const answer = await runTool(root, name, args);
|
|
1165
1204
|
const gesture = BY_COMPONENT[name];
|
|
1166
|
-
const
|
|
1167
|
-
|
|
1205
|
+
const subject = SUBJECT_ARG[name];
|
|
1206
|
+
const target = subject
|
|
1207
|
+
? String(args[subject] ?? "")
|
|
1168
1208
|
.trim()
|
|
1169
1209
|
.toLowerCase()
|
|
1170
1210
|
: "";
|
package/dist/commands/status.js
CHANGED
|
@@ -52,7 +52,21 @@ export async function status(opts) {
|
|
|
52
52
|
}
|
|
53
53
|
console.log(section("Status"));
|
|
54
54
|
if (installed.length === 0) {
|
|
55
|
+
/**
|
|
56
|
+
* NADA INSTALADO NÃO SIGNIFICA NADA A OFERECER, e mandar `list` era o conselho da outra pessoa.
|
|
57
|
+
*
|
|
58
|
+
* `list` mostra a GALERIA - sistemas que outros publicaram. Quem roda isto num repositório que
|
|
59
|
+
* já tem o próprio vocabulário recebia "escolha o de alguém", quando o comando que serve a ela
|
|
60
|
+
* lê o repositório DELA. O `doctor` cometia o mesmo desvio no parágrafo final, e ali o
|
|
61
|
+
* comentário até diagnosticava (medido em 18/08).
|
|
62
|
+
*
|
|
63
|
+
* As duas continuam ditas, na ordem certa: o dela primeiro, o de outra pessoa como alternativa.
|
|
64
|
+
*/
|
|
55
65
|
console.log(body("No design system installed in this project, so there is nothing to be in sync with."));
|
|
66
|
+
console.log("");
|
|
67
|
+
console.log(body("Make one out of this repo:"));
|
|
68
|
+
console.log(paint.blue(snippet(["npx synthesisui@latest import --dry"])));
|
|
69
|
+
console.log(body("Or bring in one somebody published:"));
|
|
56
70
|
console.log(paint.blue(snippet(["npx synthesisui@latest list"])));
|
|
57
71
|
return;
|
|
58
72
|
}
|
package/dist/config.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
1
|
+
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
/**
|
|
@@ -76,6 +76,30 @@ export async function writeToken(token, registry) {
|
|
|
76
76
|
mode: 0o600,
|
|
77
77
|
});
|
|
78
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* SAIR DA MÁQUINA - o outro lado da porta que o `login` abre.
|
|
81
|
+
*
|
|
82
|
+
* Existir era o mínimo: até aqui a única forma de encerrar a sessão era apagar
|
|
83
|
+
* `~/.synthesisui/credentials.json` à mão, e um produto que só sabe entrar
|
|
84
|
+
* obriga a pessoa a mexer no disco para trocar de conta.
|
|
85
|
+
*
|
|
86
|
+
* O arquivo inteiro vai embora, e não só o campo `token`: um arquivo sem token
|
|
87
|
+
* é indistinguível de nenhum arquivo para quem lê (`readCredentials` devolve
|
|
88
|
+
* `null` nos dois casos) e ainda deixaria o host da sessão antiga gravado.
|
|
89
|
+
*
|
|
90
|
+
* Devolve `false` quando não havia nada - a diferença entre "saí" e "você já
|
|
91
|
+
* estava fora" é a única coisa que o comando tem para dizer.
|
|
92
|
+
*/
|
|
93
|
+
export async function clearCredentials() {
|
|
94
|
+
const existing = await readCredentials();
|
|
95
|
+
try {
|
|
96
|
+
await rm(credentialsPath, { force: true });
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// já não existe, ou o disco recusou - o estado final é o mesmo
|
|
100
|
+
}
|
|
101
|
+
return existing !== null;
|
|
102
|
+
}
|
|
79
103
|
/** Project-level config (committed): `<root>/_synthesisui/config.json`. */
|
|
80
104
|
export const DEFAULT_CONFIG = {
|
|
81
105
|
target: "next",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FAMILY_PREFIX, familySays, normalizeValue, } from "./tokens.js";
|
|
1
|
+
import { FAMILY_PREFIX, familySays, formDecides, normalizeValue, UNAMBIGUOUS, } from "./tokens.js";
|
|
2
2
|
/**
|
|
3
3
|
* COMO ELE CHAMA O VALOR - para a gente parar de renomear as variáveis dele.
|
|
4
4
|
*
|
|
@@ -47,14 +47,6 @@ import { FAMILY_PREFIX, familySays, normalizeValue, } from "./tokens.js";
|
|
|
47
47
|
* que o próprio css dele nomeia `--dashboard-font-family`. É pouco, e é o único grupo que sobrou do
|
|
48
48
|
* item que eu tinha nomeado - os `em` saíram na leva anterior.
|
|
49
49
|
*/
|
|
50
|
-
const UNAMBIGUOUS = {
|
|
51
|
-
/** `#rrggbbaa`, que é onde toda a família de dialetos cai. */
|
|
52
|
-
color: /^#[0-9a-f]{8}$/,
|
|
53
|
-
/** `s` e `ms` não aparecem em nenhuma outra família do contrato. */
|
|
54
|
-
motion: /^-?[\d.]+ms$/,
|
|
55
|
-
/** Uma pilha de fontes: tem vírgula, ou é uma das palavras genéricas do CSS. */
|
|
56
|
-
font: /,|^(?:serif|sans-serif|monospace|cursive|fantasy|system-ui)$/,
|
|
57
|
-
};
|
|
58
50
|
const segments = (name) => name.replace(/^--/, "").split("-");
|
|
59
51
|
/**
|
|
60
52
|
* QUAL DOS NOMES DELE, quando mais de um segura o mesmo valor - e são 18 no repo real.
|
|
@@ -142,8 +134,7 @@ export function theirNames(ours, theirs) {
|
|
|
142
134
|
* Recusar aqui não perde informação: sem alias, `nameToWrite` cai no NOSSO token, que é da
|
|
143
135
|
* família certa porque foi o prefixo dela que o trouxe a este laço.
|
|
144
136
|
*/
|
|
145
|
-
const
|
|
146
|
-
const usable = formDecides
|
|
137
|
+
const usable = formDecides(value)
|
|
147
138
|
? candidates
|
|
148
139
|
: candidates.filter((n) => familySays(kind, n));
|
|
149
140
|
if (usable.length === 0)
|
package/dist/doctor/tokens.js
CHANGED
|
@@ -569,6 +569,27 @@ export const FAMILY_WORDS = {
|
|
|
569
569
|
* `--dashboard-radius-lg` é um raio e o primeiro segmento é o namespace dele. Olhar só o começo
|
|
570
570
|
* recusaria um nome certo por causa de um prefixo de produto, que é a metade oposta do mesmo erro.
|
|
571
571
|
*/
|
|
572
|
+
/**
|
|
573
|
+
* OS VALORES CUJA FORMA JÁ DIZ A FAMÍLIA - e por isso o nome não precisa dizer.
|
|
574
|
+
*
|
|
575
|
+
* Morava em `their-names.ts`, privada, e a falta dela aqui foi medida no corpus: filtrar por
|
|
576
|
+
* palavra sem esta porta trocou `--brand-500` por `--loader-color` num hex. Os dois são cor, e
|
|
577
|
+
* o segundo só ganhou por ter a palavra "color" no nome - a doc de `FAMILY_WORDS` já avisava
|
|
578
|
+
* que 748 dos 755 nomes sem palavra de categoria são cor.
|
|
579
|
+
*
|
|
580
|
+
* O que fica de fora é o COMPRIMENTO, e fica de propósito: `24px` pode ser raio, espaçamento ou
|
|
581
|
+
* tamanho de fonte, e ali o nome é a única pista que existe.
|
|
582
|
+
*/
|
|
583
|
+
export const UNAMBIGUOUS = {
|
|
584
|
+
/** `#rrggbbaa`, que é onde toda a família de dialetos cai. */
|
|
585
|
+
color: /^#[0-9a-f]{8}$/,
|
|
586
|
+
/** `s` e `ms` não aparecem em nenhuma outra família do contrato. */
|
|
587
|
+
motion: /^-?[\d.]+ms$/,
|
|
588
|
+
/** Uma pilha de fontes: tem vírgula, ou é uma das palavras genéricas do CSS. */
|
|
589
|
+
font: /,|^(?:serif|sans-serif|monospace|cursive|fantasy|system-ui)$/,
|
|
590
|
+
};
|
|
591
|
+
/** A forma deste valor já decide a família dele, então a palavra no nome não precisa. */
|
|
592
|
+
export const formDecides = (value) => Object.values(UNAMBIGUOUS).some((f) => f.test(value));
|
|
572
593
|
export const familySays = (kind, name) => {
|
|
573
594
|
const words = FAMILY_WORDS[kind] ?? [];
|
|
574
595
|
const segments = name.replace(/^--/, "").toLowerCase().split("-");
|
|
@@ -596,8 +617,33 @@ export function tokenMatch(table, literal, kind) {
|
|
|
596
617
|
const hit = table.byValue.get(normalizeValue(literal, table.rootPx));
|
|
597
618
|
if (!hit || hit.length === 0)
|
|
598
619
|
return null;
|
|
620
|
+
/**
|
|
621
|
+
* O PREFIXO É NOSSO; O NOME PODE SER DELA - e olhar só o prefixo reprovava todo o vocabulário
|
|
622
|
+
* dela como coincidência entre famílias (medido em 18/08, no caminho de quem começa do zero).
|
|
623
|
+
*
|
|
624
|
+
* `--ds-radius-md` carrega a família por construção, e é isso que o prefixo lê. `--radius-card`
|
|
625
|
+
* não carrega prefixo nenhum, então nenhum token dela casava e TODO achado saía marcado como
|
|
626
|
+
* erro de categoria - com a frase se contradizendo na mesma linha: "no radius named for it ·
|
|
627
|
+
* the value lives as --radius-card". O `--fix` então deixava de trocar exatamente os valores
|
|
628
|
+
* que ela acabou de nomear.
|
|
629
|
+
*
|
|
630
|
+
* `familySays` é a resposta e ela já existia para o outro lado da mesma pergunta (`their-names`,
|
|
631
|
+
* `absorb-plan`): a família sai de QUALQUER segmento do nome, então o namespace de produto dela
|
|
632
|
+
* não atrapalha. Os dois caminhos somam - a garantia por construção continua valendo primeiro.
|
|
633
|
+
*/
|
|
599
634
|
const prefix = kind ? FAMILY_PREFIX[kind] : undefined;
|
|
600
|
-
|
|
635
|
+
/**
|
|
636
|
+
* E A PALAVRA SÓ DECIDE QUANDO A FORMA NÃO DECIDE - a mesma porta que `their-names` usa.
|
|
637
|
+
*
|
|
638
|
+
* Sem ela, filtrar por palavra num hex escolhia `--loader-color` em vez de `--brand-500`
|
|
639
|
+
* (medido no corpus dourado): os dois são cor, e o segundo perdia por não ter a palavra
|
|
640
|
+
* "color" no nome. Num comprimento cru é o contrário - ali a palavra é a única pista.
|
|
641
|
+
*/
|
|
642
|
+
const byWord = kind && !formDecides(normalizeValue(literal, table.rootPx));
|
|
643
|
+
const family = kind
|
|
644
|
+
? hit.filter((n) => (prefix ? n.startsWith(prefix) : false) ||
|
|
645
|
+
(byWord ? familySays(kind, n) : false))
|
|
646
|
+
: [];
|
|
601
647
|
const pool = family.length > 0 ? family : hit;
|
|
602
648
|
// Semantic roles name intent; primitives name a shelf. Prefer intent.
|
|
603
649
|
const semantic = pool.find((n) => n.includes("-semantic-"));
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
|
+
import { boolFlag, parseFlags } from "./cli-flags.js";
|
|
4
5
|
import { absorb } from "./commands/absorb.js";
|
|
5
6
|
import { add } from "./commands/add.js";
|
|
6
7
|
import { adopt } from "./commands/adopt.js";
|
|
@@ -18,6 +19,7 @@ import { runImport } from "./commands/import.js";
|
|
|
18
19
|
import { init } from "./commands/init.js";
|
|
19
20
|
import { list } from "./commands/list.js";
|
|
20
21
|
import { login } from "./commands/login.js";
|
|
22
|
+
import { logout } from "./commands/logout.js";
|
|
21
23
|
import { mcp } from "./commands/mcp.js";
|
|
22
24
|
import { refit } from "./commands/refit.js";
|
|
23
25
|
import { request } from "./commands/request.js";
|
|
@@ -37,6 +39,7 @@ const HELP = `synthesisui - bring SynthesisUI design systems into your project
|
|
|
37
39
|
|
|
38
40
|
Usage - deterministic, FREE:
|
|
39
41
|
synthesisui login [options] connect the CLI to your account (device-flow; --force to switch accounts)
|
|
42
|
+
synthesisui logout sign out of this machine (removes the saved token)
|
|
40
43
|
synthesisui init [options] write _synthesisui/config.json (target, dirs); --ds to bring one in
|
|
41
44
|
synthesisui list [options] list the published design systems
|
|
42
45
|
synthesisui list --mine your own systems, with their group
|
|
@@ -135,61 +138,6 @@ Examples:
|
|
|
135
138
|
synthesisui advise "habit-building app for tracking personal finances"
|
|
136
139
|
synthesisui generate "an upgrade banner with a title, message and a primary CTA"
|
|
137
140
|
`;
|
|
138
|
-
/** Extracts simple `--flag value` pairs and the remaining positionals. */
|
|
139
|
-
/**
|
|
140
|
-
* A REPEATED FLAG ACCUMULATES rather than overwriting.
|
|
141
|
-
*
|
|
142
|
-
* `--usage apps/web --usage apps/admin` is the natural way to say two, and keeping
|
|
143
|
-
* only the last would drop one silently - which is the failure mode this codebase
|
|
144
|
-
* refuses everywhere else. Every existing flag is passed once and still arrives as
|
|
145
|
-
* a string, so nothing that reads `typeof flags.x === "string"` changes.
|
|
146
|
-
*/
|
|
147
|
-
function parseFlags(argv) {
|
|
148
|
-
const positionals = [];
|
|
149
|
-
const flags = {};
|
|
150
|
-
const put = (key, value) => {
|
|
151
|
-
const had = flags[key];
|
|
152
|
-
if (had === undefined) {
|
|
153
|
-
flags[key] = value;
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
if (typeof value !== "string")
|
|
157
|
-
return;
|
|
158
|
-
flags[key] = [
|
|
159
|
-
...(Array.isArray(had) ? had : typeof had === "string" ? [had] : []),
|
|
160
|
-
value,
|
|
161
|
-
];
|
|
162
|
-
};
|
|
163
|
-
for (let i = 0; i < argv.length; i++) {
|
|
164
|
-
const arg = argv[i];
|
|
165
|
-
if (arg === "-h" || arg === "--help") {
|
|
166
|
-
flags.help = true;
|
|
167
|
-
}
|
|
168
|
-
else if (arg.startsWith("--")) {
|
|
169
|
-
const body = arg.slice(2);
|
|
170
|
-
const eq = body.indexOf("=");
|
|
171
|
-
if (eq !== -1) {
|
|
172
|
-
// `--key=value` form (e.g. --out=templates/page.tsx)
|
|
173
|
-
put(body.slice(0, eq), body.slice(eq + 1));
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
// `--key value` form
|
|
177
|
-
const next = argv[i + 1];
|
|
178
|
-
if (next !== undefined && !next.startsWith("--")) {
|
|
179
|
-
put(body, next);
|
|
180
|
-
i++;
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
put(body, true);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
else {
|
|
188
|
-
positionals.push(arg);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
return { positionals, flags };
|
|
192
|
-
}
|
|
193
141
|
async function main() {
|
|
194
142
|
const { positionals, flags } = parseFlags(process.argv.slice(2));
|
|
195
143
|
const [command, ...args] = positionals;
|
|
@@ -397,11 +345,19 @@ async function main() {
|
|
|
397
345
|
await add(slug, { registry, dir, version, cli: CLI_VERSION });
|
|
398
346
|
break;
|
|
399
347
|
}
|
|
348
|
+
case "logout":
|
|
349
|
+
/**
|
|
350
|
+
* O outro lado do `login`. Sem ele a única saída era apagar
|
|
351
|
+
* `~/.synthesisui/credentials.json` à mão - e trocar de conta é o
|
|
352
|
+
* caminho normal de quem testa a plataforma em mais de um repositório.
|
|
353
|
+
*/
|
|
354
|
+
await logout();
|
|
355
|
+
break;
|
|
400
356
|
case "login":
|
|
401
357
|
// `--force` porque o comando agora sai cedo quando esta máquina já tem
|
|
402
358
|
// sessão para este host - trocar de conta continua possível, e passa a
|
|
403
359
|
// ser dito em vez de ser o comportamento padrão.
|
|
404
|
-
await login({ registry, force:
|
|
360
|
+
await login({ registry, force: boolFlag(flags, "force") });
|
|
405
361
|
break;
|
|
406
362
|
case "init": {
|
|
407
363
|
const target = typeof flags.target === "string" ? flags.target : undefined;
|
|
@@ -562,10 +518,10 @@ async function main() {
|
|
|
562
518
|
dir,
|
|
563
519
|
registry,
|
|
564
520
|
cli: CLI_VERSION,
|
|
565
|
-
recordOnly:
|
|
566
|
-
yes:
|
|
521
|
+
recordOnly: boolFlag(flags, "record-only"),
|
|
522
|
+
yes: boolFlag(flags, "yes"),
|
|
567
523
|
/** `--full`: o relatório inteiro do leitor. Por padrão a re-medição conta o que MUDOU. */
|
|
568
|
-
full:
|
|
524
|
+
full: boolFlag(flags, "full"),
|
|
569
525
|
});
|
|
570
526
|
break;
|
|
571
527
|
/**
|
package/dist/install-marks.js
CHANGED
|
@@ -159,7 +159,7 @@ export const MATERIALISER_SINCE = "0.16.241";
|
|
|
159
159
|
* `var(--text-caption)` - um token de tipo numa posição de raio. Medido no repositório real: 290
|
|
160
160
|
* sugestões com a categoria trocada, 66 delas graváveis por um `--fix --write`.
|
|
161
161
|
*/
|
|
162
|
-
export const CHECKER_SINCE = "0.16.
|
|
162
|
+
export const CHECKER_SINCE = "0.16.250";
|
|
163
163
|
/**
|
|
164
164
|
* A ÚLTIMA VERSÃO EM QUE OS LEITORES PASSARAM A PRODUZIR UM CENSO DIFERENTE.
|
|
165
165
|
*
|
package/package.json
CHANGED