synthesisui 0.16.489 → 0.16.491

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.
@@ -1947,7 +1947,7 @@ cli) {
1947
1947
  const section = args.section;
1948
1948
  if (section !== undefined && (kind !== "landing" || !isSection(section)))
1949
1949
  return fromContract(`section goes with kind landing and is one of ${SECTIONS.join(", ")} - for any other part, call with the kind alone.`);
1950
- const prefs = await fetchPreferences({ base: resolveRegistry(), token }, kind, section);
1950
+ const prefs = await fetchPreferences({ base: resolveRegistry(), token }, kind, section, await installedSlug(root));
1951
1951
  if ("failed" in prefs)
1952
1952
  return fromContract(`Their preferences could not be read: ${prefs.failed}. Build with the system as usual and say so in one line.`);
1953
1953
  return preferencesAnswer(kind, prefs, await readSelection(root), await readOff(root));
@@ -48,6 +48,32 @@ import { upgrade } from "./upgrade.js";
48
48
  export function draftLine(slug, base) {
49
49
  return `this went into your DRAFT - your repository still has what you installed. It reaches the disk once you publish${base ? `: ${base}/dashboard/mine/${slug}/publish` : ""}\n then: npx synthesisui@latest upgrade ${slug}`;
50
50
  }
51
+ /**
52
+ * O QUE O AUTOPILOT FEZ COM ESTE ENVIO - jornada "o Autopilot que age", E05 (05/10).
53
+ *
54
+ * A rota do censo manda `autopilot` desde que ele existe, com o comentário "o CLI imprime isto" - e este comando nunca o
55
+ * leu. Medido no localhost em 05/10: o Autopilot publicou a v2 e a v3 sozinho, e o terminal continuou dizendo "this went
56
+ * into your DRAFT (...) It reaches the disk once you publish", mandando publicar o que já estava publicado. A regra do
57
+ * dono: sempre dizer o que publicou, ou o que segurou e por quê.
58
+ *
59
+ * Um servidor que não manda o campo (anterior a 05/10) cai na frase de sempre - o que ele não disse, a gente não inventa.
60
+ */
61
+ export function afterSendLines(input) {
62
+ const ap = input.autopilot;
63
+ const why = (ap?.why ?? "").replace(/^Autopilot:\s*/, "").trim();
64
+ if (ap?.published) {
65
+ return [
66
+ `✓ Autopilot published v${ap.published}${why ? ` - ${why}` : ""}`,
67
+ ` your repository gets it with: npx synthesisui@latest upgrade ${input.slug}`,
68
+ ];
69
+ }
70
+ if (input.written <= 0)
71
+ return [];
72
+ const draft = draftLine(input.slug, input.base);
73
+ return ap && why
74
+ ? [`· Autopilot held this version for you: ${why}`, draft]
75
+ : [draft];
76
+ }
51
77
  /**
52
78
  * O TRABALHO DELA FOI PARA A RAMIFICAÇÃO DELA, E ISSO SE DIZ - `INV-BRANCH-02`.
53
79
  *
@@ -864,8 +890,13 @@ export async function remeasure(args) {
864
890
  * Só aparece quando algo FOI escrito: um `sync` que não mudou nada não tem o que publicar, e
865
891
  * cobrar um publish vazio é o aviso que ensina a ignorar o próximo.
866
892
  */
867
- if ((out.written ?? 0) > 0)
868
- console.log(body(paint.faint(draftLine(slug, base))));
893
+ for (const line of afterSendLines({
894
+ slug,
895
+ base,
896
+ written: out.written ?? 0,
897
+ autopilot: out.autopilot,
898
+ }))
899
+ console.log(body(line.startsWith("✓") ? paint.strong(line) : paint.faint(line)));
869
900
  /**
870
901
  * O QUE MUDOU DESDE A ÚLTIMA VEZ - a linha que só uma RE-medição pode dar.
871
902
  *
@@ -2719,12 +2719,59 @@ export function rootClasses(source, name) {
2719
2719
  const own = ownClassNameExpr(tag);
2720
2720
  if (own == null)
2721
2721
  return [];
2722
- // Every string literal inside the className expression. Template literals and
2723
- // computed values are skipped on purpose: a class we cannot see in full is a
2724
- // class we would be guessing at.
2725
- return [...own.matchAll(/["']([^"']+)["']/g)]
2726
- .flatMap((m) => m[1].split(/\s+/))
2727
- .filter((c) => c.length > 0 && !c.includes("${"));
2722
+ /**
2723
+ * O TEXTO FIXO DE UM TEMPLATE TAMBÉM É CLASSE ESCRITA - dono, 04/10 18:28Z, no PASS com a conta zerada: o botão do
2724
+ * projeto importado chegou sem centralizar e de canto reto. O `Button.tsx` dele escreve
2725
+ *
2726
+ * className={`inline-flex items-center justify-center gap-2 rounded-pill font-medium ${variants[variant]} ${sizes[size]} ${className}`}
2727
+ *
2728
+ * e esta função pulava template inteiro ("a class we cannot see in full"). Só que o texto FORA do `${}` se vê
2729
+ * inteiro: o que não se vê é a classe COLADA numa interpolação (`p-${n}`, `${tone}-500`). Então entram as classes
2730
+ * inteiras do texto fixo, e a colada continua de fora. O que vem DENTRO de `${}` é cálculo (o mapa da variante, uma
2731
+ * condição) e não é lido daqui - as variantes têm o leitor delas.
2732
+ */
2733
+ const fromTemplates = [];
2734
+ const outside = own.replace(/`(?:\\[\s\S]|\$\{(?:[^{}]|\{[^{}]*\})*\}|[^`\\])*`/g, (lit) => {
2735
+ fromTemplates.push(...templateStatics(lit.slice(1, -1)));
2736
+ return " ";
2737
+ });
2738
+ // Every string literal inside the className expression - outside a template.
2739
+ return [
2740
+ ...[...outside.matchAll(/["']([^"']+)["']/g)].flatMap((m) => m[1].split(/\s+/)),
2741
+ ...fromTemplates,
2742
+ ].filter((c) => c.length > 0 && !c.includes("${"));
2743
+ }
2744
+ /**
2745
+ * As classes INTEIRAS do texto fixo de um template: cada `${...}` vira uma marca, e a classe que encosta nela (sem
2746
+ * espaço no meio) sai - ela só existe completa depois do cálculo.
2747
+ */
2748
+ export function templateStatics(body) {
2749
+ let out = "";
2750
+ for (let i = 0; i < body.length; i++) {
2751
+ if (body[i] === "\\") {
2752
+ out += body[i + 1] ?? "";
2753
+ i++;
2754
+ continue;
2755
+ }
2756
+ if (body[i] === "$" && body[i + 1] === "{") {
2757
+ let depth = 0;
2758
+ let j = i + 1;
2759
+ for (; j < body.length; j++) {
2760
+ if (body[j] === "{")
2761
+ depth++;
2762
+ else if (body[j] === "}") {
2763
+ depth--;
2764
+ if (depth === 0)
2765
+ break;
2766
+ }
2767
+ }
2768
+ out += "\u0000";
2769
+ i = j;
2770
+ continue;
2771
+ }
2772
+ out += body[i];
2773
+ }
2774
+ return out.split(/\s+/).filter((c) => c.length > 0 && !c.includes("\u0000"));
2728
2775
  }
2729
2776
  /**
2730
2777
  * A EXPRESSÃO do `className` que é atributo DIRETO desta tag de abertura, ou `null`.
@@ -95,8 +95,17 @@ export function chosen(all, selection) {
95
95
  const want = new Set(selection.map((s) => s.toLowerCase()));
96
96
  return all.filter((b) => want.has(b.name.toLowerCase()) || want.has(b.id.toLowerCase()));
97
97
  }
98
- export async function fetchPreferences(reach, kind, section) {
99
- const q = kind ? `?kind=${kind}${section ? `&section=${section}` : ""}` : "";
98
+ export async function fetchPreferences(reach, kind, section,
99
+ /** O projeto instalado aqui - a estrutura que vale é a dele ("a alma da estrutura", 04/10). */
100
+ ds) {
101
+ const params = new URLSearchParams();
102
+ if (kind)
103
+ params.set("kind", kind);
104
+ if (kind && section)
105
+ params.set("section", section);
106
+ if (ds)
107
+ params.set("ds", ds);
108
+ const q = params.size ? `?${params}` : "";
100
109
  const res = await fetch(`${reach.base}/api/preferences${q}`, {
101
110
  headers: { Authorization: `Bearer ${reach.token}` },
102
111
  }).catch(() => null);
@@ -180,9 +189,13 @@ function craftOf(kind, prefs) {
180
189
  const lines = prefs.craft?.[kind] ?? [];
181
190
  if (lines.length === 0)
182
191
  return [];
192
+ // a estrutura só existe para a landing: é ela que o rhythm e o type abaixo trazem
193
+ const structure = kind === "landing" && prefs.structure
194
+ ? ` with THIS project's structure, "${prefs.structure.name}"${prefs.structure.chosen ? "" : " (the default - they can pick another under Structure on the site)"}`
195
+ : "";
183
196
  return [
184
197
  "",
185
- `HOW THIS PLATFORM BUILDS A ${kind.toUpperCase()} - the same rules its guide uses; their blueprint wins where the two disagree:`,
198
+ `HOW THIS PLATFORM BUILDS A ${kind.toUpperCase()}${structure} - the same rules its guide uses; their blueprint wins where the two disagree:`,
186
199
  ...lines.map((l) => `- ${l}`),
187
200
  ];
188
201
  }
@@ -213,6 +226,8 @@ off = false) {
213
226
  return composed([
214
227
  ...sectionOf(prefs),
215
228
  `${why} Build the ${kind} with the system as usual, and tell them in one line that they can keep their ${kind} preferences under Memory -> Preference blueprints on the site.`,
229
+ // a estrutura do projeto vale com ou sem blueprint: ela é do projeto, não da pessoa
230
+ ...craftOf(kind, prefs),
216
231
  ].join("\n"), `preferences:${kind}:0${prefs.section ? `:${prefs.section.name}` : ""}`);
217
232
  }
218
233
  return composed([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.489",
3
+ "version": "0.16.491",
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": {