synthesisui 0.16.368 → 0.16.369

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.
@@ -201,6 +201,24 @@ const TOOLS = [
201
201
  required: ["skill"],
202
202
  },
203
203
  },
204
+ {
205
+ name: "apply_upgrade",
206
+ description: "The optimisation this system can write on its OWN, and the one question to ask before writing it. Call it with { slug } to GET the question - it comes back composed, with their numbers in it, and you deliver it as it is rather than rephrasing it. Only after they say yes, call again with { slug, confirmed: true }. What it writes never adds a word they did not write and never moves a value they chose: a literal only becomes a reference when it resolves to the same value. Everything that would need a NAME from them stays out and comes back counted, so you can say what is still waiting. Do NOT call this with confirmed:true off your own judgement - the whole point of the question is that the answer is theirs.",
207
+ inputSchema: {
208
+ type: "object",
209
+ properties: {
210
+ slug: {
211
+ type: "string",
212
+ description: "The system's slug, as the import printed it.",
213
+ },
214
+ confirmed: {
215
+ type: "boolean",
216
+ description: "false or omitted: returns the question and the numbers, writes nothing. true: applies it - only after they answered yes in their own words.",
217
+ },
218
+ },
219
+ required: ["slug"],
220
+ },
221
+ },
204
222
  {
205
223
  name: "recipe_vocabulary",
206
224
  description: "What a recipe CAN hold: every state that compiles, every preview form, the floor per kind, and the rules a media region needs. Call this BEFORE writing a recipe, not after - the reader that skipped it sent a `dark:` inside a variant and a state the compiler cannot spell, and both were dropped in silence. Served from the catalogue, so it grows as the contract grows.",
@@ -603,6 +621,54 @@ async function listComponents(root) {
603
621
  * sumário; com, UM capítulo. O corpo inteiro nunca viaja - a dieta de contexto
604
622
  * é servida por construção.
605
623
  */
624
+ /**
625
+ * A OTIMIZAÇÃO QUE UMA RESPOSTA "SIM" ESCREVE - e a pergunta que a precede, composta na plataforma.
626
+ *
627
+ * O QUE O CLIENTE GANHA: ele acaba de importar e o agente lhe faz UMA pergunta ali mesmo, em vez de
628
+ * lhe entregar um link para uma tela com quarenta e seis decisões enfileiradas. Ele responde, e o
629
+ * sistema é otimizado na mesma conversa.
630
+ *
631
+ * A PERGUNTA NÃO É COMPOSTA AQUI NEM PELO AGENTE, e essa é a decisão que faz o texto sobreviver: o
632
+ * agente escreve bem e escreve DIFERENTE a cada execução, e uma pergunta que muda de forma a cada
633
+ * vez é uma paráfrase e não uma pergunta do produto. Foi assim que dois fechamentos consecutivos
634
+ * afirmaram que 198 declarações não chegaram a receita nenhuma quando 22 utilities dele já estavam
635
+ * no sistema - o resumo dropou exatamente a metade que tinha acabado de entrar. Então o texto vem
636
+ * pronto de `askToUpgrade`, com os números da medição dentro dele.
637
+ *
638
+ * DOIS PASSOS DE PROPÓSITO. Sem `confirmed` nada é escrito: é o que impede a jornada de pular a
639
+ * pergunta, que é a única coisa nela que pertence à pessoa.
640
+ */
641
+ async function applyUpgrade(slug, confirmed) {
642
+ const answer = await askPlatform(`/api/registry/ds/${encodeURIComponent(slug)}/upgrade`, confirmed ? "POST" : "GET");
643
+ if (!answer.ok)
644
+ return answer.because;
645
+ const body = answer.body;
646
+ if (body.error)
647
+ return `${body.error}${body.message ? `: ${body.message}` : ""}`;
648
+ if (!confirmed) {
649
+ if (!body.ask)
650
+ return "Nothing here is safe to apply on its own - ask them nothing, and say the system is already on its own names.";
651
+ return [
652
+ "ASK THEM THIS, and deliver it as it is - it is composed here so the numbers cannot drift:",
653
+ "",
654
+ body.ask,
655
+ "",
656
+ `Then, and only then: call apply_upgrade again with { slug: "${slug}", confirmed: true }. If they say no, say what they are choosing - the system stays exactly as their code has it, and the optimisation waits on a button.`,
657
+ ].join("\n");
658
+ }
659
+ if (body.applied === false)
660
+ return body.message ?? "Nothing was applied.";
661
+ return [
662
+ `Done - v${body.version} published.`,
663
+ `${body.repointed ?? 0} literal${body.repointed === 1 ? "" : "s"} now follow their own tokens, and ${body.named ?? 0} value${body.named === 1 ? "" : "s"} became a named token.`,
664
+ body.waiting
665
+ ? `${body.waiting} decision${body.waiting === 1 ? "" : "s"} still need a word only they have - say the number, and that those wait on their own screen.`
666
+ : "",
667
+ "The version they had before is published and frozen, so going back is one click.",
668
+ ]
669
+ .filter(Boolean)
670
+ .join(" ");
671
+ }
606
672
  async function playbook(skill, section) {
607
673
  const answer = await askCatalogue("playbook", undefined, section ? { skill, section } : { skill });
608
674
  if (!answer.ok)
@@ -993,6 +1059,45 @@ cli) {
993
1059
  }
994
1060
  })();
995
1061
  }
1062
+ /**
1063
+ * UMA ROTA DA PLATAFORMA QUE NÃO É O CATÁLOGO, com a mesma sessão do device-login.
1064
+ *
1065
+ * `askCatalogue` monta `/api/catalogue?want=…` na própria assinatura, o que é certo para o que É
1066
+ * catálogo - e a otimização não é: ela ESCREVE no sistema dele, e uma escrita atrás de um `?want=`
1067
+ * leria como leitura. Então a única coisa compartilhada é o que deve ser: o token e o host.
1068
+ *
1069
+ * O MODO DE FALHA É DITO EM VOZ ALTA, nas três formas em que ele acontece - sem sessão, resposta de
1070
+ * erro, sem rede. Um `catch` que devolve silêncio faria o agente concluir que não havia nada a
1071
+ * fazer, e o cliente perderia a otimização sem nunca saber que ela existia.
1072
+ */
1073
+ async function askPlatform(path, method) {
1074
+ const token = await readToken();
1075
+ if (!token)
1076
+ return {
1077
+ ok: false,
1078
+ because: "Not signed in, so the platform could not answer. Run `synthesisui login` in the terminal and call this again.",
1079
+ };
1080
+ try {
1081
+ const res = await fetch(`${resolveRegistry()}${path}`, {
1082
+ method,
1083
+ headers: { Authorization: `Bearer ${token}` },
1084
+ });
1085
+ if (!res.ok)
1086
+ return {
1087
+ ok: false,
1088
+ because: res.status === 404
1089
+ ? "No system by that slug on this account - check the slug the import printed."
1090
+ : `The platform answered ${res.status}. ${res.status === 401 ? "Run `synthesisui login` and try again." : "Nothing was written."}`,
1091
+ };
1092
+ return { ok: true, body: await res.json() };
1093
+ }
1094
+ catch {
1095
+ return {
1096
+ ok: false,
1097
+ because: "No network, so the platform could not answer. Nothing was written - say that, and offer to try again rather than describing what would have happened.",
1098
+ };
1099
+ }
1100
+ }
996
1101
  async function askCatalogue(want, post,
997
1102
  /** Parâmetros extras do GET (ex.: o playbook e o capítulo pedidos). */
998
1103
  query) {
@@ -1547,6 +1652,9 @@ cli) {
1547
1652
  const section = args?.section ? String(args.section) : undefined;
1548
1653
  return fromContract(await playbook(skill, section));
1549
1654
  }
1655
+ case "apply_upgrade": {
1656
+ return fromContract(await applyUpgrade(String(args?.slug ?? ""), args?.confirmed === true));
1657
+ }
1550
1658
  case "recipe_vocabulary":
1551
1659
  return fromContract(await recipeVocabulary());
1552
1660
  case "validate_recipe": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.368",
3
+ "version": "0.16.369",
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": {