synthesisui 0.16.394 → 0.16.396

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.
@@ -450,6 +450,26 @@ export function describeValueRuler(values) {
450
450
  const decisions = values.seen - values.structure;
451
451
  const closed = values.interpreted + values.answered;
452
452
  const percent = decisions > 0 ? Math.round((closed / decisions) * 100) : 0;
453
+ /**
454
+ * NADA PARA MEDIR NÃO É ZERO POR CENTO - e a frase dizia zero três vezes.
455
+ *
456
+ * O QUE O CLIENTE VIA, caminhado em 07/09 num `create-next-app` recém-criado: *"Of the 0 class
457
+ * declarations on your components, 0 are structure. Of the 0 design decisions, 0 are interpreted -
458
+ * 0%."* Três zeros e um 0% sobre um projeto onde a régua não tinha o que medir, porque ele ainda
459
+ * não escreveu um componente - só páginas, e uma página não é componente de design system, o que o
460
+ * próprio relatório explica seis linhas acima.
461
+ *
462
+ * `0%` é um número de DESEMPENHO, e ali não houve desempenho nenhum. É a lei 14 do `CLAUDE.md`:
463
+ * *"um zero pelado lê como falha nossa; um zero com motivo lê como fato"* - e para quem acabou de
464
+ * apontar a plataforma para o próprio projeto, uma linha de 0% é a primeira impressão.
465
+ *
466
+ * A frase que substitui diz o FATO e o caminho, sem inventar percentual: não há componente para
467
+ * medir ainda.
468
+ */
469
+ if (values.seen === 0)
470
+ return [
471
+ "No component of yours carries a class declaration yet - so there is nothing for this ruler to read. It starts answering once a component exists, and pages do not count as components.",
472
+ ];
453
473
  return [
454
474
  `Of the ${values.seen} class declarations on your components, ${values.structure} are structure (layout plumbing, not design decisions). Of the ${decisions} design decisions, ${closed} are interpreted${values.answered > 0 ? ` (${values.answered} of them answered by you)` : ""} - ${percent}%.`,
455
475
  ];
package/dist/index.js CHANGED
@@ -34,6 +34,7 @@ import { appendEvent } from "./doctor/ledger.js";
34
34
  import { blueprintTarget, installedSlugs } from "./installed.js";
35
35
  import { useLang } from "./lang.js";
36
36
  import { RegistryError } from "./registry.js";
37
+ import { bearing, openingFor } from "./where-you-are.js";
37
38
  /** Our own version, for pinning the hook and MCP commands we write into a
38
39
  * project. Read from the package we are running out of, so a pinned command
39
40
  * always names the version that produced it. */
@@ -155,6 +156,21 @@ async function main() {
155
156
  const { positionals, flags } = parseFlags(process.argv.slice(2));
156
157
  const [command, ...args] = positionals;
157
158
  if (!command || flags.help || command === "help") {
159
+ /**
160
+ * A PRIMEIRA LINHA FALA DO PROJETO ONDE ELA FOI RODADA - ver `where-you-are.ts`.
161
+ *
162
+ * A lista continua inteira logo abaixo. O que muda é que quem digita `npx synthesisui` pela
163
+ * primeira vez lê uma frase sobre o próprio repositório antes de 113 linhas que serviam
164
+ * igualmente a um diretório vazio.
165
+ *
166
+ * Só na tela SEM comando: `--help` e `help` são um pedido pela lista, e enfeitar um pedido
167
+ * explícito é o oposto de responder a ele.
168
+ */
169
+ if (!command && !flags.help) {
170
+ const root = typeof flags.dir === "string" ? flags.dir : process.cwd();
171
+ for (const line of openingFor(await bearing(root)))
172
+ console.log(line);
173
+ }
158
174
  console.log(HELP);
159
175
  return;
160
176
  }
@@ -0,0 +1,78 @@
1
+ import { readdir, stat } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ const exists = async (path) => stat(path).then(() => true, () => false);
4
+ const SKIP = new Set(["node_modules", ".next", ".git", "dist", "build", "out"]);
5
+ /**
6
+ * Existe folha de estilo aqui? Para no PRIMEIRO acerto - a pergunta é "existe", não "quantas", e
7
+ * quantas é a resposta que o `doctor` dá depois de ser chamado.
8
+ */
9
+ async function anyStylesheet(dir, depth = 2) {
10
+ const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);
11
+ for (const e of entries) {
12
+ if (e.isFile() && /\.(css|scss|sass|less)$/i.test(e.name))
13
+ return true;
14
+ }
15
+ if (depth <= 0)
16
+ return false;
17
+ for (const e of entries) {
18
+ if (!e.isDirectory() || SKIP.has(e.name) || e.name.startsWith("."))
19
+ continue;
20
+ if (await anyStylesheet(join(dir, e.name), depth - 1))
21
+ return true;
22
+ }
23
+ return false;
24
+ }
25
+ export async function bearing(root) {
26
+ if (!(await exists(join(root, "package.json"))))
27
+ return { where: "no-project", slug: null, hasStyles: false };
28
+ const installed = (await readdir(join(root, "_synthesisui", "ds"), {
29
+ withFileTypes: true,
30
+ }).catch(() => [])).filter((e) => e.isDirectory());
31
+ const hasStyles = await anyStylesheet(root);
32
+ if (installed.length > 0)
33
+ return {
34
+ where: "system-installed",
35
+ slug: installed[0]?.name ?? null,
36
+ hasStyles,
37
+ };
38
+ if (await exists(join(root, "_synthesisui", "config.json")))
39
+ return { where: "configured-without-system", slug: null, hasStyles };
40
+ return { where: "project-untouched", slug: null, hasStyles };
41
+ }
42
+ /**
43
+ * A ABERTURA: uma linha sobre ESTE projeto, e o comando que responde a partir daqui.
44
+ *
45
+ * Não substitui a lista - ela continua inteira logo abaixo. O que muda é que a primeira coisa que a
46
+ * pessoa lê fala do repositório onde ela está, em vez de um sistema da galeria que ela não tem.
47
+ */
48
+ export function openingFor(b) {
49
+ if (b.where === "no-project")
50
+ return [
51
+ " There is no package.json here, so there is no project to read yet.",
52
+ " Run this from your project's root, or browse what exists:",
53
+ " synthesisui list",
54
+ "",
55
+ ];
56
+ if (b.where === "system-installed")
57
+ return [
58
+ ` ${b.slug} is installed here.`,
59
+ " This tells you what your code still writes outside it, and what --fix can swap:",
60
+ " synthesisui doctor",
61
+ "",
62
+ ];
63
+ if (b.where === "configured-without-system")
64
+ return [
65
+ " This project is configured, and no design system is installed yet.",
66
+ " This reads what you already have and turns it into one - local, free, nothing is sent:",
67
+ " synthesisui import --dry",
68
+ "",
69
+ ];
70
+ return [
71
+ b.hasStyles
72
+ ? " A project with its own CSS, and nothing of ours in it yet."
73
+ : " A project with no design values written yet - so this starts empty and stays honest about it.",
74
+ " This reads what is here and tells you what has a name and what does not:",
75
+ " synthesisui doctor",
76
+ "",
77
+ ];
78
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.394",
3
+ "version": "0.16.396",
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": {