synthesisui 0.16.421 → 0.16.422
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 +37 -97
- 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/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/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
|
@@ -2,8 +2,9 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { generateComponentFiles } from "../component-codegen.js";
|
|
4
4
|
import { readProjectConfig, resolveRegistry } from "../config.js";
|
|
5
|
+
import { detectAppDirs } from "../global-sheet.js";
|
|
5
6
|
import { installedSlugs } from "../installed.js";
|
|
6
|
-
import {
|
|
7
|
+
import { reactMajorOf, readInstalledConvention, readInstalledScheme, theirThemeVars, } from "../project-facts.js";
|
|
7
8
|
import { postGenerate, RegistryError } from "../registry.js";
|
|
8
9
|
import { flavourResolver } from "../styles-flavour.js";
|
|
9
10
|
import { projectTongue } from "../their-tongue.js";
|
|
@@ -75,7 +76,17 @@ export async function generate(description, opts) {
|
|
|
75
76
|
// project as the stylesheet it has to match.
|
|
76
77
|
await readInstalledConvention(root, slug), res.name, await readInstalledScheme(root, slug),
|
|
77
78
|
/** O VOCABULÁRIO DELE - um componente gerado cai no mesmo projeto e fala a mesma língua. */
|
|
78
|
-
await projectTongue(root, slug),
|
|
79
|
+
await projectTongue(root, slug),
|
|
80
|
+
/**
|
|
81
|
+
* AS PASTAS DE APP, para a resposta ser a INTERSEÇÃO delas - ver `theirThemeVars`.
|
|
82
|
+
*
|
|
83
|
+
* Um componente materializado vai para uma pasta que num monorepo os dois apps importam, e
|
|
84
|
+
* ele não sabe em qual será usado. Varrer da raiz faria o `@theme` do app A responder por
|
|
85
|
+
* um componente escrito no app B: emitimos `bg-brand`, aquele app não gera a classe, e a
|
|
86
|
+
* propriedade renderiza NADA - pior que o valor arbitrário, porque nada falta na tela. É a
|
|
87
|
+
* mesma lição de `INV-VOLTA-12`, que saiu com a instrução de import e não com a topologia.
|
|
88
|
+
*/
|
|
89
|
+
await theirThemeVars(root, await detectAppDirs(root, config.pagesDir)));
|
|
79
90
|
/**
|
|
80
91
|
* A EDICAO DELE VENCE A REESCRITA (T7) - a leitura que faltava.
|
|
81
92
|
*
|
|
@@ -109,8 +120,18 @@ export async function generate(description, opts) {
|
|
|
109
120
|
console.log(` • <${comp} /> - compose its parts + content (see the recipe)`);
|
|
110
121
|
}
|
|
111
122
|
else {
|
|
112
|
-
|
|
113
|
-
|
|
123
|
+
/**
|
|
124
|
+
* O ARQUIVO NÃO É IMPORTADO DA NOSSA PASTA - `INV-GERAL-13`, 11/09.
|
|
125
|
+
*
|
|
126
|
+
* A instrução mandava `@import "_synthesisui/ds/<slug>/generated/<name>.css"` e envolver a
|
|
127
|
+
* marcação num `data-ds` nosso. As duas apontavam para dentro da nossa pasta, e é a dependência
|
|
128
|
+
* que esta etapa fechou.
|
|
129
|
+
*
|
|
130
|
+
* A folha gerada já passou pela porta de tradução, então ela fala o vocabulário dele: copiá-la
|
|
131
|
+
* para onde as folhas dele vivem não perde nada, e o que fica aqui segue sendo a referência.
|
|
132
|
+
*/
|
|
133
|
+
console.log(` • copy _synthesisui/ds/${slug}/generated/${res.name}.css next to your own stylesheets - it already speaks your vocabulary, and nothing of ours has to be loaded`);
|
|
134
|
+
console.log(` • <div class="ds-${res.name}">…</div>`);
|
|
114
135
|
}
|
|
115
136
|
console.log(` (${res.usage.inputTokens} in / ${res.usage.outputTokens} out tokens · AI action - additive; nothing else changed)`);
|
|
116
137
|
}
|
package/dist/commands/import.js
CHANGED
|
@@ -4643,7 +4643,7 @@ export async function runImport(opts) {
|
|
|
4643
4643
|
*/
|
|
4644
4644
|
if (payload?.slug) {
|
|
4645
4645
|
/**
|
|
4646
|
-
*
|
|
4646
|
+
* O QUE O CSS DELE AINDA IMPORTA - e este aviso sai do CLI, não da skill.
|
|
4647
4647
|
*
|
|
4648
4648
|
* MEDIDO em 24/08: o `globals.css` dele importa `_synthesisui/ds/codelevel/`, o nome escolhido
|
|
4649
4649
|
* derivou `codelevel-ds`, ninguém mencionou, e o `next build` dele terminou em exit code 1 com
|
|
@@ -4658,7 +4658,7 @@ export async function runImport(opts) {
|
|
|
4658
4658
|
const warning = wiringWarning(census.wiredSlugs ?? [], payload.slug);
|
|
4659
4659
|
if (warning) {
|
|
4660
4660
|
console.log("");
|
|
4661
|
-
console.log(section("Your CSS
|
|
4661
|
+
console.log(section("Your CSS still imports a stylesheet of ours"));
|
|
4662
4662
|
for (const line of warning.split("\n"))
|
|
4663
4663
|
console.log(body(line));
|
|
4664
4664
|
}
|
package/dist/commands/init.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_CONFIG, writeProjectConfig } from "../config.js";
|
|
2
2
|
import { body, section, snippet } from "../output.js";
|
|
3
|
-
import { setupPrompt } from "../setup-prompt.js";
|
|
4
3
|
import { resolveDeps, stylesFor, tailwindMajor } from "../stack.js";
|
|
5
4
|
import { formMix, measuredStyle } from "../styles-flavour.js";
|
|
6
5
|
import { add } from "./add.js";
|
|
@@ -134,19 +133,23 @@ export async function init(opts) {
|
|
|
134
133
|
dir: root,
|
|
135
134
|
setupHints: false,
|
|
136
135
|
});
|
|
136
|
+
/**
|
|
137
|
+
* ERAM DOIS PASSOS E É UM - `INV-GERAL-13`, 11/09.
|
|
138
|
+
*
|
|
139
|
+
* O passo 2 colava `setupPrompt` no agente dele: dois `@import` da nossa folha, um `data-ds` na
|
|
140
|
+
* árvore dele, e o mapa de tipografia. Ele não existe mais, porque nada que a plataforma escreve
|
|
141
|
+
* precisa de folha nossa carregada - e um comando de primeira vez é o pior lugar possível para
|
|
142
|
+
* ensinar uma dependência que o produto promete não criar.
|
|
143
|
+
*/
|
|
137
144
|
console.log("");
|
|
138
|
-
console.log(section("
|
|
139
|
-
console.log(body("
|
|
140
|
-
console.log(body("
|
|
145
|
+
console.log(section("One step left, and it is not a file you edit"));
|
|
146
|
+
console.log(body("Turn the check and the tools on - run this BEFORE you open your agent,"));
|
|
147
|
+
console.log(body("because hooks and tools are read when a session starts:"));
|
|
141
148
|
console.log("");
|
|
142
149
|
console.log(snippet(["npx synthesisui@latest connect"]));
|
|
143
150
|
console.log("");
|
|
144
|
-
console.log(body("
|
|
145
|
-
console.log("");
|
|
146
|
-
console.log(snippet(setupPrompt(opts.ds).split("\n")));
|
|
147
|
-
console.log("");
|
|
148
|
-
console.log(body("Then ask it for something real. The check introduces itself on the first"));
|
|
149
|
-
console.log(body("clean file and goes quiet after that."));
|
|
151
|
+
console.log(body("Then ask your agent for something real. The check introduces itself on the"));
|
|
152
|
+
console.log(body("first clean file and goes quiet after that."));
|
|
150
153
|
return;
|
|
151
154
|
}
|
|
152
155
|
console.log("");
|
package/dist/commands/refit.js
CHANGED
|
@@ -2,9 +2,10 @@ import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
|
2
2
|
import { basename, join } from "node:path";
|
|
3
3
|
import { generateComponentFiles } from "../component-codegen.js";
|
|
4
4
|
import { readProjectConfig, resolveRegistry } from "../config.js";
|
|
5
|
+
import { detectAppDirs } from "../global-sheet.js";
|
|
5
6
|
import { installedSlugs } from "../installed.js";
|
|
6
7
|
import { body, section, snippet } from "../output.js";
|
|
7
|
-
import {
|
|
8
|
+
import { reactMajorOf, readInstalledConvention, readInstalledScheme, theirThemeVars, } from "../project-facts.js";
|
|
8
9
|
import { fetchComponent, postRefit, postSaveComponent, RegistryError, } from "../registry.js";
|
|
9
10
|
import { flavourResolver } from "../styles-flavour.js";
|
|
10
11
|
import { projectTongue } from "../their-tongue.js";
|
|
@@ -121,7 +122,17 @@ export async function refit(file, opts) {
|
|
|
121
122
|
const flavourOf = await flavourResolver(root, config.styles);
|
|
122
123
|
const { files } = generateComponentFiles(slug, res.name, res.recipe, res.css, saved.version, flavourOf(res.name), await reactMajorOf(root), await readInstalledConvention(root, slug), res.name, await readInstalledScheme(root, slug),
|
|
123
124
|
/** O VOCABULÁRIO DELE - o `refit` reescreve o componente e não passava pela porta. */
|
|
124
|
-
await projectTongue(root, slug),
|
|
125
|
+
await projectTongue(root, slug),
|
|
126
|
+
/**
|
|
127
|
+
* AS PASTAS DE APP, para a resposta ser a INTERSEÇÃO delas - ver `theirThemeVars`.
|
|
128
|
+
*
|
|
129
|
+
* Um componente materializado vai para uma pasta que num monorepo os dois apps importam, e
|
|
130
|
+
* ele não sabe em qual será usado. Varrer da raiz faria o `@theme` do app A responder por
|
|
131
|
+
* um componente escrito no app B: emitimos `bg-brand`, aquele app não gera a classe, e a
|
|
132
|
+
* propriedade renderiza NADA - pior que o valor arbitrário, porque nada falta na tela. É a
|
|
133
|
+
* mesma lição de `INV-VOLTA-12`, que saiu com a instrução de import e não com a topologia.
|
|
134
|
+
*/
|
|
135
|
+
await theirThemeVars(root, await detectAppDirs(root, config.pagesDir)));
|
|
125
136
|
/**
|
|
126
137
|
* A EDICAO DELE VENCE A REESCRITA (T7) - a leitura que faltava, a mesma do `generate`.
|
|
127
138
|
*
|
package/dist/commands/summary.js
CHANGED
|
@@ -68,12 +68,16 @@ export async function summary(slug, opts) {
|
|
|
68
68
|
/**
|
|
69
69
|
* LINHA 3 - O QUE FAZER AGORA, e é uma coisa só.
|
|
70
70
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
71
|
+
* AS DUAS LINHAS DE FIAÇÃO SAÍRAM EM 11/09 - `INV-GERAL-13`. Elas eram descritas aqui como *"o
|
|
72
|
+
* portão de tudo o mais"*, e essa frase era verdadeira enquanto o que a plataforma escrevia
|
|
73
|
+
* dependia da nossa folha. Não depende mais: um componente chega falando os nomes que o código
|
|
74
|
+
* dele declara, ou carregando o valor.
|
|
75
|
+
*
|
|
76
|
+
* Este é o último ecrã da primeira corrida, e é o pior lugar do produto para ensinar uma
|
|
77
|
+
* dependência - ele é lido uma vez, com atenção, por alguém que está decidindo se fica.
|
|
74
78
|
*/
|
|
75
79
|
console.log("");
|
|
76
|
-
console.log(body("
|
|
77
|
-
console.log(body(
|
|
80
|
+
console.log(body("Nothing of ours goes into your code - there is no"));
|
|
81
|
+
console.log(body("stylesheet to import and no attribute to add."));
|
|
78
82
|
console.log(paint.blue(snippet(["npx synthesisui@latest doctor"])));
|
|
79
83
|
}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import { dirname, join, relative } from "node:path";
|
|
3
3
|
import { readProjectConfig, resolveRegistry } from "../config.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { inTheirTongue, projectTongue } from "../their-tongue.js";
|
|
4
|
+
import { installedSheetCss, RECIPE_HEADER, recipeRulesFor, } from "../recipe-css.js";
|
|
5
|
+
import { fetchDesignSystem, fetchTemplate } from "../registry.js";
|
|
6
|
+
import { inTheirTongue, projectTongue, tongueFromArtifacts, } from "../their-tongue.js";
|
|
7
7
|
import { keptLine, recordWritten, editedHere as theirEdits, } from "../written.js";
|
|
8
8
|
/**
|
|
9
|
+
* A INSTRUÇÃO SAI DE TODA PÁGINA, SEMPRE - `INV-GERAL-13`, 11/09.
|
|
10
|
+
*
|
|
11
|
+
* Esta filtragem era CONDICIONAL: ela rodava só quando a medição dizia que a página não precisava
|
|
12
|
+
* mais da folha, e no caso contrário o comentário ficava no arquivo dele mandando importar. Não há
|
|
13
|
+
* mais caso contrário - as regras que a página veste são copiadas para o `.css` ao lado dela
|
|
14
|
+
* (`recipe-css.ts`), e nada no arquivo aponta para nós.
|
|
15
|
+
*
|
|
9
16
|
* O QUE O ARQUIVO DIZ TAMBÉM É COBRANÇA - e ela é a metade que FICA no repositório dele.
|
|
10
17
|
*
|
|
11
18
|
* O DEFEITO, achado pela revisão de DX no fecho da etapa 11: o fecho no terminal parou de mandar
|
|
@@ -88,12 +95,28 @@ export async function template(slug, name, opts) {
|
|
|
88
95
|
return;
|
|
89
96
|
}
|
|
90
97
|
/**
|
|
91
|
-
* NENHUMA MATERIALIZAÇÃO VAZA VOCABULÁRIO INTERNO (INV-VOLTA-02) - a mesma porta do
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
98
|
+
* NENHUMA MATERIALIZAÇÃO VAZA VOCABULÁRIO INTERNO (INV-VOLTA-02) - a mesma porta do `component`,
|
|
99
|
+
* e agora também o mesmo CAMINHO DE LEITURA.
|
|
100
|
+
*
|
|
101
|
+
* SEM `add`, O SISTEMA VEM DO REGISTRY. Uma página trazida antes do install - e o próprio guard
|
|
102
|
+
* de edição deste comando já reconhece esse fluxo - não tinha pasta para ler, `projectTongue`
|
|
103
|
+
* respondia `null`, e o arquivo ia a disco com `var(--ds-*)` cru e as classes `.ds-*` sem uma
|
|
104
|
+
* regra sequer. Calado: o relatório da tradução só existe quando houve tradução.
|
|
105
|
+
*
|
|
106
|
+
* O `component` recebeu este conserto em 10/09 (`tongueFromArtifacts`) e o `template` não - "a
|
|
107
|
+
* mesma promessa, duas implementações, uma delas ausente" é literalmente o defeito que
|
|
108
|
+
* `INV-VOLTA-02` nomeia, e ele estava aqui.
|
|
109
|
+
*
|
|
110
|
+
* UMA IDA A MAIS À REDE, e só neste caminho: quem já instalou lê do disco como sempre.
|
|
95
111
|
*/
|
|
96
|
-
const
|
|
112
|
+
const installedTongue = await projectTongue(root, slug);
|
|
113
|
+
const fromRegistry = installedTongue
|
|
114
|
+
? null
|
|
115
|
+
: await fetchDesignSystem(base, slug, opts.version).catch(() => null);
|
|
116
|
+
const tongue = installedTongue ??
|
|
117
|
+
(fromRegistry
|
|
118
|
+
? await tongueFromArtifacts(root, fromRegistry.artifacts)
|
|
119
|
+
: null);
|
|
97
120
|
const speak = (code) => (tongue ? inTheirTongue(code, tongue) : null);
|
|
98
121
|
let named = 0;
|
|
99
122
|
let inlined = 0;
|
|
@@ -130,38 +153,55 @@ export async function template(slug, name, opts) {
|
|
|
130
153
|
content: translate(f.code),
|
|
131
154
|
});
|
|
132
155
|
/**
|
|
133
|
-
*
|
|
134
|
-
* `sheet-needed.ts`, a mesma porta que o `component` usa.
|
|
156
|
+
* AS REGRAS DE RECEITA VÊM JUNTO, no `.css` ao lado da página - `INV-GERAL-13`, 11/09.
|
|
135
157
|
*
|
|
136
|
-
* O
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* que renderiza igual sem os dois passava a pedi-los, e pedir cria exatamente a dependência que
|
|
140
|
-
* a plataforma promete não criar: a gente é referência, não dependência.
|
|
158
|
+
* O QUE MUDOU PARA O CLIENTE: a página renderiza sem nada nosso carregado no app dele. Ela veste
|
|
159
|
+
* `.ds-hero`, `.ds-nav` e as outras classes que o sistema declara, e essas regras passam a morar
|
|
160
|
+
* no arquivo ao lado dela - traduzidas para o vocabulário dele, como todo o resto.
|
|
141
161
|
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
162
|
+
* POR QUE A PÁGINA ERA O ÚLTIMO CASO. Ela é a única materialização que dependia da folha por
|
|
163
|
+
* CLASSE, e não por variável: a tradução reescreve `var(--ds-*)` e não tem o que fazer com
|
|
164
|
+
* `.ds-hero`, porque o corpo daquela regra nunca esteve no arquivo. Enquanto isso fosse verdade,
|
|
165
|
+
* este comando terminava mandando instalar o sistema e colar um `@import` - e foi essa instrução
|
|
166
|
+
* que abriu esta etapa.
|
|
145
167
|
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
168
|
+
* O CSS COPIADO PASSA PELA MESMA PORTA: `translate` é a tradução que todo byte deste comando
|
|
169
|
+
* atravessa, e um caminho que escreve CSS sem passá-la é o defeito que `INV-VOLTA-02` nomeia.
|
|
148
170
|
*/
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
171
|
+
const recipes = recipeRulesFor({
|
|
172
|
+
source: pieces.map((f) => f.content).join("\n"),
|
|
173
|
+
/**
|
|
174
|
+
* A FOLHA DE ONDE AS REGRAS SÃO COPIADAS - do disco quando ele instalou, do registry quando não.
|
|
175
|
+
*
|
|
176
|
+
* Sem as duas, `recipes.rules` é 0 e a página sai vestindo `.ds-*` que ninguém declara - com o
|
|
177
|
+
* cabeçalho dela afirmando que a folha ao lado escopa cada regra. Uma frase falsa dentro do
|
|
178
|
+
* arquivo dele é pior que uma instrução: o terminal rola, o arquivo fica.
|
|
179
|
+
*/
|
|
180
|
+
sheetCss: fromRegistry?.artifacts?.["tokens.css"] ??
|
|
181
|
+
(await installedSheetCss(root, slug)),
|
|
182
|
+
});
|
|
183
|
+
if (recipes.rules > 0) {
|
|
184
|
+
/**
|
|
185
|
+
* O ARQUIVO IRMÃO É O DESTINO, e ele já existe no alvo `next` - a página o importa desde que
|
|
186
|
+
* as media queries e o hambúrguer CSS-only passaram a viajar nele. Criar um terceiro arquivo
|
|
187
|
+
* daria à página dois CSS para importar e a ninguém uma razão.
|
|
188
|
+
*/
|
|
189
|
+
const sibling = pieces.find((p) => p.filename.endsWith(".css"));
|
|
190
|
+
const block = `${RECIPE_HEADER}\n${translate(recipes.css)}\n`;
|
|
191
|
+
if (sibling)
|
|
192
|
+
sibling.content = `${block}\n${sibling.content}`;
|
|
193
|
+
else
|
|
194
|
+
pieces.push({
|
|
195
|
+
rel: join(dirname(pageRel), pageFile.filename.replace(/\.tsx$/, ".css")),
|
|
196
|
+
filename: pageFile.filename.replace(/\.tsx$/, ".css"),
|
|
197
|
+
content: block,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
158
200
|
await mkdir(pageDir, { recursive: true });
|
|
159
201
|
/** OS BYTES QUE FORAM A DISCO, para o fingerprint lembrar EXATAMENTE o que escrevemos. */
|
|
160
202
|
const landed = [];
|
|
161
203
|
for (const piece of pieces) {
|
|
162
|
-
const content =
|
|
163
|
-
? piece.content
|
|
164
|
-
: withoutTheSheetInstruction(piece.content);
|
|
204
|
+
const content = withoutTheSheetInstruction(piece.content);
|
|
165
205
|
await writeFile(join(root, piece.rel), content, "utf8");
|
|
166
206
|
landed.push({ filename: piece.filename, content });
|
|
167
207
|
console.log(piece.rel === pageRel
|
|
@@ -180,35 +220,23 @@ export async function template(slug, name, opts) {
|
|
|
180
220
|
console.log(` ${named} reference${named === 1 ? "" : "s"} now speak${named === 1 ? "s" : ""} the name YOUR code gives the value${inlined > 0 ? `, and ${inlined} carr${inlined === 1 ? "ies" : "y"} the value because your code names no token for it` : ""}.`);
|
|
181
221
|
if (still.size > 0) {
|
|
182
222
|
const sample = [...still].sort().slice(0, 3).join(", ");
|
|
183
|
-
console.log(` ${still.size}
|
|
223
|
+
console.log(` ${still.size} value${still.size === 1 ? "" : "s"} the system declares no value for (${sample}${still.size > 3 ? ", …" : ""}) - ${still.size === 1 ? "that declaration is" : "those declarations are"} dropped by the browser. Please report this: the sheet we read is incomplete.`);
|
|
184
224
|
}
|
|
185
225
|
}
|
|
226
|
+
if (recipes.rules > 0)
|
|
227
|
+
console.log(` ${recipes.rules} rule${recipes.rules === 1 ? "" : "s"} for ${recipes.classes.slice(0, 3).join(", ")}${recipes.classes.length > 3 ? `, +${recipes.classes.length - 3}` : ""} came along in the stylesheet next to it - nothing to import.`);
|
|
186
228
|
console.log("");
|
|
187
229
|
console.log("Next steps:");
|
|
188
230
|
console.log(` • use it in a route, e.g. ${join(config.pagesDir, "page.tsx")}:`);
|
|
189
231
|
console.log(` import Page from "@/${defaultDir.replace(/\\/g, "/")}/${pageFile.filename.replace(/\.tsx$/, "")}";`);
|
|
190
|
-
|
|
191
|
-
/** E ELE DIZ O QUE PEDE A FOLHA - um setup cobrado sem motivo dito ensina a ignorar o próximo. */
|
|
192
|
-
if (need)
|
|
193
|
-
console.log(` • what still needs the sheet here: ${[...need.recipeClasses, ...need.classes, ...need.variables].slice(0, 3).join(", ")}`);
|
|
194
|
-
console.log(` • ensure the DS is installed: synthesisui add ${slug} (provides tokens.css)`);
|
|
195
|
-
console.log(` • @import "_synthesisui/ds/${slug}/tokens.css" in your global CSS`);
|
|
196
|
-
}
|
|
197
|
-
else {
|
|
198
|
-
console.log(` • nothing to install: every value in this page is a name YOUR code declares, so it renders without our stylesheet`);
|
|
199
|
-
}
|
|
232
|
+
console.log(` • nothing to install: this page and its stylesheet stand on their own`);
|
|
200
233
|
console.log(" • refine the file: wire real data, split into components, swap placeholders");
|
|
201
234
|
/**
|
|
202
|
-
* E A LINHA DO ESCOPO
|
|
235
|
+
* E A LINHA DO ESCOPO NÃO SAI MAIS - `INV-GERAL-13`, 11/09.
|
|
203
236
|
*
|
|
204
|
-
* Ela mandava *"keep the data-ds wrapper and the ds-* classes (stays on-system)"
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
* frases que não podem ser verdadeiras ao mesmo tempo -, e a medição já responde qual das duas é:
|
|
209
|
-
* chegar aqui com `chargesTheSheet` falso significa zero variável nossa e zero classe nossa no
|
|
210
|
-
* que acabou de ser escrito.
|
|
237
|
+
* Ela mandava *"keep the data-ds wrapper and the ds-* classes (stays on-system)"*. O `data-ds`
|
|
238
|
+
* existia para a NOSSA folha aplicar dentro dele, e o app dele não a carrega: pedir que ele
|
|
239
|
+
* mantenha um atributo nosso na árvore dele é a mesma dependência com outro nome. As classes
|
|
240
|
+
* continuam valendo, e agora elas são declaradas pelo arquivo ao lado da própria página.
|
|
211
241
|
*/
|
|
212
|
-
if (chargesTheSheet)
|
|
213
|
-
console.log(` • keep the data-ds="${slug}" wrapper and the ds-* / layout classes (stays on-system)`);
|
|
214
242
|
}
|
package/dist/commands/upgrade.js
CHANGED
|
@@ -7,9 +7,10 @@ import { generateComponentFiles } from "../component-codegen.js";
|
|
|
7
7
|
import { readProjectConfig, readToken, resolveRegistry } from "../config.js";
|
|
8
8
|
import { unsentEvents } from "../doctor/ledger.js";
|
|
9
9
|
import { diffLocalDocuments, localChangelogMarkdown, } from "../document-diff.js";
|
|
10
|
+
import { detectAppDirs } from "../global-sheet.js";
|
|
10
11
|
import { installedBehind, MATERIALISER_SINCE } from "../install-marks.js";
|
|
11
12
|
import { body, section, snippet } from "../output.js";
|
|
12
|
-
import {
|
|
13
|
+
import { reactMajorOf, readInstalledConvention, readInstalledScheme, theirThemeVars, } from "../project-facts.js";
|
|
13
14
|
import { fetchChangelog, fetchComponent, fetchDesignSystem, RegistryError, } from "../registry.js";
|
|
14
15
|
import { flavourResolver } from "../styles-flavour.js";
|
|
15
16
|
import { projectTongue } from "../their-tongue.js";
|
|
@@ -419,8 +420,9 @@ export async function upgrade(asked, opts) {
|
|
|
419
420
|
* língua do repositório. Resolvido uma vez para a corrida inteira, como o sabor.
|
|
420
421
|
*/
|
|
421
422
|
const tongue = await projectTongue(root, slug);
|
|
422
|
-
/**
|
|
423
|
-
|
|
423
|
+
/** O `@theme` DELE é o MESMO para a corrida inteira - ver `theirThemeVars`. */
|
|
424
|
+
/** As pastas de app - a resposta é a INTERSEÇÃO delas. Ver `theirThemeVars`. */
|
|
425
|
+
const themeVars = await theirThemeVars(root, await detectAppDirs(root, config.pagesDir));
|
|
424
426
|
for (const entry of entries) {
|
|
425
427
|
const tsxPath = join(componentsRoot, entry, `${entry}.tsx`);
|
|
426
428
|
let head = "";
|
package/dist/commands/use.js
CHANGED
|
@@ -90,10 +90,12 @@ export async function use(slug, intent, opts) {
|
|
|
90
90
|
// The styling contract differs by target: Next projects in this product use
|
|
91
91
|
// Tailwind v4 backed by the DS; the "general" target is framework-agnostic CSS.
|
|
92
92
|
const stylingRule = config.target === "general"
|
|
93
|
-
? `- Style with the design system only:
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
? `- Style with the design system only: bring its recipes in as code ` +
|
|
94
|
+
`(\`npx synthesisui component ${slug} <name>\`) and write the names THIS project declares - ` +
|
|
95
|
+
`\`find_token\` answers with the exact one. Never use raw hex/px outside the system's scale.`
|
|
96
|
+
: `- Style with the design system only: bring its recipes in as code ` +
|
|
97
|
+
`(\`npx synthesisui component ${slug} <name>\`) and use this project's own Tailwind utilities ` +
|
|
98
|
+
`(${utilities}…). Never use raw hex/px outside the system's scale.`;
|
|
97
99
|
const task = intent.trim() || "build the UI I describe next";
|
|
98
100
|
const prompt = [
|
|
99
101
|
`Use the "${name}" design system (slug: ${slug}, v${version}) to: ${task}`,
|
|
@@ -106,11 +108,8 @@ export async function use(slug, intent, opts) {
|
|
|
106
108
|
`\`${config.componentsDir}/\` and \`${config.pagesDir}/\`). If it does, modify only what's ` +
|
|
107
109
|
`needed and keep the rest of the file intact and on-system. If it doesn't, build it new - ` +
|
|
108
110
|
`components in \`${config.componentsDir}/\`, pages in \`${config.pagesDir}/\`.`,
|
|
109
|
-
`- Scope the markup with \`data-ds="${slug}"\` (or rely on it at the app root).`,
|
|
110
111
|
stylingRule,
|
|
111
|
-
|
|
112
|
-
? '- Make sure `tokens.css` + `theme.css` are imported in the global CSS (see the GUIDE\'s "How to apply").'
|
|
113
|
-
: '- Make sure `tokens.css` is imported in the global CSS (see the GUIDE\'s "How to apply").',
|
|
112
|
+
"- Nothing of the platform's is imported into this project: a component brought in by `component` carries everything it needs.",
|
|
114
113
|
"- Implement the behavior yourself (open/close, focus, routing) - the system ships the looks, not the JS.",
|
|
115
114
|
"",
|
|
116
115
|
"Composition (make it look composed, not just correct):",
|
|
@@ -470,8 +470,16 @@ const scaleKey = (v) => {
|
|
|
470
470
|
const m = v.match(/^\{typography\.scale\.([a-zA-Z0-9-]+)\.fontSize\}$/);
|
|
471
471
|
return m ? kebab(m[1]) : null;
|
|
472
472
|
};
|
|
473
|
-
/**
|
|
474
|
-
*
|
|
473
|
+
/**
|
|
474
|
+
* "{color.semantic.primary}" → "var(--ds-color-semantic-primary)" - a grafia INTERNA, que a porta
|
|
475
|
+
* de tradução (`speak`) reescreve no nome dele ou no valor literal antes de qualquer byte ir a
|
|
476
|
+
* disco.
|
|
477
|
+
*
|
|
478
|
+
* ELA NUNCA SOBREVIVE ATÉ O ARQUIVO DELE (`INV-GERAL-13`): `speak` é a última coisa que roda em
|
|
479
|
+
* `generateComponentFiles`, e `nothing-of-ours-is-asked-for.spec.ts` reprova o texto que sair daqui
|
|
480
|
+
* com a nossa grafia dentro. Existe como forma intermediária porque é ela que carrega o caminho da
|
|
481
|
+
* referência (`color.semantic.primary`) até a folha que sabe o valor.
|
|
482
|
+
*/
|
|
475
483
|
const refToDsVar = (v) => v.replace(/\{([a-z0-9.-]+)\}/gi, (_, path) => {
|
|
476
484
|
return `var(--ds-${path.split(".").map(kebab).join("-")})`;
|
|
477
485
|
});
|
|
@@ -531,25 +539,28 @@ function remToTwScale(value) {
|
|
|
531
539
|
return Number.isInteger(n) && n >= 0 && n <= 96 ? String(n) : null;
|
|
532
540
|
}
|
|
533
541
|
/**
|
|
534
|
-
* O UTILITÁRIO NOMEADO SÓ VALE QUANDO
|
|
542
|
+
* O UTILITÁRIO NOMEADO SÓ VALE QUANDO O `@theme` **DELE** O DECLARA - e é isso que decide o VALOR.
|
|
535
543
|
*
|
|
536
544
|
* `rounded-lg` existe em qualquer projeto com Tailwind, então a classe nunca "falta". O que muda é
|
|
537
|
-
* de quem é o valor: quando o
|
|
538
|
-
*
|
|
539
|
-
* mente em silêncio, que é pior que uma classe morta, porque nada na tela parece faltar.
|
|
545
|
+
* de quem é o valor: quando o `@theme` do projeto dele declara `--radius-lg`, a classe pinta o raio
|
|
546
|
+
* DELE, e a decisão continua sendo dele; quando não declara, ela pinta o default do Tailwind - e o
|
|
547
|
+
* componente mente em silêncio, que é pior que uma classe morta, porque nada na tela parece faltar.
|
|
540
548
|
*
|
|
541
|
-
* A
|
|
542
|
-
*
|
|
543
|
-
*
|
|
544
|
-
*
|
|
549
|
+
* A PERGUNTA ERA SOBRE A NOSSA FOLHA ATÉ 11/09, e era a última dependência de runtime que o código
|
|
550
|
+
* entregue carregava. `rounded-lg` escrito porque o NOSSO `theme.css` declara `--radius-lg` só pinta
|
|
551
|
+
* o sistema num app que importa aquele arquivo - e `INV-GERAL-13` diz que nenhum app dele importa. O
|
|
552
|
+
* componente saía com a aparência certa na nossa cabeça e o raio do Tailwind na tela dele.
|
|
545
553
|
*
|
|
546
|
-
*
|
|
554
|
+
* QUANDO ELE NÃO DECLARA, a resposta é o valor arbitrário - e a porta de tradução o resolve no nome
|
|
555
|
+
* dele ou no literal, nunca numa variável nossa.
|
|
547
556
|
*
|
|
548
|
-
*
|
|
557
|
+
* MEDIDO em 07/09 sobre TODOS os componentes das duas populações, com a folha NOSSA respondendo:
|
|
558
|
+
*
|
|
559
|
+
* codelevel, repo real 58 de 110 utilitários de token (53%) já caíam no arbitrário
|
|
549
560
|
* ember, app novo 34 de 241 (14%)
|
|
550
561
|
*
|
|
551
|
-
* `null` é
|
|
552
|
-
*
|
|
562
|
+
* `null` é "ninguém mediu" - `refit` e `generate` já dizem que nada pinta sem o `add`, e ali o nome
|
|
563
|
+
* legível não custa nada.
|
|
553
564
|
*/
|
|
554
565
|
const minted = (themeVars, cssVar) => themeVars === null || themeVars.has(cssVar);
|
|
555
566
|
/** One declaration → Tailwind classes (pretty when mappable, arbitrary-property
|
|
@@ -890,15 +901,27 @@ function variantOwnedProps(variants, axis) {
|
|
|
890
901
|
return [...props];
|
|
891
902
|
}
|
|
892
903
|
// ── Emission ─────────────────────────────────────────────────────────────────
|
|
904
|
+
/**
|
|
905
|
+
* O CABEÇALHO DO ARQUIVO DELE - e as duas linhas de setup saíram dele em 11/09.
|
|
906
|
+
*
|
|
907
|
+
* O QUE ELAS DIZIAM, dentro de TODO `.tsx` que a plataforma escreve no repositório dele:
|
|
908
|
+
* *"Global setup (once per app): import _synthesisui/ds/<slug>/tokens.css"* e *"put data-ds=<slug>
|
|
909
|
+
* on a root element"*. Era a instrução que o produto promete não dar, escrita no lugar onde ela
|
|
910
|
+
* sobrevive a qualquer conserto do terminal - e ela ficava lá, num arquivo dele, para todo agente
|
|
911
|
+
* e toda pessoa lerem depois (`INV-GERAL-13`).
|
|
912
|
+
*
|
|
913
|
+
* E ELA FAZIA UM SEGUNDO ESTRAGO, medido em 10/09: `readWiring` procurava essas mesmas strings no
|
|
914
|
+
* repositório para responder *"este projeto carrega o sistema?"*, então a partir do primeiro
|
|
915
|
+
* componente que NÓS escrevemos ela respondia `imported: true` sobre um projeto que não importa
|
|
916
|
+
* nada. Um comentário nosso nunca provou nada sobre o projeto dele.
|
|
917
|
+
*
|
|
918
|
+
* O que fica é a PROCEDÊNCIA - quem escreveu, de qual sistema, em que versão. Ela não pede nada; ela
|
|
919
|
+
* responde a pergunta de quem abre o arquivo daqui a seis meses.
|
|
920
|
+
*/
|
|
893
921
|
function header(slug, name, version, mode) {
|
|
894
|
-
const setup = mode === "tailwind"
|
|
895
|
-
? `import _synthesisui/ds/${slug}/theme.css (Tailwind adapter) + tokens.css`
|
|
896
|
-
: `import _synthesisui/ds/${slug}/tokens.css`;
|
|
897
922
|
return [
|
|
898
923
|
`// Generated by SynthesisUI - "${name}" from the "${slug}" design system (v${version}).`,
|
|
899
|
-
`//
|
|
900
|
-
`// Global setup (once per app): ${setup}`,
|
|
901
|
-
`// and put data-ds="${slug}" on a root element (e.g. <body data-ds="${slug}">).`,
|
|
924
|
+
`// Every value here is a name YOUR code declares, or the value itself - nothing to import.`,
|
|
902
925
|
...(mode === "tailwind" ? [OVERRIDE_WARNING] : []),
|
|
903
926
|
].join("\n");
|
|
904
927
|
}
|
|
@@ -1507,12 +1530,16 @@ scheme,
|
|
|
1507
1530
|
*/
|
|
1508
1531
|
tongue,
|
|
1509
1532
|
/**
|
|
1510
|
-
* O QUE
|
|
1533
|
+
* O QUE O `@theme` **DELE** DECLARA - `theirThemeVars(root)`.
|
|
1511
1534
|
*
|
|
1512
1535
|
* OBRIGATÓRIO, pelo mesmo argumento do `scheme` e do `tongue`: o utilitário nomeado que este
|
|
1513
|
-
* módulo escreve só carrega
|
|
1536
|
+
* módulo escreve só carrega um valor de design quando o `@theme` do PROJETO dele declara a
|
|
1514
1537
|
* variável. Sem essa resposta o codegen escreve `rounded-lg` e a classe pinta o default do
|
|
1515
|
-
* Tailwind - o componente mente sem nada faltar na tela.
|
|
1538
|
+
* Tailwind - o componente mente sem nada faltar na tela.
|
|
1539
|
+
*
|
|
1540
|
+
* ERA A NOSSA FOLHA QUE RESPONDIA ISTO, e essa era a última dependência de runtime que o código
|
|
1541
|
+
* entregue ainda tinha (`INV-GERAL-13`, 11/09). `null` é "ninguém mediu", e continua significando
|
|
1542
|
+
* que o nome legível não custa nada - `refit` e `generate` já dizem que nada pinta sem o `add`.
|
|
1516
1543
|
*/
|
|
1517
1544
|
themeVars) {
|
|
1518
1545
|
const files = [];
|
|
@@ -66,6 +66,9 @@ register("pt-BR", {
|
|
|
66
66
|
"already current": "já está em dia",
|
|
67
67
|
"updated to this CLI's pipeline": "atualizada para esta versão",
|
|
68
68
|
"removed - renamed to /sui-import-ds": "removida - virou /sui-import-ds",
|
|
69
|
+
/** A skill aposentada fica no repositório dele, nomeada - ver `RETIRED_SKILLS`. */
|
|
70
|
+
"retired - nothing of ours loads in your app any more": "aposentada - nada nosso carrega no seu app",
|
|
71
|
+
"it stays in your repo - yours to delete": "ela fica no seu repositório - sua para apagar",
|
|
69
72
|
// ── onde o bloco de regras caiu ──
|
|
70
73
|
"how to turn this repo into your system": "como transformar este repo no seu sistema",
|
|
71
74
|
"rewritten for what is installed": "reescrito para o que está instalado",
|
package/dist/doctor/apply-fix.js
CHANGED
|
@@ -437,7 +437,7 @@ export function describeFix(result, dry) {
|
|
|
437
437
|
const lines = [];
|
|
438
438
|
if (applied.length === 0) {
|
|
439
439
|
lines.push(decisions > 0
|
|
440
|
-
? `Nothing to apply. All ${decisions} findings are values your
|
|
440
|
+
? `Nothing to apply. All ${decisions} findings are values your own code names nowhere - those are design decisions, not fixes. Name one and \`--fix\` picks it up.`
|
|
441
441
|
: relative > 0
|
|
442
442
|
? `Nothing to apply. All ${relative} findings are lengths in \`em\`, which follow the element's font size - swapping them can move the layout, so that call is yours.`
|
|
443
443
|
: /**
|
|
@@ -531,6 +531,6 @@ export function describeFix(result, dry) {
|
|
|
531
531
|
const rewritten = new Set(applied.map((a) => `${a.file}:${a.line}`));
|
|
532
532
|
const halfWritten = skipped.filter((s) => rewritten.has(`${s.file}:${s.line}`)).length;
|
|
533
533
|
if (halfWritten > 0)
|
|
534
|
-
lines.push(` ${halfWritten} of those ${halfWritten === 1 ? "sits" : "sit"} on a line this command just rewrote - a shorthand comes back with a token and a literal side by side (\`padding: 8px var(--
|
|
534
|
+
lines.push(` ${halfWritten} of those ${halfWritten === 1 ? "sits" : "sit"} on a line this command just rewrote - a shorthand comes back with a token and a literal side by side (\`padding: 8px var(--spacing-24)\`). See them by value: npx synthesisui doctor --migrate`);
|
|
535
535
|
return lines;
|
|
536
536
|
}
|