@semacode/cli 3.8.5 → 3.9.1

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.
@@ -130,6 +130,7 @@ function criarPoliticaDesignVisualAgentContext() {
130
130
  criteriosMinimos: [
131
131
  "não parecer template de 2010",
132
132
  "não reciclar a mesma estética para domínios diferentes",
133
+ "declarar bloco design no contrato antes de construir UI",
133
134
  "domínio e público moldam layout, linguagem, componentes e interação",
134
135
  "hierarquia visual clara",
135
136
  "paleta com contraste e identidade do domínio",
@@ -39,7 +39,7 @@ export interface OpcoesDriftLegado {
39
39
  observador?: ObservadorOperacaoDrift | undefined;
40
40
  }
41
41
  export interface DiagnosticoDrift {
42
- tipo: "impl_quebrado" | "task_sem_impl" | "rota_divergente" | "recurso_divergente" | "vinculo_quebrado" | "seguranca_frouxa" | "pontuacao_semantica_insuficiente" | "contrato_monolitico" | "codigo_monolitico" | "codigo_governado_sem_cabecalho" | "escopo_estreito_sem_vinculos" | "escopo_estreito_ambiguo";
42
+ tipo: "impl_quebrado" | "task_sem_impl" | "rota_divergente" | "recurso_divergente" | "vinculo_quebrado" | "seguranca_frouxa" | "pontuacao_semantica_insuficiente" | "contrato_monolitico" | "codigo_monolitico" | "codigo_governado_sem_cabecalho" | "escopo_estreito_sem_vinculos" | "escopo_estreito_ambiguo" | "design_nao_declarado";
43
43
  modulo: string;
44
44
  task?: string;
45
45
  route?: string;
@@ -68,6 +68,14 @@ export function analisarModulosSelecionadosDrift(estado) {
68
68
  || task.dados.campos.some((campo) => ["credencial", "segredo"].includes(campo.classificacao))),
69
69
  });
70
70
  }
71
+ if (ir.routes.length > 0 && !ir.design) {
72
+ diagnosticos.push({
73
+ tipo: "design_nao_declarado",
74
+ modulo: ir.nome,
75
+ severidade: "aviso",
76
+ mensagem: `Modulo "${ir.nome}" expoe rotas de UI sem bloco design; declare identidade e tokens para a interface nao regredir ao padrao.`,
77
+ });
78
+ }
71
79
  for (const route of ir.routes) {
72
80
  if (!route.task || route.perfilCompatibilidade !== "publico") {
73
81
  continue;
@@ -34,6 +34,10 @@ export declare function validarCompatibilidadeFramework(alvo: AlvoGeracao, frame
34
34
  export declare function normalizarFonteImportacao(valor: string | undefined): FonteImportacao | undefined;
35
35
  export declare function normalizarTemplateIniciar(valor?: string): TemplateIniciar;
36
36
  export declare function garantirIr(resultado: ReturnType<typeof compilarCodigo>, caminho: string): IrModulo;
37
+ export declare function gerarDesignTokensArquivos(ir: IrModulo, alvo: AlvoGeracao): Array<{
38
+ caminhoRelativo: string;
39
+ conteudo: string;
40
+ }>;
37
41
  export declare function gerarArquivosPorAlvo(ir: IrModulo, alvo: AlvoGeracao, framework: FrameworkGeracao): import("@sema/padroes").ArquivoGerado[];
38
42
  export declare function aplicarEstruturaSaida(arquivos: Array<{
39
43
  caminhoRelativo: string;
@@ -3,7 +3,7 @@
3
3
  import path from "node:path";
4
4
  import { spawnSync } from "node:child_process";
5
5
  import { formatarDiagnosticos } from "@sema/nucleo";
6
- import { descreverEstruturaModulo } from "@sema/padroes";
6
+ import { descreverEstruturaModulo, resolverDesignTokens } from "@sema/padroes";
7
7
  import { gerarDart } from "@sema/gerador-dart";
8
8
  import { gerarLua } from "@sema/gerador-lua";
9
9
  import { gerarPython } from "@sema/gerador-python";
@@ -135,35 +135,132 @@ export function garantirIr(resultado, caminho) {
135
135
  }
136
136
  return resultado.ir;
137
137
  }
138
+ export function gerarDesignTokensArquivos(ir, alvo) {
139
+ if (!ir.design || !["css", "html", "typescript", "javascript"].includes(alvo)) {
140
+ return [];
141
+ }
142
+ const design = resolverDesignTokens(ir.design);
143
+ const cabecalho = `/* SEMA-GOVERNED — design tokens de ${ir.nome}; edite o bloco design do contrato, nao este arquivo. */\n`;
144
+ const cssEscuro = `
145
+ @media (prefers-color-scheme: dark) {
146
+ :root {
147
+ --sema-cor-primaria: ${design.coresEscuras.primaria};
148
+ --sema-cor-primaria-hover: ${design.coresEscuras.primariaHover};
149
+ --sema-cor-fundo: ${design.coresEscuras.fundo};
150
+ --sema-cor-superficie: ${design.coresEscuras.superficie};
151
+ --sema-cor-texto: ${design.coresEscuras.texto};
152
+ --sema-cor-texto-secundario: ${design.coresEscuras.textoSecundario};
153
+ --sema-cor-borda: ${design.coresEscuras.borda};
154
+ }
155
+ }
156
+ `;
157
+ const css = `${cabecalho}:root {
158
+ --sema-cor-primaria: ${design.cores.primaria};
159
+ --sema-cor-primaria-hover: ${design.cores.primariaHover};
160
+ --sema-cor-primaria-suave: ${design.cores.primariaSuave};
161
+ --sema-cor-fundo: ${design.cores.fundo};
162
+ --sema-cor-superficie: ${design.cores.superficie};
163
+ --sema-cor-texto: ${design.cores.texto};
164
+ --sema-cor-texto-secundario: ${design.cores.textoSecundario};
165
+ --sema-cor-borda: ${design.cores.borda};
166
+ --sema-cor-borda-foco: ${design.cores.bordaFoco};
167
+ --sema-fonte: ${design.tipografia.fonte};
168
+ --sema-fonte-titulo: ${design.tipografia.fonteTitulo};
169
+ --sema-fonte-mono: ${design.tipografia.fonteMono};
170
+ --sema-raio: ${design.forma.raio};
171
+ --sema-movimento-duracao: ${design.movimentoDuracao};
172
+ }
173
+ ${cssEscuro}`;
174
+ const objetoTokens = JSON.stringify({
175
+ colors: design.cores,
176
+ darkColors: design.coresEscuras,
177
+ typography: { ...design.tipografia, scale: design.escala },
178
+ shape: design.forma,
179
+ motion: { duration: design.movimentoDuracao },
180
+ domain: ir.design.dominio ?? null,
181
+ identity: ir.design.identidade ?? null,
182
+ }, null, 2);
183
+ const ts = `// SEMA-GOVERNED — design tokens de ${ir.nome}; edite o bloco design do contrato, nao este arquivo.
184
+ export const designTokens = ${objetoTokens} as const;
185
+ export type DesignTokens = typeof designTokens;
186
+ `;
187
+ const js = `// SEMA-GOVERNED — design tokens de ${ir.nome}; edite o bloco design do contrato, nao este arquivo.
188
+ export const designTokens = ${objetoTokens};
189
+ `;
190
+ const scss = `${cabecalho}$sema-cor-primaria: ${design.cores.primaria};
191
+ $sema-cor-primaria-hover: ${design.cores.primariaHover};
192
+ $sema-cor-fundo: ${design.cores.fundo};
193
+ $sema-cor-superficie: ${design.cores.superficie};
194
+ $sema-cor-texto: ${design.cores.texto};
195
+ $sema-cor-texto-secundario: ${design.cores.textoSecundario};
196
+ $sema-cor-borda: ${design.cores.borda};
197
+ $sema-fonte: ${design.tipografia.fonte};
198
+ $sema-fonte-titulo: ${design.tipografia.fonteTitulo};
199
+ $sema-raio: ${design.forma.raio};
200
+ `;
201
+ const tailwind = `// SEMA-GOVERNED — tema Tailwind derivado do bloco design de ${ir.nome}.
202
+ export const theme = {
203
+ extend: {
204
+ colors: {
205
+ sema: {
206
+ primary: "${design.cores.primaria}",
207
+ "primary-hover": "${design.cores.primariaHover}",
208
+ "primary-soft": "${design.cores.primariaSuave}",
209
+ background: "${design.cores.fundo}",
210
+ surface: "${design.cores.superficie}",
211
+ text: "${design.cores.texto}",
212
+ "text-muted": "${design.cores.textoSecundario}",
213
+ border: "${design.cores.borda}",
214
+ },
215
+ },
216
+ borderRadius: { sema: "${design.forma.raio}" },
217
+ transitionDuration: { sema: "${design.movimentoDuracao}" },
218
+ },
219
+ };
220
+ `;
221
+ const tui = `{\n "comentario": "SEMA-GOVERNED — tema de terminal derivado do bloco design de ${ir.nome}",\n "cores": ${JSON.stringify(design.cores, null, 2)},\n "movimento": "${design.movimentoDuracao}"\n}\n`;
222
+ return [
223
+ { caminhoRelativo: `design/design-tokens.css`, conteudo: css },
224
+ { caminhoRelativo: `design/tokens.ts`, conteudo: ts },
225
+ { caminhoRelativo: `design/tokens.js`, conteudo: js },
226
+ { caminhoRelativo: `design/_tokens.scss`, conteudo: scss },
227
+ { caminhoRelativo: `design/tailwind.theme.js`, conteudo: tailwind },
228
+ { caminhoRelativo: `design/theme-tui.json`, conteudo: tui },
229
+ ];
230
+ }
138
231
  export function gerarArquivosPorAlvo(ir, alvo, framework) {
139
- if (alvo === "python") {
140
- return gerarPython(ir, { framework });
141
- }
142
- if (alvo === "dart") {
143
- return gerarDart(ir);
144
- }
145
- if (alvo === "lua") {
146
- return gerarLua(ir);
147
- }
148
- if (alvo === "javascript") {
149
- return gerarJavaScript(ir);
150
- }
151
- if (alvo === "html") {
152
- return gerarHtml(ir);
153
- }
154
- if (alvo === "css") {
155
- return gerarCss(ir);
156
- }
157
- if (alvo === "php") {
158
- return gerarPhp(ir);
159
- }
160
- if (alvo === "dotnet") {
161
- return gerarDotNet(ir);
162
- }
163
- if (alvo === "cpp") {
164
- return gerarCpp(ir);
165
- }
166
- return gerarTypeScript(ir, { framework });
232
+ const extras = gerarDesignTokensArquivos(ir, alvo);
233
+ const base = (() => {
234
+ if (alvo === "python") {
235
+ return gerarPython(ir, { framework });
236
+ }
237
+ if (alvo === "dart") {
238
+ return gerarDart(ir);
239
+ }
240
+ if (alvo === "lua") {
241
+ return gerarLua(ir);
242
+ }
243
+ if (alvo === "javascript") {
244
+ return gerarJavaScript(ir);
245
+ }
246
+ if (alvo === "html") {
247
+ return gerarHtml(ir);
248
+ }
249
+ if (alvo === "css") {
250
+ return gerarCss(ir);
251
+ }
252
+ if (alvo === "php") {
253
+ return gerarPhp(ir);
254
+ }
255
+ if (alvo === "dotnet") {
256
+ return gerarDotNet(ir);
257
+ }
258
+ if (alvo === "cpp") {
259
+ return gerarCpp(ir);
260
+ }
261
+ return gerarTypeScript(ir, { framework });
262
+ })();
263
+ return extras.length > 0 ? [...base, ...extras] : base;
167
264
  }
168
265
  export function aplicarEstruturaSaida(arquivos, ir, estrutura) {
169
266
  if (estrutura === "flat" || estrutura === "backend") {
@@ -0,0 +1,68 @@
1
+ module exemplos.painel.agro {
2
+ design {
3
+ dominio: agro
4
+ identidade: rustico_moderno
5
+ tokens {
6
+ paleta: terra
7
+ tipografia: display
8
+ densidade: confortavel
9
+ forma: arredondada
10
+ movimento: suave
11
+ cor_primaria: "#7c2d12"
12
+ }
13
+ }
14
+
15
+ entity Safra {
16
+ fields {
17
+ id: Id
18
+ cultura: Texto
19
+ hectares: Decimal
20
+ }
21
+ }
22
+
23
+ task registrar_safra {
24
+ input {
25
+ cultura: Texto required
26
+ hectares: Decimal required
27
+ }
28
+ output {
29
+ safra: Safra
30
+ }
31
+ rules {
32
+ hectares deve_ser positivo
33
+ }
34
+ effects {
35
+ persistencia Safra
36
+ auditoria safra_registrada
37
+ }
38
+ guarantees {
39
+ safra existe
40
+ }
41
+ tests {
42
+ caso "registra safra" {
43
+ given {
44
+ cultura: "Cafe"
45
+ hectares: 12.5
46
+ }
47
+
48
+ expect {
49
+ sucesso: verdadeiro
50
+ }
51
+ }
52
+ }
53
+ }
54
+
55
+ route safras_criar {
56
+ metodo: POST
57
+ caminho: /safras
58
+ task: registrar_safra
59
+ finalidade: cadastro_safra
60
+ input {
61
+ cultura: Texto
62
+ hectares: Decimal
63
+ }
64
+ output {
65
+ safra: Safra
66
+ }
67
+ }
68
+ }