synthesisui 0.16.363 → 0.16.365

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.
@@ -0,0 +1,42 @@
1
+ /**
2
+ * A NOTA DO SISTEMA DELE E AS TRÊS LENTES QUE A COMPÕEM, no fim de um import.
3
+ *
4
+ * O QUE O CLIENTE GANHA: ele fecha o import sabendo em que pé o sistema dele nasceu - a nota, e as
5
+ * três lentes que dizem POR QUE ela é aquela - sem abrir o navegador. Quem apaga e recria um
6
+ * sistema para comparar antes e depois tinha de abrir a tela ou rodar um script sobre o banco, e o
7
+ * número que mais interessa naquele momento é exatamente esse.
8
+ *
9
+ * OS NÚMEROS SÃO IMPRESSOS, NUNCA COMPOSTOS - e a razão foi medida duas vezes em 24/08, quando o
10
+ * resumo escrito pelo agente derrubou justamente a metade que tinha acabado de entrar. Este módulo
11
+ * não calcula nada: ele formata o que o servidor devolveu, pela mesma função que desenha a tela
12
+ * pós-import. Um número calculado em dois lugares tem duas chances de discordar de si mesmo.
13
+ *
14
+ * E TODA LINHA CARREGA O SEU DENOMINADOR. "Token Discipline 62" sozinho não é auditável; "62, on 41
15
+ * of your 62 components" é - e é a mesma frase que a tela mostra embaixo de cada barra.
16
+ */
17
+ import { body, bodyWrapped, paint } from "./output.js";
18
+ /**
19
+ * AS LINHAS DO BLOCO, ou vazio quando não há nota para dar.
20
+ *
21
+ * Vazio e não uma linha vazia: quem chama decide se imprime o título, e um bloco com cabeçalho e
22
+ * nada embaixo é pior que bloco nenhum.
23
+ */
24
+ export function craftLines(craft) {
25
+ if (!craft)
26
+ return [];
27
+ if (craft.score === null) {
28
+ return bodyWrapped("No component of yours was read yet, so there is no line to draw. Your tokens came through - the components are next.").map(body);
29
+ }
30
+ const lines = [
31
+ body(`${paint.strong(`${craft.score}/100`)} on your ${craft.authored} component${craft.authored === 1 ? "" : "s"} - never on our kit, never on a demo.`),
32
+ ];
33
+ /**
34
+ * OS RÓTULOS ALINHADOS PELO MAIS LONGO, e a largura é medida e não estimada: os nomes chegam do
35
+ * servidor, então um padding fixo desalinharia no dia em que uma lente for renomeada lá.
36
+ */
37
+ const width = Math.max(...craft.lenses.map((l) => l.label.length));
38
+ for (const lens of craft.lenses) {
39
+ lines.push(body(` ${lens.label.padEnd(width)} ${paint.strong(String(lens.score).padStart(3))} ${paint.dim(`on ${lens.measuredOn} of them`)}`));
40
+ }
41
+ return lines;
42
+ }
@@ -10,6 +10,7 @@ import { readRequests } from "../doctor/requests.js";
10
10
  import { declaredReference } from "../group-role.js";
11
11
  import { CHECKER_SINCE, installedBehind, MATERIALISER_SINCE, READER_SINCE, } from "../install-marks.js";
12
12
  import { fmt, say } from "../lang.js";
13
+ import { mcpAwaitingApproval } from "../mcp-approval.js";
13
14
  import { measuredScope } from "../measured-scope.js";
14
15
  import { body, bodyWrapped, paint, section, snippet } from "../output.js";
15
16
  import { SKILLS } from "../skills.js";
@@ -96,6 +97,25 @@ export async function localMisalignments(root,
96
97
  opts = {}) {
97
98
  const { cli, home = homedir() } = opts;
98
99
  const out = [];
100
+ /**
101
+ * O PORTÃO QUE MATOU UM IMPORT INTEIRO, dito na sessão em que ele está fechado.
102
+ *
103
+ * Medido em 03/09: o agente mediu 262 arquivos, leu 78 componentes, descreveu a paleta dele - e
104
+ * parou, porque o playbook do import é servido pelo MCP e a aprovação estava pendente. Isto vem
105
+ * ANTES de qualquer outro desalinho porque é o único que impede a jornada principal de começar:
106
+ * um repo sem sistema não está desalinhado, e um repo cujas ferramentas ninguém aprovou não pode
107
+ * nem medir de volta.
108
+ *
109
+ * `/mcp` e não um comando de terminal: quem aprova é o agente, e um `npx` aqui mandaria a pessoa
110
+ * ao lugar errado. Ver `mcp-approval.ts` para de onde o estado é lido, e para o silêncio quando
111
+ * não há como saber.
112
+ */
113
+ if ((await mcpAwaitingApproval(root, home).catch(() => null)) === true)
114
+ out.push({
115
+ says: "The system's tools are declared here and still waiting for your approval - until you give it, I cannot reach the import playbook, only measure your files.",
116
+ run: "/mcp",
117
+ then: "then say: import my design system",
118
+ });
99
119
  const locks = (await locksIn(root)).filter((l) => l.slug && !l.adopted);
100
120
  /** Sem sistema instalado não há alinho a cobrar - não é desalinho, é um repo sem DS. */
101
121
  if (locks.length === 0)
@@ -3,6 +3,7 @@ import { basename, dirname, join, relative, resolve, sep } from "node:path";
3
3
  import { anatomyFromSketch } from "../anatomy-from-sketch.js";
4
4
  import { applyAnatomyPatch, hasEdits, } from "../anatomy-patch.js";
5
5
  import { resolveAnatomy, resolveFlatParts, safePartName, } from "../anatomy-read.js";
6
+ import { craftLines } from "../baseline-craft.js";
6
7
  import { PAGES_MAX, pageCompositionOf } from "../census-pages.js";
7
8
  import { readCredentials, readToken, resolveRegistry, sameRegistry, } from "../config.js";
8
9
  import { declaredElsewhere } from "../declared-elsewhere.js";
@@ -4524,6 +4525,22 @@ export async function runImport(opts) {
4524
4525
  console.log(body(paint.dim(`In the group ${payload.group}.`)));
4525
4526
  for (const note of payload?.notes ?? [])
4526
4527
  console.log(body(paint.dim(note)));
4528
+ /**
4529
+ * A NOTA COM QUE O SISTEMA DELE NASCEU, e as três lentes - ver `baseline-craft.ts`.
4530
+ *
4531
+ * AQUI E NÃO DEPOIS DO v2, porque o v2 argumenta com estes mesmos números: uma proposta que
4532
+ * promete melhorar a disciplina de token precisa que a disciplina de hoje já esteja na tela.
4533
+ * É a ordem que a tela pós-import usa, e ela é deliberada lá pelo mesmo motivo.
4534
+ *
4535
+ * O bloco cala sozinho quando não há nota - servidor anterior a esta versão, ou análise que não
4536
+ * pôde rodar. Um cabeçalho sem número embaixo seria pior que o silêncio.
4537
+ */
4538
+ const craft = craftLines(payload?.quality);
4539
+ if (craft.length > 0) {
4540
+ console.log(section("The line your system starts on"));
4541
+ for (const line of craft)
4542
+ console.log(line);
4543
+ }
4527
4544
  // What a v2 would be worth, in their own values. Said here because this is
4528
4545
  // where the person is standing, and because a number they can check beats an
4529
4546
  // invitation they have to trust.
@@ -0,0 +1,79 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ /**
4
+ * AS FERRAMENTAS DECLARADAS E ESPERANDO APROVAÇÃO - o portão que matou um import inteiro.
5
+ *
6
+ * O QUE O CLIENTE GANHA: a sessão em que a aprovação está pendente é a sessão que lhe diz isso.
7
+ * Antes ele descobria no meio do import, quando o agente já tinha medido o repositório e não tinha
8
+ * como continuar.
9
+ *
10
+ * MEDIDO em 03/09, no segundo import real do dono. Ele rodou `import my design system`, o agente
11
+ * mediu 262 arquivos, leu 78 componentes, descreveu a paleta dele - e parou:
12
+ *
13
+ * synthesisui: npx synthesisui@latest mcp - ⏸ Pending approval
14
+ *
15
+ * O playbook do import é SERVIDO pelo MCP, então sem aprovação não há import: só medição. E o
16
+ * `connect` avisa - em uma linha cinza, a terceira de um bloco secundário. Um portão que interrompe
17
+ * a jornada principal não pode ser anunciado como nota de pé de página.
18
+ *
19
+ * A ORIGEM DO DADO. O Claude Code guarda a decisão no `~/.claude.json`, por projeto:
20
+ *
21
+ * enabledMcpjsonServers aprovados
22
+ * disabledMcpjsonServers recusados
23
+ *
24
+ * Um servidor declarado no `.mcp.json` que não está em nenhuma das duas listas está PENDENTE - e é
25
+ * exatamente o estado dele. Medido: as duas listas vazias, para aquele projeto.
26
+ *
27
+ * SÓ LEITURA, NUNCA ESCRITA. Aquele arquivo é a configuração pessoal dele e vale para todos os
28
+ * projetos dele - a mesma fronteira do `.zshrc`, que este produto só atravessa perguntando.
29
+ * Escrever a aprovação por ele seria decidir em nome dele sobre um portão de segurança.
30
+ *
31
+ * E CALA QUANDO NÃO SABE. Arquivo ausente, JSON que não parseia, projeto sem entrada, formato
32
+ * diferente do que a gente conhece: em todos, resposta `null` e nenhuma linha na tela. Um aviso
33
+ * baseado num formato que mudou é pior que silêncio, porque manda a pessoa procurar um botão que
34
+ * talvez não exista mais.
35
+ */
36
+ /** O nome do nosso servidor no `.mcp.json` - ver `wireMcpAt`. */
37
+ const SERVER = "synthesisui";
38
+ /**
39
+ * `true` quando o nosso servidor está declarado no repositório e a decisão dele ainda não foi
40
+ * tomada. `null` quando não há como saber - e aí quem chama não diz nada.
41
+ */
42
+ export async function mcpAwaitingApproval(root, home) {
43
+ const declared = await readFile(join(root, ".mcp.json"), "utf8").then((raw) => {
44
+ try {
45
+ const j = JSON.parse(raw);
46
+ return Boolean(j.mcpServers && SERVER in j.mcpServers);
47
+ }
48
+ catch {
49
+ return null;
50
+ }
51
+ }, () => false);
52
+ /** Sem declaração não há aprovação pendente: o caso é OUTRO, e o `connect` já o cobre. */
53
+ if (declared !== true)
54
+ return declared === null ? null : false;
55
+ const raw = await readFile(join(home, ".claude.json"), "utf8").catch(() => null);
56
+ if (raw == null)
57
+ return null;
58
+ let conf;
59
+ try {
60
+ conf = JSON.parse(raw);
61
+ }
62
+ catch {
63
+ return null;
64
+ }
65
+ const entry = conf.projects?.[root];
66
+ /**
67
+ * SEM ENTRADA PARA ESTE PROJETO a pessoa provavelmente nunca abriu o agente aqui - e aí não há
68
+ * aprovação pendente, há uma sessão que ainda não aconteceu. Dizer "aprove" a quem não foi
69
+ * perguntado é inventar um estado.
70
+ */
71
+ if (!entry)
72
+ return null;
73
+ const enabled = entry.enabledMcpjsonServers;
74
+ const disabled = entry.disabledMcpjsonServers;
75
+ /** Formato diferente do que a gente conhece: silêncio, nunca um palpite. */
76
+ if (!Array.isArray(enabled) || !Array.isArray(disabled))
77
+ return null;
78
+ return !enabled.includes(SERVER) && !disabled.includes(SERVER);
79
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.363",
3
+ "version": "0.16.365",
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": {