synthesisui 0.16.460 → 0.16.462

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.
@@ -199,7 +199,9 @@ export async function add(slug, opts) {
199
199
  * Falha calada de propósito: um repositório sem folha de estilo, ou sem build, devolve o que veio
200
200
  * do servidor. A folha nunca fica pior do que estava.
201
201
  */
202
- const theirVars = await pointTokensAtTheirNames(projectRoot, payload);
202
+ const theirVars = await pointTokensAtTheirNames(projectRoot, payload,
203
+ /** O que um build anterior provou - ver `provenBefore`. Sem build aqui, é a melhor prova que há. */
204
+ (prev?.tokenMap ?? []).map((p) => p.theirs));
203
205
  /**
204
206
  * O `theme.css` ALINHA ONDE HÁ O QUE ALINHAR - ver `onlyWhatMatched`.
205
207
  *
@@ -619,6 +621,12 @@ export async function add(slug, opts) {
619
621
  */
620
622
  if (theirVars.cycles > 0)
621
623
  console.log(` ${theirVars.cycles} ${theirVars.cycles === 1 ? "value" : "values"} already had the bridge pointing the other way, so ${theirVars.cycles === 1 ? "it was" : "they were"} left alone - your own utility still resolves through this system, and pointing back would have cancelled both.`);
624
+ /**
625
+ * SEM BUILD, A TELA DIZ DE ONDE VEIO A PROVA - 27/09. Antes, o mapa sumia e a única pista era "0
626
+ * Tailwind utilities now point at your own decisions"; o dono passou uma tarde sem saber por quê.
627
+ */
628
+ if (theirVars.provedBy === "before")
629
+ console.log(` No build found here (no CSS in .next, dist, build or out), so the ${theirVars.pairs.length} name${theirVars.pairs.length === 1 ? "" : "s"} an earlier build proved ${theirVars.pairs.length === 1 ? "was" : "were"} kept. Run your build and \`connect\` again to prove them on this machine.`);
622
630
  if (theirVars.pointed > 0)
623
631
  console.log(` ${theirVars.pointed} value${theirVars.pointed === 1 ? "" : "s"} in tokens.css now point at the name YOUR code already gives ${theirVars.pointed === 1 ? "it" : "them"} - change yours and the system follows${theirVars.pruned > 0 ? `; ${theirVars.pruned} matched but your build does not emit ${theirVars.pruned === 1 ? "that name" : "those names"}, so ${theirVars.pruned === 1 ? "it keeps" : "they keep"} the value` : ""}`);
624
632
  /**
@@ -262,7 +262,7 @@ async function askWhichAgents(pre) {
262
262
  ? fmt(say("{dir} is here"), { dir: agent.evidence })
263
263
  : fmt(say("no {dir} in this repo"), { dir: agent.evidence }),
264
264
  })),
265
- picked: pre,
265
+ picked: preselectedAgents(pre),
266
266
  });
267
267
  return picked;
268
268
  }
@@ -863,11 +863,36 @@ export async function connect(opts) {
863
863
  .join("\n"));
864
864
  }
865
865
  }
866
+ /**
867
+ * A RESPOSTA DA PERGUNTA DO ENVIO - Enter é SIM desde 27/09.
868
+ *
869
+ * O padrão era NÃO (`[y/N]`), com o motivo "enviar é a mudança, e uma mudança de promessa pede um sim
870
+ * dito". O dono, na rodada 1 do refinamento, olhando a tela: *"a parte do sync estava como default N, acho
871
+ * que o correto aqui seria default Y"*. Desde a jornada "o sistema só muda com commit" o envio do fim do
872
+ * turno manda só as checagens - o sistema não muda por ele -, e é isso que a própria pergunta diz. Um não
873
+ * dito continua sendo não, nas duas línguas.
874
+ */
875
+ export function sendsAtTurnEnd(answer) {
876
+ const said = answer.trim();
877
+ if (said === "")
878
+ return true;
879
+ return !/^(n(o)?|n[aã]o)$/i.test(said);
880
+ }
881
+ /**
882
+ * OS AGENTES QUE COMEÇAM MARCADOS - a evidência do repositório, ou todos quando ele não prova nenhum.
883
+ *
884
+ * Num projeto novo, sem `.claude` nem `.codex`, a lista abria sem nada marcado e o Enter confirmava
885
+ * nenhum. O dono, na rodada 1 do refinamento (27/09): *"por padrão dá para deixar os 2 selecionados"*.
886
+ * Onde o repositório prova um agente, continua marcado só o que ele prova - ali a evidência é melhor que
887
+ * um padrão.
888
+ */
889
+ export function preselectedAgents(proven) {
890
+ return proven.length > 0 ? [...proven] : AGENTS.map((agent) => agent.id);
891
+ }
866
892
  /**
867
893
  * Pergunta uma vez, e só num terminal de verdade - o mesmo molde do `askToOverwrite` do `sync`.
868
894
  *
869
- * Sem TTY devolve `null`: não há quem responder, e nada é gravado. O padrão do terminal é NÃO
870
- * (`[y/N]`), porque enviar é a mudança, e uma mudança de promessa pede um sim dito.
895
+ * Sem TTY devolve `null`: não há quem responder, e nada é gravado. Ver `sendsAtTurnEnd` para o padrão.
871
896
  */
872
897
  async function askToSendAtTurnEnd() {
873
898
  if (!process.stdin.isTTY || !process.stdout.isTTY)
@@ -875,8 +900,8 @@ async function askToSendAtTurnEnd() {
875
900
  const { createInterface } = await import("node:readline/promises");
876
901
  const rl = createInterface({ input: process.stdin, output: process.stdout });
877
902
  try {
878
- const answer = await rl.question(` ${say("send what the check records to your dashboard at the end of each turn? Your system itself changes only from a commit on a clean main.")} [y/N]: `);
879
- return /^(y(es)?|s(im)?)$/i.test(answer.trim());
903
+ const answer = await rl.question(` ${say("send what the check records to your dashboard at the end of each turn? Your system itself changes only from a commit on a clean main.")} [Y/n]: `);
904
+ return sendsAtTurnEnd(answer);
880
905
  }
881
906
  catch {
882
907
  return null;
@@ -367,12 +367,30 @@ function propsType(axes, tag, base, withAs = false) {
367
367
  const extras = axes.map((a) => a.boolean
368
368
  ? ` ${a.prop}?: boolean;`
369
369
  : ` ${a.prop}?: ${a.options.map((o) => `"${o}"`).join(" | ")};`);
370
- if (withAs)
371
- extras.push(" /** Render as a different element (th, dt, h2, li…) - the recipe is", " * styling only, so the document's semantics stay yours. */", " as?: ElementType;");
370
+ /**
371
+ * COM `as`, AS PROPS SEGUEM O ELEMENTO ESCOLHIDO - rodada 1 do refinamento, 27/09.
372
+ *
373
+ * O tipo era `ComponentProps<"button"> & { as?: ElementType }`: aceitava `as={Link}` e recusava o
374
+ * `href` que o `Link` exige - o `npm run build` do leigo quebrou em "Property 'href' does not exist",
375
+ * e ele contornou com `{...{ href }}`. Genérico no elemento, com o padrão sendo a tag da receita: sem
376
+ * `as`, nada muda para quem chama.
377
+ */
378
+ if (withAs) {
379
+ extras.push(" /** Render as a different element (th, dt, h2, li, a Link…) - the recipe is", " * styling only, so the document's semantics stay yours, and the props follow it. */", " as?: T;");
380
+ /**
381
+ * SOBREPOSIÇÃO, e não troca: o tipo da tag da receita continua escrito por inteiro, e o elemento
382
+ * escolhido só ACRESCENTA o que ele tem a mais (o `href` do `Link`). Sem `as`, o `Omit` é vazio e o
383
+ * tipo é o de antes - e quem lê a raiz no texto (`ComponentProps<"button">`) continua lendo.
384
+ */
385
+ const own = ["as", ...axes.map((a) => a.prop)].map((k) => `"${k}"`).join(" | ");
386
+ return `${base}<"${tag}"> & Omit<${base}<T>, keyof ${base}<"${tag}"> | ${own}> & {\n${extras.join("\n")}\n}`;
387
+ }
372
388
  if (extras.length === 0)
373
389
  return `${base}<"${tag}">`;
374
390
  return `${base}<"${tag}"> & {\n${extras.join("\n")}\n}`;
375
391
  }
392
+ /** O parâmetro de tipo que acompanha `propsType(..., withAs)` - vazio quando não há `as`. */
393
+ const asGeneric = (tag, withAs) => withAs ? `<T extends ElementType = "${tag}">` : "";
376
394
  /**
377
395
  * THE ELEMENT IS THE CALLER'S DECISION (1kro2o, 29/07).
378
396
  *
@@ -385,7 +403,7 @@ function propsType(axes, tag, base, withAs = false) {
385
403
  * offered takes the same attributes in practice - the pattern is the exact
386
404
  * one the field agent wrote by hand.
387
405
  */
388
- const asTagLine = (tag) => ` const Tag = (as ?? "${tag}") as "${tag}";`;
406
+ const asTagLine = (tag) => ` const Tag = (as ?? "${tag}") as ElementType;`;
389
407
  /** The render pieces for an element that offers `as`. `type="button"` must
390
408
  * follow the RENDERED tag - a Button rendered as an <a> with type="button"
391
409
  * is invalid HTML wearing a straight face. Void elements never offer `as`:
@@ -1324,7 +1342,7 @@ localName = name) {
1324
1342
  ].join(", ");
1325
1343
  return `
1326
1344
  /** Part "${partName}" of ${comp}${formOf.get(partName) ? ` (${formOf.get(partName)})` : ""} - compose it inside <${comp}>. */
1327
- export function ${partComp}({ ${partDestructure} }: ${propsType(partAxes, partTag, props, partEl.offersAs)}) {
1345
+ export function ${partComp}${asGeneric(partTag, partEl.offersAs)}({ ${partDestructure} }: ${propsType(partAxes, partTag, props, partEl.offersAs)}) {
1328
1346
  ${partEl.setup} return (
1329
1347
  <${partEl.jsxTag}${partEl.jsxAttrs}
1330
1348
  className={${joinCls([`"${partClassName(name, partName, convention)}"`, "className"])}}
@@ -1339,10 +1357,10 @@ import "./${localName}.css";
1339
1357
 
1340
1358
  import type { ${needsElementType ? `ElementType, ${props}` : props} } from "react";
1341
1359
 
1342
- type ${comp}Props = ${propsType(axes, tag, props, el.offersAs)};
1360
+ type ${comp}Props${asGeneric(tag, el.offersAs)} = ${propsType(axes, tag, props, el.offersAs)};
1343
1361
 
1344
1362
  ${compositionHint(comp, name, recipe, voidEl)}
1345
- export function ${comp}({ ${destructure} }: ${comp}Props) {
1363
+ export function ${comp}${asGeneric(tag, el.offersAs)}({ ${destructure} }: ${comp}Props${el.offersAs ? "<T>" : ""}) {
1346
1364
  ${el.setup} return (
1347
1365
  ${rootJsx}
1348
1366
  );
@@ -1454,10 +1472,10 @@ import { cn } from "../cn";
1454
1472
  const BASE = ${JSON.stringify([needsGroup ? "group" : "", tailwindClassList(recipe, resolved, themeVars, excluded)].filter(Boolean).join(" "))};
1455
1473
  ${[...variantConsts, ...booleanConsts].join("\n")}
1456
1474
 
1457
- type ${comp}Props = ${propsType(axes, tag, props, el.offersAs)};
1475
+ type ${comp}Props${asGeneric(tag, el.offersAs)} = ${propsType(axes, tag, props, el.offersAs)};
1458
1476
 
1459
1477
  ${compositionHint(comp, name, recipe, voidEl)}
1460
- export function ${comp}({ ${destructure} }: ${comp}Props) {
1478
+ export function ${comp}${asGeneric(tag, el.offersAs)}({ ${destructure} }: ${comp}Props${el.offersAs ? "<T>" : ""}) {
1461
1479
  ${el.setup} return (
1462
1480
  ${hasShape
1463
1481
  ? `${rootOpen} {...props}
@@ -1525,7 +1543,7 @@ ${orderedParts
1525
1543
  ].join(", ");
1526
1544
  return `
1527
1545
  /** Part "${partName}" of ${comp}${formOf.get(partName) ? ` (${formOf.get(partName)})` : ""} - compose it inside <${comp}>. */
1528
- export function ${partComp}({ ${partDestructure} }: ${propsType(partAxes, partTag, props, partEl.offersAs)}) {
1546
+ export function ${partComp}${asGeneric(partTag, partEl.offersAs)}({ ${partDestructure} }: ${propsType(partAxes, partTag, props, partEl.offersAs)}) {
1529
1547
  ${partEl.setup} return (
1530
1548
  <${partEl.jsxTag}${partEl.jsxAttrs}
1531
1549
  className={${resolveCls([JSON.stringify(partCls), "className"])}}
package/dist/fonts.js CHANGED
@@ -248,9 +248,15 @@ export function nextFontSnippet(input) {
248
248
  * Nenhuma linha aqui menciona o sistema, o slug ou uma variável nossa: é a fonte dele, ligada ao
249
249
  * Tailwind dele.
250
250
  */
251
+ /**
252
+ * `@theme inline`, e não `@theme` - rodada 1 do refinamento, 27/09. O Tailwind escreve um `@theme`
253
+ * comum no `:root`, e a variável do `next/font` mora na classe do `<body>`: no `:root` ela não existe,
254
+ * e `font-display` caía na fonte genérica. `inline` faz a utility ler a variável no próprio elemento,
255
+ * que é o padrão do `create-next-app`.
256
+ */
251
257
  const css = [
252
258
  `/* ${appDir}/globals.css - in your own @theme */`,
253
- `@theme {`,
259
+ `@theme inline {`,
254
260
  ...emitted.map((role) => ` --font-${role}: var(${roleVar(role)});`),
255
261
  `}`,
256
262
  ];
package/dist/guide.js CHANGED
@@ -841,8 +841,9 @@ ${pageBaseSection}${pendingSection}${keyframeLines.length > 0
841
841
  ## Motion vocabulary
842
842
 
843
843
  The base is QUIET: nothing moves until someone asks. When they do, animation is **selection
844
- from this list**, not improvisation - these are the system's own animations, already compiled
845
- into ${hasTailwind && hasAnimateKeys ? "`theme.css` as ready utilities" : `\`tokens.css\` as \`@keyframes ds-${slug}-<name>\``}, each on the clock its intent calls for:
844
+ from this list**, not improvisation - these are the system's own animations, each on the clock its
845
+ intent calls for. They are written in ${hasTailwind && hasAnimateKeys ? "`theme.css`" : "`tokens.css`"} next to this guide, which your app does not load -
846
+ nothing of ours is imported. To use one, copy its \`@keyframes\` block${hasTailwind && hasAnimateKeys ? " and its `--animate-<name>` line into your own `@theme`, and the utility below starts to exist" : " into your own stylesheet, and write the `animation` below"}:
846
847
 
847
848
  ${keyframeLines.join("\n")}
848
849
  ${patternLines.length > 0
@@ -258,7 +258,13 @@
258
258
  * o nome dele pelo valor quando a receita pede um degrau - rodada 1 do refinamento. Um componente escrito
259
259
  * antes carrega o valor cru onde o projeto tem nome.
260
260
  */
261
- export const MATERIALISER_SINCE = "0.16.459";
261
+ /**
262
+ * 0.16.459 -> 0.16.462 em 27/09, e o passo 1 dá **SIM**: o `GUIDE.md` que cai na pasta passa a entregar
263
+ * as fontes num `@theme inline` (no `@theme` comum a fonte não carregava) e a dizer de onde vem cada
264
+ * animação, e os componentes com `as` passam a ter o tipo genérico - rodada 1 do refinamento. Uma pasta
265
+ * escrita antes ensina o agente a colar uma fonte que não carrega.
266
+ */
267
+ export const MATERIALISER_SINCE = "0.16.462";
262
268
  /**
263
269
  * A ÚLTIMA VERSÃO EM QUE O QUE O HOOK RODA MUDOU.
264
270
  *
@@ -180,13 +180,14 @@ const FAMILY_KIND = {
180
180
  "--ds-motion-durations-": "motion",
181
181
  "--ds-motion-easings-": "motion",
182
182
  };
183
+ export async function pointTokensAtTheirNames(root, payload,
183
184
  /**
184
- * A JORNADA INTEIRA, num chamador só - varrer, medir o build, reescrever.
185
- *
186
- * Recebe o payload em vez do CSS solto porque um argumento opcional a menos é uma chamada pela
187
- * metade a menos: quem chama não tem como esquecer de passar a folha certa.
185
+ * Os nomes DELE que um build anterior provou - `theirs` do `tokenMap` do `.lock`. Usados só quando
186
+ * esta máquina não tem build: antes de 27/09, sem build o mapa saía vazio e o `connect` apagava 36
187
+ * pares provados no CodeLevel, sem dizer por quê. O cruzamento é refeito contra o CSS dele de hoje,
188
+ * então um nome que sumiu do código continua não casando.
188
189
  */
189
- export async function pointTokensAtTheirNames(root, payload) {
190
+ provenBefore = []) {
190
191
  const css = payload.artifacts["tokens.css"] ?? "";
191
192
  if (!css)
192
193
  return {
@@ -196,12 +197,20 @@ export async function pointTokensAtTheirNames(root, payload) {
196
197
  compiledAway: 0,
197
198
  cycles: 0,
198
199
  pairs: [],
200
+ provedBy: "nothing",
199
201
  };
200
- const [theirs, resolvable] = await Promise.all([
202
+ const [theirs, built] = await Promise.all([
201
203
  harvestTheirCss(root),
202
204
  resolvableVars(root),
203
205
  ]);
204
- return pointAtTheirNames(css, theirs, resolvable);
206
+ if (built)
207
+ return { ...pointAtTheirNames(css, theirs, built), provedBy: "build" };
208
+ if (provenBefore.length > 0)
209
+ return {
210
+ ...pointAtTheirNames(css, theirs, new Set(provenBefore)),
211
+ provedBy: "before",
212
+ };
213
+ return { ...pointAtTheirNames(css, theirs, null), provedBy: "nothing" };
205
214
  }
206
215
  /** As folhas de estilo DELE, e nenhuma da nossa pasta. Gêmeo de `harvestOwnTokens` no doctor. */
207
216
  async function harvestTheirCss(root) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.460",
3
+ "version": "0.16.462",
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": {