@semacode/cli 0.8.2
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/LICENSE +22 -0
- package/README.md +52 -0
- package/dist/cpp-symbols.d.ts +10 -0
- package/dist/cpp-symbols.js +71 -0
- package/dist/cpp-symbols.js.map +1 -0
- package/dist/dotnet-http.d.ts +23 -0
- package/dist/dotnet-http.js +301 -0
- package/dist/dotnet-http.js.map +1 -0
- package/dist/drift.d.ts +74 -0
- package/dist/drift.js +878 -0
- package/dist/drift.js.map +1 -0
- package/dist/go-http.d.ts +23 -0
- package/dist/go-http.js +90 -0
- package/dist/go-http.js.map +1 -0
- package/dist/importador.d.ts +29 -0
- package/dist/importador.js +2094 -0
- package/dist/importador.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2150 -0
- package/dist/index.js.map +1 -0
- package/dist/java-http.d.ts +23 -0
- package/dist/java-http.js +204 -0
- package/dist/java-http.js.map +1 -0
- package/dist/projeto.d.ts +48 -0
- package/dist/projeto.js +560 -0
- package/dist/projeto.js.map +1 -0
- package/dist/python-http.d.ts +23 -0
- package/dist/python-http.js +200 -0
- package/dist/python-http.js.map +1 -0
- package/dist/rust-http.d.ts +23 -0
- package/dist/rust-http.js +95 -0
- package/dist/rust-http.js.map +1 -0
- package/dist/tipos.d.ts +3 -0
- package/dist/tipos.js +2 -0
- package/dist/tipos.js.map +1 -0
- package/dist/typescript-http.d.ts +35 -0
- package/dist/typescript-http.js +854 -0
- package/dist/typescript-http.js.map +1 -0
- package/logo.png +0 -0
- package/node_modules/@sema/gerador-dart/dist/index.d.ts +3 -0
- package/node_modules/@sema/gerador-dart/dist/index.js +44 -0
- package/node_modules/@sema/gerador-dart/dist/index.js.map +1 -0
- package/node_modules/@sema/gerador-dart/package.json +7 -0
- package/node_modules/@sema/gerador-python/dist/index.d.ts +6 -0
- package/node_modules/@sema/gerador-python/dist/index.js +510 -0
- package/node_modules/@sema/gerador-python/dist/index.js.map +1 -0
- package/node_modules/@sema/gerador-python/package.json +7 -0
- package/node_modules/@sema/gerador-typescript/dist/index.d.ts +6 -0
- package/node_modules/@sema/gerador-typescript/dist/index.js +646 -0
- package/node_modules/@sema/gerador-typescript/dist/index.js.map +1 -0
- package/node_modules/@sema/gerador-typescript/package.json +7 -0
- package/node_modules/@sema/nucleo/dist/ast/tipos.d.ts +103 -0
- package/node_modules/@sema/nucleo/dist/ast/tipos.js +2 -0
- package/node_modules/@sema/nucleo/dist/ast/tipos.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/diagnosticos/index.d.ts +21 -0
- package/node_modules/@sema/nucleo/dist/diagnosticos/index.js +12 -0
- package/node_modules/@sema/nucleo/dist/diagnosticos/index.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/formatador/index.d.ts +9 -0
- package/node_modules/@sema/nucleo/dist/formatador/index.js +289 -0
- package/node_modules/@sema/nucleo/dist/formatador/index.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/index.d.ts +34 -0
- package/node_modules/@sema/nucleo/dist/index.js +95 -0
- package/node_modules/@sema/nucleo/dist/index.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/ir/conversor.d.ts +5 -0
- package/node_modules/@sema/nucleo/dist/ir/conversor.js +241 -0
- package/node_modules/@sema/nucleo/dist/ir/conversor.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/ir/modelos.d.ts +131 -0
- package/node_modules/@sema/nucleo/dist/ir/modelos.js +2 -0
- package/node_modules/@sema/nucleo/dist/ir/modelos.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/lexer/lexer.d.ts +7 -0
- package/node_modules/@sema/nucleo/dist/lexer/lexer.js +122 -0
- package/node_modules/@sema/nucleo/dist/lexer/lexer.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/lexer/tokens.d.ts +8 -0
- package/node_modules/@sema/nucleo/dist/lexer/tokens.js +30 -0
- package/node_modules/@sema/nucleo/dist/lexer/tokens.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.d.ts +9 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.js +423 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.d.ts +52 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.js +837 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/semantico/estruturas.d.ts +99 -0
- package/node_modules/@sema/nucleo/dist/semantico/estruturas.js +395 -0
- package/node_modules/@sema/nucleo/dist/semantico/estruturas.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/util/arquivos.d.ts +2 -0
- package/node_modules/@sema/nucleo/dist/util/arquivos.js +25 -0
- package/node_modules/@sema/nucleo/dist/util/arquivos.js.map +1 -0
- package/node_modules/@sema/nucleo/package.json +7 -0
- package/node_modules/@sema/padroes/dist/index.d.ts +20 -0
- package/node_modules/@sema/padroes/dist/index.js +79 -0
- package/node_modules/@sema/padroes/dist/index.js.map +1 -0
- package/node_modules/@sema/padroes/package.json +7 -0
- package/package.json +57 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2150 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { compilarCodigo, formatarCodigo, formatarDiagnosticos, lerArquivoTexto, temErros, } from "@sema/nucleo";
|
|
7
|
+
import { descreverEstruturaModulo } from "@sema/padroes";
|
|
8
|
+
import { gerarDart } from "@sema/gerador-dart";
|
|
9
|
+
import { gerarPython } from "@sema/gerador-python";
|
|
10
|
+
import { gerarTypeScript } from "@sema/gerador-typescript";
|
|
11
|
+
import { carregarConfiguracaoProjeto, carregarProjeto, resolverAlvoPadrao, resolverAlvosVerificacao, resolverEstruturaSaidaPadrao, resolverFrameworkPadrao, resolverSaidaPadrao, } from "./projeto.js";
|
|
12
|
+
import { importarProjetoLegado, resumoImportacao } from "./importador.js";
|
|
13
|
+
import { analisarDriftLegado } from "./drift.js";
|
|
14
|
+
const STARTER_IA = `Voce esta trabalhando com Sema, um Protocolo de Governanca de Intencao para IA e backend vivo.
|
|
15
|
+
|
|
16
|
+
Importante:
|
|
17
|
+
- a Sema se apresenta publicamente como protocolo e funciona tecnicamente como linguagem de intencao
|
|
18
|
+
- a Sema modela contratos, estados, fluxos, erros, efeitos e garantias
|
|
19
|
+
- a Sema gera codigo e scaffolding real para TypeScript, Python e Dart
|
|
20
|
+
- a Sema pode servir de base para interfaces graficas elegantes e coerentes
|
|
21
|
+
- a Sema nao gera uma interface completa sozinha no estado atual
|
|
22
|
+
- trate a Sema como cerebro semantico da aplicacao, nao como gerador magico de front-end pronto
|
|
23
|
+
- se a tarefa envolver UI, prefira pedir Sema + React + TypeScript ou Sema + arquitetura de front-end
|
|
24
|
+
- evite pedir HTML unico solto quando a intencao for testar a Sema de verdade
|
|
25
|
+
|
|
26
|
+
Regras:
|
|
27
|
+
- nao invente sintaxe fora da gramatica e dos exemplos oficiais
|
|
28
|
+
- trate \`ir --json\` como fonte de verdade semantica
|
|
29
|
+
- trate \`diagnosticos --json\` como fonte de correcao
|
|
30
|
+
- use \`sema formatar\` como fonte unica de estilo
|
|
31
|
+
- preserve a intencao do contrato
|
|
32
|
+
|
|
33
|
+
Comandos essenciais:
|
|
34
|
+
- contexto completo do modulo: \`sema contexto-ia <arquivo.sema>\`
|
|
35
|
+
- estrutura sintatica: \`sema ast <arquivo.sema> --json\`
|
|
36
|
+
- estrutura semantica: \`sema ir <arquivo.sema> --json\`
|
|
37
|
+
- validacao: \`sema validar <arquivo.sema> --json\`
|
|
38
|
+
- diagnosticos: \`sema diagnosticos <arquivo.sema> --json\`
|
|
39
|
+
- formatacao: \`sema formatar <arquivo.sema>\`
|
|
40
|
+
- geracao de codigo: \`sema compilar <arquivo-ou-pasta> --alvo <typescript|python|dart> --saida <diretorio>\`
|
|
41
|
+
- verificacao final: \`sema verificar <arquivo-ou-pasta> [--json]\`
|
|
42
|
+
|
|
43
|
+
Antes de editar:
|
|
44
|
+
1. leia README, docs de IA e um exemplo oficial parecido
|
|
45
|
+
2. consulte AST e IR do modulo alvo
|
|
46
|
+
|
|
47
|
+
Depois de editar:
|
|
48
|
+
1. rode \`sema formatar\`
|
|
49
|
+
2. rode \`sema validar --json\`
|
|
50
|
+
3. se houver falha, use \`diagnosticos --json\`
|
|
51
|
+
4. se a tarefa pedir codigo derivado, rode \`sema compilar\`
|
|
52
|
+
5. feche com \`sema verificar\` ou \`npm run project:check\`
|
|
53
|
+
|
|
54
|
+
Priorize sempre:
|
|
55
|
+
- exemplos oficiais
|
|
56
|
+
- JSON da CLI
|
|
57
|
+
- consistencia semantica
|
|
58
|
+
|
|
59
|
+
Nao improvise quando faltar contexto.
|
|
60
|
+
`;
|
|
61
|
+
const PROMPT_BASE_IA = `Voce esta trabalhando com Sema, um Protocolo de Governanca de Intencao orientado a contrato, desenhado para facilitar entendimento e operacao por IA.
|
|
62
|
+
|
|
63
|
+
Trate a Sema como camada semantica e linguagem de especificacao executavel. Nao invente sintaxe, palavras-chave ou blocos fora da gramatica e dos exemplos oficiais.
|
|
64
|
+
|
|
65
|
+
Fontes de verdade, em ordem:
|
|
66
|
+
1. README do projeto
|
|
67
|
+
2. gramatica e documentacao de sintaxe da Sema
|
|
68
|
+
3. especificacao semantica da linguagem
|
|
69
|
+
4. exemplos oficiais, com prioridade para o vertical de pagamento
|
|
70
|
+
5. AST, IR e diagnosticos exportados pela CLI em JSON
|
|
71
|
+
|
|
72
|
+
Regras de operacao:
|
|
73
|
+
- preserve o significado semantico
|
|
74
|
+
- use o formatador oficial da Sema como fonte unica de estilo
|
|
75
|
+
- use diagnosticos estruturados como contrato de correcao
|
|
76
|
+
- use a IR como fonte de verdade semantica quando houver duvida
|
|
77
|
+
- nao conclua uma alteracao sem validar e verificar o modulo
|
|
78
|
+
|
|
79
|
+
Antes de editar \`.sema\`, entenda:
|
|
80
|
+
- o module alvo
|
|
81
|
+
- os contratos de task, route, error, effects, guarantees, state e flow
|
|
82
|
+
- os exemplos oficiais relacionados
|
|
83
|
+
|
|
84
|
+
Depois de editar \`.sema\`, execute este fluxo:
|
|
85
|
+
1. formatar
|
|
86
|
+
2. validar
|
|
87
|
+
3. diagnosticar, se houver falha
|
|
88
|
+
4. verificar
|
|
89
|
+
|
|
90
|
+
Se houver conflito entre texto livre e IR/diagnosticos, priorize a IR e os diagnosticos da CLI.
|
|
91
|
+
|
|
92
|
+
Se algo nao estiver claro, siga a forma ja usada nos exemplos oficiais. Nao improvise sem base.
|
|
93
|
+
`;
|
|
94
|
+
const PROMPT_IA_UI = `Atue como Engenheiro de Software Senior e UX/UI Designer de elite.
|
|
95
|
+
|
|
96
|
+
Quero que voce trabalhe com Sema como fonte de verdade semantica do sistema e com React + TypeScript como camada de interface.
|
|
97
|
+
|
|
98
|
+
Entregue obrigatoriamente duas partes integradas:
|
|
99
|
+
1. os arquivos \`.sema\` do dominio
|
|
100
|
+
2. a proposta ou implementacao da interface em React + TypeScript
|
|
101
|
+
|
|
102
|
+
Regras:
|
|
103
|
+
- nao entregue apenas HTML solto em arquivo unico
|
|
104
|
+
- nao trate a Sema como enfeite conceitual
|
|
105
|
+
- a interface deve nascer do contrato semantico definido em Sema
|
|
106
|
+
- use os exemplos oficiais da Sema como referencia de estilo e semantica
|
|
107
|
+
- nao invente sintaxe fora da gramatica suportada
|
|
108
|
+
|
|
109
|
+
A Sema deve modelar, quando fizer sentido:
|
|
110
|
+
- \`module\`
|
|
111
|
+
- \`use\`
|
|
112
|
+
- \`entity\`
|
|
113
|
+
- \`enum\`
|
|
114
|
+
- \`state\`
|
|
115
|
+
- \`task\`
|
|
116
|
+
- \`flow\`
|
|
117
|
+
- \`route\`
|
|
118
|
+
- \`effects\`
|
|
119
|
+
- \`error\`
|
|
120
|
+
- \`guarantees\`
|
|
121
|
+
- \`tests\`
|
|
122
|
+
- \`docs\`
|
|
123
|
+
|
|
124
|
+
A interface deve refletir visualmente:
|
|
125
|
+
- \`state\` como status e progresso observavel
|
|
126
|
+
- \`flow\` como etapas ou orquestracao visivel
|
|
127
|
+
- \`error\` como falhas tratadas com clareza
|
|
128
|
+
- \`effects\` como operacoes relevantes para usuario ou operacao
|
|
129
|
+
- \`guarantees\` como confianca, confirmacao ou consistencia final
|
|
130
|
+
|
|
131
|
+
Estruture a entrega assim:
|
|
132
|
+
1. visao do produto
|
|
133
|
+
2. dominio modelado em Sema
|
|
134
|
+
3. arquitetura de pastas em React + TypeScript
|
|
135
|
+
4. componentes principais
|
|
136
|
+
5. estrategia visual
|
|
137
|
+
6. codigo principal da interface
|
|
138
|
+
7. explicacao curta de como a UI conversa com a semantica da Sema
|
|
139
|
+
|
|
140
|
+
Se a tarefa envolver app visual, a Sema governa o significado e o React renderiza a experiencia. Nao atropele essa separacao.
|
|
141
|
+
`;
|
|
142
|
+
const PROMPT_IA_REACT = `Crie uma solucao com Sema + React + TypeScript.
|
|
143
|
+
|
|
144
|
+
Regras principais:
|
|
145
|
+
- a Sema deve ser a fonte de verdade semantica do dominio
|
|
146
|
+
- React + TypeScript deve ser a camada de interface e experiencia
|
|
147
|
+
- nao entregue HTML unico solto
|
|
148
|
+
- nao trate a Sema como enfeite
|
|
149
|
+
|
|
150
|
+
Entregue obrigatoriamente:
|
|
151
|
+
1. arquivos \`.sema\` do dominio
|
|
152
|
+
2. arquitetura de pastas do frontend
|
|
153
|
+
3. componentes React principais
|
|
154
|
+
4. contratos e tipos derivados da semantica
|
|
155
|
+
5. interface elegante e implementavel
|
|
156
|
+
|
|
157
|
+
A modelagem Sema deve cobrir, quando fizer sentido:
|
|
158
|
+
- \`entity\`
|
|
159
|
+
- \`enum\`
|
|
160
|
+
- \`state\`
|
|
161
|
+
- \`task\`
|
|
162
|
+
- \`flow\`
|
|
163
|
+
- \`route\`
|
|
164
|
+
- \`effects\`
|
|
165
|
+
- \`error\`
|
|
166
|
+
- \`guarantees\`
|
|
167
|
+
- \`tests\`
|
|
168
|
+
|
|
169
|
+
A interface React deve tornar visiveis:
|
|
170
|
+
- estado atual e transicoes relevantes
|
|
171
|
+
- fluxo operacional
|
|
172
|
+
- erros publicos
|
|
173
|
+
- efeitos operacionais importantes
|
|
174
|
+
- garantias ou confirmacoes finais
|
|
175
|
+
|
|
176
|
+
Estruture a entrega assim:
|
|
177
|
+
1. visao do produto
|
|
178
|
+
2. arquivos \`.sema\`
|
|
179
|
+
3. arquitetura React + TypeScript
|
|
180
|
+
4. componentes e telas
|
|
181
|
+
5. codigo principal
|
|
182
|
+
6. explicacao de como a UI deriva da semantica da Sema
|
|
183
|
+
|
|
184
|
+
Se houver duvida, siga os exemplos oficiais e mantenha a separacao:
|
|
185
|
+
- Sema governa o significado
|
|
186
|
+
- React governa a apresentacao
|
|
187
|
+
`;
|
|
188
|
+
const PROMPT_IA_SEMA_PRIMEIRO = `Quero que voce trabalhe no modo "Sema primeiro".
|
|
189
|
+
|
|
190
|
+
Regra principal:
|
|
191
|
+
- modele primeiro o dominio em arquivos \`.sema\`
|
|
192
|
+
- so depois proponha ou gere codigo de aplicacao derivado disso
|
|
193
|
+
|
|
194
|
+
Fluxo obrigatorio:
|
|
195
|
+
1. entender o dominio pedido
|
|
196
|
+
2. modelar o contrato em Sema
|
|
197
|
+
3. validar coerencia entre \`task\`, \`route\`, \`state\`, \`flow\`, \`error\`, \`effects\` e \`guarantees\`
|
|
198
|
+
4. so depois gerar TypeScript, Python, React ou outra camada de implementacao
|
|
199
|
+
|
|
200
|
+
Nao entregue apenas codigo de interface ou codigo imperativo direto sem antes entregar a camada semantica.
|
|
201
|
+
|
|
202
|
+
A modelagem em Sema deve:
|
|
203
|
+
- preservar a intencao do dominio
|
|
204
|
+
- explicitar entradas, saidas, erros, efeitos e garantias
|
|
205
|
+
- usar apenas blocos e sintaxe oficiais
|
|
206
|
+
- incluir testes embutidos quando fizer sentido
|
|
207
|
+
|
|
208
|
+
Se houver interface grafica:
|
|
209
|
+
- entregue a modelagem Sema primeiro
|
|
210
|
+
- depois explique como a interface deve refletir a semantica
|
|
211
|
+
- se gerar UI, use React + TypeScript em vez de HTML unico solto
|
|
212
|
+
|
|
213
|
+
Se houver backend:
|
|
214
|
+
- entregue a modelagem Sema primeiro
|
|
215
|
+
- depois gere a borda publica e a implementacao derivada
|
|
216
|
+
|
|
217
|
+
Nao pule a etapa semantica. A camada \`.sema\` e a ancora principal da solucao.
|
|
218
|
+
`;
|
|
219
|
+
const EXEMPLOS_PROMPT_IA = `Exemplos de prompt oficial para trabalhar com Sema
|
|
220
|
+
|
|
221
|
+
1. Sema primeiro
|
|
222
|
+
|
|
223
|
+
Crie uma solucao seguindo a estrategia "Sema primeiro".
|
|
224
|
+
Entregue primeiro os arquivos \`.sema\` do dominio e so depois a implementacao derivada.
|
|
225
|
+
Nao entregue apenas codigo imperativo.
|
|
226
|
+
Use Sema como fonte de verdade para contratos, estados, erros, efeitos e garantias.
|
|
227
|
+
|
|
228
|
+
2. Sema + React + TypeScript
|
|
229
|
+
|
|
230
|
+
Crie um projeto com Sema + React + TypeScript.
|
|
231
|
+
Entregue:
|
|
232
|
+
- os arquivos \`.sema\` do dominio
|
|
233
|
+
- a arquitetura de pastas do frontend
|
|
234
|
+
- componentes React que reflitam \`state\`, \`flow\`, \`error\`, \`effects\` e \`guarantees\`
|
|
235
|
+
- uma interface elegante e implementavel
|
|
236
|
+
- nao entregue HTML solto em arquivo unico
|
|
237
|
+
|
|
238
|
+
3. Revisar ou corrigir um modulo Sema
|
|
239
|
+
|
|
240
|
+
Revise e corrija um modulo \`.sema\`.
|
|
241
|
+
Antes de editar:
|
|
242
|
+
- leia os exemplos oficiais parecidos
|
|
243
|
+
- consulte AST e IR
|
|
244
|
+
Depois de editar:
|
|
245
|
+
- rode \`sema formatar\`
|
|
246
|
+
- rode \`sema validar --json\`
|
|
247
|
+
- use \`diagnosticos --json\` se houver falha
|
|
248
|
+
- feche com \`sema verificar\`
|
|
249
|
+
|
|
250
|
+
4. Caso de UI sem perder a semantica
|
|
251
|
+
|
|
252
|
+
Quero uma interface premium para este dominio, mas a solucao deve continuar ancorada em Sema.
|
|
253
|
+
Modele primeiro o dominio em \`.sema\`.
|
|
254
|
+
Depois proponha uma interface em React + TypeScript que torne visiveis:
|
|
255
|
+
- estado
|
|
256
|
+
- fluxo
|
|
257
|
+
- erros
|
|
258
|
+
- efeitos
|
|
259
|
+
- garantias
|
|
260
|
+
Nao transforme isso em um \`index.html\` solto.
|
|
261
|
+
|
|
262
|
+
Comandos uteis da CLI para esse fluxo:
|
|
263
|
+
- \`sema starter-ia\`
|
|
264
|
+
- \`sema ajuda-ia\`
|
|
265
|
+
- \`sema prompt-ia\`
|
|
266
|
+
- \`sema prompt-ia-ui\`
|
|
267
|
+
- \`sema prompt-ia-react\`
|
|
268
|
+
- \`sema prompt-ia-sema-primeiro\`
|
|
269
|
+
- \`sema contexto-ia <arquivo.sema>\`
|
|
270
|
+
`;
|
|
271
|
+
const DIRETORIO_CLI_ATUAL = path.dirname(fileURLToPath(import.meta.url));
|
|
272
|
+
function obterArgumentos() {
|
|
273
|
+
const [, , comando, ...resto] = process.argv;
|
|
274
|
+
return { comando: comando, resto };
|
|
275
|
+
}
|
|
276
|
+
function ajuda() {
|
|
277
|
+
return `Sema CLI
|
|
278
|
+
|
|
279
|
+
Comandos:
|
|
280
|
+
sema iniciar
|
|
281
|
+
sema validar <arquivo-ou-pasta>
|
|
282
|
+
sema ast <arquivo.sema>
|
|
283
|
+
sema ir <arquivo.sema>
|
|
284
|
+
sema compilar <arquivo-ou-pasta> --alvo <python|typescript|dart> --saida <diretorio> [--estrutura <flat|modulos|backend>] [--framework <base|nestjs|fastapi>]
|
|
285
|
+
sema gerar <python|typescript|dart> <arquivo-ou-pasta> --saida <diretorio> [--estrutura <flat|modulos|backend>] [--framework <base|nestjs|fastapi>]
|
|
286
|
+
sema testar <arquivo.sema> --alvo <python|typescript|dart> --saida <diretorio-temporario> [--estrutura <flat|modulos|backend>] [--framework <base|nestjs|fastapi>]
|
|
287
|
+
sema diagnosticos <arquivo.sema> [--json]
|
|
288
|
+
sema verificar <arquivo-ou-pasta> [--saida <diretorio-base>] [--json]
|
|
289
|
+
sema inspecionar [arquivo-ou-pasta] [--json]
|
|
290
|
+
sema drift <arquivo-ou-pasta> [--json]
|
|
291
|
+
sema importar <nestjs|fastapi|flask|nextjs|firebase|dotnet|java|go|rust|cpp|typescript|python|dart> <diretorio> [--saida <diretorio>] [--namespace <base>] [--json]
|
|
292
|
+
sema doctor
|
|
293
|
+
sema formatar <arquivo-ou-pasta> [--check] [--json]
|
|
294
|
+
sema ajuda-ia
|
|
295
|
+
sema starter-ia
|
|
296
|
+
sema prompt-ia
|
|
297
|
+
sema prompt-ia-ui
|
|
298
|
+
sema prompt-ia-react
|
|
299
|
+
sema prompt-ia-sema-primeiro
|
|
300
|
+
sema exemplos-prompt-ia
|
|
301
|
+
sema contexto-ia <arquivo.sema> [--saida <diretorio>] [--json]
|
|
302
|
+
`;
|
|
303
|
+
}
|
|
304
|
+
async function carregarModulos(entrada, cwd = process.cwd()) {
|
|
305
|
+
return (await carregarProjeto(entrada, cwd)).modulosSelecionados;
|
|
306
|
+
}
|
|
307
|
+
async function escreverArquivos(base, arquivos) {
|
|
308
|
+
await mkdir(base, { recursive: true });
|
|
309
|
+
for (const arquivo of arquivos) {
|
|
310
|
+
const destino = path.join(base, arquivo.caminhoRelativo);
|
|
311
|
+
await mkdir(path.dirname(destino), { recursive: true });
|
|
312
|
+
await writeFile(destino, arquivo.conteudo, "utf8");
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
function obterOpcao(args, nome, padrao) {
|
|
316
|
+
const indice = args.findIndex((arg) => arg === nome);
|
|
317
|
+
if (indice === -1) {
|
|
318
|
+
return padrao;
|
|
319
|
+
}
|
|
320
|
+
return args[indice + 1] ?? padrao;
|
|
321
|
+
}
|
|
322
|
+
function possuiFlag(args, nome) {
|
|
323
|
+
return args.includes(nome);
|
|
324
|
+
}
|
|
325
|
+
function obterPosicionais(args) {
|
|
326
|
+
const posicionais = [];
|
|
327
|
+
for (let indice = 0; indice < args.length; indice += 1) {
|
|
328
|
+
const atual = args[indice];
|
|
329
|
+
if (atual.startsWith("--")) {
|
|
330
|
+
indice += 1;
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
posicionais.push(atual);
|
|
334
|
+
}
|
|
335
|
+
return posicionais;
|
|
336
|
+
}
|
|
337
|
+
function comandoDisponivel(comando, argumentos = ["--version"]) {
|
|
338
|
+
const execucao = spawnSync(comando, argumentos, { stdio: "ignore", shell: process.platform === "win32" });
|
|
339
|
+
return (execucao.status ?? 1) === 0;
|
|
340
|
+
}
|
|
341
|
+
async function comandoDoctor() {
|
|
342
|
+
const checks = [
|
|
343
|
+
{ nome: "node", ok: comandoDisponivel("node") },
|
|
344
|
+
{ nome: "npm", ok: comandoDisponivel("npm") },
|
|
345
|
+
{ nome: "python", ok: comandoDisponivel("python") || comandoDisponivel("py") },
|
|
346
|
+
{ nome: "dotnet", ok: comandoDisponivel("dotnet") },
|
|
347
|
+
{ nome: "go", ok: comandoDisponivel("go") },
|
|
348
|
+
{ nome: "cargo", ok: comandoDisponivel("cargo") },
|
|
349
|
+
{ nome: "java", ok: comandoDisponivel("java") },
|
|
350
|
+
{ nome: "code", ok: comandoDisponivel("code", ["--version"]) },
|
|
351
|
+
];
|
|
352
|
+
console.log("Sema doctor");
|
|
353
|
+
for (const check of checks) {
|
|
354
|
+
console.log(`- ${check.nome}: ${check.ok ? "ok" : "ausente"}`);
|
|
355
|
+
}
|
|
356
|
+
const obrigatorios = checks.filter((check) => ["node", "npm"].includes(check.nome));
|
|
357
|
+
return obrigatorios.every((check) => check.ok) ? 0 : 1;
|
|
358
|
+
}
|
|
359
|
+
function validarCompatibilidadeFramework(alvo, framework) {
|
|
360
|
+
if (framework === "base") {
|
|
361
|
+
return undefined;
|
|
362
|
+
}
|
|
363
|
+
if (framework === "nestjs" && alvo !== "typescript") {
|
|
364
|
+
return `Framework "${framework}" so pode ser usado com o alvo typescript.`;
|
|
365
|
+
}
|
|
366
|
+
if (framework === "fastapi" && alvo !== "python") {
|
|
367
|
+
return `Framework "${framework}" so pode ser usado com o alvo python.`;
|
|
368
|
+
}
|
|
369
|
+
if (alvo === "dart") {
|
|
370
|
+
return `Framework "${framework}" nao e suportado para o alvo dart.`;
|
|
371
|
+
}
|
|
372
|
+
return undefined;
|
|
373
|
+
}
|
|
374
|
+
function normalizarFonteImportacao(valor) {
|
|
375
|
+
if (!valor) {
|
|
376
|
+
return undefined;
|
|
377
|
+
}
|
|
378
|
+
if (valor === "ts") {
|
|
379
|
+
return "typescript";
|
|
380
|
+
}
|
|
381
|
+
if (valor === "py") {
|
|
382
|
+
return "python";
|
|
383
|
+
}
|
|
384
|
+
if (valor === "nest") {
|
|
385
|
+
return "nestjs";
|
|
386
|
+
}
|
|
387
|
+
if (valor === "api") {
|
|
388
|
+
return "fastapi";
|
|
389
|
+
}
|
|
390
|
+
if (valor === "next") {
|
|
391
|
+
return "nextjs";
|
|
392
|
+
}
|
|
393
|
+
if (valor === "fb") {
|
|
394
|
+
return "firebase";
|
|
395
|
+
}
|
|
396
|
+
if (valor === "csharp" || valor === "cs" || valor === "dotnet") {
|
|
397
|
+
return "dotnet";
|
|
398
|
+
}
|
|
399
|
+
if (valor === "java") {
|
|
400
|
+
return "java";
|
|
401
|
+
}
|
|
402
|
+
if (valor === "go" || valor === "golang") {
|
|
403
|
+
return "go";
|
|
404
|
+
}
|
|
405
|
+
if (valor === "rust" || valor === "rs") {
|
|
406
|
+
return "rust";
|
|
407
|
+
}
|
|
408
|
+
if (valor === "cpp" || valor === "cxx" || valor === "cc" || valor === "c++") {
|
|
409
|
+
return "cpp";
|
|
410
|
+
}
|
|
411
|
+
if (valor === "nestjs"
|
|
412
|
+
|| valor === "fastapi"
|
|
413
|
+
|| valor === "flask"
|
|
414
|
+
|| valor === "nextjs"
|
|
415
|
+
|| valor === "firebase"
|
|
416
|
+
|| valor === "dotnet"
|
|
417
|
+
|| valor === "java"
|
|
418
|
+
|| valor === "go"
|
|
419
|
+
|| valor === "rust"
|
|
420
|
+
|| valor === "cpp"
|
|
421
|
+
|| valor === "typescript"
|
|
422
|
+
|| valor === "python"
|
|
423
|
+
|| valor === "dart") {
|
|
424
|
+
return valor;
|
|
425
|
+
}
|
|
426
|
+
return undefined;
|
|
427
|
+
}
|
|
428
|
+
function normalizarTemplateIniciar(valor) {
|
|
429
|
+
if (valor === "nestjs"
|
|
430
|
+
|| valor === "fastapi"
|
|
431
|
+
|| valor === "nextjs-api"
|
|
432
|
+
|| valor === "node-firebase-worker"
|
|
433
|
+
|| valor === "aspnet-api"
|
|
434
|
+
|| valor === "springboot-api"
|
|
435
|
+
|| valor === "go-http-api"
|
|
436
|
+
|| valor === "rust-axum-api"
|
|
437
|
+
|| valor === "cpp-service-bridge") {
|
|
438
|
+
return valor;
|
|
439
|
+
}
|
|
440
|
+
return "base";
|
|
441
|
+
}
|
|
442
|
+
function garantirIr(resultado, caminho) {
|
|
443
|
+
if (!resultado.ir) {
|
|
444
|
+
throw new Error(`Nao foi possivel gerar IR para ${caminho}.\n${formatarDiagnosticos(resultado.diagnosticos)}`);
|
|
445
|
+
}
|
|
446
|
+
return resultado.ir;
|
|
447
|
+
}
|
|
448
|
+
function gerarArquivosPorAlvo(ir, alvo, framework) {
|
|
449
|
+
if (alvo === "python") {
|
|
450
|
+
return gerarPython(ir, { framework });
|
|
451
|
+
}
|
|
452
|
+
if (alvo === "dart") {
|
|
453
|
+
return gerarDart(ir);
|
|
454
|
+
}
|
|
455
|
+
return gerarTypeScript(ir, { framework });
|
|
456
|
+
}
|
|
457
|
+
function aplicarEstruturaSaida(arquivos, ir, estrutura) {
|
|
458
|
+
if (estrutura === "flat" || estrutura === "backend") {
|
|
459
|
+
return arquivos;
|
|
460
|
+
}
|
|
461
|
+
const estruturaModulo = descreverEstruturaModulo(ir.nome);
|
|
462
|
+
const pastaModulo = estruturaModulo.contextoSegmentos.join(path.sep);
|
|
463
|
+
const nomeArquivo = estruturaModulo.nomeArquivo;
|
|
464
|
+
const nomeBaseAntigo = estruturaModulo.nomeBase;
|
|
465
|
+
return arquivos.map((arquivo) => {
|
|
466
|
+
const basename = path.basename(arquivo.caminhoRelativo);
|
|
467
|
+
let novoBasename = basename;
|
|
468
|
+
let conteudo = arquivo.conteudo;
|
|
469
|
+
if (basename === `${nomeBaseAntigo}.ts`) {
|
|
470
|
+
novoBasename = `${nomeArquivo}.ts`;
|
|
471
|
+
}
|
|
472
|
+
else if (basename === `${nomeBaseAntigo}.test.ts`) {
|
|
473
|
+
novoBasename = `${nomeArquivo}.test.ts`;
|
|
474
|
+
conteudo = conteudo.replace(`./${nomeBaseAntigo}.ts`, `./${nomeArquivo}.ts`);
|
|
475
|
+
}
|
|
476
|
+
else if (basename === `${nomeBaseAntigo}.py`) {
|
|
477
|
+
novoBasename = `${nomeArquivo}.py`;
|
|
478
|
+
}
|
|
479
|
+
else if (basename === `test_${nomeBaseAntigo}.py`) {
|
|
480
|
+
novoBasename = `test_${nomeArquivo}.py`;
|
|
481
|
+
conteudo = conteudo.replace(`from ${nomeBaseAntigo} import *`, `from ${nomeArquivo} import *`);
|
|
482
|
+
}
|
|
483
|
+
else if (basename === `${nomeBaseAntigo}.dart`) {
|
|
484
|
+
novoBasename = `${nomeArquivo}.dart`;
|
|
485
|
+
}
|
|
486
|
+
return {
|
|
487
|
+
caminhoRelativo: pastaModulo ? path.join(pastaModulo, novoBasename) : novoBasename,
|
|
488
|
+
conteudo,
|
|
489
|
+
};
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
function contarCasosDeTesteGerados(alvo, arquivos) {
|
|
493
|
+
if (alvo === "dart") {
|
|
494
|
+
return 0;
|
|
495
|
+
}
|
|
496
|
+
if (alvo === "typescript") {
|
|
497
|
+
const arquivoTeste = arquivos.find((item) => item.caminhoRelativo.endsWith(".test.ts"));
|
|
498
|
+
if (!arquivoTeste) {
|
|
499
|
+
return 0;
|
|
500
|
+
}
|
|
501
|
+
return (arquivoTeste.conteudo.match(/\btest\(/g) ?? []).length;
|
|
502
|
+
}
|
|
503
|
+
const arquivoTeste = arquivos.find((item) => path.basename(item.caminhoRelativo).startsWith("test_"));
|
|
504
|
+
if (!arquivoTeste) {
|
|
505
|
+
return 0;
|
|
506
|
+
}
|
|
507
|
+
return (arquivoTeste.conteudo.match(/\bdef test_/g) ?? []).length;
|
|
508
|
+
}
|
|
509
|
+
function executarTestesGerados(alvo, baseSaida, arquivos, silencioso = false) {
|
|
510
|
+
const quantidadeTestes = contarCasosDeTesteGerados(alvo, arquivos);
|
|
511
|
+
if (quantidadeTestes === 0) {
|
|
512
|
+
if (!silencioso) {
|
|
513
|
+
console.log(`Nenhum teste ${alvo === "typescript" ? "TypeScript" : "Python"} foi gerado.`);
|
|
514
|
+
}
|
|
515
|
+
return { codigoSaida: 0, quantidadeTestes, saidaPadrao: "", saidaErro: "" };
|
|
516
|
+
}
|
|
517
|
+
if (alvo === "typescript") {
|
|
518
|
+
const arquivoTeste = arquivos.find((item) => item.caminhoRelativo.endsWith(".test.ts"))?.caminhoRelativo;
|
|
519
|
+
if (!arquivoTeste) {
|
|
520
|
+
if (!silencioso) {
|
|
521
|
+
console.log("Nenhum teste TypeScript foi gerado.");
|
|
522
|
+
}
|
|
523
|
+
return { codigoSaida: 0, quantidadeTestes, saidaPadrao: "", saidaErro: "" };
|
|
524
|
+
}
|
|
525
|
+
const execucao = spawnSync("node", ["--import", "tsx", path.join(baseSaida, arquivoTeste)], {
|
|
526
|
+
stdio: silencioso ? "pipe" : "inherit",
|
|
527
|
+
encoding: silencioso ? "utf8" : undefined,
|
|
528
|
+
});
|
|
529
|
+
return {
|
|
530
|
+
codigoSaida: execucao.status ?? 1,
|
|
531
|
+
quantidadeTestes,
|
|
532
|
+
saidaPadrao: typeof execucao.stdout === "string" ? execucao.stdout : "",
|
|
533
|
+
saidaErro: typeof execucao.stderr === "string" ? execucao.stderr : "",
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
const arquivoTeste = arquivos.find((item) => path.basename(item.caminhoRelativo).startsWith("test_"))?.caminhoRelativo;
|
|
537
|
+
if (!arquivoTeste) {
|
|
538
|
+
if (!silencioso) {
|
|
539
|
+
console.log("Nenhum teste Python foi gerado.");
|
|
540
|
+
}
|
|
541
|
+
return { codigoSaida: 0, quantidadeTestes, saidaPadrao: "", saidaErro: "" };
|
|
542
|
+
}
|
|
543
|
+
const execucao = spawnSync("pytest", [arquivoTeste], {
|
|
544
|
+
stdio: silencioso ? "pipe" : "inherit",
|
|
545
|
+
cwd: baseSaida,
|
|
546
|
+
encoding: silencioso ? "utf8" : undefined,
|
|
547
|
+
});
|
|
548
|
+
return {
|
|
549
|
+
codigoSaida: execucao.status ?? 1,
|
|
550
|
+
quantidadeTestes,
|
|
551
|
+
saidaPadrao: typeof execucao.stdout === "string" ? execucao.stdout : "",
|
|
552
|
+
saidaErro: typeof execucao.stderr === "string" ? execucao.stderr : "",
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
function nomeSubpastaModulo(caminhoArquivo) {
|
|
556
|
+
return path.basename(caminhoArquivo, ".sema");
|
|
557
|
+
}
|
|
558
|
+
async function caminhoExiste(caminhoAlvo) {
|
|
559
|
+
try {
|
|
560
|
+
await stat(caminhoAlvo);
|
|
561
|
+
return true;
|
|
562
|
+
}
|
|
563
|
+
catch {
|
|
564
|
+
return false;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
async function descobrirDocsIa() {
|
|
568
|
+
const candidatosBase = [];
|
|
569
|
+
let atual = DIRETORIO_CLI_ATUAL;
|
|
570
|
+
for (let tentativas = 0; tentativas < 8; tentativas += 1) {
|
|
571
|
+
candidatosBase.push(atual);
|
|
572
|
+
const proximo = path.dirname(atual);
|
|
573
|
+
if (proximo === atual) {
|
|
574
|
+
break;
|
|
575
|
+
}
|
|
576
|
+
atual = proximo;
|
|
577
|
+
}
|
|
578
|
+
const nomesDocs = [
|
|
579
|
+
"AGENT_STARTER.md",
|
|
580
|
+
"como-ensinar-a-sema-para-ia.md",
|
|
581
|
+
"prompt-base-ia-sema.md",
|
|
582
|
+
"fluxo-pratico-ia-sema.md",
|
|
583
|
+
];
|
|
584
|
+
for (const base of candidatosBase) {
|
|
585
|
+
const documentos = [];
|
|
586
|
+
let encontrouTodos = true;
|
|
587
|
+
for (const nome of nomesDocs) {
|
|
588
|
+
const caminhoDoc = path.join(base, "docs", nome);
|
|
589
|
+
if (!(await caminhoExiste(caminhoDoc))) {
|
|
590
|
+
encontrouTodos = false;
|
|
591
|
+
break;
|
|
592
|
+
}
|
|
593
|
+
documentos.push({ nome, caminho: caminhoDoc });
|
|
594
|
+
}
|
|
595
|
+
if (encontrouTodos) {
|
|
596
|
+
return {
|
|
597
|
+
origemInstalacao: DIRETORIO_CLI_ATUAL,
|
|
598
|
+
baseDetectada: base,
|
|
599
|
+
documentos,
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
return {
|
|
604
|
+
origemInstalacao: DIRETORIO_CLI_ATUAL,
|
|
605
|
+
baseDetectada: null,
|
|
606
|
+
documentos: [],
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
function renderizarCabecalhoDocsIa(descoberta) {
|
|
610
|
+
const linhas = [
|
|
611
|
+
"Informacoes da instalacao atual",
|
|
612
|
+
`- Origem da instalacao: ${descoberta.origemInstalacao}`,
|
|
613
|
+
`- Base detectada: ${descoberta.baseDetectada ?? "nao encontrada"}`,
|
|
614
|
+
];
|
|
615
|
+
if (descoberta.documentos.length > 0) {
|
|
616
|
+
linhas.push("- Documentos locais encontrados:");
|
|
617
|
+
for (const documento of descoberta.documentos) {
|
|
618
|
+
linhas.push(` - ${documento.nome}: ${documento.caminho}`);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
else {
|
|
622
|
+
linhas.push("- Documentos locais encontrados: nenhum");
|
|
623
|
+
linhas.push(" - Esta instalacao da CLI nao conseguiu localizar a pasta docs ao redor do pacote atual.");
|
|
624
|
+
}
|
|
625
|
+
return linhas.join("\n");
|
|
626
|
+
}
|
|
627
|
+
function falharContextoIa(mensagem) {
|
|
628
|
+
throw new Error(mensagem);
|
|
629
|
+
}
|
|
630
|
+
function garantirArquivoSema(caminhoArquivo) {
|
|
631
|
+
if (!caminhoArquivo.toLowerCase().endsWith(".sema")) {
|
|
632
|
+
falharContextoIa("O caminho informado precisa apontar para um arquivo .sema.");
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
function resumirDriftPorModulo(modulo, caminho, resultadoDrift) {
|
|
636
|
+
const tasks = modulo
|
|
637
|
+
? resultadoDrift.tasks.filter((task) => task.modulo === modulo)
|
|
638
|
+
: [];
|
|
639
|
+
const implsValidos = modulo
|
|
640
|
+
? resultadoDrift.impls_validos.filter((impl) => impl.modulo === modulo)
|
|
641
|
+
: [];
|
|
642
|
+
const implsQuebrados = modulo
|
|
643
|
+
? resultadoDrift.impls_quebrados.filter((impl) => impl.modulo === modulo)
|
|
644
|
+
: [];
|
|
645
|
+
const rotasDivergentes = modulo
|
|
646
|
+
? resultadoDrift.rotas_divergentes.filter((rota) => rota.modulo === modulo)
|
|
647
|
+
: [];
|
|
648
|
+
const recursosValidos = modulo
|
|
649
|
+
? resultadoDrift.recursos_validos.filter((recurso) => recurso.modulo === modulo)
|
|
650
|
+
: [];
|
|
651
|
+
const recursosDivergentes = modulo
|
|
652
|
+
? resultadoDrift.recursos_divergentes.filter((recurso) => recurso.modulo === modulo)
|
|
653
|
+
: [];
|
|
654
|
+
return {
|
|
655
|
+
caminho,
|
|
656
|
+
modulo,
|
|
657
|
+
implsValidos: implsValidos.length,
|
|
658
|
+
implsQuebrados: implsQuebrados.length,
|
|
659
|
+
recursosValidos: recursosValidos.length,
|
|
660
|
+
recursosDivergentesCount: recursosDivergentes.length,
|
|
661
|
+
tasksSemImplementacao: tasks.filter((task) => task.semImplementacao).length,
|
|
662
|
+
arquivosRelacionados: [...new Set([
|
|
663
|
+
...tasks.flatMap((task) => task.arquivosReferenciados),
|
|
664
|
+
...implsValidos.map((impl) => impl.arquivo).filter((item) => Boolean(item)),
|
|
665
|
+
...implsQuebrados.flatMap((impl) => impl.candidatos?.map((candidato) => candidato.arquivo) ?? []),
|
|
666
|
+
...recursosValidos.map((recurso) => recurso.arquivo).filter(Boolean),
|
|
667
|
+
...recursosDivergentes.map((recurso) => recurso.arquivo).filter(Boolean),
|
|
668
|
+
])].sort((a, b) => a.localeCompare(b, "pt-BR")),
|
|
669
|
+
tasks,
|
|
670
|
+
rotasDivergentes,
|
|
671
|
+
recursosDivergentes,
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
async function gerarContextoIa(arquivoEntrada, pastaSaidaOpcional) {
|
|
675
|
+
const arquivo = path.resolve(arquivoEntrada);
|
|
676
|
+
garantirArquivoSema(arquivo);
|
|
677
|
+
const pastaBase = pastaSaidaOpcional
|
|
678
|
+
? path.resolve(pastaSaidaOpcional)
|
|
679
|
+
: path.resolve(process.cwd(), ".tmp", "contexto-ia", path.basename(arquivo, ".sema"));
|
|
680
|
+
await mkdir(pastaBase, { recursive: true });
|
|
681
|
+
const contextoProjeto = await carregarProjeto(arquivo, process.cwd());
|
|
682
|
+
const resultadoModulo = contextoProjeto.modulosSelecionados.find((item) => path.resolve(item.caminho) === arquivo)?.resultado;
|
|
683
|
+
if (!resultadoModulo) {
|
|
684
|
+
falharContextoIa(`Nao foi possivel encontrar o modulo correspondente ao arquivo ${arquivo}.`);
|
|
685
|
+
}
|
|
686
|
+
const sucesso = !temErros(resultadoModulo.diagnosticos);
|
|
687
|
+
const modulo = resultadoModulo.modulo?.nome ?? path.basename(arquivo, ".sema");
|
|
688
|
+
const resultadoDrift = await analisarDriftLegado(contextoProjeto);
|
|
689
|
+
const drift = {
|
|
690
|
+
comando: "drift",
|
|
691
|
+
caminho: arquivo,
|
|
692
|
+
modulo: resultadoModulo.modulo?.nome ?? null,
|
|
693
|
+
sucesso: resultadoDrift.sucesso,
|
|
694
|
+
resumo: resumirDriftPorModulo(resultadoModulo.modulo?.nome ?? null, arquivo, resultadoDrift),
|
|
695
|
+
drift: resultadoDrift,
|
|
696
|
+
};
|
|
697
|
+
const validar = {
|
|
698
|
+
comando: "validar",
|
|
699
|
+
sucesso,
|
|
700
|
+
resultados: [
|
|
701
|
+
{
|
|
702
|
+
caminho: arquivo,
|
|
703
|
+
modulo: resultadoModulo.modulo?.nome ?? null,
|
|
704
|
+
sucesso,
|
|
705
|
+
diagnosticos: resultadoModulo.diagnosticos,
|
|
706
|
+
},
|
|
707
|
+
],
|
|
708
|
+
};
|
|
709
|
+
const diagnosticos = {
|
|
710
|
+
comando: "diagnosticos",
|
|
711
|
+
caminho: arquivo,
|
|
712
|
+
modulo: resultadoModulo.modulo?.nome ?? null,
|
|
713
|
+
diagnosticos: resultadoModulo.diagnosticos,
|
|
714
|
+
};
|
|
715
|
+
const ast = {
|
|
716
|
+
comando: "ast",
|
|
717
|
+
caminho: arquivo,
|
|
718
|
+
modulo: resultadoModulo.modulo?.nome ?? null,
|
|
719
|
+
sucesso,
|
|
720
|
+
diagnosticos: resultadoModulo.diagnosticos,
|
|
721
|
+
ast: resultadoModulo.modulo ?? null,
|
|
722
|
+
};
|
|
723
|
+
const ir = {
|
|
724
|
+
comando: "ir",
|
|
725
|
+
caminho: arquivo,
|
|
726
|
+
modulo: resultadoModulo.modulo?.nome ?? null,
|
|
727
|
+
sucesso,
|
|
728
|
+
diagnosticos: resultadoModulo.diagnosticos,
|
|
729
|
+
ir: resultadoModulo.ir ?? null,
|
|
730
|
+
};
|
|
731
|
+
await writeFile(path.join(pastaBase, "validar.json"), `${JSON.stringify(validar, null, 2)}\n`, "utf8");
|
|
732
|
+
await writeFile(path.join(pastaBase, "diagnosticos.json"), `${JSON.stringify(diagnosticos, null, 2)}\n`, "utf8");
|
|
733
|
+
await writeFile(path.join(pastaBase, "ast.json"), `${JSON.stringify(ast, null, 2)}\n`, "utf8");
|
|
734
|
+
await writeFile(path.join(pastaBase, "ir.json"), `${JSON.stringify(ir, null, 2)}\n`, "utf8");
|
|
735
|
+
await writeFile(path.join(pastaBase, "drift.json"), `${JSON.stringify(drift, null, 2)}\n`, "utf8");
|
|
736
|
+
const resumo = `# Contexto de IA para ${modulo}
|
|
737
|
+
|
|
738
|
+
- Arquivo alvo: \`${arquivo}\`
|
|
739
|
+
- Modulo: \`${modulo}\`
|
|
740
|
+
- Sucesso em validar: \`${sucesso}\`
|
|
741
|
+
- Quantidade de diagnosticos: \`${resultadoModulo.diagnosticos.length}\`
|
|
742
|
+
|
|
743
|
+
## Arquivos gerados neste pacote
|
|
744
|
+
|
|
745
|
+
- \`validar.json\`
|
|
746
|
+
- \`diagnosticos.json\`
|
|
747
|
+
- \`ast.json\`
|
|
748
|
+
- \`ir.json\`
|
|
749
|
+
- \`drift.json\`
|
|
750
|
+
|
|
751
|
+
## Fluxo recomendado para o agente
|
|
752
|
+
|
|
753
|
+
1. Ler \`ast.json\` para entender a forma escrita.
|
|
754
|
+
2. Ler \`ir.json\` para entender a forma semantica resolvida.
|
|
755
|
+
3. Ler \`drift.json\` para ver quais arquivos e simbolos vivos sustentam a implementacao.
|
|
756
|
+
4. Ler \`diagnosticos.json\` se houver falha ou aviso relevante.
|
|
757
|
+
5. Editar o arquivo \`.sema\`.
|
|
758
|
+
6. Rodar \`sema formatar "${arquivo}"\`.
|
|
759
|
+
7. Rodar \`sema validar "${arquivo}" --json\`.
|
|
760
|
+
8. Fechar com \`sema verificar exemplos --json --saida ./.tmp/verificacao-ia\` ou \`npm run project:check\`.
|
|
761
|
+
|
|
762
|
+
## Textos base para onboarding do agente
|
|
763
|
+
|
|
764
|
+
- \`sema starter-ia\`
|
|
765
|
+
- \`sema prompt-ia\`
|
|
766
|
+
`;
|
|
767
|
+
await writeFile(path.join(pastaBase, "README.md"), resumo, "utf8");
|
|
768
|
+
return {
|
|
769
|
+
sucesso: true,
|
|
770
|
+
arquivo,
|
|
771
|
+
modulo,
|
|
772
|
+
pastaSaida: pastaBase,
|
|
773
|
+
artefatos: ["validar.json", "diagnosticos.json", "ast.json", "ir.json", "drift.json", "README.md"],
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
async function comandoIniciar(cwd, template) {
|
|
777
|
+
const arquivosBase = [
|
|
778
|
+
{
|
|
779
|
+
caminhoRelativo: "contratos/pedidos.sema",
|
|
780
|
+
conteudo: `module app.pedidos {
|
|
781
|
+
entity Pedido {
|
|
782
|
+
fields {
|
|
783
|
+
id: Id
|
|
784
|
+
status: Texto
|
|
785
|
+
total: Decimal
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
task criar_pedido {
|
|
790
|
+
input {
|
|
791
|
+
cliente_id: Id required
|
|
792
|
+
total: Decimal required
|
|
793
|
+
}
|
|
794
|
+
output {
|
|
795
|
+
pedido_id: Id
|
|
796
|
+
status: Texto
|
|
797
|
+
}
|
|
798
|
+
rules {
|
|
799
|
+
total > 0
|
|
800
|
+
}
|
|
801
|
+
effects {
|
|
802
|
+
persistencia Pedido criticidade=alta
|
|
803
|
+
auditoria pedidos
|
|
804
|
+
}
|
|
805
|
+
guarantees {
|
|
806
|
+
pedido_id existe
|
|
807
|
+
status existe
|
|
808
|
+
}
|
|
809
|
+
tests {
|
|
810
|
+
caso "pedido valido" {
|
|
811
|
+
given {
|
|
812
|
+
cliente_id: "cli-1"
|
|
813
|
+
total: 10
|
|
814
|
+
}
|
|
815
|
+
expect {
|
|
816
|
+
sucesso: verdadeiro
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
route criar_pedido_publico {
|
|
823
|
+
metodo: POST
|
|
824
|
+
caminho: /pedidos
|
|
825
|
+
task: criar_pedido
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
`,
|
|
829
|
+
},
|
|
830
|
+
];
|
|
831
|
+
let arquivos = arquivosBase;
|
|
832
|
+
if (template === "nestjs") {
|
|
833
|
+
arquivos = [
|
|
834
|
+
{
|
|
835
|
+
caminhoRelativo: "sema.config.json",
|
|
836
|
+
conteudo: `{
|
|
837
|
+
"origens": ["./contratos"],
|
|
838
|
+
"saida": "./generated/nestjs",
|
|
839
|
+
"alvos": ["typescript"],
|
|
840
|
+
"alvoPadrao": "typescript",
|
|
841
|
+
"estruturaSaida": "backend",
|
|
842
|
+
"framework": "nestjs",
|
|
843
|
+
"modoEstrito": true,
|
|
844
|
+
"diretoriosSaidaPorAlvo": {
|
|
845
|
+
"typescript": "./generated/nestjs"
|
|
846
|
+
},
|
|
847
|
+
"convencoesGeracaoPorProjeto": "backend"
|
|
848
|
+
}
|
|
849
|
+
`,
|
|
850
|
+
},
|
|
851
|
+
{ caminhoRelativo: "src/.gitkeep", conteudo: "" },
|
|
852
|
+
{ caminhoRelativo: "test/.gitkeep", conteudo: "" },
|
|
853
|
+
...arquivosBase,
|
|
854
|
+
];
|
|
855
|
+
}
|
|
856
|
+
else if (template === "fastapi") {
|
|
857
|
+
arquivos = [
|
|
858
|
+
{
|
|
859
|
+
caminhoRelativo: "sema.config.json",
|
|
860
|
+
conteudo: `{
|
|
861
|
+
"origens": ["./contratos"],
|
|
862
|
+
"saida": "./generated/fastapi",
|
|
863
|
+
"alvos": ["python"],
|
|
864
|
+
"alvoPadrao": "python",
|
|
865
|
+
"estruturaSaida": "backend",
|
|
866
|
+
"framework": "fastapi",
|
|
867
|
+
"modoEstrito": true,
|
|
868
|
+
"diretoriosSaidaPorAlvo": {
|
|
869
|
+
"python": "./generated/fastapi"
|
|
870
|
+
},
|
|
871
|
+
"convencoesGeracaoPorProjeto": "backend"
|
|
872
|
+
}
|
|
873
|
+
`,
|
|
874
|
+
},
|
|
875
|
+
{ caminhoRelativo: "app/.gitkeep", conteudo: "" },
|
|
876
|
+
{ caminhoRelativo: "tests/.gitkeep", conteudo: "" },
|
|
877
|
+
...arquivosBase,
|
|
878
|
+
];
|
|
879
|
+
}
|
|
880
|
+
else if (template === "nextjs-api") {
|
|
881
|
+
arquivos = [
|
|
882
|
+
{
|
|
883
|
+
caminhoRelativo: "sema.config.json",
|
|
884
|
+
conteudo: `{
|
|
885
|
+
"origens": ["./contratos"],
|
|
886
|
+
"saida": "./generated",
|
|
887
|
+
"alvos": ["typescript"],
|
|
888
|
+
"alvoPadrao": "typescript",
|
|
889
|
+
"estruturaSaida": "modulos",
|
|
890
|
+
"framework": "base",
|
|
891
|
+
"modoEstrito": true,
|
|
892
|
+
"diretoriosCodigo": ["./src"],
|
|
893
|
+
"fontesLegado": ["nextjs", "typescript"],
|
|
894
|
+
"diretoriosSaidaPorAlvo": {
|
|
895
|
+
"typescript": "./generated/typescript"
|
|
896
|
+
},
|
|
897
|
+
"convencoesGeracaoPorProjeto": "base"
|
|
898
|
+
}
|
|
899
|
+
`,
|
|
900
|
+
},
|
|
901
|
+
{
|
|
902
|
+
caminhoRelativo: "contratos/health.sema",
|
|
903
|
+
conteudo: `module app.health {
|
|
904
|
+
task get_api_health {
|
|
905
|
+
output {
|
|
906
|
+
status: Texto
|
|
907
|
+
runtime: Texto
|
|
908
|
+
}
|
|
909
|
+
impl {
|
|
910
|
+
ts: src.app.api.health.route.GET
|
|
911
|
+
}
|
|
912
|
+
guarantees {
|
|
913
|
+
status existe
|
|
914
|
+
runtime existe
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
route get_api_health_publico {
|
|
919
|
+
metodo: GET
|
|
920
|
+
caminho: /api/health
|
|
921
|
+
task: get_api_health
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
`,
|
|
925
|
+
},
|
|
926
|
+
{
|
|
927
|
+
caminhoRelativo: "src/app/api/health/route.ts",
|
|
928
|
+
conteudo: `export async function GET() {
|
|
929
|
+
return Response.json({
|
|
930
|
+
status: "ok",
|
|
931
|
+
runtime: "nextjs",
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
`,
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
caminhoRelativo: "README.md",
|
|
938
|
+
conteudo: `# Starter Next.js API + Sema
|
|
939
|
+
|
|
940
|
+
- Contratos em \`contratos/\`
|
|
941
|
+
- Handlers App Router em \`src/app/api/\`
|
|
942
|
+
- Rota de exemplo validada por \`drift\`
|
|
943
|
+
`,
|
|
944
|
+
},
|
|
945
|
+
];
|
|
946
|
+
}
|
|
947
|
+
else if (template === "node-firebase-worker") {
|
|
948
|
+
arquivos = [
|
|
949
|
+
{
|
|
950
|
+
caminhoRelativo: "sema.config.json",
|
|
951
|
+
conteudo: `{
|
|
952
|
+
"origens": ["./contratos"],
|
|
953
|
+
"saida": "./generated",
|
|
954
|
+
"alvos": ["typescript"],
|
|
955
|
+
"alvoPadrao": "typescript",
|
|
956
|
+
"estruturaSaida": "modulos",
|
|
957
|
+
"framework": "base",
|
|
958
|
+
"modoEstrito": true,
|
|
959
|
+
"diretoriosCodigo": ["./src"],
|
|
960
|
+
"fontesLegado": ["firebase", "typescript"],
|
|
961
|
+
"diretoriosSaidaPorAlvo": {
|
|
962
|
+
"typescript": "./generated/typescript"
|
|
963
|
+
},
|
|
964
|
+
"convencoesGeracaoPorProjeto": "base"
|
|
965
|
+
}
|
|
966
|
+
`,
|
|
967
|
+
},
|
|
968
|
+
{
|
|
969
|
+
caminhoRelativo: "contratos/worker_runtime.sema",
|
|
970
|
+
conteudo: `module worker.runtime {
|
|
971
|
+
task publicar_payload_health {
|
|
972
|
+
output {
|
|
973
|
+
status: Texto
|
|
974
|
+
timestamp: Texto
|
|
975
|
+
}
|
|
976
|
+
effects {
|
|
977
|
+
evento payload_health criticidade = alta
|
|
978
|
+
}
|
|
979
|
+
impl {
|
|
980
|
+
ts: src.sema_contract_bridge.semaWorkerHealthPayload
|
|
981
|
+
}
|
|
982
|
+
guarantees {
|
|
983
|
+
status existe
|
|
984
|
+
timestamp existe
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
task inventariar_colecoes {
|
|
989
|
+
output {
|
|
990
|
+
collections: Json
|
|
991
|
+
}
|
|
992
|
+
effects {
|
|
993
|
+
consulta runtime criticidade = baixa
|
|
994
|
+
}
|
|
995
|
+
impl {
|
|
996
|
+
ts: src.sema_contract_bridge.semaCollectionNames
|
|
997
|
+
}
|
|
998
|
+
guarantees {
|
|
999
|
+
collections existe
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
route get_health_worker {
|
|
1004
|
+
metodo: GET
|
|
1005
|
+
caminho: /health
|
|
1006
|
+
task: publicar_payload_health
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
`,
|
|
1010
|
+
},
|
|
1011
|
+
{
|
|
1012
|
+
caminhoRelativo: "src/config/collections.ts",
|
|
1013
|
+
conteudo: `export const COLLECTIONS = {
|
|
1014
|
+
worker_status: "worker_status",
|
|
1015
|
+
audit_log: "audit_log",
|
|
1016
|
+
} as const;
|
|
1017
|
+
`,
|
|
1018
|
+
},
|
|
1019
|
+
{
|
|
1020
|
+
caminhoRelativo: "src/services/health-check.ts",
|
|
1021
|
+
conteudo: `import http from "node:http";
|
|
1022
|
+
|
|
1023
|
+
export type HealthStatus = {
|
|
1024
|
+
status: "healthy" | "degraded" | "unhealthy" | "initializing";
|
|
1025
|
+
timestamp: string;
|
|
1026
|
+
};
|
|
1027
|
+
|
|
1028
|
+
export type HealthProvider = () => HealthStatus;
|
|
1029
|
+
|
|
1030
|
+
export function startHealthCheckServer(port: number, provider: HealthProvider) {
|
|
1031
|
+
const server = http.createServer((req, res) => {
|
|
1032
|
+
if (req.url === "/health" && req.method === "GET") {
|
|
1033
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1034
|
+
res.end(JSON.stringify(provider()));
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
1037
|
+
res.writeHead(404);
|
|
1038
|
+
res.end();
|
|
1039
|
+
});
|
|
1040
|
+
|
|
1041
|
+
server.listen(port);
|
|
1042
|
+
return server;
|
|
1043
|
+
}
|
|
1044
|
+
`,
|
|
1045
|
+
},
|
|
1046
|
+
{
|
|
1047
|
+
caminhoRelativo: "src/sema_contract_bridge.ts",
|
|
1048
|
+
conteudo: `import { COLLECTIONS } from "./config/collections";
|
|
1049
|
+
import { startHealthCheckServer, type HealthProvider, type HealthStatus } from "./services/health-check";
|
|
1050
|
+
|
|
1051
|
+
export function semaStartWorkerHealthServer(port: number, provider: HealthProvider) {
|
|
1052
|
+
return startHealthCheckServer(port, provider);
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
export function semaWorkerHealthPayload(payload: HealthStatus): HealthStatus {
|
|
1056
|
+
return payload;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
export function semaCollectionNames() {
|
|
1060
|
+
return COLLECTIONS;
|
|
1061
|
+
}
|
|
1062
|
+
`,
|
|
1063
|
+
},
|
|
1064
|
+
{
|
|
1065
|
+
caminhoRelativo: "README.md",
|
|
1066
|
+
conteudo: `# Starter Node Firebase Worker + Sema
|
|
1067
|
+
|
|
1068
|
+
- Contratos em \`contratos/\`
|
|
1069
|
+
- Worker e bridges em \`src/\`
|
|
1070
|
+
- \`drift\` valida impl, endpoint de health e recursos Firestore declarados
|
|
1071
|
+
`,
|
|
1072
|
+
},
|
|
1073
|
+
];
|
|
1074
|
+
}
|
|
1075
|
+
else if (template === "aspnet-api") {
|
|
1076
|
+
arquivos = [
|
|
1077
|
+
{
|
|
1078
|
+
caminhoRelativo: "sema.config.json",
|
|
1079
|
+
conteudo: `{
|
|
1080
|
+
"origens": ["./contratos"],
|
|
1081
|
+
"saida": "./generated",
|
|
1082
|
+
"alvos": ["typescript"],
|
|
1083
|
+
"alvoPadrao": "typescript",
|
|
1084
|
+
"estruturaSaida": "modulos",
|
|
1085
|
+
"framework": "base",
|
|
1086
|
+
"modoEstrito": true,
|
|
1087
|
+
"diretoriosCodigo": ["./src"],
|
|
1088
|
+
"fontesLegado": ["dotnet"],
|
|
1089
|
+
"diretoriosSaidaPorAlvo": {
|
|
1090
|
+
"typescript": "./generated/typescript"
|
|
1091
|
+
},
|
|
1092
|
+
"convencoesGeracaoPorProjeto": "base"
|
|
1093
|
+
}
|
|
1094
|
+
`,
|
|
1095
|
+
},
|
|
1096
|
+
{
|
|
1097
|
+
caminhoRelativo: "contratos/health.sema",
|
|
1098
|
+
conteudo: `module app.health {
|
|
1099
|
+
task get_health {
|
|
1100
|
+
output {
|
|
1101
|
+
status: Texto
|
|
1102
|
+
runtime: Texto
|
|
1103
|
+
}
|
|
1104
|
+
impl {
|
|
1105
|
+
cs: src.Controllers.HealthController.Get
|
|
1106
|
+
}
|
|
1107
|
+
guarantees {
|
|
1108
|
+
status existe
|
|
1109
|
+
runtime existe
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
route get_health_publico {
|
|
1114
|
+
metodo: GET
|
|
1115
|
+
caminho: /api/health
|
|
1116
|
+
task: get_health
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
`,
|
|
1120
|
+
},
|
|
1121
|
+
{
|
|
1122
|
+
caminhoRelativo: "src/Controllers/HealthController.cs",
|
|
1123
|
+
conteudo: `using Microsoft.AspNetCore.Mvc;
|
|
1124
|
+
|
|
1125
|
+
[ApiController]
|
|
1126
|
+
[Route("api/health")]
|
|
1127
|
+
public class HealthController : ControllerBase
|
|
1128
|
+
{
|
|
1129
|
+
[HttpGet]
|
|
1130
|
+
public object Get()
|
|
1131
|
+
{
|
|
1132
|
+
return new { status = "ok", runtime = "aspnet" };
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
`,
|
|
1136
|
+
},
|
|
1137
|
+
{
|
|
1138
|
+
caminhoRelativo: "README.md",
|
|
1139
|
+
conteudo: `# Starter ASP.NET Core API + Sema
|
|
1140
|
+
|
|
1141
|
+
- Contratos em \`contratos/\`
|
|
1142
|
+
- Controllers/Minimal API em \`src/\`
|
|
1143
|
+
- \`drift\` valida impl e rota publica
|
|
1144
|
+
`,
|
|
1145
|
+
},
|
|
1146
|
+
];
|
|
1147
|
+
}
|
|
1148
|
+
else if (template === "springboot-api") {
|
|
1149
|
+
arquivos = [
|
|
1150
|
+
{
|
|
1151
|
+
caminhoRelativo: "sema.config.json",
|
|
1152
|
+
conteudo: `{
|
|
1153
|
+
"origens": ["./contratos"],
|
|
1154
|
+
"saida": "./generated",
|
|
1155
|
+
"alvos": ["typescript"],
|
|
1156
|
+
"alvoPadrao": "typescript",
|
|
1157
|
+
"estruturaSaida": "modulos",
|
|
1158
|
+
"framework": "base",
|
|
1159
|
+
"modoEstrito": true,
|
|
1160
|
+
"diretoriosCodigo": ["./src"],
|
|
1161
|
+
"fontesLegado": ["java"],
|
|
1162
|
+
"diretoriosSaidaPorAlvo": {
|
|
1163
|
+
"typescript": "./generated/typescript"
|
|
1164
|
+
},
|
|
1165
|
+
"convencoesGeracaoPorProjeto": "base"
|
|
1166
|
+
}
|
|
1167
|
+
`,
|
|
1168
|
+
},
|
|
1169
|
+
{
|
|
1170
|
+
caminhoRelativo: "contratos/health.sema",
|
|
1171
|
+
conteudo: `module app.health {
|
|
1172
|
+
task get_health {
|
|
1173
|
+
output {
|
|
1174
|
+
status: Texto
|
|
1175
|
+
runtime: Texto
|
|
1176
|
+
}
|
|
1177
|
+
impl {
|
|
1178
|
+
java: src.main.java.com.acme.health.HealthController.health
|
|
1179
|
+
}
|
|
1180
|
+
guarantees {
|
|
1181
|
+
status existe
|
|
1182
|
+
runtime existe
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
route get_health_publico {
|
|
1187
|
+
metodo: GET
|
|
1188
|
+
caminho: /api/health
|
|
1189
|
+
task: get_health
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
`,
|
|
1193
|
+
},
|
|
1194
|
+
{
|
|
1195
|
+
caminhoRelativo: "src/main/java/com/acme/health/HealthController.java",
|
|
1196
|
+
conteudo: `package com.acme.health;
|
|
1197
|
+
|
|
1198
|
+
import java.util.Map;
|
|
1199
|
+
import org.springframework.web.bind.annotation.GetMapping;
|
|
1200
|
+
import org.springframework.web.bind.annotation.RequestMapping;
|
|
1201
|
+
import org.springframework.web.bind.annotation.RestController;
|
|
1202
|
+
|
|
1203
|
+
@RestController
|
|
1204
|
+
@RequestMapping("/api/health")
|
|
1205
|
+
public class HealthController {
|
|
1206
|
+
@GetMapping
|
|
1207
|
+
public Map<String, String> health() {
|
|
1208
|
+
return Map.of("status", "ok", "runtime", "spring");
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
`,
|
|
1212
|
+
},
|
|
1213
|
+
{
|
|
1214
|
+
caminhoRelativo: "README.md",
|
|
1215
|
+
conteudo: `# Starter Spring Boot API + Sema
|
|
1216
|
+
|
|
1217
|
+
- Contratos em \`contratos/\`
|
|
1218
|
+
- Controllers REST em \`src/main/java/\`
|
|
1219
|
+
- \`drift\` valida impl e rota publica
|
|
1220
|
+
`,
|
|
1221
|
+
},
|
|
1222
|
+
];
|
|
1223
|
+
}
|
|
1224
|
+
else if (template === "go-http-api") {
|
|
1225
|
+
arquivos = [
|
|
1226
|
+
{
|
|
1227
|
+
caminhoRelativo: "sema.config.json",
|
|
1228
|
+
conteudo: `{
|
|
1229
|
+
"origens": ["./contratos"],
|
|
1230
|
+
"saida": "./generated",
|
|
1231
|
+
"alvos": ["typescript"],
|
|
1232
|
+
"alvoPadrao": "typescript",
|
|
1233
|
+
"estruturaSaida": "modulos",
|
|
1234
|
+
"framework": "base",
|
|
1235
|
+
"modoEstrito": true,
|
|
1236
|
+
"diretoriosCodigo": ["./internal"],
|
|
1237
|
+
"fontesLegado": ["go"],
|
|
1238
|
+
"diretoriosSaidaPorAlvo": {
|
|
1239
|
+
"typescript": "./generated/typescript"
|
|
1240
|
+
},
|
|
1241
|
+
"convencoesGeracaoPorProjeto": "base"
|
|
1242
|
+
}
|
|
1243
|
+
`,
|
|
1244
|
+
},
|
|
1245
|
+
{
|
|
1246
|
+
caminhoRelativo: "contratos/health.sema",
|
|
1247
|
+
conteudo: `module app.health {
|
|
1248
|
+
task get_health {
|
|
1249
|
+
output {
|
|
1250
|
+
resultado: Json
|
|
1251
|
+
}
|
|
1252
|
+
impl {
|
|
1253
|
+
go: internal.health.getHealth
|
|
1254
|
+
}
|
|
1255
|
+
guarantees {
|
|
1256
|
+
resultado existe
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
route get_health_publico {
|
|
1261
|
+
metodo: GET
|
|
1262
|
+
caminho: /health
|
|
1263
|
+
task: get_health
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
`,
|
|
1267
|
+
},
|
|
1268
|
+
{
|
|
1269
|
+
caminhoRelativo: "internal/health.go",
|
|
1270
|
+
conteudo: `package internal
|
|
1271
|
+
|
|
1272
|
+
import "github.com/gin-gonic/gin"
|
|
1273
|
+
|
|
1274
|
+
func registerRoutes(router *gin.Engine) {
|
|
1275
|
+
router.GET("/health", getHealth)
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
func getHealth(ctx *gin.Context) {
|
|
1279
|
+
ctx.JSON(200, gin.H{"status": "ok", "runtime": "go"})
|
|
1280
|
+
}
|
|
1281
|
+
`,
|
|
1282
|
+
},
|
|
1283
|
+
{
|
|
1284
|
+
caminhoRelativo: "README.md",
|
|
1285
|
+
conteudo: `# Starter Go HTTP API + Sema
|
|
1286
|
+
|
|
1287
|
+
- Contratos em \`contratos/\`
|
|
1288
|
+
- Handlers em \`internal/\`
|
|
1289
|
+
- \`drift\` valida impl e rota publica
|
|
1290
|
+
`,
|
|
1291
|
+
},
|
|
1292
|
+
];
|
|
1293
|
+
}
|
|
1294
|
+
else if (template === "rust-axum-api") {
|
|
1295
|
+
arquivos = [
|
|
1296
|
+
{
|
|
1297
|
+
caminhoRelativo: "sema.config.json",
|
|
1298
|
+
conteudo: `{
|
|
1299
|
+
"origens": ["./contratos"],
|
|
1300
|
+
"saida": "./generated",
|
|
1301
|
+
"alvos": ["typescript"],
|
|
1302
|
+
"alvoPadrao": "typescript",
|
|
1303
|
+
"estruturaSaida": "modulos",
|
|
1304
|
+
"framework": "base",
|
|
1305
|
+
"modoEstrito": true,
|
|
1306
|
+
"diretoriosCodigo": ["./src"],
|
|
1307
|
+
"fontesLegado": ["rust"],
|
|
1308
|
+
"diretoriosSaidaPorAlvo": {
|
|
1309
|
+
"typescript": "./generated/typescript"
|
|
1310
|
+
},
|
|
1311
|
+
"convencoesGeracaoPorProjeto": "base"
|
|
1312
|
+
}
|
|
1313
|
+
`,
|
|
1314
|
+
},
|
|
1315
|
+
{
|
|
1316
|
+
caminhoRelativo: "contratos/health.sema",
|
|
1317
|
+
conteudo: `module app.health {
|
|
1318
|
+
task get_health {
|
|
1319
|
+
output {
|
|
1320
|
+
resultado: Json
|
|
1321
|
+
}
|
|
1322
|
+
impl {
|
|
1323
|
+
rust: src.handlers.health
|
|
1324
|
+
}
|
|
1325
|
+
guarantees {
|
|
1326
|
+
resultado existe
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
route get_health_publico {
|
|
1331
|
+
metodo: GET
|
|
1332
|
+
caminho: /health
|
|
1333
|
+
task: get_health
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
`,
|
|
1337
|
+
},
|
|
1338
|
+
{
|
|
1339
|
+
caminhoRelativo: "src/main.rs",
|
|
1340
|
+
conteudo: `use axum::{routing::get, Router};
|
|
1341
|
+
|
|
1342
|
+
mod handlers;
|
|
1343
|
+
|
|
1344
|
+
fn app() -> Router {
|
|
1345
|
+
Router::new().route("/health", get(handlers::health))
|
|
1346
|
+
}
|
|
1347
|
+
`,
|
|
1348
|
+
},
|
|
1349
|
+
{
|
|
1350
|
+
caminhoRelativo: "src/handlers.rs",
|
|
1351
|
+
conteudo: `pub async fn health() -> &'static str {
|
|
1352
|
+
"ok"
|
|
1353
|
+
}
|
|
1354
|
+
`,
|
|
1355
|
+
},
|
|
1356
|
+
{
|
|
1357
|
+
caminhoRelativo: "README.md",
|
|
1358
|
+
conteudo: `# Starter Rust Axum API + Sema
|
|
1359
|
+
|
|
1360
|
+
- Contratos em \`contratos/\`
|
|
1361
|
+
- Handlers em \`src/\`
|
|
1362
|
+
- \`drift\` valida impl e rota publica
|
|
1363
|
+
`,
|
|
1364
|
+
},
|
|
1365
|
+
];
|
|
1366
|
+
}
|
|
1367
|
+
else if (template === "cpp-service-bridge") {
|
|
1368
|
+
arquivos = [
|
|
1369
|
+
{
|
|
1370
|
+
caminhoRelativo: "sema.config.json",
|
|
1371
|
+
conteudo: `{
|
|
1372
|
+
"origens": ["./contratos"],
|
|
1373
|
+
"saida": "./generated",
|
|
1374
|
+
"alvos": ["typescript"],
|
|
1375
|
+
"alvoPadrao": "typescript",
|
|
1376
|
+
"estruturaSaida": "modulos",
|
|
1377
|
+
"framework": "base",
|
|
1378
|
+
"modoEstrito": true,
|
|
1379
|
+
"diretoriosCodigo": ["./src"],
|
|
1380
|
+
"fontesLegado": ["cpp"],
|
|
1381
|
+
"diretoriosSaidaPorAlvo": {
|
|
1382
|
+
"typescript": "./generated/typescript"
|
|
1383
|
+
},
|
|
1384
|
+
"convencoesGeracaoPorProjeto": "base"
|
|
1385
|
+
}
|
|
1386
|
+
`,
|
|
1387
|
+
},
|
|
1388
|
+
{
|
|
1389
|
+
caminhoRelativo: "contratos/runtime_bridge.sema",
|
|
1390
|
+
conteudo: `module app.runtime_bridge {
|
|
1391
|
+
task processar_snapshot {
|
|
1392
|
+
input {
|
|
1393
|
+
payload: Json required
|
|
1394
|
+
}
|
|
1395
|
+
output {
|
|
1396
|
+
resultado: Json
|
|
1397
|
+
}
|
|
1398
|
+
impl {
|
|
1399
|
+
cpp: src.runtime.RuntimeBridge.processSnapshot
|
|
1400
|
+
}
|
|
1401
|
+
guarantees {
|
|
1402
|
+
resultado existe
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
`,
|
|
1407
|
+
},
|
|
1408
|
+
{
|
|
1409
|
+
caminhoRelativo: "src/runtime.cpp",
|
|
1410
|
+
conteudo: `class RuntimeBridge {
|
|
1411
|
+
public:
|
|
1412
|
+
int processSnapshot(int payload) {
|
|
1413
|
+
return payload;
|
|
1414
|
+
}
|
|
1415
|
+
};
|
|
1416
|
+
`,
|
|
1417
|
+
},
|
|
1418
|
+
{
|
|
1419
|
+
caminhoRelativo: "README.md",
|
|
1420
|
+
conteudo: `# Starter C++ Service Bridge + Sema
|
|
1421
|
+
|
|
1422
|
+
- Contratos em \`contratos/\`
|
|
1423
|
+
- Symbols e bridges em \`src/\`
|
|
1424
|
+
- \`drift\` valida impl de simbolos, sem prometer rota HTTP
|
|
1425
|
+
`,
|
|
1426
|
+
},
|
|
1427
|
+
];
|
|
1428
|
+
}
|
|
1429
|
+
else {
|
|
1430
|
+
arquivos = [
|
|
1431
|
+
{
|
|
1432
|
+
caminhoRelativo: "sema.config.json",
|
|
1433
|
+
conteudo: `{
|
|
1434
|
+
"origens": ["./contratos"],
|
|
1435
|
+
"saida": "./generated",
|
|
1436
|
+
"alvos": ["typescript", "python", "dart"],
|
|
1437
|
+
"alvoPadrao": "typescript",
|
|
1438
|
+
"estruturaSaida": "modulos",
|
|
1439
|
+
"framework": "base",
|
|
1440
|
+
"modoEstrito": true,
|
|
1441
|
+
"diretoriosSaidaPorAlvo": {
|
|
1442
|
+
"typescript": "./generated/typescript",
|
|
1443
|
+
"python": "./generated/python",
|
|
1444
|
+
"dart": "./generated/dart"
|
|
1445
|
+
},
|
|
1446
|
+
"convencoesGeracaoPorProjeto": "base"
|
|
1447
|
+
}
|
|
1448
|
+
`,
|
|
1449
|
+
},
|
|
1450
|
+
...arquivosBase,
|
|
1451
|
+
];
|
|
1452
|
+
}
|
|
1453
|
+
await escreverArquivos(cwd, arquivos);
|
|
1454
|
+
console.log(`Projeto Sema inicializado com template ${template}.`);
|
|
1455
|
+
return 0;
|
|
1456
|
+
}
|
|
1457
|
+
async function comandoValidar(entrada) {
|
|
1458
|
+
const modulos = await carregarModulos(entrada);
|
|
1459
|
+
const diagnosticos = modulos.flatMap((item) => item.resultado.diagnosticos);
|
|
1460
|
+
console.log(formatarDiagnosticos(diagnosticos));
|
|
1461
|
+
return temErros(diagnosticos) ? 1 : 0;
|
|
1462
|
+
}
|
|
1463
|
+
async function comandoValidarJson(entrada) {
|
|
1464
|
+
const modulos = await carregarModulos(entrada);
|
|
1465
|
+
const resultados = modulos.map((item) => ({
|
|
1466
|
+
caminho: item.caminho,
|
|
1467
|
+
modulo: item.resultado.modulo?.nome ?? null,
|
|
1468
|
+
sucesso: !temErros(item.resultado.diagnosticos),
|
|
1469
|
+
diagnosticos: item.resultado.diagnosticos,
|
|
1470
|
+
}));
|
|
1471
|
+
console.log(JSON.stringify({
|
|
1472
|
+
comando: "validar",
|
|
1473
|
+
sucesso: resultados.every((resultado) => resultado.sucesso),
|
|
1474
|
+
resultados,
|
|
1475
|
+
}, null, 2));
|
|
1476
|
+
return resultados.every((resultado) => resultado.sucesso) ? 0 : 1;
|
|
1477
|
+
}
|
|
1478
|
+
async function comandoInspecionar(entrada, emJson, cwd = process.cwd()) {
|
|
1479
|
+
const contextoProjeto = await carregarProjeto(entrada, cwd);
|
|
1480
|
+
const resultadoDrift = await analisarDriftLegado(contextoProjeto);
|
|
1481
|
+
const framework = resolverFrameworkPadrao(undefined, contextoProjeto.configCarregada);
|
|
1482
|
+
const estruturaSaida = resolverEstruturaSaidaPadrao(undefined, framework, contextoProjeto.configCarregada);
|
|
1483
|
+
const alvos = resolverAlvosVerificacao(contextoProjeto.configCarregada);
|
|
1484
|
+
const saidas = Object.fromEntries(alvos.map((alvo) => [alvo, resolverSaidaPadrao(undefined, alvo, contextoProjeto.configCarregada)]));
|
|
1485
|
+
const payload = {
|
|
1486
|
+
comando: "inspecionar",
|
|
1487
|
+
entrada: contextoProjeto.entradaResolvida,
|
|
1488
|
+
configuracao: {
|
|
1489
|
+
caminho: contextoProjeto.configCarregada?.caminho ?? null,
|
|
1490
|
+
baseProjeto: contextoProjeto.baseProjeto,
|
|
1491
|
+
framework,
|
|
1492
|
+
estruturaSaida,
|
|
1493
|
+
alvos,
|
|
1494
|
+
saidas,
|
|
1495
|
+
origens: contextoProjeto.origensProjeto,
|
|
1496
|
+
diretoriosCodigo: contextoProjeto.diretoriosCodigo,
|
|
1497
|
+
fontesLegado: contextoProjeto.fontesLegado,
|
|
1498
|
+
modoAdocao: contextoProjeto.modoAdocao,
|
|
1499
|
+
},
|
|
1500
|
+
projeto: {
|
|
1501
|
+
arquivos: contextoProjeto.arquivosProjeto,
|
|
1502
|
+
modulos: contextoProjeto.modulosSelecionados.map((item) => ({
|
|
1503
|
+
caminho: item.caminho,
|
|
1504
|
+
modulo: item.resultado.modulo?.nome ?? null,
|
|
1505
|
+
sucesso: !temErros(item.resultado.diagnosticos),
|
|
1506
|
+
diagnosticos: item.resultado.diagnosticos.length,
|
|
1507
|
+
implementacao: resumirDriftPorModulo(item.resultado.modulo?.nome ?? null, item.caminho, resultadoDrift),
|
|
1508
|
+
})),
|
|
1509
|
+
},
|
|
1510
|
+
};
|
|
1511
|
+
if (emJson) {
|
|
1512
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
1513
|
+
return 0;
|
|
1514
|
+
}
|
|
1515
|
+
console.log("Inspecao de projeto Sema");
|
|
1516
|
+
console.log(`- Entrada: ${payload.entrada}`);
|
|
1517
|
+
console.log(`- Configuracao: ${payload.configuracao.caminho ?? "nenhuma"}`);
|
|
1518
|
+
console.log(`- Base do projeto: ${payload.configuracao.baseProjeto}`);
|
|
1519
|
+
console.log(`- Framework: ${payload.configuracao.framework}`);
|
|
1520
|
+
console.log(`- Estrutura de saida: ${payload.configuracao.estruturaSaida}`);
|
|
1521
|
+
console.log(`- Alvos: ${payload.configuracao.alvos.join(", ")}`);
|
|
1522
|
+
console.log(`- Modo de adocao: ${payload.configuracao.modoAdocao}`);
|
|
1523
|
+
console.log("- Saidas por alvo:");
|
|
1524
|
+
for (const [alvo, saida] of Object.entries(payload.configuracao.saidas)) {
|
|
1525
|
+
console.log(` - ${alvo}: ${saida}`);
|
|
1526
|
+
}
|
|
1527
|
+
console.log("- Origens do projeto:");
|
|
1528
|
+
for (const origem of payload.configuracao.origens) {
|
|
1529
|
+
console.log(` - ${origem}`);
|
|
1530
|
+
}
|
|
1531
|
+
console.log("- Diretorios de codigo:");
|
|
1532
|
+
for (const diretorio of payload.configuracao.diretoriosCodigo) {
|
|
1533
|
+
console.log(` - ${diretorio}`);
|
|
1534
|
+
}
|
|
1535
|
+
console.log(`- Fontes de legado detectadas: ${payload.configuracao.fontesLegado.join(", ") || "nenhuma"}`);
|
|
1536
|
+
console.log("- Modulos selecionados:");
|
|
1537
|
+
for (const modulo of payload.projeto.modulos) {
|
|
1538
|
+
console.log(` - ${modulo.modulo ?? "(sem modulo)"} :: ${modulo.caminho} :: diagnosticos=${modulo.diagnosticos}`);
|
|
1539
|
+
console.log(` impls validos=${modulo.implementacao.implsValidos} quebrados=${modulo.implementacao.implsQuebrados} recursos divergentes=${modulo.implementacao.recursosDivergentesCount} sem_impl=${modulo.implementacao.tasksSemImplementacao}`);
|
|
1540
|
+
for (const arquivoRelacionado of modulo.implementacao.arquivosRelacionados.slice(0, 5)) {
|
|
1541
|
+
console.log(` arquivo relacionado: ${arquivoRelacionado}`);
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
return 0;
|
|
1545
|
+
}
|
|
1546
|
+
async function comandoDrift(entrada, emJson, cwd = process.cwd()) {
|
|
1547
|
+
const contextoProjeto = await carregarProjeto(entrada, cwd);
|
|
1548
|
+
const resultado = await analisarDriftLegado(contextoProjeto);
|
|
1549
|
+
if (emJson) {
|
|
1550
|
+
console.log(JSON.stringify(resultado, null, 2));
|
|
1551
|
+
return resultado.sucesso ? 0 : 1;
|
|
1552
|
+
}
|
|
1553
|
+
console.log("Drift entre Sema e codigo legado");
|
|
1554
|
+
console.log(`- Modulos analisados: ${resultado.modulos.length}`);
|
|
1555
|
+
console.log(`- Tasks analisadas: ${resultado.tasks.length}`);
|
|
1556
|
+
console.log(`- Impl validos: ${resultado.impls_validos.length}`);
|
|
1557
|
+
console.log(`- Impl quebrados: ${resultado.impls_quebrados.length}`);
|
|
1558
|
+
console.log(`- Rotas divergentes: ${resultado.rotas_divergentes.length}`);
|
|
1559
|
+
console.log(`- Recursos vivos validos: ${resultado.recursos_validos.length}`);
|
|
1560
|
+
console.log(`- Recursos vivos divergentes: ${resultado.recursos_divergentes.length}`);
|
|
1561
|
+
if (resultado.impls_quebrados.length > 0) {
|
|
1562
|
+
console.log("- Impl quebrados:");
|
|
1563
|
+
for (const impl of resultado.impls_quebrados) {
|
|
1564
|
+
console.log(` - ${impl.modulo}.${impl.task} :: ${impl.origem}:${impl.caminho}`);
|
|
1565
|
+
if (impl.candidatos && impl.candidatos.length > 0) {
|
|
1566
|
+
console.log(" candidatos provaveis:");
|
|
1567
|
+
for (const candidato of impl.candidatos) {
|
|
1568
|
+
console.log(` - [${candidato.confianca}] ${candidato.caminho} :: ${candidato.arquivo} :: ${candidato.simbolo}`);
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
if (resultado.rotas_divergentes.length > 0) {
|
|
1574
|
+
console.log("- Rotas divergentes:");
|
|
1575
|
+
for (const rota of resultado.rotas_divergentes) {
|
|
1576
|
+
console.log(` - ${rota.modulo}.${rota.route} :: ${rota.metodo ?? "?"} ${rota.caminho ?? "?"}`);
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
if (resultado.recursos_divergentes.length > 0) {
|
|
1580
|
+
console.log("- Recursos divergentes:");
|
|
1581
|
+
for (const recurso of resultado.recursos_divergentes) {
|
|
1582
|
+
console.log(` - ${recurso.modulo}.${recurso.task} :: ${recurso.categoria} ${recurso.alvo}`);
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
const semImpl = resultado.tasks.filter((task) => task.semImplementacao);
|
|
1586
|
+
if (semImpl.length > 0) {
|
|
1587
|
+
console.log("- Tasks sem implementacao vinculada:");
|
|
1588
|
+
for (const task of semImpl) {
|
|
1589
|
+
console.log(` - ${task.modulo}.${task.task}`);
|
|
1590
|
+
if (task.candidatosImpl.length > 0) {
|
|
1591
|
+
console.log(" candidatos provaveis:");
|
|
1592
|
+
for (const candidato of task.candidatosImpl) {
|
|
1593
|
+
console.log(` - [${candidato.confianca}] ${candidato.caminho} :: ${candidato.arquivo} :: ${candidato.simbolo}`);
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
if (resultado.diagnosticos.length === 0) {
|
|
1599
|
+
console.log("Nenhum drift relevante encontrado.");
|
|
1600
|
+
}
|
|
1601
|
+
return resultado.sucesso ? 0 : 1;
|
|
1602
|
+
}
|
|
1603
|
+
async function comandoImportar(fonte, diretorio, saida, namespaceBase, emJson) {
|
|
1604
|
+
const resultado = await importarProjetoLegado(fonte, diretorio, namespaceBase);
|
|
1605
|
+
const resumo = resumoImportacao(resultado);
|
|
1606
|
+
if (!resumo.sucesso) {
|
|
1607
|
+
const payloadErro = {
|
|
1608
|
+
comando: "importar",
|
|
1609
|
+
fonte,
|
|
1610
|
+
diretorio: path.resolve(diretorio),
|
|
1611
|
+
namespaceBase: resultado.namespaceBase,
|
|
1612
|
+
resumo,
|
|
1613
|
+
arquivos: resultado.arquivos.map((arquivo) => ({
|
|
1614
|
+
caminho: path.join(path.resolve(saida), arquivo.caminhoRelativo),
|
|
1615
|
+
modulo: arquivo.modulo,
|
|
1616
|
+
tarefas: arquivo.tarefas,
|
|
1617
|
+
rotas: arquivo.rotas,
|
|
1618
|
+
entidades: arquivo.entidades,
|
|
1619
|
+
enums: arquivo.enums,
|
|
1620
|
+
})),
|
|
1621
|
+
diagnosticos: resultado.diagnosticos,
|
|
1622
|
+
};
|
|
1623
|
+
if (emJson) {
|
|
1624
|
+
console.log(JSON.stringify(payloadErro, null, 2));
|
|
1625
|
+
}
|
|
1626
|
+
else {
|
|
1627
|
+
console.error("Falha na importacao assistida. O rascunho gerado ainda nao ficou semanticamente valido.");
|
|
1628
|
+
console.error(formatarDiagnosticos(resultado.diagnosticos));
|
|
1629
|
+
}
|
|
1630
|
+
return 1;
|
|
1631
|
+
}
|
|
1632
|
+
await escreverArquivos(saida, resultado.arquivos.map((arquivo) => ({
|
|
1633
|
+
caminhoRelativo: arquivo.caminhoRelativo,
|
|
1634
|
+
conteudo: arquivo.conteudo,
|
|
1635
|
+
})));
|
|
1636
|
+
const payload = {
|
|
1637
|
+
comando: "importar",
|
|
1638
|
+
fonte,
|
|
1639
|
+
diretorio: path.resolve(diretorio),
|
|
1640
|
+
saida: path.resolve(saida),
|
|
1641
|
+
namespaceBase: resultado.namespaceBase,
|
|
1642
|
+
resumo,
|
|
1643
|
+
arquivos: resultado.arquivos.map((arquivo) => ({
|
|
1644
|
+
caminho: path.join(path.resolve(saida), arquivo.caminhoRelativo),
|
|
1645
|
+
modulo: arquivo.modulo,
|
|
1646
|
+
tarefas: arquivo.tarefas,
|
|
1647
|
+
rotas: arquivo.rotas,
|
|
1648
|
+
entidades: arquivo.entidades,
|
|
1649
|
+
enums: arquivo.enums,
|
|
1650
|
+
})),
|
|
1651
|
+
};
|
|
1652
|
+
if (emJson) {
|
|
1653
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
1654
|
+
return 0;
|
|
1655
|
+
}
|
|
1656
|
+
console.log("Importacao assistida para Sema concluida.");
|
|
1657
|
+
console.log(`- Fonte: ${fonte}`);
|
|
1658
|
+
console.log(`- Diretorio analisado: ${payload.diretorio}`);
|
|
1659
|
+
console.log(`- Namespace base: ${payload.namespaceBase}`);
|
|
1660
|
+
console.log(`- Saida: ${payload.saida}`);
|
|
1661
|
+
console.log(`- Modulos: ${resumo.modulos}`);
|
|
1662
|
+
console.log(`- Tarefas: ${resumo.tarefas}`);
|
|
1663
|
+
console.log(`- Rotas: ${resumo.rotas}`);
|
|
1664
|
+
console.log(`- Entidades: ${resumo.entidades}`);
|
|
1665
|
+
console.log(`- Enums: ${resumo.enums}`);
|
|
1666
|
+
console.log("- Arquivos gerados:");
|
|
1667
|
+
for (const arquivo of payload.arquivos) {
|
|
1668
|
+
console.log(` - ${arquivo.caminho} :: modulo=${arquivo.modulo} tarefas=${arquivo.tarefas} rotas=${arquivo.rotas}`);
|
|
1669
|
+
}
|
|
1670
|
+
console.log("Ajuste os rascunhos .sema, rode `sema formatar`, `sema validar --json` e depois `sema compilar`.");
|
|
1671
|
+
return 0;
|
|
1672
|
+
}
|
|
1673
|
+
async function comandoAst(arquivo) {
|
|
1674
|
+
const codigo = await lerArquivoTexto(arquivo);
|
|
1675
|
+
const resultado = compilarCodigo(codigo, arquivo);
|
|
1676
|
+
console.log(JSON.stringify(resultado.modulo ?? null, null, 2));
|
|
1677
|
+
return temErros(resultado.diagnosticos) ? 1 : 0;
|
|
1678
|
+
}
|
|
1679
|
+
async function comandoAstJson(arquivo) {
|
|
1680
|
+
const codigo = await lerArquivoTexto(arquivo);
|
|
1681
|
+
const resultado = compilarCodigo(codigo, arquivo);
|
|
1682
|
+
console.log(JSON.stringify({
|
|
1683
|
+
comando: "ast",
|
|
1684
|
+
caminho: path.resolve(arquivo),
|
|
1685
|
+
modulo: resultado.modulo?.nome ?? null,
|
|
1686
|
+
sucesso: !temErros(resultado.diagnosticos),
|
|
1687
|
+
diagnosticos: resultado.diagnosticos,
|
|
1688
|
+
ast: resultado.modulo ?? null,
|
|
1689
|
+
}, null, 2));
|
|
1690
|
+
return temErros(resultado.diagnosticos) ? 1 : 0;
|
|
1691
|
+
}
|
|
1692
|
+
async function comandoIr(arquivo) {
|
|
1693
|
+
const codigo = await lerArquivoTexto(arquivo);
|
|
1694
|
+
const resultado = compilarCodigo(codigo, arquivo);
|
|
1695
|
+
console.log(JSON.stringify(resultado.ir ?? null, null, 2));
|
|
1696
|
+
return temErros(resultado.diagnosticos) ? 1 : 0;
|
|
1697
|
+
}
|
|
1698
|
+
async function comandoIrJson(arquivo) {
|
|
1699
|
+
const codigo = await lerArquivoTexto(arquivo);
|
|
1700
|
+
const resultado = compilarCodigo(codigo, arquivo);
|
|
1701
|
+
console.log(JSON.stringify({
|
|
1702
|
+
comando: "ir",
|
|
1703
|
+
caminho: path.resolve(arquivo),
|
|
1704
|
+
modulo: resultado.modulo?.nome ?? null,
|
|
1705
|
+
sucesso: !temErros(resultado.diagnosticos),
|
|
1706
|
+
diagnosticos: resultado.diagnosticos,
|
|
1707
|
+
ir: resultado.ir ?? null,
|
|
1708
|
+
}, null, 2));
|
|
1709
|
+
return temErros(resultado.diagnosticos) ? 1 : 0;
|
|
1710
|
+
}
|
|
1711
|
+
async function comandoCompilar(entrada, alvo, saida, estrutura, framework, cwd = process.cwd()) {
|
|
1712
|
+
const incompatibilidade = validarCompatibilidadeFramework(alvo, framework);
|
|
1713
|
+
if (incompatibilidade) {
|
|
1714
|
+
console.error(incompatibilidade);
|
|
1715
|
+
return 1;
|
|
1716
|
+
}
|
|
1717
|
+
const modulos = await carregarModulos(entrada, cwd);
|
|
1718
|
+
const diagnosticos = modulos.flatMap((item) => item.resultado.diagnosticos);
|
|
1719
|
+
if (temErros(diagnosticos)) {
|
|
1720
|
+
console.error(formatarDiagnosticos(diagnosticos));
|
|
1721
|
+
return 1;
|
|
1722
|
+
}
|
|
1723
|
+
for (const modulo of modulos) {
|
|
1724
|
+
const ir = garantirIr(modulo.resultado, modulo.caminho);
|
|
1725
|
+
const arquivos = aplicarEstruturaSaida(gerarArquivosPorAlvo(ir, alvo, framework), ir, estrutura);
|
|
1726
|
+
await escreverArquivos(saida, arquivos);
|
|
1727
|
+
}
|
|
1728
|
+
console.log(`Compilacao concluida para o alvo ${alvo} com estrutura ${estrutura} e framework ${framework}.`);
|
|
1729
|
+
return 0;
|
|
1730
|
+
}
|
|
1731
|
+
async function comandoDiagnosticos(arquivo, emJson) {
|
|
1732
|
+
const codigo = await lerArquivoTexto(arquivo);
|
|
1733
|
+
const resultado = compilarCodigo(codigo, arquivo);
|
|
1734
|
+
if (emJson) {
|
|
1735
|
+
console.log(JSON.stringify(resultado.diagnosticos, null, 2));
|
|
1736
|
+
}
|
|
1737
|
+
else {
|
|
1738
|
+
console.log(formatarDiagnosticos(resultado.diagnosticos));
|
|
1739
|
+
}
|
|
1740
|
+
return temErros(resultado.diagnosticos) ? 1 : 0;
|
|
1741
|
+
}
|
|
1742
|
+
async function comandoFormatar(entrada, verificarApenas, emJson) {
|
|
1743
|
+
const contextoProjeto = await carregarProjeto(entrada, process.cwd());
|
|
1744
|
+
const entradaResolvida = contextoProjeto.entradaResolvida;
|
|
1745
|
+
const estatisticas = await stat(entradaResolvida);
|
|
1746
|
+
const arquivos = estatisticas.isFile()
|
|
1747
|
+
? [entradaResolvida]
|
|
1748
|
+
: contextoProjeto.arquivosProjeto.filter((arquivo) => arquivo.startsWith(path.resolve(entradaResolvida)));
|
|
1749
|
+
const resultados = [];
|
|
1750
|
+
for (const arquivo of arquivos) {
|
|
1751
|
+
const codigo = await lerArquivoTexto(arquivo);
|
|
1752
|
+
const resultado = formatarCodigo(codigo, arquivo);
|
|
1753
|
+
const sucesso = !temErros(resultado.diagnosticos) && Boolean(resultado.codigoFormatado);
|
|
1754
|
+
resultados.push({
|
|
1755
|
+
caminho: arquivo,
|
|
1756
|
+
alterado: resultado.alterado,
|
|
1757
|
+
sucesso,
|
|
1758
|
+
diagnosticos: resultado.diagnosticos,
|
|
1759
|
+
});
|
|
1760
|
+
if (sucesso && !verificarApenas && resultado.alterado && resultado.codigoFormatado) {
|
|
1761
|
+
await writeFile(arquivo, resultado.codigoFormatado, "utf8");
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
const possuiErros = resultados.some((resultado) => !resultado.sucesso);
|
|
1765
|
+
const possuiDiferencas = resultados.some((resultado) => resultado.alterado);
|
|
1766
|
+
const codigoSaida = possuiErros ? 1 : verificarApenas && possuiDiferencas ? 1 : 0;
|
|
1767
|
+
if (emJson) {
|
|
1768
|
+
console.log(JSON.stringify({
|
|
1769
|
+
comando: "formatar",
|
|
1770
|
+
sucesso: codigoSaida === 0,
|
|
1771
|
+
modo: verificarApenas ? "check" : "write",
|
|
1772
|
+
arquivos: resultados,
|
|
1773
|
+
totais: {
|
|
1774
|
+
arquivos: resultados.length,
|
|
1775
|
+
alterados: resultados.filter((resultado) => resultado.alterado).length,
|
|
1776
|
+
erros: resultados.filter((resultado) => !resultado.sucesso).length,
|
|
1777
|
+
},
|
|
1778
|
+
}, null, 2));
|
|
1779
|
+
return codigoSaida;
|
|
1780
|
+
}
|
|
1781
|
+
if (possuiErros) {
|
|
1782
|
+
console.error(formatarDiagnosticos(resultados.flatMap((resultado) => resultado.diagnosticos)));
|
|
1783
|
+
return 1;
|
|
1784
|
+
}
|
|
1785
|
+
if (verificarApenas) {
|
|
1786
|
+
if (possuiDiferencas) {
|
|
1787
|
+
console.error("Arquivos fora do formato canonico:");
|
|
1788
|
+
for (const resultado of resultados.filter((item) => item.alterado)) {
|
|
1789
|
+
console.error(`- ${resultado.caminho}`);
|
|
1790
|
+
}
|
|
1791
|
+
return 1;
|
|
1792
|
+
}
|
|
1793
|
+
console.log("Todos os arquivos ja estao no formato canonico.");
|
|
1794
|
+
return 0;
|
|
1795
|
+
}
|
|
1796
|
+
console.log(`Formatacao concluida. Arquivos verificados=${resultados.length} alterados=${resultados.filter((resultado) => resultado.alterado).length}`);
|
|
1797
|
+
return 0;
|
|
1798
|
+
}
|
|
1799
|
+
async function comandoStarterIa() {
|
|
1800
|
+
const descoberta = await descobrirDocsIa();
|
|
1801
|
+
console.log("Starter de IA da Sema");
|
|
1802
|
+
console.log("");
|
|
1803
|
+
console.log(renderizarCabecalhoDocsIa(descoberta));
|
|
1804
|
+
console.log("");
|
|
1805
|
+
console.log(STARTER_IA);
|
|
1806
|
+
return 0;
|
|
1807
|
+
}
|
|
1808
|
+
async function comandoAjudaIa() {
|
|
1809
|
+
const descoberta = await descobrirDocsIa();
|
|
1810
|
+
console.log("Ajuda de IA da Sema");
|
|
1811
|
+
console.log("");
|
|
1812
|
+
console.log(renderizarCabecalhoDocsIa(descoberta));
|
|
1813
|
+
console.log("");
|
|
1814
|
+
console.log("Fluxo recomendado");
|
|
1815
|
+
console.log("- Use `sema starter-ia` para um texto curto de onboarding.");
|
|
1816
|
+
console.log("- Use `sema prompt-ia` para o prompt-base geral.");
|
|
1817
|
+
console.log("- Use `sema prompt-ia-ui` para tarefas visuais com Sema + UI.");
|
|
1818
|
+
console.log("- Use `sema prompt-ia-react` para projeto com Sema + React + TypeScript.");
|
|
1819
|
+
console.log("- Use `sema prompt-ia-sema-primeiro` para forcar modelagem semantica antes da implementacao.");
|
|
1820
|
+
console.log("- Use `sema exemplos-prompt-ia` para pegar modelos prontos de prompt.");
|
|
1821
|
+
console.log("- Use `sema contexto-ia <arquivo.sema>` para gerar AST, IR e diagnosticos do modulo alvo.");
|
|
1822
|
+
console.log("- Use `sema compilar <arquivo-ou-pasta> --alvo <typescript|python|dart> --saida <diretorio>` quando a tarefa pedir codigo derivado.");
|
|
1823
|
+
console.log("");
|
|
1824
|
+
console.log("Regra pratica");
|
|
1825
|
+
console.log("- Se voce quer testar a Sema de verdade, nao peca so HTML solto.");
|
|
1826
|
+
console.log("- Peca `.sema` + arquitetura + React + TypeScript, ou use o modo `Sema primeiro`.");
|
|
1827
|
+
return 0;
|
|
1828
|
+
}
|
|
1829
|
+
async function comandoPromptIa() {
|
|
1830
|
+
const descoberta = await descobrirDocsIa();
|
|
1831
|
+
console.log("Prompt-base de IA da Sema");
|
|
1832
|
+
console.log("");
|
|
1833
|
+
console.log(renderizarCabecalhoDocsIa(descoberta));
|
|
1834
|
+
console.log("");
|
|
1835
|
+
console.log(PROMPT_BASE_IA);
|
|
1836
|
+
return 0;
|
|
1837
|
+
}
|
|
1838
|
+
async function comandoPromptIaUi() {
|
|
1839
|
+
const descoberta = await descobrirDocsIa();
|
|
1840
|
+
console.log("Prompt de IA da Sema para UI");
|
|
1841
|
+
console.log("");
|
|
1842
|
+
console.log(renderizarCabecalhoDocsIa(descoberta));
|
|
1843
|
+
console.log("");
|
|
1844
|
+
console.log(PROMPT_IA_UI);
|
|
1845
|
+
return 0;
|
|
1846
|
+
}
|
|
1847
|
+
async function comandoPromptIaReact() {
|
|
1848
|
+
const descoberta = await descobrirDocsIa();
|
|
1849
|
+
console.log("Prompt de IA da Sema para React");
|
|
1850
|
+
console.log("");
|
|
1851
|
+
console.log(renderizarCabecalhoDocsIa(descoberta));
|
|
1852
|
+
console.log("");
|
|
1853
|
+
console.log(PROMPT_IA_REACT);
|
|
1854
|
+
return 0;
|
|
1855
|
+
}
|
|
1856
|
+
async function comandoPromptIaSemaPrimeiro() {
|
|
1857
|
+
const descoberta = await descobrirDocsIa();
|
|
1858
|
+
console.log("Prompt de IA da Sema no modo Sema primeiro");
|
|
1859
|
+
console.log("");
|
|
1860
|
+
console.log(renderizarCabecalhoDocsIa(descoberta));
|
|
1861
|
+
console.log("");
|
|
1862
|
+
console.log(PROMPT_IA_SEMA_PRIMEIRO);
|
|
1863
|
+
return 0;
|
|
1864
|
+
}
|
|
1865
|
+
async function comandoExemplosPromptIa() {
|
|
1866
|
+
const descoberta = await descobrirDocsIa();
|
|
1867
|
+
console.log("Exemplos de prompt de IA da Sema");
|
|
1868
|
+
console.log("");
|
|
1869
|
+
console.log(renderizarCabecalhoDocsIa(descoberta));
|
|
1870
|
+
console.log("");
|
|
1871
|
+
console.log(EXEMPLOS_PROMPT_IA);
|
|
1872
|
+
return 0;
|
|
1873
|
+
}
|
|
1874
|
+
async function comandoContextoIa(arquivo, pastaSaida, emJson) {
|
|
1875
|
+
const resultado = await gerarContextoIa(arquivo, pastaSaida);
|
|
1876
|
+
if (emJson) {
|
|
1877
|
+
console.log(JSON.stringify(resultado, null, 2));
|
|
1878
|
+
return 0;
|
|
1879
|
+
}
|
|
1880
|
+
const resumoGerado = await readFile(path.join(resultado.pastaSaida, "README.md"), "utf8");
|
|
1881
|
+
console.log(`Pacote de contexto gerado em ${resultado.pastaSaida}`);
|
|
1882
|
+
console.log("");
|
|
1883
|
+
console.log(resumoGerado);
|
|
1884
|
+
return 0;
|
|
1885
|
+
}
|
|
1886
|
+
async function comandoTestar(arquivo, alvo, saida, estrutura, framework) {
|
|
1887
|
+
const incompatibilidade = validarCompatibilidadeFramework(alvo, framework);
|
|
1888
|
+
if (incompatibilidade) {
|
|
1889
|
+
console.error(incompatibilidade);
|
|
1890
|
+
return 1;
|
|
1891
|
+
}
|
|
1892
|
+
const codigo = await lerArquivoTexto(arquivo);
|
|
1893
|
+
const resultado = compilarCodigo(codigo, arquivo);
|
|
1894
|
+
if (temErros(resultado.diagnosticos)) {
|
|
1895
|
+
console.error(formatarDiagnosticos(resultado.diagnosticos));
|
|
1896
|
+
return 1;
|
|
1897
|
+
}
|
|
1898
|
+
const ir = garantirIr(resultado, arquivo);
|
|
1899
|
+
const arquivos = aplicarEstruturaSaida(gerarArquivosPorAlvo(ir, alvo, framework), ir, estrutura);
|
|
1900
|
+
await escreverArquivos(saida, arquivos);
|
|
1901
|
+
if (framework !== "base") {
|
|
1902
|
+
console.log(`Scaffold ${framework} gerado em ${saida}. A execucao automatica de testes continua focada no framework base da Sema.`);
|
|
1903
|
+
return 0;
|
|
1904
|
+
}
|
|
1905
|
+
return executarTestesGerados(alvo, saida, arquivos).codigoSaida;
|
|
1906
|
+
}
|
|
1907
|
+
function imprimirResumoVerificacao(resumos) {
|
|
1908
|
+
console.log("\nResumo da verificacao:");
|
|
1909
|
+
let totalArquivos = 0;
|
|
1910
|
+
let totalTestes = 0;
|
|
1911
|
+
let totalAlvos = 0;
|
|
1912
|
+
for (const resumo of resumos) {
|
|
1913
|
+
console.log(`- Modulo ${resumo.modulo} (${resumo.arquivoFonte})`);
|
|
1914
|
+
for (const alvo of resumo.alvos) {
|
|
1915
|
+
totalArquivos += alvo.arquivosGerados;
|
|
1916
|
+
totalTestes += alvo.quantidadeTestes;
|
|
1917
|
+
totalAlvos += 1;
|
|
1918
|
+
console.log(` alvo=${alvo.alvo} status=${alvo.sucesso ? "ok" : "falhou"} arquivos=${alvo.arquivosGerados} testes=${alvo.quantidadeTestes} saida=${alvo.pastaSaida}`);
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
console.log(`Totais: modulos=${resumos.length} alvos=${totalAlvos} arquivos=${totalArquivos} testes=${totalTestes}`);
|
|
1922
|
+
}
|
|
1923
|
+
async function comandoVerificar(entrada, baseSaida, cwd = process.cwd()) {
|
|
1924
|
+
const contextoProjeto = await carregarProjeto(entrada, cwd);
|
|
1925
|
+
const modulos = contextoProjeto.modulosSelecionados;
|
|
1926
|
+
const diagnosticos = modulos.flatMap((item) => item.resultado.diagnosticos);
|
|
1927
|
+
if (temErros(diagnosticos)) {
|
|
1928
|
+
console.error(formatarDiagnosticos(diagnosticos));
|
|
1929
|
+
return 1;
|
|
1930
|
+
}
|
|
1931
|
+
const alvos = resolverAlvosVerificacao(contextoProjeto.configCarregada);
|
|
1932
|
+
const resumos = [];
|
|
1933
|
+
for (const modulo of modulos) {
|
|
1934
|
+
const ir = garantirIr(modulo.resultado, modulo.caminho);
|
|
1935
|
+
console.log(`Verificando modulo ${modulo.caminho}`);
|
|
1936
|
+
const resumoModulo = {
|
|
1937
|
+
modulo: ir.nome,
|
|
1938
|
+
arquivoFonte: modulo.caminho,
|
|
1939
|
+
alvos: [],
|
|
1940
|
+
};
|
|
1941
|
+
for (const alvo of alvos) {
|
|
1942
|
+
const pastaAlvo = path.join(baseSaida, alvo, nomeSubpastaModulo(modulo.caminho));
|
|
1943
|
+
const framework = alvo === "typescript" ? "base" : alvo === "python" ? "base" : "base";
|
|
1944
|
+
const arquivos = gerarArquivosPorAlvo(ir, alvo, framework);
|
|
1945
|
+
await escreverArquivos(pastaAlvo, arquivos);
|
|
1946
|
+
const execucao = executarTestesGerados(alvo, pastaAlvo, arquivos);
|
|
1947
|
+
resumoModulo.alvos.push({
|
|
1948
|
+
alvo,
|
|
1949
|
+
arquivosGerados: arquivos.length,
|
|
1950
|
+
quantidadeTestes: execucao.quantidadeTestes,
|
|
1951
|
+
pastaSaida: pastaAlvo,
|
|
1952
|
+
sucesso: execucao.codigoSaida === 0,
|
|
1953
|
+
});
|
|
1954
|
+
if (execucao.codigoSaida !== 0) {
|
|
1955
|
+
imprimirResumoVerificacao([...resumos, resumoModulo]);
|
|
1956
|
+
console.error(`Falha na verificacao do modulo ${modulo.caminho} para o alvo ${alvo}.`);
|
|
1957
|
+
return execucao.codigoSaida;
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
resumos.push(resumoModulo);
|
|
1961
|
+
}
|
|
1962
|
+
imprimirResumoVerificacao(resumos);
|
|
1963
|
+
console.log("Verificacao completa concluida com sucesso.");
|
|
1964
|
+
return 0;
|
|
1965
|
+
}
|
|
1966
|
+
async function comandoVerificarJson(entrada, baseSaida, cwd = process.cwd()) {
|
|
1967
|
+
const contextoProjeto = await carregarProjeto(entrada, cwd);
|
|
1968
|
+
const modulos = contextoProjeto.modulosSelecionados;
|
|
1969
|
+
const diagnosticos = modulos.flatMap((item) => item.resultado.diagnosticos);
|
|
1970
|
+
if (temErros(diagnosticos)) {
|
|
1971
|
+
console.log(JSON.stringify({
|
|
1972
|
+
comando: "verificar",
|
|
1973
|
+
sucesso: false,
|
|
1974
|
+
diagnosticos,
|
|
1975
|
+
modulos: [],
|
|
1976
|
+
totais: { modulos: 0, alvos: 0, arquivos: 0, testes: 0 },
|
|
1977
|
+
}, null, 2));
|
|
1978
|
+
return 1;
|
|
1979
|
+
}
|
|
1980
|
+
const alvos = resolverAlvosVerificacao(contextoProjeto.configCarregada);
|
|
1981
|
+
const resumos = [];
|
|
1982
|
+
let codigoSaida = 0;
|
|
1983
|
+
for (const modulo of modulos) {
|
|
1984
|
+
const ir = garantirIr(modulo.resultado, modulo.caminho);
|
|
1985
|
+
const resumoModulo = {
|
|
1986
|
+
modulo: ir.nome,
|
|
1987
|
+
arquivoFonte: modulo.caminho,
|
|
1988
|
+
alvos: [],
|
|
1989
|
+
saidaTestes: [],
|
|
1990
|
+
};
|
|
1991
|
+
for (const alvo of alvos) {
|
|
1992
|
+
const pastaAlvo = path.join(baseSaida, alvo, nomeSubpastaModulo(modulo.caminho));
|
|
1993
|
+
const arquivos = gerarArquivosPorAlvo(ir, alvo, "base");
|
|
1994
|
+
await escreverArquivos(pastaAlvo, arquivos);
|
|
1995
|
+
const execucao = executarTestesGerados(alvo, pastaAlvo, arquivos, true);
|
|
1996
|
+
resumoModulo.alvos.push({
|
|
1997
|
+
alvo,
|
|
1998
|
+
arquivosGerados: arquivos.length,
|
|
1999
|
+
quantidadeTestes: execucao.quantidadeTestes,
|
|
2000
|
+
pastaSaida: pastaAlvo,
|
|
2001
|
+
sucesso: execucao.codigoSaida === 0,
|
|
2002
|
+
});
|
|
2003
|
+
resumoModulo.saidaTestes.push({ alvo, stdout: execucao.saidaPadrao, stderr: execucao.saidaErro });
|
|
2004
|
+
if (execucao.codigoSaida !== 0) {
|
|
2005
|
+
codigoSaida = execucao.codigoSaida;
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
resumos.push(resumoModulo);
|
|
2009
|
+
}
|
|
2010
|
+
const totais = {
|
|
2011
|
+
modulos: resumos.length,
|
|
2012
|
+
alvos: resumos.reduce((total, resumo) => total + resumo.alvos.length, 0),
|
|
2013
|
+
arquivos: resumos.reduce((total, resumo) => total + resumo.alvos.reduce((subTotal, alvo) => subTotal + alvo.arquivosGerados, 0), 0),
|
|
2014
|
+
testes: resumos.reduce((total, resumo) => total + resumo.alvos.reduce((subTotal, alvo) => subTotal + alvo.quantidadeTestes, 0), 0),
|
|
2015
|
+
};
|
|
2016
|
+
console.log(JSON.stringify({
|
|
2017
|
+
comando: "verificar",
|
|
2018
|
+
sucesso: codigoSaida === 0,
|
|
2019
|
+
modulos: resumos,
|
|
2020
|
+
totais,
|
|
2021
|
+
}, null, 2));
|
|
2022
|
+
return codigoSaida;
|
|
2023
|
+
}
|
|
2024
|
+
async function principal() {
|
|
2025
|
+
const { comando, resto } = obterArgumentos();
|
|
2026
|
+
const comandoCru = process.argv[2];
|
|
2027
|
+
if (!comando || comandoCru === "--help" || comandoCru === "-h") {
|
|
2028
|
+
console.log(ajuda());
|
|
2029
|
+
process.exit(0);
|
|
2030
|
+
}
|
|
2031
|
+
const cwd = process.cwd();
|
|
2032
|
+
const posicionais = obterPosicionais(resto);
|
|
2033
|
+
let codigoSaida = 0;
|
|
2034
|
+
switch (comando) {
|
|
2035
|
+
case "iniciar":
|
|
2036
|
+
codigoSaida = await comandoIniciar(cwd, normalizarTemplateIniciar(obterOpcao(resto, "--template")));
|
|
2037
|
+
break;
|
|
2038
|
+
case "validar":
|
|
2039
|
+
codigoSaida = possuiFlag(resto, "--json")
|
|
2040
|
+
? await comandoValidarJson(posicionais[0])
|
|
2041
|
+
: await comandoValidar(posicionais[0]);
|
|
2042
|
+
break;
|
|
2043
|
+
case "ast":
|
|
2044
|
+
codigoSaida = possuiFlag(resto, "--json")
|
|
2045
|
+
? await comandoAstJson(resto[0] ?? "")
|
|
2046
|
+
: await comandoAst(resto[0] ?? "");
|
|
2047
|
+
break;
|
|
2048
|
+
case "ir":
|
|
2049
|
+
codigoSaida = possuiFlag(resto, "--json")
|
|
2050
|
+
? await comandoIrJson(resto[0] ?? "")
|
|
2051
|
+
: await comandoIr(resto[0] ?? "");
|
|
2052
|
+
break;
|
|
2053
|
+
case "compilar":
|
|
2054
|
+
{
|
|
2055
|
+
const config = await carregarConfiguracaoProjeto(posicionais[0] ? path.resolve(cwd, posicionais[0]) : cwd);
|
|
2056
|
+
const alvo = resolverAlvoPadrao(obterOpcao(resto, "--alvo"), config);
|
|
2057
|
+
const framework = resolverFrameworkPadrao(obterOpcao(resto, "--framework"), config);
|
|
2058
|
+
const estrutura = resolverEstruturaSaidaPadrao(obterOpcao(resto, "--estrutura"), framework, config);
|
|
2059
|
+
const saida = resolverSaidaPadrao(obterOpcao(resto, "--saida"), alvo, config);
|
|
2060
|
+
codigoSaida = await comandoCompilar(posicionais[0], alvo, saida, estrutura, framework, cwd);
|
|
2061
|
+
}
|
|
2062
|
+
break;
|
|
2063
|
+
case "gerar":
|
|
2064
|
+
{
|
|
2065
|
+
const config = await carregarConfiguracaoProjeto(posicionais[1] ? path.resolve(cwd, posicionais[1]) : cwd);
|
|
2066
|
+
const alvo = resolverAlvoPadrao(posicionais[0] ?? obterOpcao(resto, "--alvo"), config);
|
|
2067
|
+
const framework = resolverFrameworkPadrao(obterOpcao(resto, "--framework"), config);
|
|
2068
|
+
const estrutura = resolverEstruturaSaidaPadrao(obterOpcao(resto, "--estrutura"), framework, config);
|
|
2069
|
+
const saida = resolverSaidaPadrao(obterOpcao(resto, "--saida"), alvo, config);
|
|
2070
|
+
codigoSaida = await comandoCompilar(posicionais[1], alvo, saida, estrutura, framework, cwd);
|
|
2071
|
+
}
|
|
2072
|
+
break;
|
|
2073
|
+
case "diagnosticos":
|
|
2074
|
+
codigoSaida = await comandoDiagnosticos(posicionais[0] ?? "", resto.includes("--json"));
|
|
2075
|
+
break;
|
|
2076
|
+
case "testar":
|
|
2077
|
+
{
|
|
2078
|
+
const config = await carregarConfiguracaoProjeto(posicionais[0] ? path.resolve(cwd, posicionais[0]) : cwd);
|
|
2079
|
+
const alvo = resolverAlvoPadrao(obterOpcao(resto, "--alvo"), config);
|
|
2080
|
+
const framework = resolverFrameworkPadrao(obterOpcao(resto, "--framework"), config);
|
|
2081
|
+
const estrutura = resolverEstruturaSaidaPadrao(obterOpcao(resto, "--estrutura"), framework, config);
|
|
2082
|
+
const saida = resolverSaidaPadrao(obterOpcao(resto, "--saida", "./.tmp/sema-testes"), alvo, config);
|
|
2083
|
+
codigoSaida = await comandoTestar(path.resolve(cwd, posicionais[0] ?? ""), alvo, saida, estrutura, framework);
|
|
2084
|
+
}
|
|
2085
|
+
break;
|
|
2086
|
+
case "verificar":
|
|
2087
|
+
codigoSaida = possuiFlag(resto, "--json")
|
|
2088
|
+
? await comandoVerificarJson(posicionais[0], resolverSaidaPadrao(obterOpcao(resto, "--saida", "./.tmp/sema-verificar"), "typescript", await carregarConfiguracaoProjeto(posicionais[0] ? path.resolve(cwd, posicionais[0]) : cwd)), cwd)
|
|
2089
|
+
: await comandoVerificar(posicionais[0], resolverSaidaPadrao(obterOpcao(resto, "--saida", "./.tmp/sema-verificar"), "typescript", await carregarConfiguracaoProjeto(posicionais[0] ? path.resolve(cwd, posicionais[0]) : cwd)), cwd);
|
|
2090
|
+
break;
|
|
2091
|
+
case "inspecionar":
|
|
2092
|
+
codigoSaida = await comandoInspecionar(posicionais[0], possuiFlag(resto, "--json"), cwd);
|
|
2093
|
+
break;
|
|
2094
|
+
case "drift":
|
|
2095
|
+
codigoSaida = await comandoDrift(posicionais[0], possuiFlag(resto, "--json"), cwd);
|
|
2096
|
+
break;
|
|
2097
|
+
case "importar":
|
|
2098
|
+
{
|
|
2099
|
+
const fonte = normalizarFonteImportacao(posicionais[0]);
|
|
2100
|
+
if (!fonte || !posicionais[1]) {
|
|
2101
|
+
console.error("Uso: sema importar <nestjs|fastapi|flask|nextjs|firebase|dotnet|java|go|rust|cpp|typescript|python|dart> <diretorio> [--saida <diretorio>] [--namespace <base>] [--json]");
|
|
2102
|
+
codigoSaida = 1;
|
|
2103
|
+
break;
|
|
2104
|
+
}
|
|
2105
|
+
codigoSaida = await comandoImportar(fonte, path.resolve(cwd, posicionais[1]), path.resolve(cwd, obterOpcao(resto, "--saida", "./sema/importado")), obterOpcao(resto, "--namespace"), possuiFlag(resto, "--json"));
|
|
2106
|
+
}
|
|
2107
|
+
break;
|
|
2108
|
+
case "formatar":
|
|
2109
|
+
codigoSaida = await comandoFormatar(posicionais[0], possuiFlag(resto, "--check"), possuiFlag(resto, "--json"));
|
|
2110
|
+
break;
|
|
2111
|
+
case "doctor":
|
|
2112
|
+
codigoSaida = await comandoDoctor();
|
|
2113
|
+
break;
|
|
2114
|
+
case "ajuda-ia":
|
|
2115
|
+
codigoSaida = await comandoAjudaIa();
|
|
2116
|
+
break;
|
|
2117
|
+
case "starter-ia":
|
|
2118
|
+
codigoSaida = await comandoStarterIa();
|
|
2119
|
+
break;
|
|
2120
|
+
case "prompt-ia":
|
|
2121
|
+
codigoSaida = await comandoPromptIa();
|
|
2122
|
+
break;
|
|
2123
|
+
case "prompt-ia-ui":
|
|
2124
|
+
codigoSaida = await comandoPromptIaUi();
|
|
2125
|
+
break;
|
|
2126
|
+
case "prompt-ia-react":
|
|
2127
|
+
codigoSaida = await comandoPromptIaReact();
|
|
2128
|
+
break;
|
|
2129
|
+
case "prompt-ia-sema-primeiro":
|
|
2130
|
+
codigoSaida = await comandoPromptIaSemaPrimeiro();
|
|
2131
|
+
break;
|
|
2132
|
+
case "exemplos-prompt-ia":
|
|
2133
|
+
codigoSaida = await comandoExemplosPromptIa();
|
|
2134
|
+
break;
|
|
2135
|
+
case "contexto-ia":
|
|
2136
|
+
codigoSaida = await comandoContextoIa(posicionais[0] ?? "", obterOpcao(resto, "--saida"), possuiFlag(resto, "--json"));
|
|
2137
|
+
break;
|
|
2138
|
+
default:
|
|
2139
|
+
console.log(ajuda());
|
|
2140
|
+
codigoSaida = 1;
|
|
2141
|
+
break;
|
|
2142
|
+
}
|
|
2143
|
+
process.exit(codigoSaida);
|
|
2144
|
+
}
|
|
2145
|
+
principal().catch((erro) => {
|
|
2146
|
+
console.error("Falha ao executar a CLI da Sema.");
|
|
2147
|
+
console.error(erro instanceof Error ? erro.stack ?? erro.message : erro);
|
|
2148
|
+
process.exit(1);
|
|
2149
|
+
});
|
|
2150
|
+
//# sourceMappingURL=index.js.map
|