synthesisui 0.16.155 → 0.16.157

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.
@@ -45,6 +45,34 @@ export async function hookCommand(root, version) {
45
45
  * the owner reading the output against the file, 27/07). Two wrong sentences
46
46
  * from one wrong variable, and both point somebody at the wrong thing to debug.
47
47
  */
48
+ /**
49
+ * A VERSÃO QUE O HOOK ESTÁ RODANDO, lida do arquivo dele - ou `null` quando não há hook pinado.
50
+ *
51
+ * O hook é PINADO de propósito (ver `hookCommand`): um verificador cujo comportamento muda sob você a
52
+ * cada edit é indebugável. O preço é que ele nunca fica mais novo sozinho, e em 06/08 o agente do dono
53
+ * montou essa comparação à mão - leu `.claude/settings.json`, leu `.mcp.json`, e reportou "0.16.153
54
+ * pinado contra 0.16.156 no MCP". Ele acertou, e nada nosso tinha dito isso a ele.
55
+ *
56
+ * Existe para o servidor MCP dizer a frase curta em vez de o agente ter que descobrir: a ferramenta sabe
57
+ * a própria versão e este leitor sabe a do hook, então a defasagem é aritmética.
58
+ *
59
+ * Instalação local devolve `null`: ali o hook segue o `node_modules` e nunca está atrás por si.
60
+ */
61
+ export async function pinnedHookVersion(root) {
62
+ const settings = await readJson(join(root, ".claude", "settings.json")).catch(() => ({}));
63
+ const hooks = (settings.hooks ?? {});
64
+ const entries = Array.isArray(hooks.PostToolUse) ? hooks.PostToolUse : [];
65
+ for (const entry of entries)
66
+ for (const h of entry.hooks ?? []) {
67
+ const command = h.command ?? "";
68
+ if (/--no-install synthesisui hook/.test(command))
69
+ return null;
70
+ const m = /synthesisui@(\d+\.\d+\.\d+)/.exec(command);
71
+ if (m)
72
+ return m[1];
73
+ }
74
+ return null;
75
+ }
48
76
  async function wireHook(root, command) {
49
77
  const dir = join(root, ".claude");
50
78
  const path = join(dir, "settings.json");
package/dist/claude-md.js CHANGED
@@ -180,24 +180,41 @@ it if it is not there.`;
180
180
  */
181
181
  const REFRESH = `
182
182
 
183
- **If the measurement is older than the reader, refresh it before you write UI.**
184
- Read \`_synthesisui/census.json\` → \`ledger.cli\` and compare it with the version
185
- of the \`synthesisui\` MCP server you are talking to. When they differ, call
186
- \`refresh_system\` once. It re-measures this repo with the current reader, reuses
187
- the reading that was already authored, and sends it - a newer reader sees styles
188
- the old one could not, and until it runs, this project's system is missing them.
183
+ **Call \`refresh_system\` once before you write UI here, or before you describe what
184
+ this system holds.** Not "if you think the measurement is stale" - always, once per
185
+ session. It costs nothing when nothing changed: the tool holds both versions and
186
+ refuses politely when there is nothing to refresh, so calling it is cheaper than
187
+ deciding whether to.
188
+
189
+ It re-measures this repo with the current reader, reuses the reading that was already
190
+ authored, and sends it - a newer reader sees styles the old one could not, and until
191
+ it runs, this project's system is missing them.
189
192
 
190
193
  It never asks anyone anything, and it never overwrites a recipe a person wrote on
191
194
  the screen: when a send would rewrite one, it refuses and names them. If it says
192
195
  nothing changed, nothing changed - carry on.
193
196
 
194
- **And if it reports that a newer CLI is published, say so to the person and stop
195
- there.** You cannot fix that one: the check that runs after your writes is pinned
196
- to the version installed at setup, and the tools you are holding were started by
197
- the editor. One command rewires both - \`npx synthesisui@latest connect\` - and it
198
- takes effect the next time the editor starts a session. Telling them is the whole
199
- job; doing it yourself would leave them with a file that says one version and a
200
- process running another.`;
197
+ **And when you describe this system, open with the age of the measurement:** the
198
+ \`ledger.cli\` and the date in \`_synthesisui/census.json\`. A long, correct report
199
+ about a census taken by an older reader is the worst way to be right - every absence
200
+ in it may have been filled since, and the reader who trusts it has no way to know.
201
+
202
+ **And if it says the design system needs updating, do these three things in order:**
203
+ say the one line, ask, and run it.
204
+
205
+ \`\`\`
206
+ Update the design system before continuing.
207
+ npx synthesisui@latest connect
208
+ \`\`\`
209
+
210
+ Then tell them to close and reopen the editor. Not as a footnote - it is the step
211
+ that makes the other two count: the check that runs after your writes is pinned to
212
+ the version installed at setup, and the tools you are holding were started by the
213
+ editor. Both rewire on a new session and not before, so anything you write in this
214
+ one is still checked by the old reader.
215
+
216
+ Do not explain the pinning to them and stop there. A paragraph is what somebody
217
+ reads; a command they approved and you ran is what changes the repo.`;
201
218
  const VERIFY = `
202
219
 
203
220
  **Verify with a build, not a running server.** If you do start a dev server, stop
@@ -1,5 +1,6 @@
1
1
  import { readdir, readFile } from "node:fs/promises";
2
2
  import { join, relative, resolve } from "node:path";
3
+ import { pinnedHookVersion } from "../agent-wiring.js";
3
4
  import { readToken, resolveRegistry } from "../config.js";
4
5
  import { fileRequest } from "../doctor/requests.js";
5
6
  import { diagnose, scanSource } from "../doctor/scan.js";
@@ -898,8 +899,24 @@ cli) {
898
899
  slug,
899
900
  cli: VERSION,
900
901
  }));
901
- return text(out.trim() ||
902
- "Nothing was reported by the refresh - which means it found nothing to measure.");
902
+ /**
903
+ * E A DEFASAGEM DO HOOK, EM TRÊS LINHAS - não num parágrafo.
904
+ *
905
+ * O hook é pinado (ver `hookCommand`) e o servidor MCP flutua, então eles divergem no dia em que
906
+ * uma versão nova é publicada. Em 06/08 o agente do dono montou essa comparação sozinho, leu os
907
+ * dois arquivos e acertou - e nada nosso tinha dito a ele. Antes disso, a regra do bloco pedia um
908
+ * parágrafo de explicação; um parágrafo é o que se lê e não é o que se faz.
909
+ *
910
+ * Vai aqui e não em toda ferramenta porque a regra manda chamar `refresh_system` uma vez por
911
+ * sessão: um lugar que sempre roda vale mais que sete que podem rodar.
912
+ */
913
+ const pinned = await pinnedHookVersion(root);
914
+ const behind = pinned && pinned !== VERSION ? pinned : null;
915
+ const said = out.trim() ||
916
+ "Nothing was reported by the refresh - which means it found nothing to measure.";
917
+ return text(behind
918
+ ? `${said}\n\nUPDATE THE DESIGN SYSTEM BEFORE CONTINUING.\nThe check that runs after your writes is pinned to ${behind} and these tools are ${VERSION}.\n\n npx synthesisui@latest connect\n\nAsk the person, run it for them, and then say this: close and reopen the editor. The hook and the tools only rewire on a new session, so nothing you write before that is checked by the reader you are holding.`
919
+ : said);
903
920
  }
904
921
  case "request_token": {
905
922
  const name = String(args.name ?? "");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.155",
3
+ "version": "0.16.157",
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": {