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/their-tongue.js
CHANGED
|
@@ -7,7 +7,7 @@ const OUR_VAR = /var\(\s*(--ds-[a-zA-Z0-9_-]+)\s*(?:,([^()]*))?\)/g;
|
|
|
7
7
|
* verdade quando nenhum dos três aponta. Somar aqui, e não em cada comando, é o que impede duas
|
|
8
8
|
* contas diferentes para a mesma pergunta.
|
|
9
9
|
*
|
|
10
|
-
* `null` quando nada foi traduzido
|
|
10
|
+
* `null` quando nada foi traduzido - e aí quem chama DIZ isso.
|
|
11
11
|
*/
|
|
12
12
|
export function sumSpoken(reports) {
|
|
13
13
|
const real = reports.filter((r) => r !== null);
|
|
@@ -20,13 +20,16 @@ export function sumSpoken(reports) {
|
|
|
20
20
|
return {
|
|
21
21
|
named: real.reduce((n, r) => n + r.named, 0),
|
|
22
22
|
inlined: real.reduce((n, r) => n + r.inlined, 0),
|
|
23
|
+
froze: real.reduce((n, r) => n + r.froze, 0),
|
|
23
24
|
left: [...left].sort(),
|
|
24
25
|
};
|
|
25
26
|
}
|
|
26
27
|
export function inTheirTongue(css, tongue, destination = "stylesheet") {
|
|
27
28
|
let named = 0;
|
|
28
29
|
let inlined = 0;
|
|
30
|
+
let froze = 0;
|
|
29
31
|
const left = new Set();
|
|
32
|
+
const write = (value) => destination === "tailwind-class" ? value.replace(/\s+/g, "_") : value;
|
|
30
33
|
const out = css.replace(OUR_VAR, (whole, name, fallback) => {
|
|
31
34
|
const theirName = tongue.names.get(name);
|
|
32
35
|
if (theirName) {
|
|
@@ -41,14 +44,28 @@ export function inTheirTongue(css, tongue, destination = "stylesheet") {
|
|
|
41
44
|
const value = tongue.values.get(name);
|
|
42
45
|
if (value) {
|
|
43
46
|
inlined += 1;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
if (tongue.frozen.has(name))
|
|
48
|
+
froze += 1;
|
|
49
|
+
return write(value);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* O FALLBACK ESCRITO NA PRÓPRIA REFERÊNCIA É A ÚLTIMA RESPOSTA, e ela é do autor do texto.
|
|
53
|
+
*
|
|
54
|
+
* Quem escreve `var(--ds-motion-durations-base, 200ms)` já disse o que aquilo vale quando a
|
|
55
|
+
* folha não responde - é o idioma de `motion.ts` e de `interactive-templates.ts`, os dois
|
|
56
|
+
* módulos que montam animação sem ter o documento em mão. Antes disto a referência inteira
|
|
57
|
+
* sobrevivia no arquivo dele, levando junto a nossa grafia e uma dependência da nossa folha
|
|
58
|
+
* que o fallback existia justamente para dispensar.
|
|
59
|
+
*/
|
|
60
|
+
const declared = fallback?.trim();
|
|
61
|
+
if (declared) {
|
|
62
|
+
inlined += 1;
|
|
63
|
+
return write(declared);
|
|
47
64
|
}
|
|
48
65
|
left.add(name);
|
|
49
|
-
return
|
|
66
|
+
return whole;
|
|
50
67
|
});
|
|
51
|
-
return { css: out, named, inlined, left: [...left].sort() };
|
|
68
|
+
return { css: out, named, inlined, froze, left: [...left].sort() };
|
|
52
69
|
}
|
|
53
70
|
/**
|
|
54
71
|
* O VOCABULARIO DESTE REPOSITORIO **SEM O `add` TER RODADO** - a folha deixa de ser pre-requisito.
|
|
@@ -63,39 +80,137 @@ export function inTheirTongue(css, tongue, destination = "stylesheet") {
|
|
|
63
80
|
* DELE e o build dele, e responde quais das nossas variaveis tem nome dele. A diferenca e' que
|
|
64
81
|
* nada disso vai para o disco - nem o mapa, nem a folha.
|
|
65
82
|
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
83
|
+
* E UM REPOSITORIO QUE NAO NOMEIA NADA CONTINUA TENDO RESPOSTA: os pares podem ser zero e a folha
|
|
84
|
+
* ainda carrega o valor compilado de cada variavel, que e' o destino 2. Enquanto este caminho
|
|
85
|
+
* respondia `null` nesse caso, o arquivo saia com `var(--ds-*)` cru - a grafia que `INV-GERAL-13`
|
|
86
|
+
* proibe, escrita justamente no projeto que tem menos chance de ter a folha carregada.
|
|
87
|
+
*
|
|
88
|
+
* `null` so' quando nem o `tokens.css` veio - e ai' nao ha' o que responder.
|
|
89
|
+
*/
|
|
90
|
+
export async function tongueFromArtifacts(root,
|
|
91
|
+
/**
|
|
92
|
+
* Os artefatos do payload - e `undefined` é um estado real, não um descuido do chamador.
|
|
93
|
+
*
|
|
94
|
+
* Uma leitura que chegou sem eles é indistinguível de uma que não chegou: a resposta é `null`
|
|
95
|
+
* nos dois casos, e quem chama DIZ isso. Sem esta tolerância o comando estoura em vez de
|
|
96
|
+
* relatar, que é a pior forma de uma lacuna aparecer.
|
|
69
97
|
*/
|
|
70
|
-
|
|
71
|
-
const tokens = artifacts["tokens.css"] ?? "";
|
|
98
|
+
artifacts) {
|
|
99
|
+
const tokens = artifacts?.["tokens.css"] ?? "";
|
|
72
100
|
if (!tokens)
|
|
73
101
|
return null;
|
|
74
102
|
const { pointTokensAtTheirNames } = await import("./their-vars.js");
|
|
75
|
-
const { pairs } = await pointTokensAtTheirNames(root, {
|
|
76
|
-
|
|
77
|
-
|
|
103
|
+
const { pairs } = await pointTokensAtTheirNames(root, {
|
|
104
|
+
artifacts: artifacts ?? {},
|
|
105
|
+
}).catch(() => ({ pairs: [] }));
|
|
78
106
|
return tongueOf(pairs, tokens);
|
|
79
107
|
}
|
|
80
108
|
/**
|
|
81
|
-
* O VOCABULÁRIO DESTE REPOSITÓRIO,
|
|
109
|
+
* O VOCABULÁRIO DESTE REPOSITÓRIO, LIDO DA FOLHA - e o mapa é confirmação, nunca pré-requisito.
|
|
110
|
+
*
|
|
111
|
+
* `installedCss` é a folha compilada deste install, e ela responde as duas perguntas sozinha porque
|
|
112
|
+
* `their-vars.ts` já a reescreveu nesta máquina:
|
|
82
113
|
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
114
|
+
* ```
|
|
115
|
+
* --ds-color-ink-50: var(--color-ink-50); -> ele nomeia: o nome DELE
|
|
116
|
+
* --ds-motion-durations-base: 180ms; -> ele não nomeia: o VALOR
|
|
117
|
+
* --ds-color-semantic-primary: var(--ds-color-brand-500); -> cadeia nossa: segue até uma das duas
|
|
118
|
+
* ```
|
|
119
|
+
*
|
|
120
|
+
* A CADEIA É SEGUIDA, e antes ela era descartada. A linha que aponta para outra variável nossa é a
|
|
121
|
+
* forma como o compilador escreve um papel semântico - `primary` é `brand-500` -, e pular essas
|
|
122
|
+
* linhas deixava sem resposta justamente os nomes que um componente mais usa. Medido na folha do
|
|
123
|
+
* `codelevel`: 53 das 119 variáveis eram puladas por essa razão, e todas elas tinham resposta uma
|
|
124
|
+
* indireção adiante.
|
|
125
|
+
*
|
|
126
|
+
* `map` vem do `.lock` (`tokenMap`) quando existe, e tem PRECEDÊNCIA: ele é o que a máquina dele
|
|
127
|
+
* mediu contra as folhas e o build, enquanto a folha reescrita é o efeito daquela medição. Onde os
|
|
128
|
+
* dois concordam a resposta é a mesma; onde só um tem resposta, ela vale.
|
|
86
129
|
*/
|
|
87
130
|
export function tongueOf(map, installedCss) {
|
|
88
131
|
const names = new Map(map.map((p) => [p.ours, p.theirs]));
|
|
89
132
|
const values = new Map();
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
133
|
+
/**
|
|
134
|
+
* O que cada variável nossa declara na folha, antes de qualquer indireção ser seguida.
|
|
135
|
+
*
|
|
136
|
+
* SEM ÂNCORA NO INÍCIO DA LINHA, e a âncora era um buraco de verdade - a mesma lição que
|
|
137
|
+
* `apply-fix.ts` já pagou uma vez. A regra antiga era `^\s*--nome:`, que só enxerga CSS formatado
|
|
138
|
+
* com uma declaração por linha. Numa folha minificada - e um `tokens.css` compilado pode chegar
|
|
139
|
+
* assim - a linha inteira é `[data-ds="x"]{--ds-a:#111;--ds-b:1rem}`: nenhuma declaração começa a
|
|
140
|
+
* linha, o mapa sai VAZIO, e o componente materializado leva a nossa grafia inteira para o
|
|
141
|
+
* repositório dele sem nada acusar.
|
|
142
|
+
*
|
|
143
|
+
* Encontrado pelo spec ponta a ponta de A3 em 11/09, rodando `add` e `component` de verdade: o
|
|
144
|
+
* `button.css` saiu com as duas referências cruas.
|
|
145
|
+
*
|
|
146
|
+
* O que delimita uma declaração é o que vem ANTES dela: o começo do texto, uma `{` que abre a
|
|
147
|
+
* regra, ou o `;` da declaração anterior. É a mesma pontuação em qualquer formatação.
|
|
148
|
+
*
|
|
149
|
+
* E O FECHO É UM LOOKAHEAD, não um consumo - senão o `;` que TERMINA uma declaração some do texto
|
|
150
|
+
* disponível e deixa de poder ABRIR a próxima. Numa folha minificada isso faz o laço ler uma
|
|
151
|
+
* declaração sim, outra não: `--ds-a` entra, `--ds-b` desaparece, e o resultado é pior que não ler
|
|
152
|
+
* nada, porque metade do mapa parece um mapa.
|
|
153
|
+
*/
|
|
154
|
+
const declared = new Map();
|
|
155
|
+
/** Quantas vezes a folha declara cada variável nossa - ver `Tongue.frozen`. */
|
|
156
|
+
const times = new Map();
|
|
157
|
+
for (const m of installedCss.matchAll(/(?:^|[{;])\s*(--ds-[a-zA-Z0-9_-]+)\s*:\s*([^;}]+)(?=[;}])/g)) {
|
|
158
|
+
times.set(m[1], (times.get(m[1]) ?? 0) + 1);
|
|
159
|
+
if (!declared.has(m[1]))
|
|
160
|
+
declared.set(m[1], m[2].trim());
|
|
161
|
+
}
|
|
162
|
+
/** `var(--alvo)` ou `var(--alvo, fallback)` como VALOR INTEIRO de uma declaração. */
|
|
163
|
+
const INDIRECTION = /^var\(\s*(--[a-zA-Z0-9_-]+)\s*(?:,([\s\S]*))?\)$/;
|
|
164
|
+
/**
|
|
165
|
+
* O DESTINO DE UMA VARIÁVEL NOSSA, seguindo a cadeia até uma das duas metades.
|
|
166
|
+
*
|
|
167
|
+
* `seen` corta o ciclo: uma folha que se referencia em volta é um defeito do compilador, e o
|
|
168
|
+
* preço dele não pode ser um `component` que nunca termina.
|
|
169
|
+
*/
|
|
170
|
+
const destinationOf = (ours, seen) => {
|
|
171
|
+
if (seen.has(ours))
|
|
172
|
+
return null;
|
|
173
|
+
seen.add(ours);
|
|
174
|
+
const value = declared.get(ours);
|
|
175
|
+
if (value === undefined)
|
|
176
|
+
return null;
|
|
177
|
+
const indirect = INDIRECTION.exec(value);
|
|
178
|
+
if (!indirect)
|
|
179
|
+
return { value };
|
|
180
|
+
const target = indirect[1];
|
|
181
|
+
/** Outra variável NOSSA: a resposta está mais adiante, nunca aqui. */
|
|
182
|
+
if (target.startsWith("--ds-")) {
|
|
183
|
+
const next = destinationOf(target, seen);
|
|
184
|
+
if (next)
|
|
185
|
+
return next;
|
|
186
|
+
/** A cadeia morreu sem resposta - o fallback escrito na indireção é a última palavra. */
|
|
187
|
+
const written = indirect[2]?.trim();
|
|
188
|
+
return written ? { value: written } : null;
|
|
189
|
+
}
|
|
190
|
+
return { name: target };
|
|
191
|
+
};
|
|
192
|
+
for (const ours of declared.keys()) {
|
|
193
|
+
if (names.has(ours))
|
|
194
|
+
continue;
|
|
195
|
+
const destination = destinationOf(ours, new Set());
|
|
196
|
+
if (!destination)
|
|
94
197
|
continue;
|
|
95
|
-
if (
|
|
96
|
-
|
|
198
|
+
if ("name" in destination)
|
|
199
|
+
names.set(ours, destination.name);
|
|
200
|
+
else
|
|
201
|
+
values.set(ours, destination.value);
|
|
97
202
|
}
|
|
98
|
-
|
|
203
|
+
/**
|
|
204
|
+
* AS QUE MUDAM ENTRE ESQUEMAS E VIRAM LITERAL - o subconjunto que congela.
|
|
205
|
+
*
|
|
206
|
+
* Só entra aqui o que caiu em `values`: onde há nome dele, o mecanismo de esquema DELE vira o
|
|
207
|
+
* valor junto e não há nada a dizer.
|
|
208
|
+
*/
|
|
209
|
+
const frozen = new Set();
|
|
210
|
+
for (const [ours, n] of times)
|
|
211
|
+
if (n > 1 && values.has(ours))
|
|
212
|
+
frozen.add(ours);
|
|
213
|
+
return { names, values, frozen };
|
|
99
214
|
}
|
|
100
215
|
/**
|
|
101
216
|
* NENHUMA MATERIALIZAÇÃO VAZA VOCABULÁRIO INTERNO - a regra da camada, num lugar só (dono, 26/08).
|
|
@@ -106,34 +221,56 @@ export function tongueOf(map, installedCss) {
|
|
|
106
221
|
* ausente. Um mecanismo novo de materialização que chamar esta função já nasce coberto; um que não
|
|
107
222
|
* chamar é reprovado pelo gate (ver contracts/camada-6-volta.md, INV-VOLTA-02).
|
|
108
223
|
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
224
|
+
* A FOLHA RESPONDE MESMO SEM MAPA - o conserto de 11/09, e ele tem três estados reais por trás.
|
|
225
|
+
*
|
|
226
|
+
* Esta função exigia um `.lock` com `tokenMap` não vazio e respondia `null` fora disso. Os três
|
|
227
|
+
* casos que caíam ali - install anterior a 0.16.290, repositório que nunca buildou, e projeto de
|
|
228
|
+
* destino que não nomeia nada nosso - recebiam o arquivo com `var(--ds-*)` cru, e o comando dizia
|
|
229
|
+
* que a folha continuava sendo o caminho. Era a única porta do produto que ainda PEDIA o import, e
|
|
230
|
+
* ela pedia exatamente a quem menos podia atender.
|
|
231
|
+
*
|
|
232
|
+
* Agora o `.lock` decide só a VERSÃO da folha a ler. Sem ele, a folha da raiz é o re-export que o
|
|
233
|
+
* `add` escreve e serve igual - e um projeto sem pasta nenhuma continua respondendo `null`, porque
|
|
234
|
+
* ali não há folha para ler.
|
|
112
235
|
*/
|
|
113
236
|
export async function projectTongue(root, slug) {
|
|
114
237
|
const { readFile } = await import("node:fs/promises");
|
|
115
238
|
const { join } = await import("node:path");
|
|
116
239
|
const dir = join(root, "_synthesisui", "ds", slug);
|
|
117
240
|
const lock = await readFile(join(dir, ".lock"), "utf8").catch(() => null);
|
|
118
|
-
if (!lock)
|
|
119
|
-
return null;
|
|
120
241
|
let map = [];
|
|
121
|
-
let version =
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
242
|
+
let version = null;
|
|
243
|
+
if (lock) {
|
|
244
|
+
try {
|
|
245
|
+
const parsed = JSON.parse(lock);
|
|
246
|
+
map = parsed.tokenMap ?? [];
|
|
247
|
+
version = parsed.version ?? 0;
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
/** Um `.lock` ilegível não apaga a folha ao lado dele - ver a leitura logo abaixo. */
|
|
251
|
+
map = [];
|
|
252
|
+
version = null;
|
|
253
|
+
}
|
|
129
254
|
}
|
|
130
|
-
if (map.length === 0)
|
|
131
|
-
return null;
|
|
132
255
|
/**
|
|
133
256
|
* O VALOR COMPILADO MORA NA PASTA DA VERSÃO - a folha da raiz é um re-export de uma linha, escrito
|
|
134
|
-
* assim de propósito para que o
|
|
135
|
-
*
|
|
257
|
+
* assim de propósito para que o caminho nunca mude entre updates (ver `add.ts`). Sem `.lock` legível
|
|
258
|
+
* não há versão para abrir, e aí a folha da raiz é o que existe: ela pode ser o re-export (e não
|
|
259
|
+
* declara nada) ou a folha inteira de um install antigo, e ler as duas custa uma chamada.
|
|
136
260
|
*/
|
|
137
|
-
const
|
|
261
|
+
const sheets = [
|
|
262
|
+
version === null ? null : join(dir, `v${version}`, "tokens.css"),
|
|
263
|
+
join(dir, "tokens.css"),
|
|
264
|
+
].filter((p) => p !== null);
|
|
265
|
+
let installed = "";
|
|
266
|
+
for (const path of sheets) {
|
|
267
|
+
const css = await readFile(path, "utf8").catch(() => "");
|
|
268
|
+
if (css.includes("--ds-")) {
|
|
269
|
+
installed = css;
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (map.length === 0 && !installed)
|
|
274
|
+
return null;
|
|
138
275
|
return tongueOf(map, installed);
|
|
139
276
|
}
|
package/dist/wired-slugs.js
CHANGED
|
@@ -47,21 +47,27 @@ export function wiredSlugs(css) {
|
|
|
47
47
|
return out;
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
|
-
* O QUE DIZER A ELE QUANDO O
|
|
50
|
+
* O QUE DIZER A ELE QUANDO O CSS DELE AINDA IMPORTA UMA FOLHA NOSSA.
|
|
51
51
|
*
|
|
52
52
|
* Roda DEPOIS do envio, com o slug que o servidor devolveu - então não é previsão, é fato: a pasta
|
|
53
53
|
* vai ser escrita com este nome e os `@import` dele apontam para outro.
|
|
54
54
|
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
55
|
+
* A SAÍDA MUDOU EM 11/09, e ela é o oposto do que era. Este aviso terminava com as duas linhas de
|
|
56
|
+
* `@import` para ele colar apontando para o slug novo - ou seja, consertava o import mantendo-o.
|
|
57
|
+
* Nenhum projeto precisa mais daquele import (`INV-GERAL-13`): o que a plataforma escreve no
|
|
58
|
+
* repositório dele não depende de folha nossa nenhuma. Então a saída é REMOVER as linhas, e o aviso
|
|
59
|
+
* diz isso com a consequência que ele precisa para decidir - o build já está quebrado hoje.
|
|
57
60
|
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
+
* E ELE PODE TER ESCRITO CÓDIGO SOBRE AQUELA FOLHA. Um `var(--ds-*)` à mão num arquivo dele, de uma
|
|
62
|
+
* versão anterior do produto, para de resolver quando o import sai - e a linha diz o que o `doctor`
|
|
63
|
+
* REALMENTE responde: ele CONTA essas referências na linha de cobertura (`N from <sistema>`), e não
|
|
64
|
+
* as lista uma a uma. Prometer a lista seria a família de defeito que o `ARCHITECTURE.md` abre
|
|
65
|
+
* citando - afirmar que um comando conserta o que ele não conserta.
|
|
66
|
+
*
|
|
67
|
+
* `null` quando o CSS não cabeia nada, que é todo projeto novo.
|
|
61
68
|
*
|
|
62
69
|
* DIZER, E NÃO CONSERTAR. O CSS é dele; reescrevê-lo por conta própria seria a plataforma editando
|
|
63
|
-
* o repositório de alguém sem pedir.
|
|
64
|
-
* cola.
|
|
70
|
+
* o repositório de alguém sem pedir.
|
|
65
71
|
*/
|
|
66
72
|
export function wiringWarning(
|
|
67
73
|
/**
|
|
@@ -71,16 +77,24 @@ export function wiringWarning(
|
|
|
71
77
|
wired, slugThatWasBorn) {
|
|
72
78
|
if (wired.length === 0)
|
|
73
79
|
return null;
|
|
74
|
-
|
|
75
|
-
return null;
|
|
80
|
+
const stale = wired.filter((w) => w !== slugThatWasBorn.toLowerCase());
|
|
76
81
|
return [
|
|
77
|
-
`Your CSS imports _synthesisui/ds/${wired[0]}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
`Your CSS imports _synthesisui/ds/${wired[0]}/ - nothing needs that any more.`,
|
|
83
|
+
...(stale.length > 0
|
|
84
|
+
? [
|
|
85
|
+
`It points at a folder this install does not write (the system is "${slugThatWasBorn}"),`,
|
|
86
|
+
`so \`next build\` fails on it today - not a missing colour, a build that stops.`,
|
|
87
|
+
]
|
|
88
|
+
: []),
|
|
89
|
+
``,
|
|
90
|
+
`Delete those @import lines. Everything we write into this repository speaks the names your`,
|
|
91
|
+
`own code declares, or carries the value itself - there is no stylesheet of ours to load.`,
|
|
92
|
+
``,
|
|
93
|
+
`If you wrote --ds-* by hand against an older version, \`npx synthesisui doctor\` COUNTS them -`,
|
|
94
|
+
`the "from <system>" number on the coverage line is how many references still point at us. Those`,
|
|
95
|
+
`stop resolving when the import goes; re-run \`component\` on whatever wrote them and they come`,
|
|
96
|
+
`back in your own names.`,
|
|
97
|
+
``,
|
|
84
98
|
"Yours to change - we do not edit your CSS.",
|
|
85
99
|
].join("\n");
|
|
86
100
|
}
|
package/package.json
CHANGED
package/dist/setup-prompt.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* O TEXTO QUE TIRA AS EDIÇÕES DE SETUP DA MÃO DA PESSOA - e que agora USA a medição.
|
|
3
|
-
*
|
|
4
|
-
* O QUE O CLIENTE GANHA: um design system instalado não muda um pixel até que alguma folha que o app
|
|
5
|
-
* carrega importe os tokens e algum elemento carregue o escopo. Em 27/07 isso foi medido em 0% - a
|
|
6
|
-
* lista numerada de três passos existia e ninguém a executava. A pessoa que roda o comando tem um
|
|
7
|
-
* agente aberto ao lado, então o fecho deixou de ser tarefa e passou a ser um texto para colar.
|
|
8
|
-
*
|
|
9
|
-
* O DEFEITO QUE ISTO CORRIGE (dono, 07/09): o texto era FIXO. O `doctor` acabava de imprimir
|
|
10
|
-
* `✗ ✓ ✓` - só o import faltava, o escopo e a tipografia já estavam lá - e o parágrafo seguinte
|
|
11
|
-
* mandava *"Do the ONE-TIME SETUP it names, all of it"*, listando as três. Um agente obediente
|
|
12
|
-
* reescreve o que já estava correto, e o próprio texto termina com "não mexa nos meus estilos": ele
|
|
13
|
-
* se contradizia dentro de si mesmo.
|
|
14
|
-
*
|
|
15
|
-
* Então o que falta é ARGUMENTO. Sem ele o texto pede tudo, que é a verdade nos dois lugares onde
|
|
16
|
-
* ninguém mediu nada: o fecho do `init` (o projeto acabou de receber o sistema) e a tela do
|
|
17
|
-
* onboarding (a plataforma não vê o disco de ninguém). Com ele, o texto pede o que falta e NOMEIA o
|
|
18
|
-
* que já está pronto para o agente deixar em paz.
|
|
19
|
-
*
|
|
20
|
-
* GÊMEO POR SPEC com `apps/web/src/lib/ds/install-mission.ts`, que serve o mesmo texto na tela -
|
|
21
|
-
* `setup-prompt.spec.ts` reprova o drift. O CLI é publicado standalone e não pode importar de
|
|
22
|
-
* `apps/web`, então a cópia é inevitável; o que não é inevitável é ela divergir em silêncio, e dois
|
|
23
|
-
* textos diferentes para o mesmo setup ensinam dois setups.
|
|
24
|
-
*/
|
|
25
|
-
export function initCommand(slug) {
|
|
26
|
-
return `npx synthesisui@latest init --styles tailwind --ds ${slug}`;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* A LINHA QUE DÁ SAÍDA QUANDO UMA VERSÃO ESTÁ PROPAGANDO (dono, 07/09).
|
|
30
|
-
*
|
|
31
|
-
* Ele rodou `npx synthesisui@latest doctor` e recebeu `ETARGET / No matching version found`: o
|
|
32
|
-
* `dist-tag` do npm já apontava para a versão nova e o tarball ainda não estava na réplica que a
|
|
33
|
-
* máquina dele consultou. O erro é do npm e acontece ANTES do nosso código rodar, então não há como
|
|
34
|
-
* interceptá-lo - o que está na nossa mão é a instrução não deixar quem lê sem saída, porque
|
|
35
|
-
* `ETARGET` não diz que é transitório nem o que fazer.
|
|
36
|
-
*/
|
|
37
|
-
const PROPAGATING = "If npm answers `ETARGET` or `No matching version found`, a release is still propagating - wait a minute and run it again, or pin the version the registry does have (`npm view synthesisui version`).";
|
|
38
|
-
const CONNECT_STEP = `Run: npx synthesisui@latest connect
|
|
39
|
-
${PROPAGATING}
|
|
40
|
-
If it answers "already had it" on both lines, everything is live and you are done.
|
|
41
|
-
If it WROTE either of them, then they are not live in this session, because hooks and tools are only read at startup. Stop there and tell me, in bold, on its own line: **RESTART THIS SESSION - the check is installed but not running yet.** Do not keep writing files after that; a session that cannot be checked is the state this whole setup exists to avoid.`;
|
|
42
|
-
/** As linhas exatas quando a folha é conhecida; a descrição do arquivo quando não é. */
|
|
43
|
-
function importStep(slug, gap) {
|
|
44
|
-
const lines = [
|
|
45
|
-
`@import "${gap.sheet ? gap.sheet.prefix : "<path to the repo root>/"}_synthesisui/ds/${slug}/tokens.css";`,
|
|
46
|
-
...(gap.imports === 2
|
|
47
|
-
? [
|
|
48
|
-
`@import "${gap.sheet ? gap.sheet.prefix : "<path to the repo root>/"}_synthesisui/ds/${slug}/theme.css";`,
|
|
49
|
-
]
|
|
50
|
-
: []),
|
|
51
|
-
];
|
|
52
|
-
const where = gap.sheet
|
|
53
|
-
? `\`${gap.sheet.path}\``
|
|
54
|
-
: "the global stylesheet this project's apps actually load (in a monorepo that is usually the shared package's, not the app's)";
|
|
55
|
-
return `Add ${gap.imports === 2 ? "these two lines" : "this line"} to ${where}, RIGHT AFTER its \`@import "tailwindcss"\` line:
|
|
56
|
-
|
|
57
|
-
${lines.map((l) => ` ${l}`).join("\n")}
|
|
58
|
-
|
|
59
|
-
The position is not cosmetic. Read there, this sheet comes BEFORE any \`@theme\` this project declares, so wherever both name the same variable the project's own value wins. Moved to the end of the file, ours would win instead - silently.`;
|
|
60
|
-
}
|
|
61
|
-
export function setupPrompt(slug, gap) {
|
|
62
|
-
const g = gap ?? {
|
|
63
|
-
tokens: true,
|
|
64
|
-
scope: true,
|
|
65
|
-
type: true,
|
|
66
|
-
imports: 2,
|
|
67
|
-
};
|
|
68
|
-
const done = [
|
|
69
|
-
g.tokens ? null : "a stylesheet already imports the system's tokens",
|
|
70
|
-
g.scope ? null : `\`data-ds="${slug}"\` is already on a root element`,
|
|
71
|
-
g.type
|
|
72
|
-
? null
|
|
73
|
-
: "this project's type is already mapped onto the system's family tokens",
|
|
74
|
-
].filter(Boolean);
|
|
75
|
-
const steps = [];
|
|
76
|
-
if (g.tokens)
|
|
77
|
-
steps.push(importStep(slug, g));
|
|
78
|
-
if (g.scope)
|
|
79
|
-
steps.push(`Put \`data-ds="${slug}"\` on a root element of each app - the element every page renders inside. Keep any classes it already has; a background they chose is a decision they made.`);
|
|
80
|
-
if (g.type)
|
|
81
|
-
steps.push(`Map this project's type onto the system's family tokens: import from the fonts file the install wrote and point the family variables at it, in the same stylesheet. This is the step people skip, and without it the pages render in the framework's default face.`);
|
|
82
|
-
steps.push(`Run: npx synthesisui@latest doctor
|
|
83
|
-
${PROPAGATING}
|
|
84
|
-
If it says "no system installed", the install never happened - run \`${initCommand(slug)}\` and then start over from step 1.
|
|
85
|
-
It must NOT say "this project does not load it yet". If it does, it names exactly which piece is still missing - fix that one and run it again.`);
|
|
86
|
-
steps.push(CONNECT_STEP);
|
|
87
|
-
const alreadyDone = done.length > 0
|
|
88
|
-
? `\nAlready in place - LEAVE THESE ALONE:\n${done.map((d) => `- ${d}`).join("\n")}\n`
|
|
89
|
-
: "";
|
|
90
|
-
return `Set up the "${slug}" design system in this project, so its tokens reach the browser. I already ran the install in my terminal.
|
|
91
|
-
${alreadyDone}
|
|
92
|
-
${steps.map((s, i) => `${i + 1}. ${s}`).join("\n")}
|
|
93
|
-
|
|
94
|
-
Do not change any of my existing styles.`;
|
|
95
|
-
}
|