synthesisui 0.16.203 → 0.16.205

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 CHANGED
@@ -350,9 +350,10 @@ Only write something new when nothing in the manifest covers the purpose - and w
350
350
  say which entry you considered and why it did not fit, then FILE it while the reasoning is
351
351
  still yours: the \`request_component\` MCP tool, or \`npx synthesisui@latest request component
352
352
  --name "<name>" --for "<the use case>" --considered "<entries and why not>"\`. That queue is
353
- what the system's author works from - a refusal said only in chat evaporates. To review a
354
- component, create an isolated sample page (e.g. \`app/synthesisui-samples/<component>/\`) - do not
355
- apply it to real production pages unless asked.${selfCheck}`;
353
+ what the system's author works from - a refusal said only in chat evaporates. If you want to eyeball a
354
+ component on its own, an isolated scratch page is optional and never required - and if you make
355
+ one, put it somewhere that does not become a route in this app, and delete it when you are done.
356
+ Do not apply a component to real production pages unless asked.${selfCheck}`;
356
357
  const locale = await readInterfaceLanguage(projectRoot);
357
358
  const language = locale === null
358
359
  ? ""
@@ -2,8 +2,10 @@ import { readdir, readFile } from "node:fs/promises";
2
2
  import { homedir } from "node:os";
3
3
  import { join, resolve } from "node:path";
4
4
  import { pinnedHookVersion } from "../agent-wiring.js";
5
+ import { isOlderCli } from "../cli-version.js";
5
6
  import { readToken, resolveRegistry } from "../config.js";
6
7
  import { unsentEvents } from "../doctor/ledger.js";
8
+ import { CHECKER_SINCE, MATERIALISER_SINCE } from "../install-marks.js";
7
9
  import { measuredScope } from "../measured-scope.js";
8
10
  import { READER } from "../reader-version.js";
9
11
  /**
@@ -59,6 +61,28 @@ async function credentials(home) {
59
61
  *
60
62
  * Separada de propósito: ela é a que sempre roda, e é testável sem servidor nenhum.
61
63
  */
64
+ /**
65
+ * O QUE ESTÁ INSTALADO AQUI FICOU PARA TRÁS - e as DUAS condições que fazem isso ser verdade.
66
+ *
67
+ * `installed` é a versão que escreveu a coisa (a pasta, ou o pin do hook); `running` é o CLI de hoje;
68
+ * `since` é a última versão em que aquilo mudou de verdade - ver `install-marks.ts`.
69
+ *
70
+ * As duas condições, e nenhuma delas basta sozinha:
71
+ *
72
+ * o que está instalado é ANTERIOR à última mudança senão `upgrade` reescreve bytes idênticos
73
+ * o CLI de hoje já ALCANÇOU essa mudança senão `upgrade` escreve a mesma coisa velha
74
+ *
75
+ * A segunda é a que quase escapou: quem roda um CLI antigo com uma pasta da mesma época não ganha
76
+ * nada com `upgrade` - o comando usa o CLI que ela tem. Mandar rodar ali é gastar a atenção dela num
77
+ * comando que não pode mudar nada, e o caminho de verdade é outro (`connect`).
78
+ */
79
+ function behind(installed, running, since) {
80
+ if (!installed || !running)
81
+ return null;
82
+ if (!isOlderCli(installed, since))
83
+ return null;
84
+ return isOlderCli(running, since) ? null : installed;
85
+ }
62
86
  export async function localMisalignments(root,
63
87
  /**
64
88
  * `home` é injetável porque a SESSÃO mora nele e não no repo - e uma verificação que lê o home da
@@ -147,8 +171,12 @@ opts = {}) {
147
171
  * O `upgrade` conserta, e esta linha existe para quem ainda não rodou: a verificação de abertura é
148
172
  * o único lugar que fala sem ser perguntado. Apontava `connect` até 07/08, quando o dono nomeou a
149
173
  * incoerência - a palavra que significa atualizar era a única que não atualizava.
174
+ *
175
+ * COMPARA `MATERIALISER_SINCE`, E NÃO A STRING DO CLI - a mesma correção que o `READER` recebeu do
176
+ * lado da medição, e que este lado não tinha. Medido: de 79 bumps, 10 mudaram o que vai para esta
177
+ * pasta. Os outros 69 mandavam rodar `upgrade` para reescrever bytes idênticos.
150
178
  */
151
- const folderBehind = cli && lock.cli && lock.cli !== cli ? lock.cli : null;
179
+ const folderBehind = behind(lock.cli, cli, MATERIALISER_SINCE);
152
180
  /**
153
181
  * O HOOK, MEDIDO NELE MESMO - e não pelo `.lock`, que é um proxy que se move sozinho.
154
182
  *
@@ -159,9 +187,13 @@ opts = {}) {
159
187
  *
160
188
  * `pinnedHookVersion` devolve `null` numa instalação local, onde o hook segue o `node_modules` e
161
189
  * nunca está atrás por si.
190
+ *
191
+ * E COMPARA `CHECKER_SINCE` pelo mesmo motivo da linha acima: o hook estar pinado numa versão
192
+ * anterior só importa quando o checador de hoje veria algo que o pinado não vê. De 79 bumps, 34
193
+ * mudaram o checador - nos outros 45 esta linha acusava um pin que se comporta igual.
162
194
  */
163
195
  const pinned = await pinnedHookVersion(root).catch(() => null);
164
- const hookBehind = cli && pinned && pinned !== cli ? pinned : null;
196
+ const hookBehind = behind(pinned, cli, CHECKER_SINCE);
165
197
  /**
166
198
  * UMA CAUSA, UMA LINHA - e as duas metades nomeadas dentro dela.
167
199
  *
@@ -1,4 +1,4 @@
1
- import { readFile, rm, stat, writeFile } from "node:fs/promises";
1
+ import { readdir, readFile, rm, stat, writeFile } from "node:fs/promises";
2
2
  import { join, relative } from "node:path";
3
3
  import { body, section } from "../output.js";
4
4
  // The five SVGs create-next-app drops into public/. Filenames are specific
@@ -100,6 +100,35 @@ export async function clean(opts) {
100
100
  run: () => rm(readmePath),
101
101
  });
102
102
  }
103
+ /**
104
+ * O RASCUNHO QUE A NOSSA PRÓPRIA INSTRUÇÃO PEDIU - e que ninguém sabia remover.
105
+ *
106
+ * O `CLAUDE.md` que este CLI escreve sugere uma página isolada para olhar um componente sozinho,
107
+ * e o agente da pessoa a cria. Nada aqui a escreve, e nada aqui a apagava: ela ficava numa rota
108
+ * de VERDADE do app dela (`src/app/synthesisui-samples/<x>` é URL acessível), sem dono e sem
109
+ * saída, até alguém commitar sem querer. Encontrada no repo do dono em 11/08.
110
+ *
111
+ * É a mesma assimetria do bloco de shell: fácil de entrar, sem porta de saída. Aqui a saída é
112
+ * este comando, e ele mantém o contrato que já tem - seco por padrão, cada caminho nomeado antes
113
+ * de qualquer escrita, `--force` para aplicar.
114
+ *
115
+ * UMA AÇÃO POR PÁGINA, e não uma pela pasta: um destrutivo que anuncia um e remove seis faz mais
116
+ * do que diz, e essa lei já foi paga uma vez na poda de órfãos.
117
+ */
118
+ const samplesDir = join(appDir, "synthesisui-samples");
119
+ for (const entry of await readdir(samplesDir, {
120
+ withFileTypes: true,
121
+ }).catch(() => [])) {
122
+ if (!entry.isDirectory())
123
+ continue;
124
+ const p = join(samplesDir, entry.name);
125
+ actions.push({
126
+ verb: "remove",
127
+ path: rel(p),
128
+ why: "scratch page for eyeballing a component - nothing depends on it",
129
+ run: () => rm(p, { recursive: true }),
130
+ });
131
+ }
103
132
  if (actions.length === 0) {
104
133
  console.log(section("Clean up scaffold"));
105
134
  console.log(body("Nothing to clean - this project is already tidy."));
@@ -0,0 +1,66 @@
1
+ /**
2
+ * QUANDO O QUE ESTÁ INSTALADO NESTA MÁQUINA FICOU PARA TRÁS DE VERDADE.
3
+ *
4
+ * Duas coisas do CLI vivem no repositório de quem usa e NÃO se atualizam sozinhas: os arquivos que o
5
+ * `add` escreve em `_synthesisui/ds/<slug>`, e o hook que roda depois de cada escrita do agente - que
6
+ * fica pinado de propósito, porque comportamento que muda sob você é indebugável.
7
+ *
8
+ * O `align` avisava sobre as duas comparando a STRING DA VERSÃO do CLI. É a mesma armadilha que o
9
+ * `READER` já tinha resolvido do lado da medição, e que ninguém tinha aplicado aqui. Medido em 11/08
10
+ * sobre os 79 últimos bumps deste repositório:
11
+ *
12
+ * mudaram o que o `upgrade` ESCREVE 20 (25%)
13
+ * mudaram o que o HOOK roda 34 (43%)
14
+ * não mudaram NENHUM dos dois 27 (34%)
15
+ *
16
+ * Um terço dos bumps mandava a pessoa rodar `upgrade` por absolutamente nada, com as DUAS linhas na
17
+ * tela. E o custo não é o incômodo: um alarme que toca quando está tudo certo é o alarme que ela
18
+ * aprende a pular no dia em que ele estiver dizendo a verdade.
19
+ *
20
+ * O dono nomeou isso em 11/08 pela pergunta certa - *"por que foi necessário atualizar o CLI dessa
21
+ * vez?"* - sobre um bump que mexeu no `clean` e numa frase, e não tocou a pasta de ninguém.
22
+ *
23
+ * ESTAS MARCAS SÃO VERSÕES, e não números de série, por um motivo prático: elas comparam contra o que
24
+ * já está gravado no `.lock` e no hook dos installs QUE JÁ EXISTEM. Um contador novo precisaria ser
25
+ * escrito primeiro, e o primeiro contato com ele acusaria todo mundo uma vez - exatamente o alarme à
26
+ * toa que isto remove.
27
+ *
28
+ * A família inteira, e o que cada uma alcança:
29
+ *
30
+ * READER a medição na máquina dela -> npx synthesisui sync
31
+ * COMPILER o CSS de uma versão já instalada -> npx synthesisui connect
32
+ * INTERPRETATION a nossa metade, no servidor -> sem comando
33
+ * MATERIALISER_SINCE os arquivos da pasta dele -> npx synthesisui upgrade
34
+ * CHECKER_SINCE o hook que lê o que o agente faz -> npx synthesisui upgrade
35
+ *
36
+ * COMO SE MEXE NELAS: não se lembra, o spec cobra. `install-marks.spec.ts` guarda o fingerprint dos
37
+ * arquivos que decidem cada marca e fica vermelho quando eles mudam sem a marca acompanhar. O
38
+ * `READER` nasceu sem esse portão em 07/08 e a disciplina falhou na primeira oportunidade que teve:
39
+ * `d90260cb` acrescentou 47 linhas a `anatomy-from-sketch.ts` - uma mudança que muda o censo dos
40
+ * mesmos arquivos - e o `READER` continua em 1 até hoje. Uma marca mantida à mão sem portão é uma
41
+ * marca errada esperando a hora.
42
+ */
43
+ /**
44
+ * A ÚLTIMA VERSÃO EM QUE O QUE O `upgrade` ESCREVE NO REPO DELE MUDOU.
45
+ *
46
+ * Um install escrito por um CLI ANTERIOR a esta está velho de verdade; escrito por qualquer versão a
47
+ * partir daqui, tem exatamente os mesmos bytes que o `upgrade` de hoje escreveria.
48
+ *
49
+ * CONJUNTO COMPLETO, e a primeira tentativa errou por incompleta: `add.ts` chama `claude-md.ts`,
50
+ * `fonts.ts`, `rule-filter.ts` e `stack.ts`, e o `upgrade.ts` escreve o `UPGRADE.md` por conta
51
+ * própria. Deixar qualquer um de fora produz FALSO NEGATIVO - a marca fica parada enquanto o
52
+ * conteúdo anda, e o alarme cala no dia em que ele é verdade. Foi exatamente o que quase aconteceu:
53
+ * o `claude-md.ts` mudou em 0.16.204 e o conjunto de quatro arquivos não via.
54
+ *
55
+ * O resto da pasta vem do servidor e já é coberto pela versão do DS.
56
+ */
57
+ export const MATERIALISER_SINCE = "0.16.204";
58
+ /**
59
+ * A ÚLTIMA VERSÃO EM QUE O QUE O HOOK RODA MUDOU.
60
+ *
61
+ * O hook fica pinado, então ele só anda quando alguém roda `upgrade`. Isso é de propósito - mas só
62
+ * vale a pena dizer quando o checador de hoje veria algo que o pinado não vê.
63
+ *
64
+ * Os arquivos que decidem: `doctor/` inteiro e `commands/hook.ts`.
65
+ */
66
+ export const CHECKER_SINCE = "0.16.202";
package/dist/last-sync.js CHANGED
@@ -24,7 +24,14 @@ export const LAST_SYNC_FILE = ".last-sync.json";
24
24
  *
25
25
  * `name` sai do valor porque já É a chave - hasheá-lo junto só gastaria bytes.
26
26
  */
27
- export function fingerprintReadings(components) {
27
+ export function fingerprintReadings(
28
+ /**
29
+ * A LINHA INTEIRA, e o tipo tem que dizer isso: `{ name?: unknown }` prometia menos do que esta
30
+ * função aceita, e o próprio spec precisou de um `as never` para passar uma linha real. Um tipo
31
+ * que obriga a burlá-lo está errado - e o `as never` que ele forçava é exatamente o que faria a
32
+ * impressão parar de ver um campo novo sem ninguém notar.
33
+ */
34
+ components) {
28
35
  const out = {};
29
36
  for (const c of components ?? []) {
30
37
  const name = typeof c?.name === "string" ? c.name : null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.203",
3
+ "version": "0.16.205",
4
4
  "description": "Bring SynthesisUI design systems into any project - tokens, typed components, whole pages and an agent-ready CLAUDE.md manifest.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,7 +32,8 @@
32
32
  "build": "tsc -p tsconfig.json && chmod +x dist/index.js",
33
33
  "dev": "tsx src/index.ts",
34
34
  "prepublishOnly": "npm run build",
35
- "test": "vitest run"
35
+ "test": "vitest run",
36
+ "check": "tsc -p tsconfig.check.json"
36
37
  },
37
38
  "license": "MIT"
38
39
  }