synthesisui 0.16.180 → 0.16.183

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.
@@ -1,6 +1,7 @@
1
1
  import { readdir, readFile } from "node:fs/promises";
2
2
  import { homedir } from "node:os";
3
3
  import { join, resolve } from "node:path";
4
+ import { pinnedHookVersion } from "../agent-wiring.js";
4
5
  import { readToken, resolveRegistry } from "../config.js";
5
6
  import { unsentEvents } from "../doctor/ledger.js";
6
7
  import { measuredScope } from "../measured-scope.js";
@@ -152,6 +153,23 @@ opts = {}) {
152
153
  says: `the files under _synthesisui/ds/${lock.slug} were written by CLI ${lock.cli} and you are running ${cli} - the design system's version has not changed, but what this CLI writes into that folder has.`,
153
154
  run: "npx synthesisui upgrade",
154
155
  });
156
+ /**
157
+ * O HOOK, MEDIDO NELE MESMO - e não pelo `.lock`, que é um proxy que se move sozinho.
158
+ *
159
+ * A linha acima compara o CLI que escreveu a PASTA. Desde que o `upgrade` passou a rematerializá-la
160
+ * (07/08), ela volta a bater sem que a fiação tenha sido refeita: o `.lock` dizia 0.16.180 e o
161
+ * `PostToolUse` continuava pinado em 0.16.178, com o `status` anunciando "In step". Um alarme
162
+ * desligado por um conserto parcial é pior que alarme nenhum.
163
+ *
164
+ * `pinnedHookVersion` devolve `null` numa instalação local, onde o hook segue o `node_modules` e
165
+ * nunca está atrás por si.
166
+ */
167
+ const pinned = await pinnedHookVersion(root).catch(() => null);
168
+ if (cli && pinned && pinned !== cli)
169
+ out.push({
170
+ says: `the check that runs after every write is pinned to CLI ${pinned} and you are running ${cli} - your agent's edits are being checked by an older reader than the one measuring this repo.`,
171
+ run: "npx synthesisui upgrade",
172
+ });
155
173
  if (cli && lock.version == null)
156
174
  out.push({
157
175
  says: `"${lock.slug}" has no version recorded, so nothing can tell whether the CSS in this repo is the one the platform publishes.`,
@@ -140,12 +140,22 @@ export async function status(opts) {
140
140
  : `${owned.slug} on the platform did not come from an import, so there is no measurement to compare.`));
141
141
  if (remote.hasCensus)
142
142
  console.log(body(paint.dim("`synthesisui sync` measures this repo again with today's reader and sends it.")));
143
- /** E a distância até o leitor publicado, com o comando que a fecha - ver `sync`. */
144
- if (remote.publishedCli && opts.cli && remote.publishedCli !== opts.cli) {
145
- console.log("");
146
- console.log(body(`Your CLI is ${opts.cli} and ${remote.publishedCli} is published - a newer reader sees styles this one cannot.`));
147
- console.log(paint.blue(snippet(["npx synthesisui@latest upgrade"])));
148
- }
143
+ /**
144
+ * A DISTÂNCIA ATÉ O LEITOR PUBLICADO - e ela desce para o veredito, em vez de ser um parágrafo solto.
145
+ *
146
+ * Isto imprimia acima e o veredito abaixo dizia "In step", no MESMO comando: duas seções
147
+ * discordando com três linhas de distância (dono, 07/08). Um comando que se contradiz não é meio
148
+ * certo, é inutilizável - quem lê passa a não acreditar em nenhuma das duas.
149
+ *
150
+ * Não vira um item do `align`: o CLI subiu seis vezes num dia e nenhuma delas mudou um leitor, e a
151
+ * verificação de abertura tem que ficar muda nesses casos. Aqui é diferente - a pessoa PERGUNTOU.
152
+ */
153
+ const behindCli = remote.publishedCli && opts.cli && remote.publishedCli !== opts.cli
154
+ ? {
155
+ says: `your CLI is ${opts.cli} and ${remote.publishedCli} is published - a newer reader sees styles this one cannot.`,
156
+ run: "npx synthesisui@latest upgrade",
157
+ }
158
+ : null;
149
159
  /**
150
160
  * O QUE ESTÁ FORA DE ALINHO - e este comando era CEGO para isso.
151
161
  *
@@ -154,11 +164,14 @@ export async function status(opts) {
154
164
  * usar a mesma medição do gancho, então `align` deixa de ser algo que alguém precisa conhecer -
155
165
  * ele continua existindo, chamado pelo `SessionStart` e pelo terminal (dono, 07/08).
156
166
  */
157
- const off = await misalignments(root, opts.cli ? { cli: opts.cli } : {});
167
+ const off = [
168
+ ...(await misalignments(root, opts.cli ? { cli: opts.cli } : {})),
169
+ ...(behindCli ? [behindCli] : []),
170
+ ];
158
171
  console.log("");
159
172
  if (off.length === 0) {
160
173
  console.log(section("In step"));
161
- console.log(body(paint.faint("Nothing here is behind the system that governs it - version, css, rules and the measurement all line up.")));
174
+ console.log(body(paint.faint("Nothing here is behind the system that governs it - version, css, rules, the measurement and this CLI all line up.")));
162
175
  return;
163
176
  }
164
177
  console.log(section("Out of step"));
@@ -1,5 +1,6 @@
1
1
  import { readdir, readFile, writeFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
+ import { pinnedHookVersion, wireAgent } from "../agent-wiring.js";
3
4
  import { generateComponentFiles } from "../component-codegen.js";
4
5
  import { readProjectConfig, resolveRegistry } from "../config.js";
5
6
  import { diffLocalDocuments, localChangelogMarkdown, } from "../document-diff.js";
@@ -115,6 +116,27 @@ async function staleInstall(root, slug, version, base, cli) {
115
116
  why.push(`these files were written by CLI ${lock.cli}`);
116
117
  return why.length > 0 ? `${why.join(", ")} - re-materializing` : null;
117
118
  }
119
+ /**
120
+ * A FIAÇÃO DO AGENTE, refeita quando ela ficou para trás.
121
+ *
122
+ * `upgrade` diz que traz para o dia tudo que está instalado aqui, e a pasta do DS é só metade: o hook
123
+ * `PostToolUse` é PINADO numa versão, então ele não anda sozinho. Em 07/08 o primeiro `upgrade` com o
124
+ * papel novo gravou `cli: 0.16.180` no `.lock` e deixou o hook em 0.16.178 - e como a verificação
125
+ * comparava o `.lock`, o `status` passou a dizer "In step" com a fiação duas versões atrás. Uma
126
+ * promessa pela metade que ainda por cima desliga o alarme.
127
+ *
128
+ * `wireAgent` é um merge idempotente: quando já está na versão certa, não escreve nada.
129
+ */
130
+ async function rewireIfBehind(root, cli) {
131
+ if (!cli)
132
+ return;
133
+ const pinned = await pinnedHookVersion(root).catch(() => null);
134
+ if (!pinned || pinned === cli)
135
+ return;
136
+ await wireAgent(root, cli, { hook: true, mcp: true }).catch(() => null);
137
+ console.log(`↻ the check after every write moved from ${pinned} to ${cli}`);
138
+ console.log(" Reopen your editor session - hooks are read at startup.");
139
+ }
118
140
  async function theOnlyInstalled(root) {
119
141
  const dsDir = join(root, "_synthesisui", "ds");
120
142
  const entries = await readdir(dsDir, { withFileTypes: true }).catch(() => []);
@@ -165,6 +187,7 @@ export async function upgrade(asked, opts) {
165
187
  setupHints: false,
166
188
  ...(opts.cli ? { cli: opts.cli } : {}),
167
189
  });
190
+ await rewireIfBehind(root, opts.cli);
168
191
  await reportWhatIsLeft(root, opts.cli ? { cli: opts.cli } : {});
169
192
  return;
170
193
  }
@@ -83,6 +83,7 @@ export function buildLedger(cli, seen) {
83
83
  files: 0,
84
84
  because: BECAUSE[reason],
85
85
  examples: [],
86
+ unreadable: [],
86
87
  seenFiles: new Set(),
87
88
  };
88
89
  group.uses += 1;
@@ -94,6 +95,30 @@ export function buildLedger(cli, seen) {
94
95
  line: f.line,
95
96
  text: f.text.replace(/\s+/g, " ").trim().slice(0, 160),
96
97
  });
98
+ /**
99
+ * SÓ `shape-not-read`, E SÓ TEXTO DISTINTO - as duas restrições vieram de medir, não de supor.
100
+ *
101
+ * DAS QUATRO RAZÕES, uma só é alcançável por um leitor novo. `value-not-read` diz que a forma FOI
102
+ * lida e o valor está fora das escalas deles - texto não ensina nada a leitor nenhum. `computed`
103
+ * é montado em runtime e não existe na fonte. `component-not-admitted` é o portão, não a leitura.
104
+ * Sobra `shape-not-read`: "nenhum leitor desta versão entende esta forma", que é exatamente a
105
+ * frase que um leitor novo responde.
106
+ *
107
+ * E TEXTO DISTINTO, porque a primeira versão disto reprovou no spec do repo vivo: guardar todo
108
+ * fragmento deu 723 215 bytes no dashboard dele, contra um teto de 65 536. Oito mil cópias da
109
+ * mesma string não ensinam mais que uma - o que um leitor precisa é da variedade de FORMAS.
110
+ *
111
+ * O teto de 512 é declarado e não mudo: `uses` continua contando tudo, então a diferença entre o
112
+ * contado e o que viajou é visível em vez de silenciosa.
113
+ */
114
+ if (reason === "shape-not-read" &&
115
+ group.unreadable.length < 512 &&
116
+ !group.unreadable.some((u) => u.text === f.text))
117
+ group.unreadable.push({
118
+ file: f.file,
119
+ line: f.line,
120
+ text: f.text.replace(/\s+/g, " ").trim().slice(0, 400),
121
+ });
97
122
  groups.set(key, group);
98
123
  }
99
124
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.180",
3
+ "version": "0.16.183",
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": {