@semacode/cli 4.1.2 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agentBootstrap.d.ts +4 -0
- package/dist/agentBootstrap.js +44 -0
- package/dist/agentContext.d.ts +1 -1
- package/dist/agentContext.js +5 -5
- package/dist/agentContextPack.js +22 -31
- package/dist/agentEntryPoints.d.ts +1 -3
- package/dist/agentEntryPoints.js +16 -262
- package/dist/cliArgs.js +1 -0
- package/dist/cliGrammar.js +8 -4
- package/dist/cliHelpTexto.js +5 -4
- package/dist/comandoSessao.d.ts +0 -33
- package/dist/comandoSessao.js +71 -70
- package/dist/contextBudget.d.ts +15 -0
- package/dist/contextBudget.js +64 -0
- package/dist/docs.part01.js +0 -1
- package/dist/docs.part02.js +11 -23
- package/dist/docsRelations.d.ts +2 -0
- package/dist/docsRelations.js +83 -0
- package/dist/geracaoCore.d.ts +1 -1
- package/dist/index.part07.d.ts +1 -0
- package/dist/index.part07.js +54 -31
- package/dist/index.part08.js +3 -3
- package/dist/indexPack.d.ts +1 -0
- package/dist/indexPack.js +1 -1
- package/dist/initCommand.d.ts +1 -0
- package/dist/initCommand.js +10 -1
- package/dist/sessionContext.d.ts +13 -0
- package/dist/sessionContext.js +41 -0
- package/dist/verificacaoPythonLocal.d.ts +17 -0
- package/dist/verificacaoPythonLocal.js +46 -0
- package/docs/ai-integration.md +5 -13
- package/docs/ai-workflow.md +8 -6
- package/docs/commands.md +1 -1
- package/docs/documentation.md +33 -0
- package/docs/testing.md +18 -0
- package/exemplos/python_verificacao.sema +68 -68
- package/node_modules/@sema/gerador-python/dist/runtime.js +65 -65
- package/package.json +1 -1
- package/skills/sema/SKILL.md +82 -169
package/dist/cliHelpTexto.js
CHANGED
|
@@ -25,11 +25,12 @@ export function criarAjudaRaiz(versao) {
|
|
|
25
25
|
"",
|
|
26
26
|
renderizarSecaoAscii("Fluxos rápidos", [
|
|
27
27
|
"[1] Projeto novo / produção inicial",
|
|
28
|
-
"sema iniciar --template <base|nestjs|fastapi|nextjs-api|nextjs-consumer|react-vite-consumer|angular-consumer|flutter-consumer|node-firebase-worker|aspnet-api|springboot-api|go-http-api|rust-axum-api|cpp-service-bridge> [--force] [--com-exemplos]",
|
|
28
|
+
"sema iniciar --template <base|nestjs|fastapi|nextjs-api|nextjs-consumer|react-vite-consumer|angular-consumer|flutter-consumer|node-firebase-worker|aspnet-api|springboot-api|go-http-api|rust-axum-api|cpp-service-bridge> [--janela-contexto <tokens>] [--orcamento-contexto <tokens>] [--reserva-saida <tokens>] [--force] [--com-exemplos]",
|
|
29
29
|
"Arquivos existentes são preservados; use --force somente para sobrescrita explícita. O starter de exemplos vem por padrão; --com-exemplos instala o pacote completo. Em subpasta de workspace já governado, a subpasta é registrada nos diretoriosCodigo do sema.config.json ancestral em vez de criar config local.",
|
|
30
30
|
"sema validar contratos/<modulo>.sema --json",
|
|
31
31
|
"sema compilar <arquivo-ou-pasta> --alvo <typescript|python|php|dart|lua|javascript|html|css|dotnet|cpp> --saida <diretorio>",
|
|
32
|
-
"sema verificar <arquivo-ou-pasta> [--saida <dir>] [--alvo <alvo>] [--sem-cache] --json",
|
|
32
|
+
"sema verificar <arquivo-ou-pasta> [--saida <dir>] [--alvo <alvo>] [--sem-cache] [--preservar-implementacao] --json",
|
|
33
|
+
" --preservar-implementacao: somente Python base; preserva implementação local, regenera testes e ignora cache. Não comprova produção.",
|
|
33
34
|
"",
|
|
34
35
|
"[2] Editar projeto que já usa Sema",
|
|
35
36
|
"sema inspecionar . [--drift <none|cache|fresh>] --json",
|
|
@@ -121,7 +122,7 @@ export function criarAjudaRaiz(versao) {
|
|
|
121
122
|
"geração: sema compilar <arquivo-ou-pasta> --alvo <typescript|python|php|dart|lua|javascript|html|css|dotnet|cpp> --saida <diretorio> [--estrutura <flat|modulos|backend>] [--framework <base|nestjs|fastapi>]",
|
|
122
123
|
"teste local: sema testar <arquivo.sema> --alvo <typescript|python|php|dart|lua|javascript|html|css|dotnet|cpp> --saida <diretorio-temporario> [--estrutura <flat|modulos|backend>] [--framework <base|nestjs|fastapi>]",
|
|
123
124
|
"aliases nativos: cs|csharp -> dotnet; c++|cxx|cc -> cpp (CLI e sema.config.json)",
|
|
124
|
-
"verificação final: sema verificar <arquivo-ou-pasta> [--saida <diretorio-base>] [--alvo <alvo>] [--sem-cache] [--json]",
|
|
125
|
+
"verificação final: sema verificar <arquivo-ou-pasta> [--saida <diretorio-base>] [--alvo <alvo>] [--sem-cache] [--preservar-implementacao] [--json]",
|
|
125
126
|
"formatação: sema formatar <arquivo-ou-pasta> [--check] [--json]",
|
|
126
127
|
"author: sema author <iniciar|validar|briefing|revisar-cliches|validar-narrativa|validar-proibicoes> [arquivo] [--tema-sensivel] [--preset conto|romance|roteiro|lore|campanha] [--saida <arquivo>] [--texto <texto>] [--json]",
|
|
127
128
|
"profile: sema profile validar <software|workflow|ops|game|simulation|legal|research|redacao|propostas|conversas> <arquivo-ou-pasta> [--maturidade draft|prototype|production|critical] [--preset <preset>] [--artefato <texto>|--artefato-arquivo <arquivo>] [--json]",
|
|
@@ -144,7 +145,7 @@ export function criarAjudaRaiz(versao) {
|
|
|
144
145
|
"sema contexto-ia <arquivo.sema> [--saida <diretorio>] [--capacidade <fraca|media|forte>] [--pacote] [--json]",
|
|
145
146
|
"sema sync-codex [--json]",
|
|
146
147
|
"sema instalar-exemplos [--json]",
|
|
147
|
-
"sema sessao [intencao] [entrada] [--json]",
|
|
148
|
+
"sema sessao [intencao] [entrada] [--arquivo <contrato-ou-codigo>] [--janela-contexto <tokens>] [--orcamento-contexto <tokens>] [--reserva-saida <tokens>] [--salvar-perfil] [--json]",
|
|
148
149
|
"sema docs-impacto --intencao <acao> [--arquivo <caminho>] [--criar-ausentes] [--completo] [--json]",
|
|
149
150
|
"sema finalizar-mudanca --intencao <acao> [--arquivo <caminho>] [--doc-lida <caminho>] [--json]",
|
|
150
151
|
"sema author briefing <arquivo.sema> [--json]",
|
package/dist/comandoSessao.d.ts
CHANGED
|
@@ -1,34 +1 @@
|
|
|
1
|
-
export interface SessaoEnvelope {
|
|
2
|
-
comando: "sessao";
|
|
3
|
-
sucesso: boolean;
|
|
4
|
-
workspace: {
|
|
5
|
-
baseProjeto: string;
|
|
6
|
-
nomePasta: string;
|
|
7
|
-
hashContratos: string;
|
|
8
|
-
cliVersao: string;
|
|
9
|
-
};
|
|
10
|
-
frescor: {
|
|
11
|
-
fresco: boolean;
|
|
12
|
-
hashArtefato: string | null;
|
|
13
|
-
hashAtual: string;
|
|
14
|
-
sugestao: string;
|
|
15
|
-
};
|
|
16
|
-
contratos: {
|
|
17
|
-
total: number;
|
|
18
|
-
modulos: string[];
|
|
19
|
-
};
|
|
20
|
-
intencoes: {
|
|
21
|
-
intencao: string;
|
|
22
|
-
categorias: string[];
|
|
23
|
-
docsBloqueantes: string[];
|
|
24
|
-
docsRecomendadas: string[];
|
|
25
|
-
};
|
|
26
|
-
gates: {
|
|
27
|
-
drift: string;
|
|
28
|
-
validar: string;
|
|
29
|
-
verificar: string;
|
|
30
|
-
finalizar: string;
|
|
31
|
-
};
|
|
32
|
-
proximosPassos: string[];
|
|
33
|
-
}
|
|
34
1
|
export declare function comandoSessao(posicionais: string[], args: string[], emJson: boolean, cwd?: string): Promise<number>;
|
package/dist/comandoSessao.js
CHANGED
|
@@ -1,86 +1,87 @@
|
|
|
1
1
|
// SEMA-GOVERNED: sema.produto.cli_sessao
|
|
2
|
-
//
|
|
2
|
+
// Descrição: abertura progressiva com perfil explícito, frescor e navegação limitada por orçamento.
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { verificarFrescorArtefatos } from "./index.part04.js";
|
|
5
5
|
import { carregarProjeto } from "./projetoCarregar.js";
|
|
6
|
+
import { carregarConfiguracaoProjeto } from "./projetoConfig.js";
|
|
6
7
|
import { resolverDocumentacaoObrigatoria } from "./docs.js";
|
|
8
|
+
import { resolverPerfilContexto, salvarPerfilContexto, estimarRespostaTokens, PERGUNTA_CONTEXTO } from "./contextBudget.js";
|
|
9
|
+
import { navegarContextoSessao } from "./sessionContext.js";
|
|
10
|
+
function opcao(args, nome) {
|
|
11
|
+
const i = args.findIndex((arg) => arg === nome || arg.startsWith(`${nome}=`));
|
|
12
|
+
return i < 0 ? undefined : args[i].startsWith(`${nome}=`) ? args[i].slice(nome.length + 1) : args[i + 1];
|
|
13
|
+
}
|
|
7
14
|
export async function comandoSessao(posicionais, args, emJson, cwd = process.cwd()) {
|
|
8
|
-
const
|
|
15
|
+
const emitir = (payload, codigo = 0) => {
|
|
16
|
+
if (emJson)
|
|
17
|
+
console.log(JSON.stringify(payload));
|
|
18
|
+
else {
|
|
19
|
+
const p = payload;
|
|
20
|
+
console.log(`Sessão Sema — ${p.status ?? "consulta"}`);
|
|
21
|
+
for (const candidato of p.contexto?.candidatos ?? [])
|
|
22
|
+
console.log(` ${candidato.contrato} — ${candidato.motivo}`);
|
|
23
|
+
for (const passo of p.proximosPassos ?? [])
|
|
24
|
+
console.log(` → ${passo}`);
|
|
25
|
+
}
|
|
26
|
+
return codigo;
|
|
27
|
+
};
|
|
28
|
+
const intencao = posicionais[0] ?? "";
|
|
29
|
+
if (intencao.length > 2048)
|
|
30
|
+
return emitir({ comando: "sessao", sucesso: false, status: "intencao_longa", proximosPassos: ["Descreva a intenção em até 2048 caracteres e informe --arquivo para fixar o escopo."] }, 1);
|
|
9
31
|
const entrada = posicionais[1];
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const modulosNomes = contextoProjeto.modulosSelecionados.map((item) => item.resultado.modulo?.nome ?? path.basename(item.caminho, ".sema"));
|
|
18
|
-
let categorias = [];
|
|
19
|
-
let docsBloqueantes = [];
|
|
20
|
-
let docsRecomendadas = [];
|
|
21
|
-
if (intencao.trim()) {
|
|
22
|
-
const impacto = await resolverDocumentacaoObrigatoria({
|
|
23
|
-
baseProjeto: contextoProjeto.baseProjeto,
|
|
24
|
-
intencao,
|
|
25
|
-
arquivosAlvo: [],
|
|
26
|
-
criarAusentes: false,
|
|
32
|
+
const configuracao = await carregarConfiguracaoProjeto(entrada ? path.resolve(cwd, entrada) : cwd);
|
|
33
|
+
const base = configuracao?.baseDiretorio ?? cwd;
|
|
34
|
+
const perfil = await resolverPerfilContexto(base, args);
|
|
35
|
+
if (!perfil)
|
|
36
|
+
return emitir({
|
|
37
|
+
comando: "sessao", sucesso: true, status: "configuracao_necessaria", execucaoAutorizada: false,
|
|
38
|
+
proximosPassos: [PERGUNTA_CONTEXTO, 'Repita sema sessao "<intenção>" --janela-contexto <tokens> --salvar-perfil --json. Não infira a janela pelo modelo.'],
|
|
27
39
|
});
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
},
|
|
40
|
+
if (args.includes("--salvar-perfil"))
|
|
41
|
+
await salvarPerfilContexto(base, perfil);
|
|
42
|
+
const projeto = await carregarProjeto(entrada, cwd, { escopo: "projeto", adiarDescobertaCodigo: true });
|
|
43
|
+
const frescor = await verificarFrescorArtefatos(projeto.baseProjeto);
|
|
44
|
+
const pacoteCli = (await import("../package.json", { with: { type: "json" } })).default;
|
|
45
|
+
const arquivo = opcao(args, "--arquivo");
|
|
46
|
+
const contexto = frescor.fresco && intencao.trim() ? await navegarContextoSessao(projeto.baseProjeto, intencao, arquivo) : undefined;
|
|
47
|
+
const contrato = contexto?.candidatos.length === 1 ? contexto.candidatos[0].contrato : undefined;
|
|
48
|
+
const docs = contrato ? await resolverDocumentacaoObrigatoria({ baseProjeto: projeto.baseProjeto, intencao, arquivosAlvo: [contrato], criarAusentes: false }) : undefined;
|
|
49
|
+
const alvo = contrato ? JSON.stringify(contrato) : "<contrato>";
|
|
50
|
+
const payload = {
|
|
51
|
+
comando: "sessao", sucesso: true,
|
|
52
|
+
status: !frescor.fresco ? "indice_desatualizado" : contexto?.status ?? "intencao_necessaria",
|
|
53
|
+
execucaoAutorizada: false,
|
|
54
|
+
workspace: { baseProjeto: projeto.baseProjeto, nomePasta: path.basename(projeto.baseProjeto), hashContratos: frescor.hashAtual, cliVersao: pacoteCli.version },
|
|
43
55
|
frescor,
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
},
|
|
48
|
-
intencoes: {
|
|
49
|
-
intencao,
|
|
50
|
-
categorias,
|
|
51
|
-
docsBloqueantes,
|
|
52
|
-
docsRecomendadas,
|
|
53
|
-
},
|
|
56
|
+
perfil,
|
|
57
|
+
contexto: contexto ? { ...contexto, candidatosOmitidos: 0 } : undefined,
|
|
58
|
+
intencoes: { intencao, docsBloqueantes: docs?.leituraObrigatoria.map((doc) => doc.relativo) ?? [], leituraPendente: true },
|
|
54
59
|
gates: {
|
|
55
|
-
drift:
|
|
56
|
-
validar:
|
|
57
|
-
verificar:
|
|
58
|
-
finalizar:
|
|
60
|
+
drift: `sema drift ${alvo} --cache fresh --json`,
|
|
61
|
+
validar: `sema validar ${alvo} --json`,
|
|
62
|
+
verificar: `sema verificar ${alvo} --alvo <alvo> --json`,
|
|
63
|
+
finalizar: `sema finalizar-mudanca --intencao "<intenção>" --arquivo ${alvo} --doc-lida <doc> --json`,
|
|
59
64
|
},
|
|
60
|
-
proximosPassos: [
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
],
|
|
65
|
+
proximosPassos: !frescor.fresco ? ["Rode sema sync-codex --json e repita a sessão."]
|
|
66
|
+
: contrato ? [`Leia ${contrato}; consulte docs-impacto com esse --arquivo para motivos e dependências. Depois inspecione apenas o código vinculado.`, "Referências do índice são navegação. Confirme regras completas e gates antes de agir."]
|
|
67
|
+
: ["Informe uma intenção específica ou --arquivo <contrato-ou-código> para resolver o escopo. Não edite enquanto houver ambiguidade."],
|
|
68
|
+
orcamento: { metodo: "chars_div_4", tokensEstimadosResposta: 0, limiteTokens: perfil.orcamentoTokens, contagemExata: false, contextoDaConversaMedido: false },
|
|
65
69
|
};
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
console.log(`Sessao Sema — ${envelope.workspace.nomePasta}`);
|
|
71
|
-
console.log(` Hash contratos: ${envelope.workspace.hashContratos}`);
|
|
72
|
-
console.log(` CLI: ${envelope.workspace.cliVersao}`);
|
|
73
|
-
console.log(` Frescor: ${frescor.fresco ? "fresco" : "STALE"} ${!frescor.fresco ? `(${frescor.sugestao})` : ""}`);
|
|
74
|
-
console.log(` Contratos: ${envelope.contratos.total}`);
|
|
75
|
-
if (intencao) {
|
|
76
|
-
console.log(` Intencao: ${intencao}`);
|
|
77
|
-
console.log(` Categorias: ${categorias.join(", ")}`);
|
|
78
|
-
console.log(` Docs bloqueantes: ${docsBloqueantes.length}`);
|
|
79
|
-
console.log(` Docs recomendadas: ${docsRecomendadas.length}`);
|
|
70
|
+
while (estimarRespostaTokens(payload) > perfil.orcamentoTokens && payload.contexto?.candidatos.length) {
|
|
71
|
+
payload.contexto.candidatos.pop();
|
|
72
|
+
payload.contexto.candidatosOmitidos++;
|
|
80
73
|
}
|
|
81
|
-
|
|
82
|
-
|
|
74
|
+
if (payload.contexto?.candidatosOmitidos) {
|
|
75
|
+
payload.status = "refinar_escopo";
|
|
76
|
+
payload.proximosPassos = ["Há candidatos omitidos pelo orçamento. Refine a intenção ou informe --arquivo; não interprete omissão como ausência de dependência."];
|
|
83
77
|
}
|
|
84
|
-
|
|
78
|
+
for (let i = 0; i < 3; i++)
|
|
79
|
+
payload.orcamento.tokensEstimadosResposta = estimarRespostaTokens(payload);
|
|
80
|
+
if (payload.orcamento.tokensEstimadosResposta > perfil.orcamentoTokens)
|
|
81
|
+
return emitir({
|
|
82
|
+
comando: "sessao", sucesso: false, status: "orcamento_insuficiente", execucaoAutorizada: false,
|
|
83
|
+
proximosPassos: ["Metadados e leituras bloqueantes excedem o orçamento. Refine --arquivo ou ajuste --orcamento-contexto; nenhuma leitura foi dispensada."],
|
|
84
|
+
}, 1);
|
|
85
|
+
return emitir(payload);
|
|
85
86
|
}
|
|
86
87
|
//# sourceMappingURL=comandoSessao.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const ARQUIVO_PERFIL_CONTEXTO = ".sema/contexto-ia.json";
|
|
2
|
+
export declare const OPCOES_CONTEXTO: readonly ["--janela-contexto", "--orcamento-contexto", "--reserva-saida"];
|
|
3
|
+
export declare const PERGUNTA_CONTEXTO = "Qual \u00E9 a janela de contexto efetivamente configurada para esta IA, em tokens?";
|
|
4
|
+
export interface PerfilContexto {
|
|
5
|
+
schema: "sema.agent-context-profile/v1";
|
|
6
|
+
janelaTokens: number;
|
|
7
|
+
orcamentoTokens: number;
|
|
8
|
+
reservaSaidaTokens: number;
|
|
9
|
+
}
|
|
10
|
+
export declare function criarPerfilContexto(janela: number, orcamento?: number, reserva?: number): PerfilContexto;
|
|
11
|
+
export declare function numeroOpcaoContexto(args: readonly string[], nome: string): number | undefined;
|
|
12
|
+
export declare function lerPerfilContexto(base: string): Promise<PerfilContexto | undefined>;
|
|
13
|
+
export declare function resolverPerfilContexto(base: string, args: readonly string[]): Promise<PerfilContexto | undefined>;
|
|
14
|
+
export declare function salvarPerfilContexto(base: string, perfil: PerfilContexto): Promise<void>;
|
|
15
|
+
export declare function estimarRespostaTokens(payload: unknown): number;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// SEMA-GOVERNED: sema.produto.cli_sessao
|
|
2
|
+
// Descrição: perfil local explícito e orçamento estimado de contexto, sem inferir capacidade pelo modelo.
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { escreverArquivoWorkspaceSeguro, validarDestinosEscritaWorkspace } from "./workspaceWrite.js";
|
|
6
|
+
export const ARQUIVO_PERFIL_CONTEXTO = ".sema/contexto-ia.json";
|
|
7
|
+
export const OPCOES_CONTEXTO = ["--janela-contexto", "--orcamento-contexto", "--reserva-saida"];
|
|
8
|
+
export const PERGUNTA_CONTEXTO = "Qual é a janela de contexto efetivamente configurada para esta IA, em tokens?";
|
|
9
|
+
export function criarPerfilContexto(janela, orcamento, reserva) {
|
|
10
|
+
const perfil = {
|
|
11
|
+
schema: "sema.agent-context-profile/v1",
|
|
12
|
+
janelaTokens: janela,
|
|
13
|
+
orcamentoTokens: orcamento ?? Math.min(4096, Math.floor(janela / 8)),
|
|
14
|
+
reservaSaidaTokens: reserva ?? Math.min(4096, Math.floor(janela / 4)),
|
|
15
|
+
};
|
|
16
|
+
if (![perfil.janelaTokens, perfil.orcamentoTokens, perfil.reservaSaidaTokens].every(Number.isSafeInteger)
|
|
17
|
+
|| janela < 4096 || perfil.orcamentoTokens < 512 || perfil.reservaSaidaTokens < 256
|
|
18
|
+
|| perfil.orcamentoTokens + perfil.reservaSaidaTokens > janela - 1024) {
|
|
19
|
+
throw new Error("Perfil inválido: janela >= 4096, orçamento >= 512, reserva >= 256 e pelo menos 1024 tokens livres para instruções e conversa.");
|
|
20
|
+
}
|
|
21
|
+
return perfil;
|
|
22
|
+
}
|
|
23
|
+
export function numeroOpcaoContexto(args, nome) {
|
|
24
|
+
const indice = args.findIndex((arg) => arg === nome || arg.startsWith(`${nome}=`));
|
|
25
|
+
if (indice < 0)
|
|
26
|
+
return undefined;
|
|
27
|
+
const raw = args[indice].startsWith(`${nome}=`) ? args[indice].slice(nome.length + 1) : args[indice + 1];
|
|
28
|
+
if (!raw || !/^[1-9]\d*$/u.test(raw) || !Number.isSafeInteger(Number(raw))) {
|
|
29
|
+
throw new Error(`${nome} exige um inteiro positivo em tokens.`);
|
|
30
|
+
}
|
|
31
|
+
return Number(raw);
|
|
32
|
+
}
|
|
33
|
+
export async function lerPerfilContexto(base) {
|
|
34
|
+
const [destino] = await validarDestinosEscritaWorkspace(base, [ARQUIVO_PERFIL_CONTEXTO]);
|
|
35
|
+
if (!destino?.existe)
|
|
36
|
+
return undefined;
|
|
37
|
+
const perfil = JSON.parse(await readFile(path.join(base, ARQUIVO_PERFIL_CONTEXTO), "utf8"));
|
|
38
|
+
if (perfil.schema !== "sema.agent-context-profile/v1")
|
|
39
|
+
throw new Error("Schema do perfil de contexto inválido.");
|
|
40
|
+
return criarPerfilContexto(perfil.janelaTokens, perfil.orcamentoTokens, perfil.reservaSaidaTokens);
|
|
41
|
+
}
|
|
42
|
+
export async function resolverPerfilContexto(base, args) {
|
|
43
|
+
const janela = numeroOpcaoContexto(args, "--janela-contexto");
|
|
44
|
+
const orcamento = numeroOpcaoContexto(args, "--orcamento-contexto");
|
|
45
|
+
const reserva = numeroOpcaoContexto(args, "--reserva-saida");
|
|
46
|
+
const salvo = await lerPerfilContexto(base);
|
|
47
|
+
if (janela !== undefined)
|
|
48
|
+
return criarPerfilContexto(janela, orcamento, reserva);
|
|
49
|
+
if (!salvo) {
|
|
50
|
+
if (orcamento !== undefined || reserva !== undefined)
|
|
51
|
+
throw new Error("Informe --janela-contexto antes de ajustar o orçamento.");
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
return criarPerfilContexto(salvo.janelaTokens, orcamento ?? salvo.orcamentoTokens, reserva ?? salvo.reservaSaidaTokens);
|
|
55
|
+
}
|
|
56
|
+
export async function salvarPerfilContexto(base, perfil) {
|
|
57
|
+
await escreverArquivoWorkspaceSeguro(base, ARQUIVO_PERFIL_CONTEXTO, `${JSON.stringify(perfil, null, 2)}\n`, { sobrescrever: true });
|
|
58
|
+
}
|
|
59
|
+
// Reserva conservadora para o envelope público e a indentação que o adaptador acrescenta.
|
|
60
|
+
export function estimarRespostaTokens(payload) {
|
|
61
|
+
const envelope = { schemaVersion: "sema.cli.result/v1", ok: true, kind: "SUCCESS", command: "sessao", code: "CLI_SUCCESS", message: null, exitCode: 0, payload };
|
|
62
|
+
return Math.ceil((JSON.stringify(envelope, null, 2).length + 256) / 4);
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=contextBudget.js.map
|
package/dist/docs.part01.js
CHANGED
|
@@ -309,7 +309,6 @@ export function resumoConteudo(conteudo) {
|
|
|
309
309
|
export async function adicionarDocsRaizExistentes(baseProjeto, registrar) {
|
|
310
310
|
const docsRaiz = [
|
|
311
311
|
{ relativo: "AGENTS.md", tipo: "raiz", motivo: "regras obrigatorias do agente no projeto" },
|
|
312
|
-
{ relativo: "SEMA_INDEX.json", tipo: "raiz", motivo: "indice IA-first do projeto" },
|
|
313
312
|
{ relativo: "README.md", tipo: "raiz", motivo: "visao geral publica do projeto" },
|
|
314
313
|
{ relativo: "docs/README.md", tipo: "documentacao", motivo: "indice de documentacao" },
|
|
315
314
|
];
|
package/dist/docs.part02.js
CHANGED
|
@@ -2,29 +2,12 @@
|
|
|
2
2
|
// Descricao: resolve e cria documentacao obrigatoria sem escapar do workspace nem gravar lotes parcialmente.
|
|
3
3
|
import { readFile } from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
|
+
import { resolverRelacoesDocumentais } from "./docsRelations.js";
|
|
5
6
|
import { emitirDiagnosticosArquivosOrcamento } from "./driftOrcamento.js";
|
|
6
7
|
import { escreverArquivoWorkspaceSeguro, validarDestinosEscritaWorkspace, } from "./workspaceWrite.js";
|
|
7
|
-
import { REGRAS_DOCUMENTACAO, adicionarDocsRaizExistentes, adicionarReadmesDeArquivos, caminhoEstaDentro, caminhoExiste, criarTemplateDoc, documentoPareceTemplateCriadoPelaSema, documentoTemSubstancia, inferirCategorias,
|
|
8
|
+
import { REGRAS_DOCUMENTACAO, adicionarDocsRaizExistentes, adicionarReadmesDeArquivos, caminhoEstaDentro, caminhoExiste, criarTemplateDoc, documentoPareceTemplateCriadoPelaSema, documentoTemSubstancia, inferirCategorias, normalizarRelativo, resumoConteudo } from "./docs.part01.js";
|
|
8
9
|
export async function adicionarContratosRelacionados(baseProjeto, intencao, arquivosAlvo, registrar) {
|
|
9
|
-
|
|
10
|
-
if (!(await caminhoExiste(pastaContratos))) {
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
const termos = termosRelacionamentoContratos(intencao, arquivosAlvo);
|
|
14
|
-
const arquivos = (await listarArquivosRecursivo(pastaContratos)).filter((arquivo) => arquivo.endsWith(".sema"));
|
|
15
|
-
for (const arquivo of arquivos) {
|
|
16
|
-
const relativo = normalizarRelativo(path.relative(baseProjeto, arquivo));
|
|
17
|
-
const nome = normalizarTexto(relativo);
|
|
18
|
-
const relacionado = termos.some((parte) => nome.includes(parte));
|
|
19
|
-
if (relacionado) {
|
|
20
|
-
registrar({
|
|
21
|
-
relativo,
|
|
22
|
-
tipo: "contrato",
|
|
23
|
-
motivo: "contrato Sema relacionado a intencao declarada",
|
|
24
|
-
permitirCriacao: false,
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
}
|
|
10
|
+
await resolverRelacoesDocumentais(baseProjeto, intencao, arquivosAlvo, registrar);
|
|
28
11
|
}
|
|
29
12
|
export function criarRegistrador(baseProjeto) {
|
|
30
13
|
const docs = [];
|
|
@@ -34,6 +17,11 @@ export function criarRegistrador(baseProjeto) {
|
|
|
34
17
|
registrar(doc) {
|
|
35
18
|
const relativo = normalizarRelativo(doc.relativo);
|
|
36
19
|
const absoluto = path.resolve(baseProjeto, relativo);
|
|
20
|
+
if (vistos.has(relativo) && doc.obrigatoriedade !== "recomendada") {
|
|
21
|
+
const anterior = docs.find((item) => item.relativo === relativo);
|
|
22
|
+
if (anterior)
|
|
23
|
+
Object.assign(anterior, doc, { relativo, obrigatoriedade: "bloqueante" });
|
|
24
|
+
}
|
|
37
25
|
if (!caminhoEstaDentro(baseProjeto, absoluto) || vistos.has(relativo)) {
|
|
38
26
|
return;
|
|
39
27
|
}
|
|
@@ -86,7 +74,7 @@ export async function resolverDocumentacaoObrigatoria(opcoes) {
|
|
|
86
74
|
existe,
|
|
87
75
|
criado,
|
|
88
76
|
criacaoAutomatica: doc.permitirCriacao,
|
|
89
|
-
obrigatorio:
|
|
77
|
+
obrigatorio: doc.obrigatoriedade !== "recomendada",
|
|
90
78
|
obrigatoriedade: doc.obrigatoriedade ?? "bloqueante",
|
|
91
79
|
template: existe ? undefined : template,
|
|
92
80
|
};
|
|
@@ -100,7 +88,7 @@ export async function resolverDocumentacaoObrigatoria(opcoes) {
|
|
|
100
88
|
}
|
|
101
89
|
leituraObrigatoria.push(item);
|
|
102
90
|
}
|
|
103
|
-
const docsAusentes = leituraObrigatoria.filter((doc) => !doc.existe);
|
|
91
|
+
const docsAusentes = leituraObrigatoria.filter((doc) => !doc.existe && doc.obrigatoriedade !== "recomendada");
|
|
104
92
|
const docsCriadas = leituraObrigatoria.filter((doc) => doc.criado);
|
|
105
93
|
const bloqueios = docsAusentes.filter((doc) => doc.obrigatoriedade !== "recomendada").map((doc) => ({
|
|
106
94
|
tipo: "documentacao_ausente",
|
|
@@ -116,7 +104,7 @@ export async function resolverDocumentacaoObrigatoria(opcoes) {
|
|
|
116
104
|
intencao,
|
|
117
105
|
categorias,
|
|
118
106
|
arquivosAlvo,
|
|
119
|
-
leituraObrigatoria,
|
|
107
|
+
leituraObrigatoria: leituraObrigatoria.filter((doc) => doc.obrigatoriedade !== "recomendada"),
|
|
120
108
|
docsAusentes,
|
|
121
109
|
docsCriadas,
|
|
122
110
|
leituraRecomendada: leituraObrigatoria
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// SEMA-GOVERNED: sema.produto.governanca_ia.documentacao
|
|
2
|
+
// Descrição: resolve contrato exato, vínculos e dependências declaradas; palavras são apenas recomendações.
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { tokenizar, parsear, listarCandidatosUseRelativo } from "@sema/nucleo";
|
|
6
|
+
import { validarDestinosEscritaWorkspace } from "./workspaceWrite.js";
|
|
7
|
+
import { caminhoExiste, caminhoEstaDentro, listarArquivosRecursivo, normalizarRelativo, normalizarTexto, termosRelacionamentoContratos } from "./docs.part01.js";
|
|
8
|
+
export async function resolverRelacoesDocumentais(base, intencao, alvos, registrar) {
|
|
9
|
+
const relativo = (p) => {
|
|
10
|
+
const absoluto = path.resolve(base, p);
|
|
11
|
+
if (!caminhoEstaDentro(base, absoluto))
|
|
12
|
+
throw new Error("Referência documental fora do workspace.");
|
|
13
|
+
return normalizarRelativo(path.relative(base, absoluto));
|
|
14
|
+
};
|
|
15
|
+
const explicitos = alvos.map(relativo);
|
|
16
|
+
const pasta = path.join(base, "contratos");
|
|
17
|
+
const caminhos = await caminhoExiste(pasta) ? (await listarArquivosRecursivo(pasta, Number.POSITIVE_INFINITY)).filter((p) => p.endsWith(".sema")).map(relativo) : [];
|
|
18
|
+
const todos = [...new Set([...caminhos, ...explicitos.filter((p) => p.endsWith(".sema"))])];
|
|
19
|
+
await validarDestinosEscritaWorkspace(base, todos);
|
|
20
|
+
const catalogo = new Map();
|
|
21
|
+
for (const p of todos) {
|
|
22
|
+
if (!await caminhoExiste(path.join(base, p)))
|
|
23
|
+
continue;
|
|
24
|
+
const lexer = tokenizar(await readFile(path.join(base, p), "utf8"), p);
|
|
25
|
+
const parser = parsear(lexer.tokens);
|
|
26
|
+
if (parser.modulo && lexer.diagnosticos.length === 0 && parser.diagnosticos.length === 0)
|
|
27
|
+
catalogo.set(p, parser.modulo);
|
|
28
|
+
}
|
|
29
|
+
const fila = explicitos.filter((p) => p.endsWith(".sema"))
|
|
30
|
+
.map((arquivo) => ({ arquivo, motivo: "Contrato informado explicitamente em --arquivo" }));
|
|
31
|
+
for (const [arquivo, modulo] of catalogo) {
|
|
32
|
+
const donos = [modulo, ...modulo.tasks, ...modulo.routes, ...modulo.flows];
|
|
33
|
+
for (const dono of donos) {
|
|
34
|
+
for (const campo of dono.vinculos?.campos ?? []) {
|
|
35
|
+
if (campo.nome !== "arquivo")
|
|
36
|
+
continue;
|
|
37
|
+
const vinculo = relativo(campo.valor.replace(/^["']|["']$/g, ""));
|
|
38
|
+
if (explicitos.includes(vinculo))
|
|
39
|
+
fila.push({ arquivo, motivo: `Vínculo declarado em ${modulo.nome}: ${vinculo}` });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const vistos = new Set();
|
|
44
|
+
for (let i = 0; i < fila.length; i++) {
|
|
45
|
+
const item = fila[i];
|
|
46
|
+
if (vistos.has(item.arquivo))
|
|
47
|
+
continue;
|
|
48
|
+
vistos.add(item.arquivo);
|
|
49
|
+
registrar({ relativo: item.arquivo, tipo: "contrato", motivo: item.motivo, permitirCriacao: false });
|
|
50
|
+
const modulo = catalogo.get(item.arquivo);
|
|
51
|
+
if (!modulo) {
|
|
52
|
+
if (await caminhoExiste(path.join(base, item.arquivo)))
|
|
53
|
+
throw new Error(`Contrato inválido: ${item.arquivo}. Rode sema validar.`);
|
|
54
|
+
continue; // O resolvedor público transforma o contrato ausente em bloqueio.
|
|
55
|
+
}
|
|
56
|
+
for (const use of modulo.uses.filter((u) => u.origem === "sema")) {
|
|
57
|
+
let encontrados = [];
|
|
58
|
+
for (const nome of [use.caminho, ...listarCandidatosUseRelativo(modulo.nome, use.caminho)]) {
|
|
59
|
+
encontrados = [...catalogo].filter(([, m]) => m.nome === nome);
|
|
60
|
+
if (encontrados.length)
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
if (encontrados.length !== 1)
|
|
64
|
+
throw new Error(`Dependência use ${use.caminho} de ${item.arquivo} ausente ou ambígua. Rode sema validar.`);
|
|
65
|
+
fila.push({ arquivo: encontrados[0][0], motivo: `Dependência use ${use.caminho} declarada em ${item.arquivo}` });
|
|
66
|
+
}
|
|
67
|
+
for (const campo of modulo.docs?.campos ?? []) {
|
|
68
|
+
if (campo.nome !== "arquivo")
|
|
69
|
+
continue;
|
|
70
|
+
const doc = relativo(campo.valor.replace(/^["']|["']$/g, ""));
|
|
71
|
+
const motivo = `Referência docs.arquivo declarada em ${item.arquivo}`;
|
|
72
|
+
registrar({ relativo: doc, tipo: doc.endsWith(".sema") ? "contrato" : "documentacao", motivo, permitirCriacao: false, obrigatoriedade: "recomendada" });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Arquivo explícito fixa o escopo; não acrescentar contratos por palavras genéricas.
|
|
76
|
+
if (explicitos.length > 0)
|
|
77
|
+
return;
|
|
78
|
+
const termos = termosRelacionamentoContratos(intencao, []);
|
|
79
|
+
const sugestoes = [...catalogo].filter(([arquivo]) => termos.some((t) => normalizarTexto(path.basename(arquivo, ".sema")).includes(t))).slice(0, 8);
|
|
80
|
+
for (const [arquivo] of sugestoes)
|
|
81
|
+
registrar({ relativo: arquivo, tipo: "contrato", motivo: "Sugestão por intenção; confirme o contrato usando --arquivo", permitirCriacao: false, obrigatoriedade: "recomendada" });
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=docsRelations.js.map
|
package/dist/geracaoCore.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export interface ResumoAlvoVerificacao {
|
|
|
18
18
|
estrutura: EstruturaSaida;
|
|
19
19
|
testesExecutados: boolean;
|
|
20
20
|
origem?: "executado" | "cache";
|
|
21
|
-
tipoEvidencia?: "andaime_demonstrativo";
|
|
21
|
+
tipoEvidencia?: "andaime_demonstrativo" | "implementacao_local_preservada";
|
|
22
22
|
implementacaoExternaExecutada?: boolean;
|
|
23
23
|
}
|
|
24
24
|
export interface ResumoModuloVerificacao {
|
package/dist/index.part07.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { EstruturaSaida } from "./tipos.js";
|
|
|
3
3
|
export interface OpcoesVerificar {
|
|
4
4
|
alvo?: string;
|
|
5
5
|
semCache?: boolean;
|
|
6
|
+
preservarImplementacao?: boolean;
|
|
6
7
|
}
|
|
7
8
|
export declare function alvosSuportadosPelaStack(fontesLegado: string[] | undefined): AlvoGeracao[] | undefined;
|
|
8
9
|
export declare function avisoEscopoStackVerificacao(fontesLegado: string[] | undefined, alvosEfetivos: AlvoGeracao[]): string | undefined;
|