synthesisui 0.16.496 → 0.16.497

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
@@ -463,6 +463,12 @@ written now** - read the code before you edit it, never a remembered signature.`
463
463
  * as duas portas e a regra que as mantém fechadas no dia a dia: quem cria sem pedir continua livre.
464
464
  * Basta o servidor registrado - a preferência não depende do sistema instalado.
465
465
  */
466
+ /**
467
+ * O PEDIDO LIVRE SAI MASTIGADO (jornada "o pedido livre sai mastigado", E03, 15/10): uma landing pedida em palavras
468
+ * livres passa pelo `landing` antes de qualquer linha - ele lista as seções do catálogo e devolve o prompt da pilha, com
469
+ * as decisões tomadas. Sem servidor também: o `landing` fala com o registro direto.
470
+ */
471
+ const landingLine = '\n\n**A landing asked in free words:** run `npx synthesisui@latest landing <slug> "<their words>"` first, and follow it.';
466
472
  const preferencesLine = recall.available
467
473
  ? `
468
474
 
@@ -523,7 +529,7 @@ If nothing covers it, say which indexed entry you considered and why it did not
523
529
  project's OWN custom properties, exactly as the guide lists them. Do not write raw colours,
524
530
  spacings or radii that a token already covers, and do not invent a new token silently - say so
525
531
  instead, because a new token is a decision for a person to make. There is no component
526
- manifest for an adopted system - the tokens ARE the contract.${theirsLine}${selfCheck}`
532
+ manifest for an adopted system - the tokens ARE the contract.${theirsLine}${landingLine}${selfCheck}`
527
533
  : `**When creating or editing components, read the system's GUIDE.md and follow it:** use the
528
534
  vocabulary it lists - every name in it is a name THIS project already declares, written exactly as
529
535
  you would write it. Do not use raw values outside the system's scale, and never a name from a
@@ -559,7 +565,7 @@ still yours: the \`request_component\` MCP tool, or \`npx synthesisui@latest req
559
565
  what the system's author works from - a refusal said only in chat evaporates. If you want to eyeball a
560
566
  component on its own, an isolated scratch page is optional and never required - and if you make
561
567
  one, put it somewhere that does not become a route in this app, and delete it when you are done.
562
- Do not apply a component to real production pages unless asked.${selfCheck}`;
568
+ Do not apply a component to real production pages unless asked.${landingLine}${selfCheck}`;
563
569
  const locale = await readInterfaceLanguage(projectRoot);
564
570
  const language = locale === null
565
571
  ? ""
@@ -0,0 +1,47 @@
1
+ import { resolveRegistry } from "../config.js";
2
+ import { fetchLandingParts, fetchLandingPrompt } from "../registry.js";
3
+ /**
4
+ * `synthesisui landing <slug> "<pedido>"` - O PEDIDO LIVRE SAI MASTIGADO (jornada "o pedido livre sai mastigado", 15/10).
5
+ *
6
+ * Em dois passos, e o agente faz os dois:
7
+ *
8
+ * sem --sections a lista das seções de landing do catálogo, com o lugar, o tipo e o nome, e o que fazer em seguida
9
+ * com --sections o MESMO prompt do "Copy prompt" da pilha para essas seções - um template por seção, fontes, menu do
10
+ * celular -, com o conteúdo vindo do pedido
11
+ *
12
+ * A única decisão que fica com o agente é escolher da lista; o resto é regra nossa, já tomada. Fala com o registro
13
+ * (a mesma fonte do site), por isso não é o `use`, que promete não usar a rede (`architecture/no-network.spec.ts`).
14
+ */
15
+ export async function landing(slug, requestText, opts) {
16
+ const base = resolveRegistry(opts.registry);
17
+ const request = requestText.trim() || "a landing page";
18
+ const chosen = (opts.sections ?? "")
19
+ .split(",")
20
+ .map((s) => s.trim())
21
+ .filter(Boolean);
22
+ if (chosen.length === 0) {
23
+ const parts = await fetchLandingParts(base, slug);
24
+ const byPlace = (place) => parts.filter((p) => p.place === place);
25
+ const line = (p) => ` ${p.id.padEnd(20)} ${p.type} · ${p.name}${p.note ? ` (${p.note})` : ""}`;
26
+ const out = [
27
+ `The landing sections of "${slug}". Pick one navigation, one hero, the body sections in order, and one footer -`,
28
+ "the ones that fit this request:",
29
+ ` "${request}"`,
30
+ "",
31
+ "Top",
32
+ ...byPlace("nav").map(line),
33
+ "Hero",
34
+ ...byPlace("hero").map(line),
35
+ "Body",
36
+ ...byPlace("body").map(line),
37
+ "Bottom",
38
+ ...byPlace("footer").map(line),
39
+ "",
40
+ "Then run, with your picks in page order, and follow the prompt it prints:",
41
+ ` npx synthesisui@latest landing ${slug} --sections <nav>,<hero>,<body...>,<footer> "${request}"`,
42
+ ];
43
+ console.log(out.join("\n"));
44
+ return;
45
+ }
46
+ console.log(await fetchLandingPrompt(base, slug, chosen, request));
47
+ }
@@ -1966,7 +1966,18 @@ cli) {
1966
1966
  const prefs = await fetchPreferences({ base: resolveRegistry(), token }, kind, section, await installedSlug(root));
1967
1967
  if ("failed" in prefs)
1968
1968
  return fromContract(`Their preferences could not be read: ${prefs.failed}. Build with the system as usual and say so in one line.`);
1969
- return preferencesAnswer(kind, prefs, await readSelection(root), await readOff(root));
1969
+ const answer = preferencesAnswer(kind, prefs, await readSelection(root), await readOff(root));
1970
+ /**
1971
+ * O PEDIDO LIVRE SAI MASTIGADO (jornada "o pedido livre sai mastigado", E03, 15/10): a landing inteira passa pelo
1972
+ * `landing`, que escolhe do catálogo e devolve o prompt com as decisões tomadas. Mora AQUI, e não no CLAUDE.md, porque
1973
+ * com o servidor o bloco tem orçamento (`claude-md.f0.spec.ts`) e esta é a ferramenta que o agente já chama antes de
1974
+ * uma página. Uma parte só (`section`) não passa por ele: é uma seção, e o pedido é dela.
1975
+ */
1976
+ if (kind === "landing" && section === undefined) {
1977
+ const slug = (await installedSlug(root)) ?? "<slug>";
1978
+ answer.body = `For the whole landing, first run \`npx synthesisui@latest landing ${slug} "<their words>"\`: pick the sections it lists, run it again with \`--sections\`, and build from the prompt it prints - every decision in it is already made. Apply what follows on top of it.\n\n${answer.body}`;
1979
+ }
1980
+ return answer;
1970
1981
  }
1971
1982
  case "remember_preference": {
1972
1983
  const { kind, layer } = args;
@@ -97,9 +97,20 @@ export async function use(slug, intent, opts) {
97
97
  `(\`npx synthesisui component ${slug} <name>\`) and use this project's own Tailwind utilities ` +
98
98
  `(${utilities}…). Never use raw hex/px outside the system's scale.`;
99
99
  const task = intent.trim() || "build the UI I describe next";
100
+ /**
101
+ * UMA LANDING TEM CAMINHO PRÓPRIO (jornada "o pedido livre sai mastigado", E01, 15/10): o `landing` devolve as seções do
102
+ * catálogo e o prompt com as decisões tomadas. O `use` não busca nada - ele promete não usar a rede -, só aponta.
103
+ */
104
+ const isLanding = /\blanding\b|\bhome ?page\b/i.test(task);
100
105
  const prompt = [
101
106
  `Use the "${name}" design system (slug: ${slug}, v${version}) to: ${task}`,
102
107
  "",
108
+ ...(isLanding
109
+ ? [
110
+ `This is a landing page: before writing anything, run \`npx synthesisui@latest landing ${slug} "${task.replace(/"/g, "'")}"\` - it lists the catalog's sections for you to pick, then prints the full prompt with every decision made. Follow that prompt instead of the rest of this one.`,
111
+ "",
112
+ ]
113
+ : []),
103
114
  "Read these files in the project first (highest authority first):",
104
115
  ...readFirst,
105
116
  "",
package/dist/index.js CHANGED
@@ -20,6 +20,7 @@ import { generate } from "./commands/generate.js";
20
20
  import { hook } from "./commands/hook.js";
21
21
  import { runImport } from "./commands/import.js";
22
22
  import { init } from "./commands/init.js";
23
+ import { landing } from "./commands/landing.js";
23
24
  import { list } from "./commands/list.js";
24
25
  import { login } from "./commands/login.js";
25
26
  import { logout } from "./commands/logout.js";
@@ -61,6 +62,7 @@ Usage - deterministic, FREE:
61
62
  synthesisui upgrade <slug> update an installed DS + regenerate your components + migration brief
62
63
  synthesisui colours [slug] write the colours you chose on the site into your CSS, in your names (asks first)
63
64
  synthesisui use <slug> "<intent>" print a ready-to-paste agent prompt to build/modify on-system
65
+ synthesisui landing <slug> "<request>" the catalog's landing sections, then (--sections a,b,c) the prompt with every decision made
64
66
  synthesisui clean [--force] strip create-next-app boilerplate (dry run without --force)
65
67
 
66
68
  Usage - governance (deterministic, FREE):
@@ -719,6 +721,19 @@ async function main() {
719
721
  });
720
722
  break;
721
723
  }
724
+ case "landing": {
725
+ const slug = args[0];
726
+ if (!slug) {
727
+ console.error('error: provide the slug and your request - `synthesisui landing <slug> "<request>"`');
728
+ process.exitCode = 1;
729
+ return;
730
+ }
731
+ await landing(slug, args.slice(1).join(" "), {
732
+ sections: typeof flags.sections === "string" ? flags.sections : undefined,
733
+ registry: typeof flags.registry === "string" ? flags.registry : undefined,
734
+ });
735
+ break;
736
+ }
722
737
  case "use": {
723
738
  const slug = args[0];
724
739
  if (!slug) {
@@ -328,7 +328,12 @@
328
328
  * 0.16.492 -> 0.16.493 em 06/10, e o passo 1 dá **SIM** ("a galeria aprende", E02): o `init` declara as durações do
329
329
  * sistema no @theme (`--duration-fast`), e o blueprint as escreve pelo nome. Um componente escrito antes traz `100ms`.
330
330
  */
331
- export const MATERIALISER_SINCE = "0.16.494";
331
+ /**
332
+ * 0.16.494 -> 0.16.497 em 15/10, e o passo 1 dá **SIM** (o pedido livre sai mastigado, E03): o bloco do `CLAUDE.md` sem o
333
+ * servidor diz que uma landing pedida em palavras livres passa primeiro pelo `landing`. Uma pasta escrita antes deixa o
334
+ * agente decidir a página inteira sozinho.
335
+ */
336
+ export const MATERIALISER_SINCE = "0.16.497";
332
337
  /**
333
338
  * A ÚLTIMA VERSÃO EM QUE O QUE O HOOK RODA MUDOU.
334
339
  *
package/dist/registry.js CHANGED
@@ -230,3 +230,27 @@ export async function postSaveComponent(base, payload) {
230
230
  }
231
231
  return (await res.json());
232
232
  }
233
+ /**
234
+ * O PEDIDO LIVRE SAI MASTIGADO (jornada "o pedido livre sai mastigado", 15/10): a lista de seções de landing do catálogo
235
+ * e o prompt da pilha para as escolhidas. Os dois saem do registro - a mesma fonte do site -, e nunca de uma cópia aqui.
236
+ */
237
+ export async function fetchLandingParts(base, slug) {
238
+ const url = new URL(`${base}/api/registry/ds/${encodeURIComponent(slug)}`);
239
+ url.searchParams.set("landing", "parts");
240
+ const res = await request(url.toString());
241
+ const body = (await res.json().catch(() => ({})));
242
+ if (!res.ok || !body.parts)
243
+ throw new RegistryError(body.message ?? `Registry responded ${res.status} for "${slug}".`);
244
+ return body.parts;
245
+ }
246
+ export async function fetchLandingPrompt(base, slug, sections, requestText) {
247
+ const url = new URL(`${base}/api/registry/ds/${encodeURIComponent(slug)}`);
248
+ url.searchParams.set("landing", "prompt");
249
+ url.searchParams.set("sections", sections.join(","));
250
+ url.searchParams.set("request", requestText);
251
+ const res = await request(url.toString());
252
+ const body = (await res.json().catch(() => ({})));
253
+ if (!res.ok || !body.prompt)
254
+ throw new RegistryError(body.message ?? `Registry responded ${res.status} for "${slug}".`);
255
+ return body.prompt;
256
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.496",
3
+ "version": "0.16.497",
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": {