synthesisui 0.16.366 → 0.16.368
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/color-forms.js +94 -2
- package/dist/commands/align.js +26 -76
- package/dist/doctor/scan.js +16 -1
- package/dist/install-marks.js +16 -2
- package/dist/mcp-approval.js +33 -1
- package/dist/skill-import.js +1 -1
- package/package.json +1 -1
package/dist/color-forms.js
CHANGED
|
@@ -130,6 +130,98 @@ function fromHsl(raw) {
|
|
|
130
130
|
alpha: Number.isFinite(alpha) ? Math.max(0, Math.min(1, alpha)) : 1,
|
|
131
131
|
};
|
|
132
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* `oklch(69.6% 0.17 162.48)` - E ELE ERA 42% DOS LITERAIS DE COR DE UM SISTEMA REAL.
|
|
135
|
+
*
|
|
136
|
+
* O QUE O CLIENTE GANHA: a cor que o Tailwind 4 escreve por padrão passa a ser interpretada como
|
|
137
|
+
* cor. Antes ela chegava na receita (o coletor a lê) e morria aqui - `colorForm` devolvia `null` -,
|
|
138
|
+
* então `deltaE` não a comparava, `namedByValue` não a indexava, o v2 nunca propunha agrupá-la nem
|
|
139
|
+
* nomeá-la, e nada a declarava como lacuna. Ela era invisível nos dois sentidos.
|
|
140
|
+
*
|
|
141
|
+
* MEDIDO em 03/09, nos `looks` de duas populações: 94 usos no `codelevel-ui` e 23 no
|
|
142
|
+
* `frontend-hub`, 39 valores distintos - e ZERO deles no `observed` das três populações, que é a
|
|
143
|
+
* régua de valores. É a decisão 1 do dono (21/08): *"toda forma de cor entra - hex, rgb, rgba, hsl,
|
|
144
|
+
* color-mix, oklch"*.
|
|
145
|
+
*
|
|
146
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
147
|
+
* O GAMUT É MAPEADO POR CHROMA, E NÃO CLAMPADO - e essa é a decisão que impede a cor errada
|
|
148
|
+
*
|
|
149
|
+
* OKLCh descreve cores que o sRGB não alcança: 25 dos 39 valores medidos caem fora. A saída barata
|
|
150
|
+
* é clampar cada canal em 0-255; a certa é a do CSS Color 4, reduzir o CHROMA mantendo o L e o H até
|
|
151
|
+
* a cor caber. As duas DISCORDAM em 22 dos 25:
|
|
152
|
+
*
|
|
153
|
+
* oklch(69.6% 0.17 162.48) clamp #00bc7d chroma-map #00b981
|
|
154
|
+
* oklch(76.9% 0.188 70.08) clamp #fe9a00 chroma-map #f69e00
|
|
155
|
+
*
|
|
156
|
+
* `#00b981` é o emerald que o navegador pinta; `#00bc7d` é uma cor que ninguém vê. Um hex errado
|
|
157
|
+
* aqui não fica quieto: ele vira a chave que decide se duas cores são a mesma e se um token dele
|
|
158
|
+
* casa com um valor - as duas afirmações que este produto não pode errar. O laço binário custa 24
|
|
159
|
+
* iterações e só roda para quem está fora.
|
|
160
|
+
*/
|
|
161
|
+
function fromOklch(raw) {
|
|
162
|
+
const m = /^oklch\(([^)]*)\)$/i.exec(raw.trim());
|
|
163
|
+
if (!m)
|
|
164
|
+
return null;
|
|
165
|
+
const [body, alphaPart] = m[1].split("/");
|
|
166
|
+
const parts = body
|
|
167
|
+
.trim()
|
|
168
|
+
.split(/[\s,]+/)
|
|
169
|
+
.filter(Boolean);
|
|
170
|
+
if (parts.length < 3)
|
|
171
|
+
return null;
|
|
172
|
+
/** L aceita 0-1 e 0%-100%; C aceita o número e o percentual, cujo 100% é 0.4 por spec. */
|
|
173
|
+
const L = unit(parts[0]);
|
|
174
|
+
const C = parts[1].trim().endsWith("%")
|
|
175
|
+
? unit(parts[1], 0.4)
|
|
176
|
+
: Number.parseFloat(parts[1]);
|
|
177
|
+
/** `none` é um ângulo ausente, e ausente é zero - com C=0 o matiz não muda nada de qualquer forma. */
|
|
178
|
+
const H = /^none$/i.test(parts[2].trim()) ? 0 : Number.parseFloat(parts[2]);
|
|
179
|
+
if (![L, C, H].every(Number.isFinite))
|
|
180
|
+
return null;
|
|
181
|
+
const linear = (chroma) => {
|
|
182
|
+
const h = (H * Math.PI) / 180;
|
|
183
|
+
const a = chroma * Math.cos(h);
|
|
184
|
+
const b = chroma * Math.sin(h);
|
|
185
|
+
const l_ = L + 0.3963377774 * a + 0.2158037573 * b;
|
|
186
|
+
const m_ = L - 0.1055613458 * a - 0.0638541728 * b;
|
|
187
|
+
const s_ = L - 0.0894841775 * a - 1.291485548 * b;
|
|
188
|
+
const l3 = l_ ** 3;
|
|
189
|
+
const m3 = m_ ** 3;
|
|
190
|
+
const s3 = s_ ** 3;
|
|
191
|
+
return [
|
|
192
|
+
4.0767416621 * l3 - 3.3077115913 * m3 + 0.2309699292 * s3,
|
|
193
|
+
-1.2684380046 * l3 + 2.6097574011 * m3 - 0.3413193965 * s3,
|
|
194
|
+
-0.0041960863 * l3 - 0.7034186147 * m3 + 1.707614701 * s3,
|
|
195
|
+
];
|
|
196
|
+
};
|
|
197
|
+
/** A folga de 1e-4 é ruído de ponto flutuante, não cor fora do gamut. */
|
|
198
|
+
const fits = (c) => c.every((x) => x >= -0.0001 && x <= 1.0001);
|
|
199
|
+
let channels = linear(Math.max(0, C));
|
|
200
|
+
if (!fits(channels)) {
|
|
201
|
+
let lo = 0;
|
|
202
|
+
let hi = Math.max(0, C);
|
|
203
|
+
for (let i = 0; i < 24; i++) {
|
|
204
|
+
const mid = (lo + hi) / 2;
|
|
205
|
+
if (fits(linear(mid)))
|
|
206
|
+
lo = mid;
|
|
207
|
+
else
|
|
208
|
+
hi = mid;
|
|
209
|
+
}
|
|
210
|
+
channels = linear(lo);
|
|
211
|
+
}
|
|
212
|
+
/** sRGB transfer function - o mesmo expoente que o navegador usa. */
|
|
213
|
+
const gamma = (x) => {
|
|
214
|
+
const v = Math.max(0, Math.min(1, x));
|
|
215
|
+
return (v <= 0.0031308 ? 12.92 * v : 1.055 * v ** (1 / 2.4) - 0.055) * 255;
|
|
216
|
+
};
|
|
217
|
+
const [r, g, b] = channels.map(gamma);
|
|
218
|
+
const rawAlpha = alphaPart ?? parts[3];
|
|
219
|
+
const alpha = rawAlpha === undefined ? 1 : unit(rawAlpha);
|
|
220
|
+
return {
|
|
221
|
+
hex: `#${hex2(r)}${hex2(g)}${hex2(b)}`,
|
|
222
|
+
alpha: Number.isFinite(alpha) ? Math.max(0, Math.min(1, alpha)) : 1,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
133
225
|
/**
|
|
134
226
|
* QUALQUER FORMA -> a canônica. `null` para o que não é uma cor literal.
|
|
135
227
|
*
|
|
@@ -140,7 +232,7 @@ export function colorForm(value) {
|
|
|
140
232
|
const v = value.trim();
|
|
141
233
|
if (!v || /^(transparent|currentcolor|inherit|initial|unset|none)$/i.test(v))
|
|
142
234
|
return null;
|
|
143
|
-
return fromHex(v) ?? fromRgb(v) ?? fromHsl(v);
|
|
235
|
+
return fromHex(v) ?? fromRgb(v) ?? fromHsl(v) ?? fromOklch(v);
|
|
144
236
|
}
|
|
145
237
|
/**
|
|
146
238
|
* AS CORES LITERAIS DENTRO DE UM VALOR - inclusive as de dentro de uma função de composição.
|
|
@@ -163,7 +255,7 @@ export function colorsIn(value) {
|
|
|
163
255
|
seen.add(key);
|
|
164
256
|
out.push(c);
|
|
165
257
|
};
|
|
166
|
-
const rest = value.replace(/\b(?:rgba?|hsla
|
|
258
|
+
const rest = value.replace(/\b(?:rgba?|hsla?|oklch)\([^)]*\)/gi, (m) => (push(colorForm(m)), " "));
|
|
167
259
|
for (const m of rest.match(/#[0-9a-f]{3,8}\b/gi) ?? [])
|
|
168
260
|
push(colorForm(m));
|
|
169
261
|
return out;
|
package/dist/commands/align.js
CHANGED
|
@@ -10,7 +10,6 @@ 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";
|
|
14
13
|
import { measuredScope } from "../measured-scope.js";
|
|
15
14
|
import { body, bodyWrapped, paint, section, snippet } from "../output.js";
|
|
16
15
|
import { SKILLS } from "../skills.js";
|
|
@@ -97,33 +96,6 @@ export async function localMisalignments(root,
|
|
|
97
96
|
opts = {}) {
|
|
98
97
|
const { cli, home = homedir() } = opts;
|
|
99
98
|
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
|
-
/**
|
|
118
|
-
* O VALOR NÃO TRAZ O PRÓPRIO RÓTULO - quem rotula é quem desenha.
|
|
119
|
-
*
|
|
120
|
-
* Ele dizia `then say: import my design system`, e o render põe "then, to pick up where you
|
|
121
|
-
* left off:" acima: a tela saía com dois rótulos e dois "then" para UM passo. É o defeito que
|
|
122
|
-
* o #1314 consertou, reintroduzido por um valor que carregava a moldura dentro.
|
|
123
|
-
*/
|
|
124
|
-
then: "import my design system",
|
|
125
|
-
where: "agent",
|
|
126
|
-
});
|
|
127
99
|
const locks = (await locksIn(root)).filter((l) => l.slug && !l.adopted);
|
|
128
100
|
/** Sem sistema instalado não há alinho a cobrar - não é desalinho, é um repo sem DS. */
|
|
129
101
|
if (locks.length === 0)
|
|
@@ -543,7 +515,7 @@ from = "session") {
|
|
|
543
515
|
: from === "shell"
|
|
544
516
|
? "This repo is out of alignment with the design system that governs it:"
|
|
545
517
|
: "Before this session starts, this environment is out of alignment with the design system that governs it:",
|
|
546
|
-
...grouped(items
|
|
518
|
+
...grouped(items),
|
|
547
519
|
].join("\n");
|
|
548
520
|
}
|
|
549
521
|
/**
|
|
@@ -562,13 +534,7 @@ from = "session") {
|
|
|
562
534
|
*
|
|
563
535
|
* A ordem é a da primeira aparição: o primeiro achado decide onde o grupo dele fica.
|
|
564
536
|
*/
|
|
565
|
-
function grouped(items
|
|
566
|
-
/**
|
|
567
|
-
* QUEM ESTÁ LENDO decide duas coisas aqui: se um remédio do agente precisa dizer onde mora, e se
|
|
568
|
-
* a linha ganha cor. Numa sessão a pessoa JÁ está no agente, e o rótulo seria a tela falando de
|
|
569
|
-
* si mesma.
|
|
570
|
-
*/
|
|
571
|
-
from = "session") {
|
|
537
|
+
function grouped(items) {
|
|
572
538
|
const order = [];
|
|
573
539
|
const byRun = new Map();
|
|
574
540
|
for (const m of items) {
|
|
@@ -585,7 +551,7 @@ from = "session") {
|
|
|
585
551
|
const group = byRun.get(key) ?? [];
|
|
586
552
|
for (const m of group)
|
|
587
553
|
out.push(` - ${m.says}`);
|
|
588
|
-
const { run, then
|
|
554
|
+
const { run, then } = group[0];
|
|
589
555
|
/**
|
|
590
556
|
* A HIERARQUIA, e ela faltava inteira - *"o texto está sem hierarquia de cor, está muito ruim"*
|
|
591
557
|
* (dono, na 0.16.365). Este bloco saía cru enquanto a ação recomendada, quinze linhas acima,
|
|
@@ -595,16 +561,8 @@ from = "session") {
|
|
|
595
561
|
* `paint` se apaga sozinho sem TTY, então o `SessionStart` - que entrega texto a um modelo -
|
|
596
562
|
* continua recebendo o mesmo texto de sempre, sem um único código de escape.
|
|
597
563
|
*/
|
|
598
|
-
if (run)
|
|
599
|
-
/**
|
|
600
|
-
* UM REMÉDIO DO AGENTE DIZ ONDE MORA, na superfície onde ele não é digitável. `/mcp` no
|
|
601
|
-
* prompt do zsh é um comando que não existe; com o rótulo, a linha continua colável no lugar
|
|
602
|
-
* certo em vez de mandar a pessoa ao lugar errado.
|
|
603
|
-
*/
|
|
604
|
-
if (where === "agent" && from !== "session")
|
|
605
|
-
out.push(paint.dim(` ${say("inside your agent session:")}`));
|
|
564
|
+
if (run)
|
|
606
565
|
out.push(paint.blue(` ${run}`));
|
|
607
|
-
}
|
|
608
566
|
/** O `then` sai numa linha própria e rotulada: um segundo comando solto lê como parte do primeiro. */
|
|
609
567
|
if (then)
|
|
610
568
|
out.push(`${paint.dim(` ${say("then, to pick up where you left off:")}`)}\n${paint.blue(` ${then}`)}`);
|
|
@@ -668,14 +626,10 @@ opts = {}) {
|
|
|
668
626
|
* repositório inteiro, e isto roda em TODA abertura de sessão. Um aviso que custa um walk completo
|
|
669
627
|
* a cada sessão é um aviso que alguém desliga.
|
|
670
628
|
*/
|
|
671
|
-
export async function nextStepFor(root
|
|
672
|
-
/** `home` porque a decisão sobre as ferramentas mora nele - ver `mcpAwaitingApproval`. */
|
|
673
|
-
opts = {}) {
|
|
629
|
+
export async function nextStepFor(root) {
|
|
674
630
|
const locks = (await locksIn(root)).filter((l) => l.slug && !l.adopted);
|
|
675
631
|
if (locks.length > 0)
|
|
676
632
|
return null;
|
|
677
|
-
/** `true` só quando declarado e sem decisão; `null` (não sei) e `false` calam do mesmo jeito. */
|
|
678
|
-
const awaiting = (await mcpAwaitingApproval(root, opts.home ?? homedir()).catch(() => null)) === true;
|
|
679
633
|
const measured = await readFile(join(root, "_synthesisui", "census.json"), "utf8").then(() => true, () => false);
|
|
680
634
|
/**
|
|
681
635
|
* MEDIDO E SEM SISTEMA INSTALADO SÃO DUAS HISTÓRIAS, e a frase antiga contava a errada.
|
|
@@ -692,17 +646,14 @@ opts = {}) {
|
|
|
692
646
|
* `list --mine` primeiro porque o slug nasce no servidor: ele não está em nenhum arquivo daqui, e
|
|
693
647
|
* chutá-lo seria pior que pedir para olhar.
|
|
694
648
|
*/
|
|
695
|
-
const awaits = awaiting ? { toolsAwaiting: true } : {};
|
|
696
649
|
return measured
|
|
697
650
|
? {
|
|
698
|
-
...awaits,
|
|
699
651
|
sentence: "This repo has been measured and has no system installed here. If you already imported, the system is in your account: `synthesisui list --mine`, then `synthesisui add <slug>`.",
|
|
700
652
|
headline: "Your system is already in your account. Bring it in here:",
|
|
701
653
|
run: ["synthesisui list --mine", "synthesisui add <slug>"],
|
|
702
654
|
why: "Re-measuring would cost minutes and change nothing the platform already knows.",
|
|
703
655
|
}
|
|
704
656
|
: {
|
|
705
|
-
...awaits,
|
|
706
657
|
sentence: 'This repo has no design system contract yet. Ask me: "import my design system."',
|
|
707
658
|
headline: "Open a new agent session in this repo",
|
|
708
659
|
open: await agentOpenCommands(root).catch(() => []),
|
|
@@ -767,15 +718,17 @@ export function renderNextStep(next, freshSession) {
|
|
|
767
718
|
: "This run moved {what}, and a new session is what reads them.", { what: said })).map(paint.dim));
|
|
768
719
|
}
|
|
769
720
|
/**
|
|
770
|
-
* A LINHA
|
|
721
|
+
* A LINHA DAS FERRAMENTAS SÓ NA RODADA QUE ACABOU DE DECLARÁ-LAS - e o segundo caso foi REMOVIDO.
|
|
722
|
+
*
|
|
723
|
+
* Havia aqui um `next.toolsAwaiting`, lido do `~/.claude.json`, para dizer que a aprovação estava
|
|
724
|
+
* pendente. Ele saiu em 04/09 porque afirmava um estado que nada observa - a medição inteira está
|
|
725
|
+
* na mensagem do PR e na lição do estado: as duas listas daquele arquivo estão vazias em SETE de
|
|
726
|
+
* sete projetos do dono, inclusive onde o MCP serve o playbook sem problema.
|
|
771
727
|
*
|
|
772
|
-
*
|
|
773
|
-
*
|
|
774
|
-
* change - this environment is already current") e a aprovação continuava pendente. `next.toolsAwaiting`
|
|
775
|
-
* é o fato lido do estado; `freshSession.mcp` continua valendo para a rodada que acabou de
|
|
776
|
-
* declarar as ferramentas, quando ainda não há decisão nenhuma para ler.
|
|
728
|
+
* `freshSession.mcp` continua e é honesto por construção: ele não infere estado nenhum, ele diz
|
|
729
|
+
* que ESTA rodada acabou de declarar o servidor - um fato sobre o que o comando fez.
|
|
777
730
|
*/
|
|
778
|
-
if (
|
|
731
|
+
if (freshSession?.mcp)
|
|
779
732
|
lines.push(...bodyWrapped(say("The project's tools ask for approval once - say yes.")).map(paint.dim));
|
|
780
733
|
return lines.join("\n");
|
|
781
734
|
}
|
|
@@ -791,25 +744,22 @@ export function renderNextStep(next, freshSession) {
|
|
|
791
744
|
*/
|
|
792
745
|
export async function reportWhatIsLeft(root, opts = {}) {
|
|
793
746
|
const items = await misalignments(root, opts).catch(() => []);
|
|
794
|
-
const next = await nextStepFor(root
|
|
795
|
-
...(opts.home ? { home: opts.home } : {}),
|
|
796
|
-
}).catch(() => null);
|
|
747
|
+
const next = await nextStepFor(root).catch(() => null);
|
|
797
748
|
/**
|
|
798
|
-
* A AÇÃO RECOMENDADA GANHA
|
|
799
|
-
*
|
|
749
|
+
* A AÇÃO RECOMENDADA GANHA DA LISTA - e a falta desta regra foi a regressão que o dono leu na
|
|
750
|
+
* 0.16.365.
|
|
800
751
|
*
|
|
801
752
|
* Isto era um OU EXCLUSIVO: um desalinho qualquer e o bloco "Do this next" não saía. O aviso da
|
|
802
|
-
* aprovação pendente nasceu em 03/09
|
|
803
|
-
* `connect` - foi ele que declarou as ferramentas
|
|
804
|
-
*
|
|
805
|
-
*
|
|
806
|
-
*
|
|
807
|
-
*
|
|
808
|
-
*
|
|
809
|
-
* que
|
|
810
|
-
* acontece na sessão que o passo 1 manda abrir.
|
|
753
|
+
* aprovação pendente, que nasceu em 03/09, era verdadeiro justamente no repo que acabou de rodar
|
|
754
|
+
* `connect` - foi ele que declarou as ferramentas -, e num repo sem sistema aquele era o ÚNICO
|
|
755
|
+
* desalinho possível. Então a instrução de abrir o agente não desaparecia às vezes: desaparecia
|
|
756
|
+
* SEMPRE, no único momento em que ela é a coisa que a pessoa procura na tela.
|
|
757
|
+
*
|
|
758
|
+
* AQUELE AVISO SAIU EM 04/09 - ele afirmava um estado que nada observa -, e a ordem FICA. Ela é o
|
|
759
|
+
* desenho certo independentemente dele: uma lista de manutenção nunca deve substituir a única
|
|
760
|
+
* ação que a tela está pedindo. O que sobra para o terminal continua saindo, embaixo da ação.
|
|
811
761
|
*/
|
|
812
|
-
const onTheTerminal = items
|
|
762
|
+
const onTheTerminal = items;
|
|
813
763
|
if (next) {
|
|
814
764
|
console.log(renderNextStep(next, opts.freshSession));
|
|
815
765
|
if (onTheTerminal.length > 0) {
|
package/dist/doctor/scan.js
CHANGED
|
@@ -38,8 +38,23 @@ const IGNORE_LINE = /^\s*(import|@import|\/\/|\*|\/\*)/;
|
|
|
38
38
|
* plain CSS values and Tailwind arbitrary values (`bg-[#2563eb]`).
|
|
39
39
|
* `#` inside a URL fragment or an id selector is excluded by requiring a full
|
|
40
40
|
* 3/6/8 digit run terminated by a non-hex character.
|
|
41
|
+
*
|
|
42
|
+
* `oklch()` ENTROU EM 03/09, e a ausência dela era a metade calada de uma lacuna maior.
|
|
43
|
+
*
|
|
44
|
+
* O QUE O CLIENTE GANHA: a cor que o Tailwind 4 escreve por padrão passa a ser contada como valor
|
|
45
|
+
* de design. Este regex alimenta TRÊS superfícies - o `observed` do censo, a lista "Values written
|
|
46
|
+
* by hand" do `doctor`, e o relatório do `hook` a cada escrita -, e as três eram cegas a ela.
|
|
47
|
+
*
|
|
48
|
+
* MEDIDO no menor caso possível, uma `@theme` com duas cores em oklch e uma em hex: o `declared`
|
|
49
|
+
* trazia as três, o `look` do componente trazia `background: oklch(...)`, e o `observed` trazia
|
|
50
|
+
* SÓ o `#ffffff` da mesma regra. Nas populações: 94 usos no `codelevel-ui`, 23 no `frontend-hub`,
|
|
51
|
+
* e zero no `observed` das três.
|
|
52
|
+
*
|
|
53
|
+
* Ler oklch aqui e não no motor de cor - ou o contrário - não entrega nada: o valor precisa ser
|
|
54
|
+
* VISTO pelo scanner e INTERPRETADO por `colorForm` para chegar a uma comparação. As duas metades
|
|
55
|
+
* entraram na mesma mudança porque meia jornada não é meio valor.
|
|
41
56
|
*/
|
|
42
|
-
const COLOR = /#[0-9a-fA-F]{8}\b|#[0-9a-fA-F]{6}\b|#[0-9a-fA-F]{3}\b|rgba?\([^)]*\)|hsla?\([^)]*\)/g;
|
|
57
|
+
const COLOR = /#[0-9a-fA-F]{8}\b|#[0-9a-fA-F]{6}\b|#[0-9a-fA-F]{3}\b|rgba?\([^)]*\)|hsla?\([^)]*\)|oklch\([^)]*\)/g;
|
|
43
58
|
/**
|
|
44
59
|
* THE QUOTE THAT MADE HALF THE DRIFT INVISIBLE.
|
|
45
60
|
*
|
package/dist/install-marks.js
CHANGED
|
@@ -235,7 +235,14 @@ export const MATERIALISER_SINCE = "0.16.362";
|
|
|
235
235
|
* "não lido" sobre um valor que o de hoje resolve - e o número é o que a pessoa lê para decidir
|
|
236
236
|
* se adotou. O `!` de important (0.16.306) já tinha mudado a mesma contagem.
|
|
237
237
|
*/
|
|
238
|
-
|
|
238
|
+
/**
|
|
239
|
+
* 0.16.308 -> 0.16.367 em 03/09: o hook passa a ver `oklch()`. O regex de cor do scanner era cego à
|
|
240
|
+
* forma, então um agente que escrevia `oklch(69.6% 0.17 162.48)` recebia SILÊNCIO mesmo com o
|
|
241
|
+
* `--color-mint-500` do próprio repositório nomeando aquele valor. Agora recebe a linha de sempre:
|
|
242
|
+
* `line 12 oklch(...) -> --color-mint-500`. Um hook pinado antes desta versão aconselha OUTRA
|
|
243
|
+
* coisa - nada -, que é a régua desta marca.
|
|
244
|
+
*/
|
|
245
|
+
export const CHECKER_SINCE = "0.16.367";
|
|
239
246
|
/**
|
|
240
247
|
* A ÚLTIMA VERSÃO EM QUE OS LEITORES PASSARAM A PRODUZIR UM CENSO DIFERENTE.
|
|
241
248
|
*
|
|
@@ -651,7 +658,14 @@ export const CHECKER_SINCE = "0.16.308";
|
|
|
651
658
|
* QUEM NÃO É AFETADO: quem tem menos de 4 096 formas em todo grupo - `web-onboarding` já chegava
|
|
652
659
|
* com 39 de 39. O `sync` daquele repositório não muda um byte.
|
|
653
660
|
*/
|
|
654
|
-
|
|
661
|
+
/**
|
|
662
|
+
* 0.16.366 -> 0.16.367 em 03/09: `oklch()` entra na leitura de cor. O regex do scanner passou a ver
|
|
663
|
+
* a forma (era cega no `observed`, no `doctor` e no `hook`) e `colorForm` passou a interpretá-la,
|
|
664
|
+
* mapeando o gamut por chroma em vez de clampar canal. Medido nos `looks`: 94 usos no
|
|
665
|
+
* `codelevel-ui` e 23 no `frontend-hub`, e ZERO no `observed` das três populações. Um censo tirado
|
|
666
|
+
* antes disto não tem aqueles valores na régua, e só um `sync` os traz.
|
|
667
|
+
*/
|
|
668
|
+
export const READER_SINCE = "0.16.367";
|
|
655
669
|
/**
|
|
656
670
|
* O QUE ESTÁ INSTALADO AQUI FICOU PARA TRÁS - e as DUAS condições que fazem isso ser verdade.
|
|
657
671
|
*
|
package/dist/mcp-approval.js
CHANGED
|
@@ -75,5 +75,37 @@ export async function mcpAwaitingApproval(root, home) {
|
|
|
75
75
|
/** Formato diferente do que a gente conhece: silêncio, nunca um palpite. */
|
|
76
76
|
if (!Array.isArray(enabled) || !Array.isArray(disabled))
|
|
77
77
|
return null;
|
|
78
|
-
|
|
78
|
+
/** Recusado explicitamente é um estado REAL, e é o único que este arquivo registra com certeza. */
|
|
79
|
+
if (disabled.includes(SERVER))
|
|
80
|
+
return true;
|
|
81
|
+
if (enabled.includes(SERVER))
|
|
82
|
+
return false;
|
|
83
|
+
/**
|
|
84
|
+
* AUSENTE DAS DUAS LISTAS É "NÃO SEI", E TRATÁ-LO COMO "PENDENTE" FOI O DEFEITO.
|
|
85
|
+
*
|
|
86
|
+
* A premissa desta função era: *"um servidor declarado que não está em nenhuma das duas listas
|
|
87
|
+
* está PENDENTE - medido, as duas listas vazias para aquele projeto"*. A medição existiu e estava
|
|
88
|
+
* certa sobre aquele projeto; a INFERÊNCIA não, porque ninguém mediu a outra metade.
|
|
89
|
+
*
|
|
90
|
+
* REMEDIDO em 04/09, na máquina do dono, nos SETE projetos que declaram este servidor: as duas
|
|
91
|
+
* listas estão vazias em TODOS - incluindo o `codelevel-monorepo`, onde o import inteiro rodou no
|
|
92
|
+
* dia anterior com o MCP servindo o playbook. Estado byte a byte idêntico entre "funciona" e
|
|
93
|
+
* "está pendente": a leitura não distinguia nada, era uma constante disfarçada de sinal.
|
|
94
|
+
*
|
|
95
|
+
* E procurei o registro em todas as casas antes de concluir - `~/.claude.json`,
|
|
96
|
+
* `.claude/settings.json`, `.claude/settings.local.json`, `.mcp.json` e `~/.claude/`. A aprovação
|
|
97
|
+
* de um servidor do `.mcp.json` não é gravada em nenhuma delas. `hasTrustDialogAccepted` é o
|
|
98
|
+
* diálogo do PROJETO, e `mcp-needs-auth-cache.json` é dos servidores do claude.ai.
|
|
99
|
+
*
|
|
100
|
+
* O CUSTO DE AFIRMAR SEM SABER, e ele não foi teórico: esta linha chega ao contexto do agente em
|
|
101
|
+
* toda abertura de sessão (`align` no `SessionStart`). Em 04/09 o dono pediu *"import my design
|
|
102
|
+
* system"*, o agente leu o aviso, acreditou nele e RECUSOU a jornada principal - mandou rodar
|
|
103
|
+
* `/mcp` num projeto cujas ferramentas estavam disponíveis. O defeito que o aviso existia para
|
|
104
|
+
* evitar era o agente parar sem saber por quê; o aviso passou a ser a causa dele.
|
|
105
|
+
*
|
|
106
|
+
* Então volta a valer a regra que o cabeçalho deste módulo sempre declarou - *"cala quando não
|
|
107
|
+
* sabe"* -, e quem observa se as ferramentas chegaram é o AGENTE, que sabe quais tem. A instrução
|
|
108
|
+
* mora no playbook, endereçada a ele.
|
|
109
|
+
*/
|
|
110
|
+
return null;
|
|
79
111
|
}
|
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\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';
|
|
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\nTOOLS DECLARED, TOOLS NOT THERE. If `.mcp.json` names `synthesisui` and you\ncannot see its tools, the approval is pending - and only YOU can see that, so\nnobody can tell it to you. Measure anyway before you ask: `npx\nsynthesisui@latest import --dry` is local and needs no tool. Show them what is\nin their repo, THEN ask for `/mcp`. Arriving empty-handed helps nobody.\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';
|
package/package.json
CHANGED