synthesisui 0.16.240 → 0.16.242
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/commands/align.js +55 -2
- package/dist/commands/init.js +32 -4
- package/dist/commands/login.js +24 -1
- package/dist/index.js +5 -2
- package/dist/install-marks.js +12 -1
- package/dist/skill-import.js +1 -1
- package/dist/wiring-prompt.js +34 -0
- package/package.json +1 -1
package/dist/commands/align.js
CHANGED
|
@@ -7,6 +7,7 @@ import { readToken, resolveRegistry } from "../config.js";
|
|
|
7
7
|
import { unsentEvents } from "../doctor/ledger.js";
|
|
8
8
|
import { CHECKER_SINCE, installedBehind, MATERIALISER_SINCE, READER_SINCE, } from "../install-marks.js";
|
|
9
9
|
import { measuredScope } from "../measured-scope.js";
|
|
10
|
+
import { body } from "../output.js";
|
|
10
11
|
import { SKILLS } from "../skills.js";
|
|
11
12
|
/**
|
|
12
13
|
* QUAL CLI MEDIU O CENSO EM DISCO - e era o `reader`, um inteiro, até 11/08.
|
|
@@ -486,17 +487,54 @@ export async function misalignments(root, opts = {}) {
|
|
|
486
487
|
items.push(remote);
|
|
487
488
|
return items;
|
|
488
489
|
}
|
|
490
|
+
/**
|
|
491
|
+
* O ESTADO DE QUEM AINDA NÃO TEM SISTEMA - o silêncio que custava a jornada inteira.
|
|
492
|
+
*
|
|
493
|
+
* `localMisalignments` devolve lista VAZIA quando não há sistema instalado, e a razão está escrita
|
|
494
|
+
* lá em cima: um repo sem DS não está desalinhado, ele só não começou. Correto - e o efeito é que a
|
|
495
|
+
* pessoa que acabou de rodar `connect`, que é exatamente quem mais precisa de uma instrução, abre a
|
|
496
|
+
* primeira sessão do agente em silêncio absoluto. A frase do próximo passo mora hoje na aba do
|
|
497
|
+
* browser que ela acabou de deixar; se fechou a aba, ou voltou no dia seguinte, não existe mais
|
|
498
|
+
* nada dizendo o que fazer.
|
|
499
|
+
*
|
|
500
|
+
* Então isto não é um desalinho e não entra naquela lista: é uma frase de ESTADO, e ela fala em
|
|
501
|
+
* forma de CONVERSA. "Peça ao seu agente: importe meu design system" é executável por quem está
|
|
502
|
+
* lendo - um comando decorado não é, e a esta altura ela nem sabe que comandos existem.
|
|
503
|
+
*
|
|
504
|
+
* DOIS ESTADOS, e não três. O terceiro que o plano previa - "instalado mas não fiado" - ficou de
|
|
505
|
+
* fora com motivo medido: a única leitura confiável de fiação (`readWiring`, no doctor) varre o
|
|
506
|
+
* repositório inteiro, e isto roda em TODA abertura de sessão. Um aviso que custa um walk completo
|
|
507
|
+
* a cada sessão é um aviso que alguém desliga.
|
|
508
|
+
*/
|
|
509
|
+
export async function nextStepFor(root) {
|
|
510
|
+
const locks = (await locksIn(root)).filter((l) => l.slug && !l.adopted);
|
|
511
|
+
if (locks.length > 0)
|
|
512
|
+
return null;
|
|
513
|
+
const measured = await readFile(join(root, "_synthesisui", "census.json"), "utf8").then(() => true, () => false);
|
|
514
|
+
return measured
|
|
515
|
+
? 'This repo has been measured but has no design system yet. Ask me: "continue the import."'
|
|
516
|
+
: 'This repo has no design system contract yet. Ask me: "import my design system."';
|
|
517
|
+
}
|
|
489
518
|
/**
|
|
490
519
|
* A CAUDA DE UM COMANDO QUE TERMINOU: o que ainda está fora, ou nada.
|
|
491
520
|
*
|
|
492
521
|
* Muda quando não falta nada, que é o caso normal e é o que a mantém legível. Ela existe porque
|
|
493
522
|
* `sync`, `connect` e `upgrade` deixavam a pessoa sem saber se tinha acabado - e a resposta exigia
|
|
494
523
|
* lembrar de um sexto comando (dono, 07/08).
|
|
524
|
+
*
|
|
525
|
+
* E QUANDO NÃO HÁ SISTEMA NENHUM ela dizia menos ainda: nada. O `connect` terminava mudo no único
|
|
526
|
+
* repo em que ele é a primeira coisa que alguém roda.
|
|
495
527
|
*/
|
|
496
528
|
export async function reportWhatIsLeft(root, opts = {}) {
|
|
497
529
|
const items = await misalignments(root, opts).catch(() => []);
|
|
498
|
-
if (items.length === 0)
|
|
530
|
+
if (items.length === 0) {
|
|
531
|
+
const next = await nextStepFor(root).catch(() => null);
|
|
532
|
+
if (next) {
|
|
533
|
+
console.log("");
|
|
534
|
+
console.log(body(next));
|
|
535
|
+
}
|
|
499
536
|
return;
|
|
537
|
+
}
|
|
500
538
|
console.log("");
|
|
501
539
|
console.log(describeMisalignments(items, "after"));
|
|
502
540
|
}
|
|
@@ -506,6 +544,21 @@ export async function align(opts) {
|
|
|
506
544
|
...(opts.cli ? { cli: opts.cli } : {}),
|
|
507
545
|
});
|
|
508
546
|
const text = describeMisalignments(items, opts.shell ? "shell" : "session");
|
|
509
|
-
if (text)
|
|
547
|
+
if (text) {
|
|
510
548
|
console.log(text);
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* A PRIMEIRA SESSÃO DEPOIS DO `connect` PASSA A TER UMA PRIMEIRA FRASE.
|
|
553
|
+
*
|
|
554
|
+
* Este é o hook `SessionStart`, e até aqui ele só falava de desalinho - então num repo sem
|
|
555
|
+
* sistema ele nunca falava. É onde a tese da landing vira experiência ou não vira nada: o agente
|
|
556
|
+
* abre sabendo o que falta, e quem está lendo descobre o que pedir sem ter guardado nada.
|
|
557
|
+
*
|
|
558
|
+
* Só quando há algo a dizer. O silêncio de um ambiente pronto é a razão de alguém ainda ler esta
|
|
559
|
+
* linha na vez em que ela aparece.
|
|
560
|
+
*/
|
|
561
|
+
const next = await nextStepFor(root).catch(() => null);
|
|
562
|
+
if (next)
|
|
563
|
+
console.log(next);
|
|
511
564
|
}
|
package/dist/commands/init.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_CONFIG, writeProjectConfig } from "../config.js";
|
|
2
|
+
import { body, section, snippet } from "../output.js";
|
|
3
|
+
import { wiringPrompt } from "../wiring-prompt.js";
|
|
2
4
|
import { add } from "./add.js";
|
|
3
5
|
/**
|
|
4
6
|
* Bootstraps a project for SynthesisUI: writes `_synthesisui/config.json`
|
|
@@ -40,11 +42,37 @@ export async function init(opts) {
|
|
|
40
42
|
// + rules + CLAUDE.md all arrive via `add`).
|
|
41
43
|
if (opts.ds) {
|
|
42
44
|
console.log("");
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
/**
|
|
46
|
+
* O FECHO DEIXA DE SER UMA LISTA DE TAREFAS (etapa 1.4 do plano).
|
|
47
|
+
*
|
|
48
|
+
* `add` imprime "One-time setup (once per app)" com três passos numerados
|
|
49
|
+
* para a PESSOA fazer à mão: os dois `@import`, o `data-ds` na raiz e a
|
|
50
|
+
* fiação das fontes. É onde 27/07 mediu 0% de fiação - ninguém fazia, e o
|
|
51
|
+
* sistema que acabara de chegar não aparecia na tela.
|
|
52
|
+
*
|
|
53
|
+
* Quem roda este comando tem um agente aberto do lado. Então o setup
|
|
54
|
+
* manual sai (`setupHints: false`) e no lugar dele vai a coisa que se
|
|
55
|
+
* cola - o mesmo texto que a tela do onboarding entrega, gêmeo por spec.
|
|
56
|
+
* As edições continuam existindo; elas só mudam de mão.
|
|
57
|
+
*/
|
|
58
|
+
await add(opts.ds, {
|
|
59
|
+
registry: opts.registry,
|
|
60
|
+
dir: root,
|
|
61
|
+
setupHints: false,
|
|
62
|
+
});
|
|
63
|
+
console.log("");
|
|
64
|
+
console.log(section("Two steps left, and neither is a file you edit"));
|
|
65
|
+
console.log(body("1. Turn the check and the tools on - run this BEFORE you open your agent,"));
|
|
66
|
+
console.log(body(" because hooks and tools are read when a session starts:"));
|
|
67
|
+
console.log("");
|
|
68
|
+
console.log(snippet(["npx synthesisui@latest connect"]));
|
|
69
|
+
console.log("");
|
|
70
|
+
console.log(body("2. Open your agent and paste this once - it does the wiring:"));
|
|
71
|
+
console.log("");
|
|
72
|
+
console.log(snippet(wiringPrompt(opts.ds).split("\n")));
|
|
45
73
|
console.log("");
|
|
46
|
-
console.log("
|
|
47
|
-
console.log("
|
|
74
|
+
console.log(body("Then ask it for something real. The check introduces itself on the first"));
|
|
75
|
+
console.log(body("clean file and goes quiet after that."));
|
|
48
76
|
return;
|
|
49
77
|
}
|
|
50
78
|
console.log("");
|
package/dist/commands/login.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { release } from "node:os";
|
|
3
|
-
import { resolveRegistry, writeToken } from "../config.js";
|
|
3
|
+
import { readCredentials, resolveRegistry, sameRegistry, writeToken, } from "../config.js";
|
|
4
4
|
import { RegistryError } from "../registry.js";
|
|
5
5
|
const CLIENT_ID = "synthesisui-cli";
|
|
6
6
|
const GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
@@ -34,6 +34,29 @@ function openBrowser(url) {
|
|
|
34
34
|
/** Device authorization (RFC 8628): opens the browser, waits for approval. */
|
|
35
35
|
export async function login(opts) {
|
|
36
36
|
const base = resolveRegistry(opts.registry);
|
|
37
|
+
/**
|
|
38
|
+
* O LOGIN QUE RECONHECE QUEM JÁ ENTROU (etapa 1.5 do plano, vazamento T1.6).
|
|
39
|
+
*
|
|
40
|
+
* Este comando abria um browser e pedia aprovação mesmo com um token válido
|
|
41
|
+
* na máquina, para o mesmo host. A install mission manda logar depois de a
|
|
42
|
+
* pessoa já ter logado no navegador, e o wizard manda logar no terminal - de
|
|
43
|
+
* modo que "faça de novo o que você acabou de fazer" era o caminho normal, e
|
|
44
|
+
* não um caso de borda. Pedir de novo o que já foi feito é a coisa que faz
|
|
45
|
+
* alguém desconfiar de que o produto sabe o que está acontecendo.
|
|
46
|
+
*
|
|
47
|
+
* Sai por aqui só quando o token é para ESTE host: um token de outro
|
|
48
|
+
* registry não serve, e reconhecê-lo seria um 401 mais tarde disfarçado de
|
|
49
|
+
* sucesso agora.
|
|
50
|
+
*/
|
|
51
|
+
if (!opts.force) {
|
|
52
|
+
const existing = await readCredentials();
|
|
53
|
+
if (existing && sameRegistry(existing.registry, base)) {
|
|
54
|
+
console.log("");
|
|
55
|
+
console.log(`✓ Already signed in to ${base} on this machine.`);
|
|
56
|
+
console.log(" Run `synthesisui login --force` to sign in as someone else.");
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
37
60
|
const codeRes = await fetch(`${base}/api/auth/device/code`, {
|
|
38
61
|
method: "POST",
|
|
39
62
|
headers: { "content-type": "application/json" },
|
package/dist/index.js
CHANGED
|
@@ -36,7 +36,7 @@ const CLI_VERSION = JSON.parse(readFileSync(new URL("../package.json", import.me
|
|
|
36
36
|
const HELP = `synthesisui - bring SynthesisUI design systems into your project
|
|
37
37
|
|
|
38
38
|
Usage - deterministic, FREE:
|
|
39
|
-
synthesisui login [options] connect the CLI to your account (device-flow)
|
|
39
|
+
synthesisui login [options] connect the CLI to your account (device-flow; --force to switch accounts)
|
|
40
40
|
synthesisui init [options] write _synthesisui/config.json (target, dirs); --ds to bring one in
|
|
41
41
|
synthesisui list [options] list the published design systems
|
|
42
42
|
synthesisui add <slug> [options] materialize a DS into _synthesisui/ds/<slug>/
|
|
@@ -387,7 +387,10 @@ async function main() {
|
|
|
387
387
|
break;
|
|
388
388
|
}
|
|
389
389
|
case "login":
|
|
390
|
-
|
|
390
|
+
// `--force` porque o comando agora sai cedo quando esta máquina já tem
|
|
391
|
+
// sessão para este host - trocar de conta continua possível, e passa a
|
|
392
|
+
// ser dito em vez de ser o comportamento padrão.
|
|
393
|
+
await login({ registry, force: args.includes("--force") });
|
|
391
394
|
break;
|
|
392
395
|
case "init": {
|
|
393
396
|
const target = typeof flags.target === "string" ? flags.target : undefined;
|
package/dist/install-marks.js
CHANGED
|
@@ -89,7 +89,18 @@
|
|
|
89
89
|
* "YOUR tokens, under YOUR names"). É a fatia de CLI da decisão de 16/08: toda superfície fala a
|
|
90
90
|
* língua do cliente.
|
|
91
91
|
*/
|
|
92
|
-
|
|
92
|
+
/**
|
|
93
|
+
* 0.16.239 -> 0.16.241 em 16/08, e é SIM: o arquivo que cai na pasta dele muda de CONDUTA, não de
|
|
94
|
+
* bytes decorativos. O stub de `sui-import-ds` respondia ao 401 do playbook com "run
|
|
95
|
+
* `npx synthesisui login` and call it again" - o que faz o agente parar a conversa e cobrar uma conta
|
|
96
|
+
* antes de mostrar um único número do repo dele. O `import --dry` nunca precisou de conta (ele
|
|
97
|
+
* retorna antes de ler credenciais), então o stub novo manda MEDIR primeiro, ler o censo de volta nos
|
|
98
|
+
* nomes dele, e só então pedir o login - e, para o MCP ausente, exigir sessão NOVA em vez de sugerir
|
|
99
|
+
* uma nova tentativa que não pode funcionar.
|
|
100
|
+
*
|
|
101
|
+
* Quem instalou antes desta versão tem o stub que estanca: o `upgrade`/`connect` é o que alcança.
|
|
102
|
+
*/
|
|
103
|
+
export const MATERIALISER_SINCE = "0.16.241";
|
|
93
104
|
/**
|
|
94
105
|
* A ÚLTIMA VERSÃO EM QUE O QUE O HOOK RODA MUDOU.
|
|
95
106
|
*
|
package/dist/skill-import.js
CHANGED
|
@@ -12,4 +12,4 @@
|
|
|
12
12
|
* invocada, e ela não é segredo - a esteira é.
|
|
13
13
|
*/
|
|
14
14
|
export const IMPORT_SKILL_PATH = ".claude/skills/sui-import-ds/SKILL.md";
|
|
15
|
-
export const IMPORT_SKILL = '---\nname: sui-import-ds\ndescription: Turn a codebase the user ALREADY has into a SynthesisUI design system. Use when someone points at an existing repo, app or component library and asks to import it, adopt it, bring it in, or "make a design system from this" (e.g. "/sui-import-ds", "importa o meu packages/ui", "turn this app into a design system"). Drives the full pipeline - measurement \u2192 your reading of the app \u2192 import \u2192 upgrade proposal - and answers the questions arithmetic cannot.\n---\n\n# Import Design System - served live\n\nThis playbook is served from the platform, not shipped in this file - it is\nalways current, and your context only carries the step you are on.\n\n1. Call the `playbook` tool on the `synthesisui` MCP server with\n { "skill": "import" } - you get the framing and a table of contents.\n2. Fetch ONLY the chapter for the step you are on:\n { "skill": "import", "section": "<id from the toc>" }. Never fetch more\n than the current step needs.\n3. Follow it exactly. When the step is done, fetch the next chapter.\n\
|
|
15
|
+
export const IMPORT_SKILL = '---\nname: sui-import-ds\ndescription: Turn a codebase the user ALREADY has into a SynthesisUI design system. Use when someone points at an existing repo, app or component library and asks to import it, adopt it, bring it in, or "make a design system from this" (e.g. "/sui-import-ds", "importa o meu packages/ui", "turn this app into a design system"). Drives the full pipeline - measurement \u2192 your reading of the app \u2192 import \u2192 upgrade proposal - and answers the questions arithmetic cannot.\n---\n\n# Import Design System - served live\n\nThis playbook is served from the platform, not shipped in this file - it is\nalways current, and your context only carries the step you are on.\n\n1. Call the `playbook` tool on the `synthesisui` MCP server with\n { "skill": "import" } - you get the framing and a table of contents.\n2. Fetch ONLY the chapter for the step you are on:\n { "skill": "import", "section": "<id from the toc>" }. Never fetch more\n than the current step needs.\n3. Follow it exactly. When the step is done, fetch the next chapter.\n\n## If something is missing, they skipped a step - do not stall them\n\nThe supported order is `login`, then `connect`, then open this session. When\nit was followed, neither case below happens.\n\nNOT SIGNED IN. Do not stop and wait. Measure first, so they see their own\nrepo before being asked for anything:\n\n1. Run `npx synthesisui@latest import --dry` - it is local, free, needs no\n account, and writes `_synthesisui/census.json`.\n2. Read that file and tell them what is in THEIR repo, in THEIR names: how\n many declarations, how many components, how much already runs on tokens.\n3. Then: "to turn this into a system on your account, run\n `npx synthesisui@latest login` and tell me when it is done."\n\nNO `synthesisui` MCP SERVER AT ALL. Tell them to run\n`npx synthesisui@latest connect` and then START A NEW SESSION - tools are read\nwhen a session opens, so this one cannot pick it up. Say it plainly and stop\nthere; carrying on in a session that cannot reach the playbook is guessing.\n';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* O PASTE QUE TIRA AS QUATRO EDIÇÕES DA MÃO DA PESSOA.
|
|
3
|
+
*
|
|
4
|
+
* `init --ds` termina imprimindo uma seção "One-time setup" com três passos
|
|
5
|
+
* numerados para o humano fazer à mão: os dois `@import`, o `data-ds` na raiz
|
|
6
|
+
* e a fiação das fontes. Foi exatamente aí que 27/07 mediu 0% de fiação -
|
|
7
|
+
* ninguém fazia, e o sistema que acabara de chegar não aparecia na tela.
|
|
8
|
+
*
|
|
9
|
+
* A pessoa que roda esse comando tem um agente aberto ao lado. Então o fecho
|
|
10
|
+
* deixa de ser uma lista de tarefas e passa a ser uma coisa para colar.
|
|
11
|
+
*
|
|
12
|
+
* GÊMEO POR SPEC com `apps/web/src/lib/ds/install-mission.ts`, que serve o
|
|
13
|
+
* mesmo texto na tela do onboarding - `wiring-prompt.spec.ts` reprova o drift.
|
|
14
|
+
* O CLI é publicado standalone e não pode importar de `apps/web`, então a
|
|
15
|
+
* cópia é inevitável; o que não é inevitável é ela divergir em silêncio, e um
|
|
16
|
+
* prompt que diverge entre a tela e o terminal ensina duas fiações diferentes
|
|
17
|
+
* para o mesmo sistema.
|
|
18
|
+
*/
|
|
19
|
+
export function initCommand(slug) {
|
|
20
|
+
return `npx synthesisui@latest init --styles tailwind --ds ${slug}`;
|
|
21
|
+
}
|
|
22
|
+
export function wiringPrompt(slug) {
|
|
23
|
+
return `Wire the "${slug}" design system into this project. I already ran the install in my terminal.
|
|
24
|
+
|
|
25
|
+
1. Run: npx synthesisui@latest doctor
|
|
26
|
+
If it says "no system installed", I skipped the install - run ${initCommand(slug)} first, then carry on.
|
|
27
|
+
2. Do the ONE-TIME SETUP it names, all of it: the two @import lines in the project's global stylesheet (the path is relative to that file), data-ds="${slug}" on the root element, and the font wiring - importing from the fonts file it writes and mapping those variables in the stylesheet. The type is the step people skip.
|
|
28
|
+
3. Run doctor again. It must NOT say "not wired up yet". If it does, it names exactly which piece is missing - fix that and run it again.
|
|
29
|
+
4. Run: npx synthesisui@latest connect
|
|
30
|
+
If it answers "already had it" on both lines, everything is live and you are done.
|
|
31
|
+
If it WROTE either of them, then they are not live in this session, because hooks and tools are only read at startup. Stop there and tell me, in bold, on its own line: **RESTART THIS SESSION - the check is installed but not running yet.** Do not keep writing files after that; a session that cannot be checked is the state this whole setup exists to avoid.
|
|
32
|
+
|
|
33
|
+
Do not change any of my existing styles.`;
|
|
34
|
+
}
|
package/package.json
CHANGED