@semacode/cli 3.8.4 → 3.9.0

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",
@@ -5,6 +5,7 @@ export interface DocumentoPlanejado {
5
5
  tipo: TipoDocumentoMudanca;
6
6
  motivo: string;
7
7
  permitirCriacao: boolean;
8
+ obrigatoriedade?: "bloqueante" | "recomendada";
8
9
  }
9
10
  export interface DocumentoObrigatorioMudanca {
10
11
  caminho: string;
@@ -20,6 +21,7 @@ export interface DocumentoObrigatorioMudanca {
20
21
  template?: string;
21
22
  templatePendente?: boolean;
22
23
  substancia?: boolean;
24
+ obrigatoriedade: "bloqueante" | "recomendada";
23
25
  }
24
26
  export interface BloqueioDocumentacaoMudanca {
25
27
  tipo: "documentacao_ausente" | "leitura_obrigatoria_nao_comprovada" | "documentacao_template_cru" | "documentacao_sem_substancia" | "arquivo_monolitico" | "codigo_governado_sem_cabecalho";
@@ -38,6 +40,7 @@ export interface ResultadoDocumentacaoObrigatoria {
38
40
  leituraObrigatoria: DocumentoObrigatorioMudanca[];
39
41
  docsAusentes: DocumentoObrigatorioMudanca[];
40
42
  docsCriadas: DocumentoObrigatorioMudanca[];
43
+ leituraRecomendada: DocumentoObrigatorioMudanca[];
41
44
  bloqueios: BloqueioDocumentacaoMudanca[];
42
45
  instrucoes: string[];
43
46
  }
@@ -45,6 +48,7 @@ export interface ResultadoVerificacaoDocumentacaoMudanca {
45
48
  sucesso: boolean;
46
49
  baseProjeto: string;
47
50
  intencao: string;
51
+ leituraRecomendada: DocumentoObrigatorioMudanca[];
48
52
  categorias: string[];
49
53
  docsLidas: string[];
50
54
  leituraObrigatoria: DocumentoObrigatorioMudanca[];
@@ -51,7 +51,7 @@ export async function resolverDocumentacaoObrigatoria(opcoes) {
51
51
  await adicionarDocsRaizExistentes(baseProjeto, registrar);
52
52
  for (const regra of REGRAS_DOCUMENTACAO.filter((item) => categorias.includes(item.categoria))) {
53
53
  for (const doc of regra.docs) {
54
- registrar(doc);
54
+ registrar({ ...doc, obrigatoriedade: "recomendada" });
55
55
  }
56
56
  }
57
57
  await adicionarReadmesDeArquivos(baseProjeto, arquivosAlvo, registrar);
@@ -87,6 +87,7 @@ export async function resolverDocumentacaoObrigatoria(opcoes) {
87
87
  criado,
88
88
  criacaoAutomatica: doc.permitirCriacao,
89
89
  obrigatorio: true,
90
+ obrigatoriedade: doc.obrigatoriedade ?? "bloqueante",
90
91
  template: existe ? undefined : template,
91
92
  };
92
93
  if (existe) {
@@ -101,7 +102,7 @@ export async function resolverDocumentacaoObrigatoria(opcoes) {
101
102
  }
102
103
  const docsAusentes = leituraObrigatoria.filter((doc) => !doc.existe);
103
104
  const docsCriadas = leituraObrigatoria.filter((doc) => doc.criado);
104
- const bloqueios = docsAusentes.map((doc) => ({
105
+ const bloqueios = docsAusentes.filter((doc) => doc.obrigatoriedade !== "recomendada").map((doc) => ({
105
106
  tipo: "documentacao_ausente",
106
107
  severidade: 4,
107
108
  caminho: doc.relativo,
@@ -118,6 +119,9 @@ export async function resolverDocumentacaoObrigatoria(opcoes) {
118
119
  leituraObrigatoria,
119
120
  docsAusentes,
120
121
  docsCriadas,
122
+ leituraRecomendada: leituraObrigatoria
123
+ .filter((doc) => doc.obrigatoriedade === "recomendada")
124
+ .map(compactarDocumentoObrigatorio),
121
125
  bloqueios,
122
126
  instrucoes: [
123
127
  "A IA deve ler todos os itens de leituraObrigatoria antes de executar a mudanca.",
@@ -149,9 +153,9 @@ export async function verificarDocumentacaoMudanca(opcoes) {
149
153
  });
150
154
  const docsLidas = [...new Set((opcoes.docsLidas ?? []).map((doc) => normalizarDocLida(baseProjeto, doc)).filter(Boolean))];
151
155
  const setDocsLidas = new Set(docsLidas);
152
- const docsNaoLidas = impacto.leituraObrigatoria.filter((doc) => doc.existe && !setDocsLidas.has(doc.relativo));
153
- const docsTemplatePendentes = impacto.leituraObrigatoria.filter((doc) => (doc.existe && doc.templatePendente && setDocsLidas.has(doc.relativo)));
154
- const docsSemSubstancia = impacto.leituraObrigatoria.filter((doc) => (doc.existe && !doc.templatePendente && doc.substancia === false));
156
+ const docsNaoLidas = impacto.leituraObrigatoria.filter((doc) => (doc.existe && doc.obrigatoriedade !== "recomendada" && !setDocsLidas.has(doc.relativo)));
157
+ const docsTemplatePendentes = impacto.leituraObrigatoria.filter((doc) => (doc.existe && doc.obrigatoriedade !== "recomendada" && doc.templatePendente && setDocsLidas.has(doc.relativo)));
158
+ const docsSemSubstancia = impacto.leituraObrigatoria.filter((doc) => (doc.existe && doc.obrigatoriedade !== "recomendada" && !doc.templatePendente && doc.substancia === false));
155
159
  const diagnosticosOrcamento = await emitirDiagnosticosArquivosOrcamento({
156
160
  baseProjeto,
157
161
  arquivos: opcoes.arquivosAlvo ?? [],
@@ -201,6 +205,7 @@ export async function verificarDocumentacaoMudanca(opcoes) {
201
205
  intencao: opcoes.intencao,
202
206
  categorias: impacto.categorias,
203
207
  docsLidas,
208
+ leituraRecomendada: impacto.leituraRecomendada,
204
209
  leituraObrigatoria: impacto.leituraObrigatoria.map(compactarDocumentoObrigatorio),
205
210
  docsNaoLidas: docsNaoLidas.map(compactarDocumentoObrigatorio),
206
211
  docsAusentes: impacto.docsAusentes.map(compactarDocumentoObrigatorio),
@@ -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,118 @@ 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 css = `${cabecalho}:root {
145
+ --sema-cor-primaria: ${design.cores.primaria};
146
+ --sema-cor-primaria-hover: ${design.cores.primariaHover};
147
+ --sema-cor-primaria-suave: ${design.cores.primariaSuave};
148
+ --sema-cor-fundo: ${design.cores.fundo};
149
+ --sema-cor-superficie: ${design.cores.superficie};
150
+ --sema-cor-texto: ${design.cores.texto};
151
+ --sema-cor-texto-secundario: ${design.cores.textoSecundario};
152
+ --sema-cor-borda: ${design.cores.borda};
153
+ --sema-cor-borda-foco: ${design.cores.bordaFoco};
154
+ --sema-fonte: ${design.tipografia.fonte};
155
+ --sema-fonte-titulo: ${design.tipografia.fonteTitulo};
156
+ --sema-fonte-mono: ${design.tipografia.fonteMono};
157
+ --sema-raio: ${design.forma.raio};
158
+ --sema-movimento-duracao: ${design.movimentoDuracao};
159
+ }
160
+ `;
161
+ const objetoTokens = JSON.stringify({
162
+ colors: design.cores,
163
+ typography: { ...design.tipografia, scale: design.escala },
164
+ shape: design.forma,
165
+ motion: { duration: design.movimentoDuracao },
166
+ domain: ir.design.dominio ?? null,
167
+ identity: ir.design.identidade ?? null,
168
+ }, null, 2);
169
+ const ts = `// SEMA-GOVERNED — design tokens de ${ir.nome}; edite o bloco design do contrato, nao este arquivo.
170
+ export const designTokens = ${objetoTokens} as const;
171
+ export type DesignTokens = typeof designTokens;
172
+ `;
173
+ const js = `// SEMA-GOVERNED — design tokens de ${ir.nome}; edite o bloco design do contrato, nao este arquivo.
174
+ export const designTokens = ${objetoTokens};
175
+ `;
176
+ const scss = `${cabecalho}$sema-cor-primaria: ${design.cores.primaria};
177
+ $sema-cor-primaria-hover: ${design.cores.primariaHover};
178
+ $sema-cor-fundo: ${design.cores.fundo};
179
+ $sema-cor-superficie: ${design.cores.superficie};
180
+ $sema-cor-texto: ${design.cores.texto};
181
+ $sema-cor-texto-secundario: ${design.cores.textoSecundario};
182
+ $sema-cor-borda: ${design.cores.borda};
183
+ $sema-fonte: ${design.tipografia.fonte};
184
+ $sema-fonte-titulo: ${design.tipografia.fonteTitulo};
185
+ $sema-raio: ${design.forma.raio};
186
+ `;
187
+ const tailwind = `// SEMA-GOVERNED — tema Tailwind derivado do bloco design de ${ir.nome}.
188
+ export const theme = {
189
+ extend: {
190
+ colors: {
191
+ sema: {
192
+ primary: "${design.cores.primaria}",
193
+ "primary-hover": "${design.cores.primariaHover}",
194
+ "primary-soft": "${design.cores.primariaSuave}",
195
+ background: "${design.cores.fundo}",
196
+ surface: "${design.cores.superficie}",
197
+ text: "${design.cores.texto}",
198
+ "text-muted": "${design.cores.textoSecundario}",
199
+ border: "${design.cores.borda}",
200
+ },
201
+ },
202
+ borderRadius: { sema: "${design.forma.raio}" },
203
+ transitionDuration: { sema: "${design.movimentoDuracao}" },
204
+ },
205
+ };
206
+ `;
207
+ 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`;
208
+ return [
209
+ { caminhoRelativo: `design/design-tokens.css`, conteudo: css },
210
+ { caminhoRelativo: `design/tokens.ts`, conteudo: ts },
211
+ { caminhoRelativo: `design/tokens.js`, conteudo: js },
212
+ { caminhoRelativo: `design/_tokens.scss`, conteudo: scss },
213
+ { caminhoRelativo: `design/tailwind.theme.js`, conteudo: tailwind },
214
+ { caminhoRelativo: `design/theme-tui.json`, conteudo: tui },
215
+ ];
216
+ }
138
217
  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 });
218
+ const extras = gerarDesignTokensArquivos(ir, alvo);
219
+ const base = (() => {
220
+ if (alvo === "python") {
221
+ return gerarPython(ir, { framework });
222
+ }
223
+ if (alvo === "dart") {
224
+ return gerarDart(ir);
225
+ }
226
+ if (alvo === "lua") {
227
+ return gerarLua(ir);
228
+ }
229
+ if (alvo === "javascript") {
230
+ return gerarJavaScript(ir);
231
+ }
232
+ if (alvo === "html") {
233
+ return gerarHtml(ir);
234
+ }
235
+ if (alvo === "css") {
236
+ return gerarCss(ir);
237
+ }
238
+ if (alvo === "php") {
239
+ return gerarPhp(ir);
240
+ }
241
+ if (alvo === "dotnet") {
242
+ return gerarDotNet(ir);
243
+ }
244
+ if (alvo === "cpp") {
245
+ return gerarCpp(ir);
246
+ }
247
+ return gerarTypeScript(ir, { framework });
248
+ })();
249
+ return extras.length > 0 ? [...base, ...extras] : base;
167
250
  }
168
251
  export function aplicarEstruturaSaida(arquivos, ir, estrutura) {
169
252
  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
+ }