@semacode/cli 3.9.2 → 3.9.4

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/README.md CHANGED
@@ -75,16 +75,16 @@ Unknown commands/subcommands, missing or invalid CLI syntax, and uncaught
75
75
  runtime exceptions use the control envelope; structured domain-level failures
76
76
  after valid dispatch use `sema.cli.result/v1` with `kind: "DOMAIN_ERROR"`.
77
77
 
78
- ## Codex Setup
78
+ ## Agent Setup
79
79
 
80
- `AGENTS.md` is the official Sema entrypoint for Codex:
80
+ `AGENTS.md` is the official Sema entrypoint for coding agents:
81
81
 
82
82
  ```bash
83
83
  sema sync-codex --json
84
84
  ```
85
85
 
86
- Codex automatically loads `AGENTS.md` as durable repository guidance. See the
87
- [Codex `AGENTS.md` documentation](https://learn.chatgpt.com/docs/agent-configuration/agents-md).
86
+ Agent tools that read `AGENTS.md` — Claude, Codex, zCode (GLM) and Kimi among
87
+ them — load it as durable repository guidance.
88
88
 
89
89
  The CLI is the engine and source of truth; `AGENTS.md` is the automatic
90
90
  workspace protocol. The Sema skill bootstraps a project that does not have Sema
@@ -107,7 +107,7 @@ If a shell still cannot resolve `sema`, invoke the managed launcher directly:
107
107
  On Windows, PowerShell resolves `sema.ps1` from `PATH`, `cmd.exe` resolves
108
108
  `sema.cmd`, and `sema-managed.ps1` is the PATH-independent fallback.
109
109
 
110
- ## Codex-Native Architecture
110
+ ## Architecture
111
111
 
112
112
  - `AGENTS.md` is the only official entrypoint. `sync-codex` changes only valid
113
113
  Sema-managed blocks and preserves malformed or manual content for review.
@@ -149,7 +149,7 @@ sema sync-codex --json
149
149
 
150
150
  Initialization preserves existing files and rejects symlink or junction
151
151
  escapes. Use `--force` only when overwriting the template destinations is an
152
- explicit human decision; the Codex bootstrap skill never adds it.
152
+ explicit human decision; the bootstrap skill never adds it.
153
153
 
154
154
  ## Code Generation
155
155
 
package/dist/bin.js CHANGED
@@ -105,6 +105,16 @@ export async function executarCliPublica(argv = process.argv.slice(2)) {
105
105
  if (!execucao) {
106
106
  return emitirFalhaControle(argv, "FATAL_ERROR", "CLI_FATAL_ERROR", "Falha ao executar a CLI da Sema.", 1);
107
107
  }
108
+ try {
109
+ const doc = JSON.parse(execucao.stdout.trim());
110
+ if (doc.schemaVersion === "sema.cli.control/v1" && typeof doc.kind === "string" && doc.exitCode === execucao.codigoSaida) {
111
+ console.log(execucao.stdout);
112
+ return execucao.codigoSaida;
113
+ }
114
+ }
115
+ catch {
116
+ // nao e um envelope de controle; segue o caminho normal
117
+ }
108
118
  return emitirResultadoCliJsonV1({
109
119
  comando: sintaxe.comando,
110
120
  codigoSaida: execucao.codigoSaida,
@@ -1,12 +1,17 @@
1
- export type CategoriaFalhaControleCli = "UNKNOWN_COMMAND" | "ARGUMENT_ERROR" | "FATAL_ERROR";
1
+ export type CategoriaFalhaControleCli = "UNKNOWN_COMMAND" | "ARGUMENT_ERROR" | "CONTRACT_NOT_FOUND" | "FATAL_ERROR";
2
2
  export declare class CliControlError extends Error {
3
3
  readonly categoria: CategoriaFalhaControleCli;
4
4
  readonly codigoPublico: string;
5
5
  readonly mensagemPublica: string;
6
6
  readonly codigoSaida: number;
7
- constructor(categoria: CategoriaFalhaControleCli);
7
+ readonly detalhes?: Record<string, unknown>;
8
+ constructor(categoria: CategoriaFalhaControleCli, detalhes?: Record<string, unknown>);
8
9
  }
9
10
  export declare function erroComandoDesconhecido(): CliControlError;
10
11
  export declare function erroArgumentoInvalido(): CliControlError;
12
+ export declare function erroContratoNaoEncontrado(detalhes: {
13
+ caminhoTentado: string;
14
+ sugeridos: string[];
15
+ }): CliControlError;
11
16
  export declare function erroFatalCli(): CliControlError;
12
17
  export declare function ehCliControlError(valor: unknown): valor is CliControlError;
@@ -1,5 +1,6 @@
1
1
  // SEMA-GOVERNED: sema.produto.cli_invocacao_publica.argumentos
2
2
  // Descrição: representa falhas públicas de controle sem carregar argv, stack ou caminhos na mensagem.
3
+ const MENSAGEM_CONTRATO_NAO_ENCONTRADO = "Contrato Sema nao encontrado. Consulte os contratos sugeridos no envelope.";
3
4
  const DEFINICOES_FALHA_CONTROLE = Object.freeze({
4
5
  UNKNOWN_COMMAND: Object.freeze({
5
6
  codigoPublico: "CLI_UNKNOWN_COMMAND",
@@ -11,6 +12,11 @@ const DEFINICOES_FALHA_CONTROLE = Object.freeze({
11
12
  mensagemPublica: "Argumentos inválidos. Consulte a ajuda do comando.",
12
13
  codigoSaida: 1,
13
14
  }),
15
+ CONTRACT_NOT_FOUND: Object.freeze({
16
+ codigoPublico: "CLI_CONTRACT_NOT_FOUND",
17
+ mensagemPublica: MENSAGEM_CONTRATO_NAO_ENCONTRADO,
18
+ codigoSaida: 2,
19
+ }),
14
20
  FATAL_ERROR: Object.freeze({
15
21
  codigoPublico: "CLI_FATAL_ERROR",
16
22
  mensagemPublica: "Falha ao executar a CLI da Sema.",
@@ -22,7 +28,8 @@ export class CliControlError extends Error {
22
28
  codigoPublico;
23
29
  mensagemPublica;
24
30
  codigoSaida;
25
- constructor(categoria) {
31
+ detalhes;
32
+ constructor(categoria, detalhes) {
26
33
  const definicao = DEFINICOES_FALHA_CONTROLE[categoria];
27
34
  super(definicao.mensagemPublica);
28
35
  this.name = "CliControlError";
@@ -30,6 +37,7 @@ export class CliControlError extends Error {
30
37
  this.codigoPublico = definicao.codigoPublico;
31
38
  this.mensagemPublica = definicao.mensagemPublica;
32
39
  this.codigoSaida = definicao.codigoSaida;
40
+ this.detalhes = detalhes;
33
41
  }
34
42
  }
35
43
  export function erroComandoDesconhecido() {
@@ -38,6 +46,9 @@ export function erroComandoDesconhecido() {
38
46
  export function erroArgumentoInvalido() {
39
47
  return new CliControlError("ARGUMENT_ERROR");
40
48
  }
49
+ export function erroContratoNaoEncontrado(detalhes) {
50
+ return new CliControlError("CONTRACT_NOT_FOUND", detalhes);
51
+ }
41
52
  export function erroFatalCli() {
42
53
  return new CliControlError("FATAL_ERROR");
43
54
  }
@@ -12,7 +12,21 @@ export async function executarCliRuntimeInterno(principalInjetado) {
12
12
  ? codigoSaida
13
13
  : CODIGO_SAIDA_FATAL_RUNTIME_CLI;
14
14
  }
15
- catch {
15
+ catch (erro) {
16
+ if (typeof erro?.categoria === "string" && erro.categoria) {
17
+ const cli = erro;
18
+ const envelope = {
19
+ schemaVersion: "sema.cli.control/v1",
20
+ ok: false,
21
+ kind: cli.categoria,
22
+ code: cli.codigoPublico,
23
+ message: cli.mensagemPublica,
24
+ exitCode: cli.codigoSaida,
25
+ ...(cli.detalhes ? { details: cli.detalhes } : {}),
26
+ };
27
+ console.log(JSON.stringify(envelope, null, 2));
28
+ return cli.codigoSaida;
29
+ }
16
30
  return CODIGO_SAIDA_FATAL_RUNTIME_CLI;
17
31
  }
18
32
  }
@@ -128,7 +128,7 @@ export async function listarArquivosRecursivo(base, limite = 80) {
128
128
  export const REGRAS_DOCUMENTACAO = [
129
129
  {
130
130
  categoria: "deploy",
131
- padroes: [/deploy/, /publicar/, /producao/, /release/, /pipeline/, /\bci\b/, /\bcd\b/, /vercel/, /cloudflare/, /docker/],
131
+ padroes: [/deploy/, /publicar/, /producao/, /release/, /pipeline/, /\bci\b/, /\bcd\b/, /vercel/, /cloudflare/, /docker/, /edge.?function/i, /\bruntime\b/i, /\blambda\b/i, /\bworker\b/i, /\bserverless\b/i],
132
132
  docs: [
133
133
  { relativo: "docs/deploy.md", tipo: "runbook", motivo: "runbook de deploy antes de publicar ou alterar pipeline", permitirCriacao: true },
134
134
  { relativo: "docs/env.md", tipo: "runbook", motivo: "variaveis, secrets e ambientes usados no deploy", permitirCriacao: true },
@@ -84,7 +84,7 @@ export function coletarResumoSemanticoModulo(contexto) {
84
84
  efeitos: limitarLista(efeitos, 8),
85
85
  erros: limitarLista(erros, 8),
86
86
  entidadesAfetadas: limitarLista(entidadesAfetadas, 8),
87
- arquivosProvaveis: limitarLista(unicosOrdenados(briefing.oQueTocar), 8),
87
+ arquivosProvaveis: limitarLista(unicosOrdenados(briefing.oQueTocar.map((item) => relativizarCaminho(item))), 8),
88
88
  simbolosRelacionados: limitarLista(unicosOrdenados(briefing.simbolosRelacionados), 8),
89
89
  riscosPrincipais: limitarLista(unicosOrdenados(briefing.riscosPrincipais), 6),
90
90
  lacunas: limitarLista(unicosOrdenados(briefing.oQueEstaFrouxo), 6),
@@ -96,7 +96,7 @@ export function coletarResumoSemanticoModulo(contexto) {
96
96
  consumerSurfaces: limitarLista(unicosOrdenados(briefing.consumerSurfaces ?? []), 8),
97
97
  consumerBridges: limitarLista(unicosOrdenados(briefing.consumerBridges ?? []), 8),
98
98
  ancoragensVinculo: limitarLista(unicosOrdenados(briefing.ancoragensVinculo ?? []), 8),
99
- arquivosProvaveisEditar: limitarLista(unicosOrdenados(briefing.arquivosProvaveisEditar ?? briefing.oQueTocar), 8),
99
+ arquivosProvaveisEditar: limitarLista(unicosOrdenados((briefing.arquivosProvaveisEditar ?? briefing.oQueTocar).map((item) => relativizarCaminho(item))), 8),
100
100
  };
101
101
  return modoVerificacaoCodigo === "codigo_completo"
102
102
  ? resumo
@@ -357,4 +357,10 @@ Contexto compacto:
357
357
  ${resumoTexto}
358
358
  `;
359
359
  }
360
+ function relativizarCaminho(caminho) {
361
+ const base = process.cwd();
362
+ const absoluto = path.resolve(base, caminho);
363
+ const relativo = path.relative(base, absoluto);
364
+ return relativo && !relativo.startsWith("..") ? relativo.replace(/[\\/]/g, "/") : caminho.replace(/[\\/]/g, "/");
365
+ }
360
366
  //# sourceMappingURL=index.part02.js.map
@@ -142,7 +142,10 @@ export async function gerarResumoProjetoIa(entrada, pastaSaidaOpcional, escrever
142
142
  entradaCanonica,
143
143
  agentContextPack,
144
144
  guiaPorCapacidade,
145
- topArquivosCodigoDetectados: arquivosCodigoDetectados,
145
+ topArquivosCodigoDetectados: arquivosCodigoDetectados.map((item) => {
146
+ const rel = path.relative(contextoProjeto.baseProjeto, item);
147
+ return rel && !rel.startsWith("..") ? rel.replace(/[\\/]/g, "/") : item.replace(/[\\/]/g, "/");
148
+ }),
146
149
  modulos,
147
150
  };
148
151
  const micro = [
@@ -14,7 +14,7 @@ import { resolverAnaliseDriftConsultaCli, resolverOpcoesDriftCli } from "./index
14
14
  export async function comandoInspecionar(entrada, emJson, cwd = process.cwd(), args = []) {
15
15
  const analiseDrift = resolverAnaliseDriftConsultaCli(args, "inspecionar");
16
16
  const alvo = entrada ? path.resolve(cwd, entrada) : cwd;
17
- const alvoEhArquivo = (await stat(alvo)).isFile();
17
+ const alvoEhArquivo = (await stat(alvo).catch(() => undefined))?.isFile() ?? false;
18
18
  const escopoEstreito = analiseDrift.opcoes.escopo === "arquivo"
19
19
  || analiseDrift.opcoes.escopo === "modulo"
20
20
  || (analiseDrift.opcoes.escopo === undefined
@@ -291,7 +291,7 @@ export async function comandoResumo(entrada, args, emJson) {
291
291
  const escreverNaRaiz = possuiFlag(args, "--raiz");
292
292
  const alvo = entrada ? path.resolve(process.cwd(), entrada) : process.cwd();
293
293
  const analiseDrift = resolverAnaliseDriftConsultaCli(args, "resumo");
294
- const alvoEhArquivo = (await stat(alvo)).isFile();
294
+ const alvoEhArquivo = (await stat(alvo).catch(() => undefined))?.isFile() ?? false;
295
295
  if (alvoEhArquivo) {
296
296
  const contexto = await carregarContextoModuloIa(alvo, analiseDrift);
297
297
  const resumoSemantico = coletarResumoSemanticoModulo(contexto);
@@ -1,2 +1,8 @@
1
1
  import type { ContextoProjetoCarregado, OpcoesCarregarProjeto } from './projetoTipos.js';
2
+ export declare class ErroContratoNaoEncontrado extends Error {
3
+ readonly caminhoTentado: string;
4
+ readonly sugeridos: string[];
5
+ constructor(mensagem: string, caminhoTentado: string, sugeridos: string[]);
6
+ paraControleCli(): import("./cliControlError.js").CliControlError;
7
+ }
2
8
  export declare function carregarProjeto(entrada: string | undefined, cwd: string, opcoes?: OpcoesCarregarProjeto): Promise<ContextoProjetoCarregado>;
@@ -1,6 +1,7 @@
1
1
  // SEMA-GOVERNED: sema.produto.governanca_ia.contexto, sema.produto.governanca_ia.drift.cache.modos
2
2
  // Descrição: orquestra leitura de contratos, compilação e seleção de módulos do projeto.
3
3
  import { stat } from 'node:fs/promises';
4
+ import { erroContratoNaoEncontrado } from './cliControlError.js';
4
5
  import path from 'node:path';
5
6
  import { compilarProjeto, listarArquivosSema } from '@sema/nucleo';
6
7
  import { canonicalizarContratosNoProjeto, carregarFechamentoContratosSema, carregarFontesContratos, } from './projetoCatalogo.js';
@@ -19,12 +20,53 @@ function resolverFontesLegadoDeclaradas(configCarregada) {
19
20
  .filter((fonte) => Boolean(fonte)))]
20
21
  .sort((a, b) => a.localeCompare(b, "pt-BR"));
21
22
  }
23
+ export class ErroContratoNaoEncontrado extends Error {
24
+ caminhoTentado;
25
+ sugeridos;
26
+ constructor(mensagem, caminhoTentado, sugeridos) {
27
+ super(mensagem);
28
+ this.caminhoTentado = caminhoTentado;
29
+ this.sugeridos = sugeridos;
30
+ this.name = "ErroContratoNaoEncontrado";
31
+ }
32
+ paraControleCli() {
33
+ return erroContratoNaoEncontrado({ caminhoTentado: this.caminhoTentado, sugeridos: this.sugeridos });
34
+ }
35
+ }
36
+ async function sugerirContratosProximos(baseProjeto, nomeArquivo) {
37
+ const origens = await resolverOrigensProjeto(baseProjeto, baseProjeto, undefined);
38
+ const encontrados = [];
39
+ for (const origem of origens) {
40
+ const arquivos = await listarArquivosDeOrigens([origem]);
41
+ for (const arquivo of arquivos) {
42
+ encontrados.push(path.relative(baseProjeto, arquivo).replace(/\\/g, "/"));
43
+ }
44
+ }
45
+ const alvo = nomeArquivo.replace(/\.sema$/i, "").toLowerCase();
46
+ return encontrados
47
+ .map((relativo) => ({
48
+ relativo,
49
+ pontuacao: relativo.toLowerCase().includes(alvo) ? 0 : 1,
50
+ }))
51
+ .sort((a, b) => a.pontuacao - b.pontuacao || a.relativo.localeCompare(b.relativo, "pt-BR"))
52
+ .map((item) => item.relativo).slice(0, 5);
53
+ }
22
54
  export async function carregarProjeto(entrada, cwd, opcoes = {}) {
23
55
  const entradaBase = entrada ? path.resolve(cwd, entrada) : cwd;
24
56
  const configCarregada = await carregarConfiguracaoProjeto(entradaBase);
25
57
  const entradaResolvida = entrada ? path.resolve(cwd, entrada) : await resolverEntradaPadrao(cwd, configCarregada);
58
+ const infoEntrada = await stat(entradaResolvida).catch(() => undefined);
59
+ if (!infoEntrada) {
60
+ const baseSugestao = configCarregada?.baseDiretorio ?? path.dirname(entradaResolvida);
61
+ const contratosProximos = entradaResolvida.toLowerCase().endsWith(".sema")
62
+ ? await sugerirContratosProximos(baseSugestao, path.basename(entradaResolvida))
63
+ : [];
64
+ throw erroContratoNaoEncontrado({
65
+ caminhoTentado: entradaResolvida,
66
+ sugeridos: contratosProximos.slice(0, 5),
67
+ });
68
+ }
26
69
  const baseProjeto = await resolverBaseProjeto(entradaResolvida, configCarregada);
27
- const infoEntrada = await stat(entradaResolvida);
28
70
  if (infoEntrada.isFile() && path.extname(entradaResolvida).toLowerCase() !== ".sema") {
29
71
  throw new Error(`Entrada de contrato precisa terminar em .sema: ${entradaResolvida}`);
30
72
  }
@@ -1,7 +1,7 @@
1
1
  import { type EntradaEnvelopeResultadoCliV1, type EnvelopeResultadoCliV1 } from "./resultadoCli.js";
2
2
  export { CODIGO_SAIDA_FATAL_RUNTIME_CLI, SCHEMA_RESULTADO_CLI_V1, criarEnvelopeResultadoCliV1, interpretarPayloadRuntimeCli, type EntradaEnvelopeResultadoCliV1, type EnvelopeResultadoCliV1, type TipoResultadoCliV1, } from "./resultadoCli.js";
3
3
  export declare const SCHEMA_CONTROLE_CLI_V1: "sema.cli.control/v1";
4
- export type TipoControleCli = "HELP" | "UNKNOWN_COMMAND" | "ARGUMENT_ERROR" | "FATAL_ERROR";
4
+ export type TipoControleCli = "HELP" | "UNKNOWN_COMMAND" | "ARGUMENT_ERROR" | "CONTRACT_NOT_FOUND" | "FATAL_ERROR";
5
5
  export interface EnvelopeControleJsonV1 {
6
6
  readonly schemaVersion: typeof SCHEMA_CONTROLE_CLI_V1;
7
7
  readonly ok: boolean;
@@ -9,12 +9,14 @@ export interface EnvelopeControleJsonV1 {
9
9
  readonly code: string;
10
10
  readonly message: string;
11
11
  readonly exitCode: number;
12
+ readonly details?: Record<string, unknown>;
12
13
  }
13
14
  export interface EntradaEnvelopeControleJsonV1 {
14
15
  readonly categoria: TipoControleCli;
15
16
  readonly codigoPublico: string;
16
17
  readonly mensagemPublica: string;
17
18
  readonly codigoSaida: number;
19
+ readonly detalhes?: Record<string, unknown>;
18
20
  }
19
21
  export interface OpcoesInvocacaoPublica {
20
22
  readonly resultado: TipoControleCli;
package/dist/saidaCli.js CHANGED
@@ -7,12 +7,14 @@ const CODIGO_PADRAO = {
7
7
  HELP: "CLI_HELP",
8
8
  UNKNOWN_COMMAND: "CLI_UNKNOWN_COMMAND",
9
9
  ARGUMENT_ERROR: "CLI_ARGUMENT_ERROR",
10
+ CONTRACT_NOT_FOUND: "CLI_CONTRACT_NOT_FOUND",
10
11
  FATAL_ERROR: "CLI_FATAL_ERROR",
11
12
  };
12
13
  const MENSAGEM_PADRAO = {
13
14
  HELP: "Ajuda da CLI Sema.",
14
15
  UNKNOWN_COMMAND: "Comando Sema desconhecido.",
15
16
  ARGUMENT_ERROR: "Argumentos inválidos. Consulte a ajuda do comando.",
17
+ CONTRACT_NOT_FOUND: "Contrato Sema nao encontrado. Consulte os detalhes no envelope.",
16
18
  FATAL_ERROR: "Falha ao executar a CLI da Sema.",
17
19
  };
18
20
  const CODIGO_PUBLICO_VALIDO = /^[A-Z][A-Z0-9_]{2,63}$/u;
@@ -75,6 +77,9 @@ export function criarEnvelopeControleJsonV1(entrada) {
75
77
  code: normalizarCodigoPublico(entrada.categoria, entrada.codigoPublico),
76
78
  message: normalizarMensagemPublica(entrada.categoria, entrada.mensagemPublica),
77
79
  exitCode,
80
+ ...(entrada.detalhes && entrada.categoria === "CONTRACT_NOT_FOUND"
81
+ ? { details: entrada.detalhes }
82
+ : {}),
78
83
  };
79
84
  }
80
85
  export function emitirResultadoCliJsonV1(entrada) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@semacode/cli",
3
- "version": "3.9.2",
3
+ "version": "3.9.4",
4
4
  "description": "Local-first semantic governance CLI for AI agents, proven with Claude, Codex, zCode (GLM) and Kimi: contracts, drift, impact, docs gates, and code generation.",
5
5
  "type": "module",
6
6
  "icon": "logo.png",