synthesisui 0.16.421 → 0.16.423
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/claude-md.js +19 -38
- package/dist/commands/add.js +57 -94
- package/dist/commands/component.js +96 -201
- package/dist/commands/connect.js +41 -0
- package/dist/commands/doctor.js +74 -428
- package/dist/commands/generate.js +25 -4
- package/dist/commands/import.js +2 -2
- package/dist/commands/init.js +13 -10
- package/dist/commands/refit.js +13 -2
- package/dist/commands/summary.js +9 -5
- package/dist/commands/sync.js +84 -0
- package/dist/commands/template.js +81 -53
- package/dist/commands/upgrade.js +5 -3
- package/dist/commands/use.js +7 -8
- package/dist/component-codegen.js +50 -23
- package/dist/copy/connect.pt-BR.js +3 -0
- package/dist/doctor/apply-fix.js +2 -2
- package/dist/doctor/scan.js +33 -2
- package/dist/doctor/their-names.js +8 -2
- package/dist/fonts.js +29 -5
- package/dist/global-sheet.js +14 -125
- package/dist/guide.js +131 -83
- package/dist/install-marks.js +4 -4
- package/dist/local-edits.js +257 -0
- package/dist/project-facts.js +138 -32
- package/dist/recipe-css.js +249 -0
- package/dist/skills.js +5 -16
- package/dist/their-tongue.js +180 -43
- package/dist/wired-slugs.js +31 -17
- package/package.json +1 -1
- package/dist/setup-prompt.js +0 -95
- package/dist/sheet-needed.js +0 -317
- package/dist/skill-configure.js +0 -13
- package/dist/wiring-read.js +0 -212
package/dist/commands/doctor.js
CHANGED
|
@@ -12,25 +12,16 @@ import { appendEvent, COVERAGE_RULE, COVERAGE_RULE_REASON, readEvents, suggestio
|
|
|
12
12
|
import { bindingsFromDocument, countComponents, findOverrides, } from "../doctor/overrides.js";
|
|
13
13
|
import { checkableName, readRequests, verifyAndCloseRequests, } from "../doctor/requests.js";
|
|
14
14
|
import { DEFAULT_ROOT_PX, rootSizeOf, saidOfRoot, } from "../doctor/root-size.js";
|
|
15
|
-
import { diagnose, nameToWrite, scanSource, siblingTokens, } from "../doctor/scan.js";
|
|
15
|
+
import { diagnose, nameToWrite, ourNameOnly, scanSource, siblingTokens, } from "../doctor/scan.js";
|
|
16
16
|
import { findSelfConflicts, forbiddenProps, isReset, propMatchesLabel, } from "../doctor/self-conflict.js";
|
|
17
17
|
import { withTheirNames } from "../doctor/their-names.js";
|
|
18
18
|
import { buildTable, EMPTY_TABLE, nearestToken, } from "../doctor/tokens.js";
|
|
19
19
|
import { parseRules } from "../doctrine.js";
|
|
20
|
-
/**
|
|
21
|
-
* `detectAppDirs` SAIU DESTE IMPORT em 09/09: quem pergunta "quais pastas são app?" agora é
|
|
22
|
-
* `readWiringPerApp`, que responde a fiação de cada uma. O comando não escolhe mais um app.
|
|
23
|
-
*/
|
|
24
|
-
import { globalSheetOf, prefixFrom } from "../global-sheet.js";
|
|
25
20
|
import { groupRole } from "../group-role.js";
|
|
26
21
|
import { actingSlug, describeScope, measuredScope, scopePaths, } from "../measured-scope.js";
|
|
27
22
|
import { body, paint, section, snippet } from "../output.js";
|
|
28
|
-
import { setupPrompt } from "../setup-prompt.js";
|
|
29
|
-
import { installedThemeCss, whatOnlyTheSheetResolves, } from "../sheet-needed.js";
|
|
30
23
|
import { resolveDeps } from "../stack.js";
|
|
31
|
-
import { projectTongue } from "../their-tongue.js";
|
|
32
24
|
import { danglingTheirVars } from "../their-vars.js";
|
|
33
|
-
import { readWiring, readWiringPerApp } from "../wiring-read.js";
|
|
34
25
|
/**
|
|
35
26
|
* `synthesisui doctor` - the check nobody else ships.
|
|
36
27
|
*
|
|
@@ -617,17 +608,6 @@ async function runFix(root, d, writing) {
|
|
|
617
608
|
console.log(body(paint.dim("Read the diff before committing - it is your code, and this replaced literals with the tokens your own system declares.")));
|
|
618
609
|
}
|
|
619
610
|
}
|
|
620
|
-
/**
|
|
621
|
-
* O NOME QUE ESTA TROCA ESCREVERIA É DELE? - a pergunta que a recusa do `--fix` nunca fez.
|
|
622
|
-
*
|
|
623
|
-
* `nameToWrite` devolve `theirToken ?? token`: quando o repositório dele nomeia aquele valor, é o
|
|
624
|
-
* nome DELE que vai para o código. Um nome dele resolve no navegador dele HOJE, com ou sem a nossa
|
|
625
|
-
* folha instalada - a folha só é necessária para os `--ds-*`, que são nossos.
|
|
626
|
-
*/
|
|
627
|
-
const ownName = (f) => {
|
|
628
|
-
const name = nameToWrite(f);
|
|
629
|
-
return Boolean(name && !name.startsWith("--ds-"));
|
|
630
|
-
};
|
|
631
611
|
export async function doctor(opts) {
|
|
632
612
|
const root = resolve(opts.dir ?? process.cwd());
|
|
633
613
|
/**
|
|
@@ -743,15 +723,6 @@ export async function doctor(opts) {
|
|
|
743
723
|
*
|
|
744
724
|
* Nobody debugs from 0%. They conclude the product does not work.
|
|
745
725
|
*/
|
|
746
|
-
const wiring = await readWiring(root, table.slug);
|
|
747
|
-
/**
|
|
748
|
-
* O QUE, NESTE REPOSITÓRIO, SÓ A NOSSA FOLHA RESOLVE - acumulado na varredura QUE JÁ ACONTECE.
|
|
749
|
-
*
|
|
750
|
-
* Uma segunda passada pelo disco para responder isto custaria o dobro num repositório de 178
|
|
751
|
-
* arquivos, e a resposta está no mesmo texto que o scan já tem na mão. Ver `sheet-needed.ts`.
|
|
752
|
-
*/
|
|
753
|
-
const themeCss = table.slug ? await installedThemeCss(root, table.slug) : "";
|
|
754
|
-
let scannedSource = "";
|
|
755
726
|
const skippedProjects = [];
|
|
756
727
|
const tally = emptyTally();
|
|
757
728
|
const internalSpecs = await internalSpecifiers(root);
|
|
@@ -763,9 +734,6 @@ export async function doctor(opts) {
|
|
|
763
734
|
continue;
|
|
764
735
|
const rel = relative(root, file);
|
|
765
736
|
reports.push(scanSource(rel, src, table));
|
|
766
|
-
/** A pasta que a plataforma escreve não conta: ela É a folha, não um consumidor dela. */
|
|
767
|
-
if (!rel.startsWith("_synthesisui"))
|
|
768
|
-
scannedSource += `\n${src}`;
|
|
769
737
|
// Composition, alongside values: the contract check needs to know which
|
|
770
738
|
// elements this file writes and with what options. Stories and tests are
|
|
771
739
|
// excluded for the reason they are excluded everywhere else - they compose
|
|
@@ -916,304 +884,28 @@ export async function doctor(opts) {
|
|
|
916
884
|
* distinção em vez de cada tela refazê-la. Ver `Reach` em `scan.ts`.
|
|
917
885
|
*/
|
|
918
886
|
const measurable = d.reach.measured;
|
|
919
|
-
// Before the number, because the number is the thing that misleads. An
|
|
920
|
-
// installed-but-unwired system reads 0%, and 0% reads as "broken product"
|
|
921
|
-
// rather than "one import missing".
|
|
922
|
-
// Fonts only count as missing when `init` actually wrote the file - a
|
|
923
|
-
// non-Next project has no fonts.ts and must not be nagged about one.
|
|
924
|
-
const fontsPending = wiring.fontsWritten && !wiring.fontsMapped;
|
|
925
887
|
/**
|
|
926
|
-
* A FIAÇÃO
|
|
888
|
+
* A FIAÇÃO SAIU DAQUI EM 11/09, e com ela o portão inteiro - `INV-GERAL-13`.
|
|
927
889
|
*
|
|
928
|
-
*
|
|
929
|
-
*
|
|
930
|
-
*
|
|
931
|
-
*
|
|
932
|
-
*/
|
|
933
|
-
/**
|
|
934
|
-
* A FIAÇÃO SÓ EXISTE PARA UM SISTEMA NOSSO - e usar "tem nomes" no lugar disso recusava o
|
|
935
|
-
* `--fix` a quem nunca instalou nada (medido em 18/08, no caminho de quem começa do zero).
|
|
936
|
-
*
|
|
937
|
-
* Ela escreve os tokens dela no próprio `:root`, o doctor passa a dizer "7 dos seus valores
|
|
938
|
-
* têm nome", e o `--fix` respondia "trocar agora apontaria para variáveis que o navegador não
|
|
939
|
-
* resolve". Ele resolve: o CSS é dela e já está na página. A frase era literalmente falsa, e
|
|
940
|
-
* ela aparece no primeiro comando que promete adotar.
|
|
941
|
-
*
|
|
942
|
-
* `table.source` é a distinção certa e ela já estava aqui, uma linha abaixo, em `unwired`:
|
|
943
|
-
* `"yours"` e `"adopted"` são o vocabulário dela, e não há duas linhas para ligar.
|
|
944
|
-
*/
|
|
945
|
-
const sheetNeed = whatOnlyTheSheetResolves({
|
|
946
|
-
source: scannedSource,
|
|
947
|
-
themeCss,
|
|
948
|
-
theirNames: installed.theirs.byName.keys(),
|
|
949
|
-
/**
|
|
950
|
-
* A TERCEIRA FONTE NÃO É MEDIDA AQUI - ver o mesmo comentário em `component.ts` e o número em
|
|
951
|
-
* `steps/11-fora-do-escopo.md`. Este comando decide `unwired` e `blocked` por `needed`, então
|
|
952
|
-
* ligar a medição muda o veredito do `doctor` num repositório real: é etapa própria, e o vazio
|
|
953
|
-
* deixa a omissão escrita em vez de escondida.
|
|
954
|
-
*/
|
|
955
|
-
sheetCss: "",
|
|
956
|
-
});
|
|
957
|
-
/**
|
|
958
|
-
* BLOQUEADO SÓ QUANDO A FOLHA É NECESSÁRIA - a mesma pergunta que decide `unwired`.
|
|
890
|
+
* O QUE ESTE TRECHO FAZIA, em 250 linhas: media se algo neste repositório ainda precisava da nossa
|
|
891
|
+
* folha, imprimia *"<sistema> is installed - but this project does not load it yet"*, listava os
|
|
892
|
+
* `✗` de `@import` e `data-ds`, colava um prompt de setup para o agente dele, e RECUSAVA o
|
|
893
|
+
* `--fix` enquanto aquilo não fosse feito.
|
|
959
894
|
*
|
|
960
|
-
*
|
|
961
|
-
*
|
|
962
|
-
*
|
|
963
|
-
* retira a exigência numa seção e a mantém na outra ensina que nenhuma das duas é para valer.
|
|
964
|
-
*/
|
|
965
|
-
const blocked = table.source === "installed" &&
|
|
966
|
-
sheetNeed.needed &&
|
|
967
|
-
(!wiring.imported || !wiring.scoped);
|
|
968
|
-
/**
|
|
969
|
-
* QUANTAS DAS DUAS FALTAM - e sem este número três frases mandavam consertar DUAS coisas quando
|
|
970
|
-
* faltava UMA.
|
|
895
|
+
* O QUE O DONO LEU NA PRÓPRIA TELA (11/09): *"isso nunca deve acontecer, a gente havia combinado
|
|
896
|
+
* (...) garanta que nunca mais você irá falar desse import e nem solicitar e nem precisar nos
|
|
897
|
+
* projetos"*.
|
|
971
898
|
*
|
|
972
|
-
*
|
|
973
|
-
*
|
|
974
|
-
*
|
|
975
|
-
*
|
|
976
|
-
*
|
|
899
|
+
* E A PERGUNTA MORREU COM A CAUSA, não com o texto. Nada que a plataforma escreve no repositório
|
|
900
|
+
* dele carrega uma variável nossa (`their-tongue.ts`) nem um utilitário que dependa do nosso
|
|
901
|
+
* `@theme` (`theirThemeVars`), e o `--fix` só escreve nomes que o código dele declara
|
|
902
|
+
* (`nameToWrite`). Então não sobra nada para uma folha nossa resolver: não há fiação a medir, não
|
|
903
|
+
* há o que cobrar, e não há por que recusar o `--fix`.
|
|
977
904
|
*
|
|
978
|
-
*
|
|
979
|
-
*
|
|
905
|
+
* A RECUSA ERA O PIOR PEDAÇO. Medido no `codelevel` em 04/09: das 216 trocas com nome esperando,
|
|
906
|
+
* 156 (72%) escreviam o nome DELE e resolviam no navegador dele naquele dia - e o comando recusava
|
|
907
|
+
* as 156 para proteger as 60 que apontavam para nós. Essas 60 não existem mais.
|
|
980
908
|
*/
|
|
981
|
-
const missingWiring = (wiring.imported ? 0 : 1) + (wiring.scoped ? 0 : 1);
|
|
982
|
-
const bothMissing = missingWiring === 2;
|
|
983
|
-
/**
|
|
984
|
-
* A FIAÇÃO SÓ É COBRADA QUANDO ALGUMA COISA NESTE REPOSITÓRIO PRECISA DELA - ver `sheet-needed.ts`.
|
|
985
|
-
*
|
|
986
|
-
* O DEFEITO, apontado pelo dono em 07/09 sobre o próprio repositório: *"por que a gente precisa
|
|
987
|
-
* desses imports, visto que o design do projeto dele já funciona? criar esse import gera
|
|
988
|
-
* dependência ao design system, que é coisa que a gente não quer - a gente quer isolar os dois
|
|
989
|
-
* pontos, sendo que o nosso deve ser apenas uma REFERÊNCIA para que qualquer agente que gera
|
|
990
|
-
* código saiba como utilizar o design system"*.
|
|
991
|
-
*
|
|
992
|
-
* MEDIDO NO `codelevel` no mesmo dia: no repositório inteiro, apenas dois arquivos mencionam
|
|
993
|
-
* `--ds-*` - um componente que a PLATAFORMA gerou com uma versão anterior à tradução, e a costura
|
|
994
|
-
* de tipografia que o nosso próprio setup pediu. Zero linhas do código que ELE escreveu. Regerado
|
|
995
|
-
* com o CLI de hoje, o componente sai com 0 referências à nossa folha, e as duas animações que ele
|
|
996
|
-
* veste são declaradas pelo `globals.css` dele.
|
|
997
|
-
*
|
|
998
|
-
* Ou seja: o comando cobrava uma dependência de runtime que nada naquele repositório usava - e o
|
|
999
|
-
* produto já promete o contrário em `their-tongue.ts` (*"nenhuma folha nossa precisa existir no
|
|
1000
|
-
* repositório dele"*). As duas metades discordavam porque nenhuma perguntava.
|
|
1001
|
-
*
|
|
1002
|
-
* O ESCOPO (`data-ds`) SEGUE A MESMA REGRA e pelo mesmo motivo: ele existe para a folha aplicar
|
|
1003
|
-
* dentro dele. Sem folha necessária, um atributo na árvore dele é a mesma dependência com outro
|
|
1004
|
-
* nome.
|
|
1005
|
-
*
|
|
1006
|
-
* E QUANDO ALGO PRECISA, tudo continua exatamente como era - inclusive o roteiro para o agente. A
|
|
1007
|
-
* mudança não é deixar de cobrar: é parar de cobrar sem ter perguntado.
|
|
1008
|
-
*/
|
|
1009
|
-
const unwired = table.source === "installed" &&
|
|
1010
|
-
sheetNeed.needed &&
|
|
1011
|
-
(!wiring.imported || !wiring.scoped || fontsPending);
|
|
1012
|
-
if (unwired) {
|
|
1013
|
-
console.log("");
|
|
1014
|
-
console.log(body(`${table.name ?? table.slug} is installed - but this project does not load it yet.`));
|
|
1015
|
-
console.log("");
|
|
1016
|
-
/**
|
|
1017
|
-
* O QUE ESTÁ COBRANDO A FOLHA, POR NOME - senão a exigência lê como uma regra nossa.
|
|
1018
|
-
*
|
|
1019
|
-
* Ela não é: é um efeito do que ESTE repositório escreveu. Medido no `codelevel` (07/09), as
|
|
1020
|
-
* duas coisas que a exigiam eram um componente gerado por uma versão anterior à tradução do CLI
|
|
1021
|
-
* e a costura de tipografia que o nosso próprio setup pediu - nenhuma linha do código dele.
|
|
1022
|
-
* Regerado com o CLI de hoje, o mesmo componente sai com zero referências e a exigência some.
|
|
1023
|
-
*
|
|
1024
|
-
* Sem esta linha, quem lê não tem como saber que a dependência é REMOVÍVEL, e a única saída
|
|
1025
|
-
* visível é aceitar o import.
|
|
1026
|
-
*/
|
|
1027
|
-
/**
|
|
1028
|
-
* E A SAÍDA SÓ É OFERECIDA QUANDO ELA EXISTE - senão o comando manda consertar o que não conserta.
|
|
1029
|
-
*
|
|
1030
|
-
* "re-run `component` and it speaks your own names instead" só é verdade onde há MAPA: onde algum
|
|
1031
|
-
* valor do sistema coincide com um nome que o repositório dele já declara. Sem mapa, a tradução
|
|
1032
|
-
* roda e não tem o que traduzir, regerar devolve o mesmo arquivo, e a folha é o caminho legítimo.
|
|
1033
|
-
*
|
|
1034
|
-
* MEDIDO EM 07/09, validando o binário publicado num `create-next-app` que instalou o
|
|
1035
|
-
* `codelevel`: `.lock` sem `tokenMap`, o componente saiu com 14 linhas `--ds-*`, e esta frase
|
|
1036
|
-
* mandava regerar. No `codelevel-monorepo`, onde o `.lock` tem 33 pares, regerar É a saída - e o
|
|
1037
|
-
* mesmo texto servia os dois. É o defeito que o `CLAUDE.md` registra em primeira pessoa: afirmar
|
|
1038
|
-
* que um comando conserta o que ele não conserta.
|
|
1039
|
-
*/
|
|
1040
|
-
const translatable = (await projectTongue(root, table.slug ?? "")) !== null;
|
|
1041
|
-
const asks = sheetNeed.variables.length > 0
|
|
1042
|
-
? `${sheetNeed.variables.slice(0, 3).join(", ")}${sheetNeed.variables.length > 3 ? `, +${sheetNeed.variables.length - 3} more` : ""}${translatable
|
|
1043
|
-
? ` - re-run \`component\` on whatever writes ${sheetNeed.variables.length === 1 ? "it" : "them"} and it speaks your own names instead`
|
|
1044
|
-
: ` - your code names no value this system also holds, so there is nothing to translate ${sheetNeed.variables.length === 1 ? "it" : "them"} into, and the sheet is the way`}`
|
|
1045
|
-
: `the ${sheetNeed.classes.slice(0, 3).join(", ")}${sheetNeed.classes.length > 3 ? `, +${sheetNeed.classes.length - 3} more` : ""} ${sheetNeed.classes.length === 1 ? "utility" : "utilities"}, which only this system's @theme generates`;
|
|
1046
|
-
console.log(body(` what asks for it: ${asks}`));
|
|
1047
|
-
console.log("");
|
|
1048
|
-
console.log(body(wiring.imported
|
|
1049
|
-
? ` ✓ some stylesheet imports _synthesisui/ds/${table.slug}/tokens.css`
|
|
1050
|
-
: ` ✗ no stylesheet imports _synthesisui/ds/${table.slug}/tokens.css`));
|
|
1051
|
-
console.log(body(wiring.scoped
|
|
1052
|
-
? ` ✓ data-ds="${table.slug}" found`
|
|
1053
|
-
: ` ✗ no element carries data-ds="${table.slug}"`));
|
|
1054
|
-
if (wiring.fontsWritten) {
|
|
1055
|
-
console.log(body(wiring.fontsMapped
|
|
1056
|
-
? " ✓ the type from fonts.ts is mapped onto the system"
|
|
1057
|
-
: " ✗ fonts.ts exists but nothing maps it - the system's type is not being used"));
|
|
1058
|
-
}
|
|
1059
|
-
console.log("");
|
|
1060
|
-
// Three requirements now, and they fail differently. Missing the import or
|
|
1061
|
-
// the scope means NOTHING reaches the browser and the number below is
|
|
1062
|
-
// noise. Missing only the type mapping means colour and spacing are
|
|
1063
|
-
// working and the faces are not - saying "nothing reaches the browser"
|
|
1064
|
-
// there would be false, and a report that overstates is one nobody trusts
|
|
1065
|
-
// the next time.
|
|
1066
|
-
if (blocked) {
|
|
1067
|
-
/**
|
|
1068
|
-
* A FRASE SEGUE O QUE VEM DEPOIS DELA. Ela dizia "o número abaixo não pode significar nada"
|
|
1069
|
-
* enquanto imprimia o número abaixo; agora não há número abaixo, e prometer um seria a mesma
|
|
1070
|
-
* incoerência ao contrário.
|
|
1071
|
-
*/
|
|
1072
|
-
console.log(body(bothMissing
|
|
1073
|
-
? `Until both are true, none of the ${table.byName.size} tokens reach the browser.`
|
|
1074
|
-
: `Until that one is true, none of the ${table.byName.size} tokens reach the browser.`));
|
|
1075
|
-
}
|
|
1076
|
-
else {
|
|
1077
|
-
console.log(body("Colour and spacing are working. Type is not: the system's faces"));
|
|
1078
|
-
console.log(body("are declared and nothing points at them, so the page renders in"));
|
|
1079
|
-
console.log(body("whatever the framework picked."));
|
|
1080
|
-
}
|
|
1081
|
-
/**
|
|
1082
|
-
* A FIAÇÃO SAI DAQUI, e não de outro comando - achado do dono em 06/09, rodando o `upgrade`.
|
|
1083
|
-
*
|
|
1084
|
-
* O QUE ELE VIU: o doctor diz `installed - but not wired up yet` e *"none of the 66 tokens
|
|
1085
|
-
* reach the browser"*, e a linha seguinte mandava ler *"the output of `init`"*. `init` é o
|
|
1086
|
-
* comando de PRIMEIRA VEZ - ele instala um sistema em quem não tem nenhum. Quem chegou até
|
|
1087
|
-
* aqui já importou, materializou e rodou upgrade: mandá-lo ao `init` é devolver ao começo
|
|
1088
|
-
* alguém que está a um passo do fim.
|
|
1089
|
-
*
|
|
1090
|
-
* E O PASSO JÁ EXISTIA PRONTO. `setupPrompt` mora em `setup-prompt.ts`, exportado, e era
|
|
1091
|
-
* usado só pelo `init`. Imprimi-lo aqui não é texto novo: é a MESMA fonte chegando na tela
|
|
1092
|
-
* onde a pergunta nasce. Duas redações do mesmo passo divergiriam no primeiro conserto.
|
|
1093
|
-
*
|
|
1094
|
-
* O PROMPT LEVA A MEDIÇÃO, e até 07/09 ele era FIXO - o defeito que o dono leu na própria tela.
|
|
1095
|
-
*
|
|
1096
|
-
* As três linhas acima acabaram de imprimir `✗ ✓ ✓`: só o import faltava. O texto seguinte
|
|
1097
|
-
* mandava *"Do the ONE-TIME SETUP it names, all of it"* e listava as três, então um agente
|
|
1098
|
-
* obediente reescreve o escopo e o mapa de tipografia que já estavam corretos - contra a última
|
|
1099
|
-
* linha do próprio texto, que pede para não mexer nos estilos dele. Um comando que mede e depois
|
|
1100
|
-
* diz outra coisa gasta a medição.
|
|
1101
|
-
*
|
|
1102
|
-
* E A FOLHA TEM NOME, ao contrário do que este comentário dizia antes. `globalSheetOf` +
|
|
1103
|
-
* `prefixFrom` são as mesmas funções que o `add` usa para achar a folha que os apps REALMENTE
|
|
1104
|
-
* carregam - num monorepo não é o `globals.css` do app - e para contar o caminho relativo até a
|
|
1105
|
-
* raiz. Elas existiam e este comando não as chamava; então ele descrevia o arquivo em vez de
|
|
1106
|
-
* nomeá-lo, e o agente tinha que redescobrir o que a gente já sabia.
|
|
1107
|
-
*
|
|
1108
|
-
* Quando a derivação falha, `sheet` fica ausente e o texto volta a descrever - nenhum caminho é
|
|
1109
|
-
* inventado.
|
|
1110
|
-
*/
|
|
1111
|
-
if (table.slug) {
|
|
1112
|
-
/**
|
|
1113
|
-
* A INSTRUÇÃO É POR APP, e não do primeiro deles.
|
|
1114
|
-
*
|
|
1115
|
-
* O DEFEITO: esta linha era `appDirs[0]` - num monorepo com três apps servidos, dois recebiam
|
|
1116
|
-
* a instrução do PRIMEIRO, com a folha e o prefixo relativo de outro app. É o mesmo defeito
|
|
1117
|
-
* que `INV-VOLTA-12` fechou uma vez ("ele seguiu a instrução no arquivo CERTO e recebeu de nós
|
|
1118
|
-
* o prefixo do arquivo errado"), voltando pela porta do plural: a invariante fala de "os apps
|
|
1119
|
-
* dele", e o comando respondia por um.
|
|
1120
|
-
*
|
|
1121
|
-
* E A FIAÇÃO TAMBÉM É POR APP (`readWiringPerApp`): `readWiring` varre a raiz e responde
|
|
1122
|
-
* "existe em algum lugar daqui", então o app fiado respondia pelo que não estava - e a pessoa
|
|
1123
|
-
* abria o app sem nada e o comando dizia que estava tudo certo.
|
|
1124
|
-
*
|
|
1125
|
-
* COM UM APP, o texto não muda em byte nenhum - é a maioria dos projetos, e um cabeçalho
|
|
1126
|
-
* por app ali seria cerimônia sobre uma lista de um.
|
|
1127
|
-
*/
|
|
1128
|
-
const perApp = await readWiringPerApp(root, table.slug, config.pagesDir);
|
|
1129
|
-
const targets = perApp.length > 0 ? perApp : [{ app: null, wiring }];
|
|
1130
|
-
/**
|
|
1131
|
-
* OS APPS QUE PEDEM A MESMA COISA VIRAM UM BLOCO SÓ, nomeando os dois.
|
|
1132
|
-
*
|
|
1133
|
-
* O DEFEITO, e ele é meu, do PR de algumas horas atrás: no `codelevel-monorepo` os DOIS apps
|
|
1134
|
-
* resolvem para a MESMA folha (`packages/ui/src/styles/globals.css`, o pacote compartilhado),
|
|
1135
|
-
* então o comando imprimiu a mesma instrução de 40 linhas DUAS VEZES, com o mesmo caminho e o
|
|
1136
|
-
* mesmo prefixo. O dono leu a parede duas vezes (medido no repositório dele, 09/09).
|
|
1137
|
-
*
|
|
1138
|
-
* Eu tinha escrito o aviso no comentário abaixo - *"num monorepo ele apareceria em escala:
|
|
1139
|
-
* dois blocos idênticos"* - sobre o caso do app JÁ FIADO, e entreguei a duplicata no caso do
|
|
1140
|
-
* que ainda falta. Nomear cada app foi o conserto certo; repetir a instrução não.
|
|
1141
|
-
*
|
|
1142
|
-
* A CHAVE É A INSTRUÇÃO, não o app: dois apps com a mesma folha, o mesmo prefixo e os mesmos
|
|
1143
|
-
* passos pendentes recebem uma instrução só. Um monorepo onde cada app tem folha própria volta
|
|
1144
|
-
* a receber uma por app, porque ali as instruções DIFEREM - é a resposta derivada, e não uma
|
|
1145
|
-
* regra sobre quantos apps existem.
|
|
1146
|
-
*/
|
|
1147
|
-
const blocks = new Map();
|
|
1148
|
-
for (const { app, wiring: w } of targets) {
|
|
1149
|
-
const sheet = app
|
|
1150
|
-
? await globalSheetOf(root, `${app}/globals.css`)
|
|
1151
|
-
: null;
|
|
1152
|
-
/**
|
|
1153
|
-
* O APP QUE JÁ ESTÁ FIADO SAI DA LISTA, nomeado. Repetir o setup para quem já o fez é o
|
|
1154
|
-
* defeito de 08/09 outra vez.
|
|
1155
|
-
*/
|
|
1156
|
-
const pending = !w.imported || !w.scoped || (w.fontsWritten && !w.fontsMapped);
|
|
1157
|
-
const text = pending
|
|
1158
|
-
? setupPrompt(table.slug, {
|
|
1159
|
-
tokens: !w.imported,
|
|
1160
|
-
scope: !w.scoped,
|
|
1161
|
-
/** Só é passo quando o projeto TEM o arquivo de fontes - ver `readWiring`. */
|
|
1162
|
-
type: w.fontsWritten && !w.fontsMapped,
|
|
1163
|
-
...(sheet
|
|
1164
|
-
? { sheet: { path: sheet, prefix: prefixFrom(sheet) } }
|
|
1165
|
-
: {}),
|
|
1166
|
-
/**
|
|
1167
|
-
* DUAS LINHAS COM TAILWIND, UMA SEM - a mesma decisão que o `add` já toma pelo
|
|
1168
|
-
* projeto. Dizer "as duas linhas" a um projeto que precisa de uma manda o agente
|
|
1169
|
-
* procurar o que não existe.
|
|
1170
|
-
*/
|
|
1171
|
-
imports: config.styles === "css" ? 1 : 2,
|
|
1172
|
-
}).split("\n")
|
|
1173
|
-
: [];
|
|
1174
|
-
const key = `${pending ? "p" : "ok"}|${text.join("\n")}`;
|
|
1175
|
-
const found = blocks.get(key);
|
|
1176
|
-
if (found)
|
|
1177
|
-
found.apps.push(app ?? "");
|
|
1178
|
-
else
|
|
1179
|
-
blocks.set(key, { apps: [app ?? ""], text, pending });
|
|
1180
|
-
}
|
|
1181
|
-
const anyPending = [...blocks.values()].some((b) => b.pending);
|
|
1182
|
-
if (anyPending) {
|
|
1183
|
-
console.log("");
|
|
1184
|
-
console.log(body("Paste this into your agent - it does the setup for you:"));
|
|
1185
|
-
}
|
|
1186
|
-
for (const { apps, text, pending } of blocks.values()) {
|
|
1187
|
-
const named = apps.filter(Boolean);
|
|
1188
|
-
/**
|
|
1189
|
-
* O CABEÇALHO SÓ APARECE QUANDO HÁ MAIS DE UM APP no projeto - com um só ele seria cerimônia
|
|
1190
|
-
* sobre uma lista de um, e a maioria dos projetos é assim. Com vários, ele diz de QUEM é a
|
|
1191
|
-
* instrução, e o plural sai naturalmente: "apps/landing/app and apps/web/app".
|
|
1192
|
-
*/
|
|
1193
|
-
if (targets.length > 1 && named.length > 0) {
|
|
1194
|
-
/**
|
|
1195
|
-
* A LISTA SE LÊ EM VOZ ALTA, e o número dela não é fixo: "A and B" com dois,
|
|
1196
|
-
* "A, B and C" com três. `join(" and ")` daria "A and B and C", e `"both"` mentiria
|
|
1197
|
-
* no dia em que o monorepo tiver três apps na mesma folha - o mesmo erro de
|
|
1198
|
-
* dimensionar pela amostra, na escala de uma palavra.
|
|
1199
|
-
*/
|
|
1200
|
-
const lista = named.length > 1
|
|
1201
|
-
? `${named.slice(0, -1).join(", ")} and ${named[named.length - 1]}`
|
|
1202
|
-
: named[0];
|
|
1203
|
-
console.log("");
|
|
1204
|
-
console.log(body(` ${lista} - ${pending
|
|
1205
|
-
? named.length > 1
|
|
1206
|
-
? "need it, and the steps are the same"
|
|
1207
|
-
: "still needs it"
|
|
1208
|
-
: "already wired, nothing to paste"}`));
|
|
1209
|
-
}
|
|
1210
|
-
if (!pending)
|
|
1211
|
-
continue;
|
|
1212
|
-
console.log("");
|
|
1213
|
-
console.log(snippet(text));
|
|
1214
|
-
}
|
|
1215
|
-
}
|
|
1216
|
-
}
|
|
1217
909
|
/**
|
|
1218
910
|
* A FOLHA APONTA PARA O VOCABULÁRIO DELE, E UM NOME SUMIU - ver `their-vars.ts`.
|
|
1219
911
|
*
|
|
@@ -1234,112 +926,26 @@ export async function doctor(opts) {
|
|
|
1234
926
|
console.log(body("Rename it back, or run `npx synthesisui add <slug>` to re-point the sheet at what you have now."));
|
|
1235
927
|
}
|
|
1236
928
|
/**
|
|
1237
|
-
*
|
|
929
|
+
* O RELATÓRIO NÃO PARA MAIS - o `return` daqui foi embora com a fiação (`INV-GERAL-13`, 11/09).
|
|
1238
930
|
*
|
|
1239
|
-
*
|
|
1240
|
-
*
|
|
1241
|
-
*
|
|
1242
|
-
*
|
|
1243
|
-
*
|
|
1244
|
-
* O ledger é gravado ANTES de sair: a corrida aconteceu, e o histórico não pode depender de o
|
|
1245
|
-
* projeto estar bem configurado.
|
|
931
|
+
* Ele existia porque, sem o `@import`, a barra de cobertura lia 0% e o `--fix` teria escrito
|
|
932
|
+
* `var(--ds-…)` que o navegador descarta. As duas razões acabaram: a cobertura conta o vocabulário
|
|
933
|
+
* dele, e o `--fix` só escreve nomes que o código dele declara. Um relatório que parava aqui hoje
|
|
934
|
+
* esconderia a cobertura de quem nunca vai importar folha nenhuma - ou seja, de todo mundo.
|
|
1246
935
|
*/
|
|
1247
|
-
if (blocked) {
|
|
1248
|
-
if (fullRun)
|
|
1249
|
-
await appendEvent(root, {
|
|
1250
|
-
kind: "doctor",
|
|
1251
|
-
at: new Date().toISOString(),
|
|
1252
|
-
...(d.reach.measured ? { coverage: d.reach.percent } : {}),
|
|
1253
|
-
rule: COVERAGE_RULE,
|
|
1254
|
-
named: d.named,
|
|
1255
|
-
...(d.findings.some((f) => f.crossFamily)
|
|
1256
|
-
? { crossFamily: d.findings.filter((f) => f.crossFamily).length }
|
|
1257
|
-
: {}),
|
|
1258
|
-
...(d.repeats.some((r) => nameToWrite(r))
|
|
1259
|
-
? { matched: suggestionsFrom(d.repeats) }
|
|
1260
|
-
: {}),
|
|
1261
|
-
/** SEMPRE, inclusive vazio - ver `CheckEvent.unrepresentedMatches`: o vazio é a medição. */
|
|
1262
|
-
unrepresentedMatches: unrepresentedFrom(d.findings, suggestionsFrom(d.repeats)),
|
|
1263
|
-
}).catch(() => { });
|
|
1264
|
-
console.log("");
|
|
1265
|
-
if (opts.fix) {
|
|
1266
|
-
/**
|
|
1267
|
-
* A RECUSA PASSA A SER POR VALOR, E NÃO PELO COMANDO INTEIRO.
|
|
1268
|
-
*
|
|
1269
|
-
* NASCEU DE UMA PERGUNTA DO DONO (04/09): *"se o design system dele já está funcionando e são
|
|
1270
|
-
* as mesmas referências, faz sentido esse ligamento? combinamos que não seria invasivo"*.
|
|
1271
|
-
*
|
|
1272
|
-
* A MEDIÇÃO DEU RAZÃO A ELE, pelo mesmo caminho que a tela usa (`loadSystem` + `scanSource` +
|
|
1273
|
-
* `diagnose` sobre packages/ui + apps/landing + apps/web do codelevel): dos 216 valores com
|
|
1274
|
-
* nome esperando, **156 (72%) escreveriam o nome DELE** - `--color-brand-violet`,
|
|
1275
|
-
* `--color-tier-gold`, `--duration-base` - e esses resolvem no navegador dele HOJE, sem folha
|
|
1276
|
-
* nenhuma instalada. Só 60 apontam para `--ds-*`, que são nossos e precisam da fiação.
|
|
1277
|
-
*
|
|
1278
|
-
* A recusa olhava `blocked` e nada mais. Ela nunca perguntava de quem era o nome que ia
|
|
1279
|
-
* escrever, embora `nameToWrite` já responda isso (`theirToken ?? token`). O produto recusava
|
|
1280
|
-
* 156 consertos que funcionariam para proteger 60 que quebrariam - e cobrava, em troca, uma
|
|
1281
|
-
* folha inteira dentro do app de alguém que só queria governar o próprio vocabulário.
|
|
1282
|
-
*
|
|
1283
|
-
* ISSO ATINGE O CASO DE USO CENTRAL: quem importa um design system que já existe tem, por
|
|
1284
|
-
* construção, a maioria dos nomes sendo dele.
|
|
1285
|
-
*
|
|
1286
|
-
* O QUE FICA DE FORA CONTINUA SENDO DITO, com o número e o motivo - Lei 8. O que muda é que a
|
|
1287
|
-
* lacuna deixou de fechar a porta inteira.
|
|
1288
|
-
*/
|
|
1289
|
-
const theirs = d.findings.filter(ownName).length;
|
|
1290
|
-
const ours = d.findings.filter((f) => nameToWrite(f) && !ownName(f)).length;
|
|
1291
|
-
if (theirs > 0) {
|
|
1292
|
-
console.log(body(`${theirs} of your hand-written values ${theirs === 1 ? "carries" : "carry"} a name your own code declares, and ${theirs === 1 ? "it resolves" : "those resolve"} today - --fix will swap ${theirs === 1 ? "it" : "them"}.`));
|
|
1293
|
-
if (ours > 0)
|
|
1294
|
-
console.log(body(`${ours} more point at ${table.name ?? table.slug} tokens, which only resolve once the wiring above is done. Left alone.`));
|
|
1295
|
-
console.log("");
|
|
1296
|
-
await runFix(root, { ...d, findings: d.findings.filter(ownName) }, opts.write === true);
|
|
1297
|
-
return;
|
|
1298
|
-
}
|
|
1299
|
-
/** Nenhum nome dele em jogo: aqui a recusa continua sendo a resposta certa, e inteira. */
|
|
1300
|
-
const one = ours === 1;
|
|
1301
|
-
console.log(body(`--fix is refused while ${bothMissing ? "those two are" : "that one is"} false. ${ours} of your hand-written values`));
|
|
1302
|
-
console.log(body(`${one ? "does" : "do"} have a name in the system, and swapping ${one ? "it" : "them"} now would point ${one ? "it" : "them"} at`));
|
|
1303
|
-
console.log(body(`variables the browser cannot resolve - the ${one ? "declaration" : "declarations"} would be dropped`));
|
|
1304
|
-
console.log(body(`and the page would change. Wire ${bothMissing ? "the two lines" : "that line"} first.`));
|
|
1305
|
-
}
|
|
1306
|
-
else {
|
|
1307
|
-
console.log(body(`${d.named} of the ${d.findings.length} hand-written values found have a name waiting in`));
|
|
1308
|
-
console.log(body("your system, and that number becomes actionable the moment both are true."));
|
|
1309
|
-
}
|
|
1310
|
-
return;
|
|
1311
|
-
}
|
|
1312
936
|
/**
|
|
1313
|
-
* SHADCN
|
|
1314
|
-
* INVISIBLE.
|
|
937
|
+
* A PONTE DO SHADCN NÃO SE PEDE MAIS - ela era um terceiro `@import` da nossa folha.
|
|
1315
938
|
*
|
|
1316
|
-
*
|
|
1317
|
-
*
|
|
1318
|
-
*
|
|
1319
|
-
*
|
|
939
|
+
* O QUE ELA ENTREGAVA: `shadcn.css` mapeia o contrato de variáveis do shadcn nos tokens do sistema,
|
|
940
|
+
* então os componentes shadcn dele parariam de usar os defaults do shadcn. O valor é real, e é por
|
|
941
|
+
* isso que o bloco existia - mas ele se cobrava colando `@import "_synthesisui/ds/<slug>/shadcn.css"`
|
|
942
|
+
* no CSS dele, que é exatamente o que `INV-GERAL-13` proíbe.
|
|
1320
943
|
*
|
|
1321
|
-
*
|
|
1322
|
-
*
|
|
1323
|
-
*
|
|
1324
|
-
*
|
|
944
|
+
* A PONTE CONTINUA SENDO COMPILADA e continua caindo em `_synthesisui/ds/<slug>/`, como insumo
|
|
945
|
+
* nosso - o mesmo estatuto do `tokens.css`. O que sai é a cobrança, não o arquivo. Quando vestir
|
|
946
|
+
* os componentes shadcn dele passar a ser uma frente própria, ela se resolve como o resto do
|
|
947
|
+
* produto se resolve: escrevendo no vocabulário DELE, e não pedindo que ele carregue o nosso.
|
|
1325
948
|
*/
|
|
1326
|
-
if (hasSystem && wiring.hasShadcn) {
|
|
1327
|
-
console.log("");
|
|
1328
|
-
if (wiring.bridged) {
|
|
1329
|
-
console.log(body(`✓ shadcn is reading ${table.name ?? table.slug}, not its own`));
|
|
1330
|
-
console.log(body(" defaults. Colour, charts, radius and the sidebar all resolve"));
|
|
1331
|
-
console.log(body(" to this system's tokens, in both schemes."));
|
|
1332
|
-
}
|
|
1333
|
-
else {
|
|
1334
|
-
console.log(body("This project has shadcn, and it is not wearing the"));
|
|
1335
|
-
console.log(body("system yet - its components are still on shadcn's defaults."));
|
|
1336
|
-
console.log("");
|
|
1337
|
-
console.log(body(` @import "_synthesisui/ds/${table.slug}/shadcn.css";`));
|
|
1338
|
-
console.log("");
|
|
1339
|
-
console.log(body(" after the tokens.css import, in the same stylesheet. One line,"));
|
|
1340
|
-
console.log(body(" and every shadcn component switches over."));
|
|
1341
|
-
}
|
|
1342
|
-
}
|
|
1343
949
|
if (hasSystem && d.reach.measured) {
|
|
1344
950
|
const { percent, uses, of } = d.reach;
|
|
1345
951
|
console.log("");
|
|
@@ -1383,8 +989,16 @@ export async function doctor(opts) {
|
|
|
1383
989
|
*/
|
|
1384
990
|
if (d.ownTokens > 0 && table.source === "installed") {
|
|
1385
991
|
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` : ""}`)));
|
|
992
|
+
/**
|
|
993
|
+
* A GRAFIA SAIU DESTA LINHA EM 11/09 - `INV-GERAL-13`.
|
|
994
|
+
*
|
|
995
|
+
* Ela dizia *"point those at the `--ds-*` that holds it"*, e aquela variável só resolve com
|
|
996
|
+
* uma folha nossa carregada no app dele. O fato continua sendo dito - ele tem N tokens que
|
|
997
|
+
* seguram um valor que o sistema também nomeia -, e o que se faz com isso é decisão dele: os
|
|
998
|
+
* dois nomes são dele, e o segundo mora num sistema que nasceu do código dele.
|
|
999
|
+
*/
|
|
1386
1000
|
if (d.ownMirrored > 0)
|
|
1387
|
-
console.log(body(paint.dim(`
|
|
1001
|
+
console.log(body(paint.dim(` ${d.ownMirrored} line${d.ownMirrored === 1 ? "" : "s"} where the two agree - yours to keep as one or as two`)));
|
|
1388
1002
|
}
|
|
1389
1003
|
/**
|
|
1390
1004
|
* O QUE UM COMANDO ALCANÇA, ao lado do que é verdade hoje - e são DUAS contas de propósito.
|
|
@@ -1815,8 +1429,16 @@ export async function doctor(opts) {
|
|
|
1815
1429
|
for (const f of frozen) {
|
|
1816
1430
|
say(body(`ds-${f.component} · ${f.where}`));
|
|
1817
1431
|
say(` binds ${f.wrote}`);
|
|
1818
|
-
/**
|
|
1819
|
-
|
|
1432
|
+
/**
|
|
1433
|
+
* O PAPEL PELO NOME, e não pela nossa grafia de variável (`INV-GERAL-13`, 11/09).
|
|
1434
|
+
*
|
|
1435
|
+
* Esta linha dizia `var(--ds-color-semantic-<role>)`, com a justificativa de que era *"a
|
|
1436
|
+
* grafia que EXISTE no repo dele"*. Ela existe dentro da NOSSA folha, que o app dele não
|
|
1437
|
+
* carrega - então imprimi-la aqui ensina uma variável que ele não pode escrever. O que a
|
|
1438
|
+
* frase precisa dizer é qual papel do sistema segura aquele valor, e `role` já é o nome
|
|
1439
|
+
* daquele papel.
|
|
1440
|
+
*/
|
|
1441
|
+
say(` the "${f.role}" surface colour of this system holds that, and becomes ${f.becomes}`);
|
|
1820
1442
|
say("");
|
|
1821
1443
|
}
|
|
1822
1444
|
say(body("The value resolves and the CSS compiles, so nothing"));
|
|
@@ -2163,6 +1785,30 @@ export async function doctor(opts) {
|
|
|
2163
1785
|
console.log(` ${i + 1}. ${what} ${paint.dim(`${j.size}${j.cheap ? " (cheap)" : ""}`)}`);
|
|
2164
1786
|
});
|
|
2165
1787
|
}
|
|
1788
|
+
/**
|
|
1789
|
+
* A4 · O VALOR QUE O SISTEMA NOMEIA E O CÓDIGO DELE NÃO - dito, nunca batizado.
|
|
1790
|
+
*
|
|
1791
|
+
* A METADE QUE SUMIRIA SEM ISTO. Desde que `nameToWrite` parou de devolver a nossa grafia
|
|
1792
|
+
* (11/09), um achado com nome só do nosso lado não entra na lista de trocas - e não entrava em
|
|
1793
|
+
* lista nenhuma. Ele saía das duas, e sumir é indistinguível de *"está tudo nomeado"* para quem
|
|
1794
|
+
* lê: o relatório dizia *"1 value by hand · 0 already have a name"* sobre um valor que o
|
|
1795
|
+
* sistema dele nomeia há meses.
|
|
1796
|
+
*
|
|
1797
|
+
* DIZER, E NÃO PROPOR. É a escolha dele de 10/09 entre as duas alternativas, literal: *"DIZER o
|
|
1798
|
+
* valor e onde ele está, sem propor nome nenhum"*. Nenhuma grafia nossa sai daqui - nem como
|
|
1799
|
+
* sugestão, nem entre parênteses - porque um relatório que roda sozinho é o pior lugar para
|
|
1800
|
+
* inventar vocabulário: o agente obedece, e a violação acontece sem ninguém decidir nada.
|
|
1801
|
+
*/
|
|
1802
|
+
const onlyOurs = d.findings.filter(ourNameOnly);
|
|
1803
|
+
if (onlyOurs.length > 0) {
|
|
1804
|
+
console.log("");
|
|
1805
|
+
console.log(body(`${onlyOurs.length} value${onlyOurs.length === 1 ? "" : "s"} ${onlyOurs.length === 1 ? "has" : "have"} a name in ${systemName} and none in your own code:`));
|
|
1806
|
+
for (const f of onlyOurs.slice(0, 5))
|
|
1807
|
+
console.log(body(paint.dim(` ${f.file}:${f.line} ${f.literal}`)));
|
|
1808
|
+
if (onlyOurs.length > 5)
|
|
1809
|
+
console.log(body(paint.dim(` (${onlyOurs.length - 5} more)`)));
|
|
1810
|
+
console.log(body(paint.dim(" Naming one is yours to decide - it may be intentional. Once your code names it, `--fix` picks it up.")));
|
|
1811
|
+
}
|
|
2166
1812
|
console.log("");
|
|
2167
1813
|
console.log(body("synthesisui doctor --verbose every finding, file by file"));
|
|
2168
1814
|
/**
|