sauron-cli 1.4.5 → 1.4.7

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.
Files changed (3) hide show
  1. package/README.md +13 -2
  2. package/dist/index.js +62 -29
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > O "Lobo Frontal" dos assistentes de código de IA. Resolva a amnésia de contexto de uma vez por todas.
4
4
 
5
- O **Sauron CLI** é uma infraestrutura passiva de orquestração de contexto para IAs. Ele injeta um "Cérebro" estruturado nos seus repositórios, forçando as Inteligências Artificiais (como Cursor, Windsurf e Aider) a respeitarem um conceito de **"Write Obligation" (Obrigação de Escrita)**. Em vez de apenas ler código, a IA passará a documentar decisões de negócio e arquitetura continuamente, garantindo que o seu projeto não quebre após meses sem ser tocado.
5
+ O **Sauron CLI** é uma infraestrutura passiva de orquestração de contexto para IAs. Ele injeta um "Cérebro" estruturado nos seus repositórios, forçando as Inteligências Artificiais (como Cursor, Windsurf, Aider, Claude Code, Codex e Opencode) a respeitarem um conceito de **"Write Obligation" (Obrigação de Escrita)**. Em vez de apenas ler código, a IA passará a documentar decisões de negócio e arquitetura continuamente, garantindo que o seu projeto não quebre após meses sem ser tocado.
6
6
 
7
7
  ## O Problema
8
8
 
@@ -12,6 +12,16 @@ Assistentes de código são incrivelmente poderosos, mas sofrem de amnésia vol
12
12
 
13
13
  O Sauron resolve isso ejetando pastas estruturadas (`.sauron` e `.agents`) no seu repositório local. A partir desse momento, as IAs são condicionadas a documentar regras passivamente de acordo com os templates gerados, preservando o **Single Source of Truth** do seu produto.
14
14
 
15
+ ## Destaques da versão 1.4.7
16
+
17
+ A versão `1.4.7` aprimora a instalação passiva do Sauron para garantir que reinstalações e atualizações não dupliquem blocos de governança nos arquivos dos agentes.
18
+
19
+ - **Injeção de memória idempotente**: o `init` agora usa o template canônico `templates/.agents/rules/memory.md` como fonte limpa para os adaptadores, evitando aninhamento repetido de `SAURON START/END`.
20
+ - **Mais agentes detectados automaticamente**: o scanner agora reconhece Codex, Opencode e Claude Code, além de Cursor, Windsurf, Aider e Antigravity.
21
+ - **Marcadores de stack aninhados**: assinaturas como `prisma/schema.prisma` agora podem ser detectadas mesmo quando o arquivo marcador está dentro de subpastas conhecidas.
22
+ - **Auditoria mais fiel ao projeto**: o `doctor` prioriza os targets definidos no manifesto local antes do registro global da máquina.
23
+ - **Versão sincronizada**: `sauron --version` passa a ler a versão diretamente do `package.json`.
24
+
15
25
 
16
26
  ## Instalação
17
27
 
@@ -26,7 +36,7 @@ npx sauron-cli init
26
36
  ### `sauron init`
27
37
 
28
38
  Inicializa o Sauron Memory System no projeto atual de forma inteligente.
29
- O comando executa uma **varredura heurística não-bloqueante** ($O(1)$) na raiz do repositório para detectar de forma autônoma a linguagem primária, frameworks, bancos de dados, gerenciadores de pacotes e ferramentas de IA ativas (Cursor, Windsurf, Aider, Antigravity).
39
+ O comando executa uma **varredura heurística não-bloqueante** ($O(1)$) na raiz do repositório para detectar de forma autônoma a linguagem primária, frameworks, bancos de dados, gerenciadores de pacotes e ferramentas de IA ativas (Cursor, Windsurf, Aider, Antigravity, Claude Code, Codex, Opencode).
30
40
 
31
41
  Durante o onboarding interativo, as perguntas são pré-populadas de forma inteligente com as informações detectadas. Ao concluir, o Sauron realiza a **injeção automática de receitas de Wiki** (Wiki Recipes) personalizadas para a sua stack tecnológica em `.sauron/wiki/standards/` (ex. TypeScript, Next.js, React, Tailwind CSS, PostgreSQL) de forma idempotente e não-destrutiva, gerando o manifesto dinâmico `AGENTS.md` e as regras de governança locais das IAs.
32
42
 
@@ -35,6 +45,7 @@ O comando é totalmente **Idempotente**. Se executado em um repositório já ini
35
45
  - **Fast-Track (Bypass)**: O CLI detecta a configuração passada e oferece a opção de pular o onboarding, atualizando os agentes internos silenciosamente.
36
46
  - **Reidratação Interativa**: Caso você queira alterar a configuração, os formulários do terminal são reidratados com o seu último estado configurado, poupando a necessidade de redigitar contextos complexos.
37
47
  - **Wiki Protection**: Um filtro cirúrgico é ativado no motor de cópia da CLI, tornando a sua Base de Conhecimento em `.sauron/wiki/` 100% blindada contra *overwrites* acidentais durante a atualização.
48
+ - **Canonical Memory Payload**: Os arquivos específicos de agentes são regenerados a partir de uma fonte limpa de template, preservando a fluidez da governança passiva sem acumular wrappers de instalações anteriores.
38
49
 
39
50
  ### Como Atualizar um Projeto Existente
40
51
  Para trazer as regras e inteligências mais recentes para o seu repositório sem perder o seu contexto salvo, basta rodar o `init` forçando a versão `@latest` do NPM:
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
+ import { createRequire } from "module";
5
6
 
6
7
  // src/features/init/init.command.ts
7
8
  import fs13 from "fs-extra";
@@ -630,6 +631,28 @@ var WikiBootstrapper = class {
630
631
  };
631
632
 
632
633
  // src/features/init/init.service.ts
634
+ var ADAPTER_OWNED_TEMPLATE_FILES = /* @__PURE__ */ new Set([".agents/rules/memory.md"]);
635
+ function stripLeadingFrontmatter(content) {
636
+ let normalized = content.trimStart();
637
+ let previous = "";
638
+ while (normalized !== previous) {
639
+ previous = normalized;
640
+ normalized = normalized.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n*/, "").trimStart();
641
+ }
642
+ return normalized;
643
+ }
644
+ function normalizeMemoryRules(content) {
645
+ const withoutMarkers = content.replace(/^\s*# SAURON START\s*$/gm, "").replace(/^\s*# SAURON END\s*$/gm, "");
646
+ const normalized = stripLeadingFrontmatter(withoutMarkers).trim();
647
+ return normalized ? `${normalized}
648
+ ` : "";
649
+ }
650
+ async function loadCanonicalMemoryRules(templatesDir, fallbackContent) {
651
+ const templateMemoryPath = path11.join(templatesDir, ".agents", "rules", "memory.md");
652
+ const rawContent = await fs11.pathExists(templateMemoryPath) ? await fs11.readFile(templateMemoryPath, "utf8") : fallbackContent;
653
+ return normalizeMemoryRules(rawContent) || `${fallbackContent.trim()}
654
+ `;
655
+ }
633
656
  var InitService = class {
634
657
  registryService = new RegistryService();
635
658
  async execute(options, driver) {
@@ -651,8 +674,11 @@ var InitService = class {
651
674
  await fs11.ensureDir(targetPath);
652
675
  await processDirectory(sourcePath, targetPath);
653
676
  } else {
654
- const content = await fs11.readFile(sourcePath, "utf8");
655
677
  const relPath = path11.relative(cwd, targetPath).replace(/\\/g, "/");
678
+ if (ADAPTER_OWNED_TEMPLATE_FILES.has(relPath)) {
679
+ continue;
680
+ }
681
+ const content = await fs11.readFile(sourcePath, "utf8");
656
682
  let shouldWrite = true;
657
683
  if (await fs11.pathExists(targetPath)) {
658
684
  const localContent = await fs11.readFile(targetPath, "utf8");
@@ -670,7 +696,7 @@ var InitService = class {
670
696
  await fs11.writeFile(targetPath, content, "utf8");
671
697
  modifiedFiles.push(relPath);
672
698
  }
673
- const isMutable = relPath.startsWith(".sauron/wiki/") || relPath === ".agents/rules/memory.md";
699
+ const isMutable = relPath.startsWith(".sauron/wiki/");
674
700
  if (!isMutable) {
675
701
  manifest.files[relPath] = generateHash(content);
676
702
  }
@@ -710,13 +736,7 @@ var InitService = class {
710
736
  };
711
737
  await saveManifest(cwd, manifest);
712
738
  modifiedFiles.push(".sauron/.manifest.json");
713
- const memoryFilePath = path11.join(cwd, ".agents", "rules", "memory.md");
714
- let memoryRulesContent = "";
715
- if (await fs11.pathExists(memoryFilePath)) {
716
- memoryRulesContent = await fs11.readFile(memoryFilePath, "utf8");
717
- } else {
718
- memoryRulesContent = agentsMdContent;
719
- }
739
+ const memoryRulesContent = await loadCanonicalMemoryRules(templatesDir, agentsMdContent);
720
740
  const projectName = path11.basename(cwd) || "Unnamed Project";
721
741
  const memoryPayload = {
722
742
  projectName,
@@ -1063,35 +1083,35 @@ var ProjectScanner = class {
1063
1083
  if (rootFiles.includes("tsconfig.json")) {
1064
1084
  context.primaryLanguage = "TypeScript";
1065
1085
  }
1066
- if (rootDirs.includes(".cursor") || rootFiles.includes(".cursorrules")) {
1067
- context.detectedIAs.push("Cursor");
1068
- }
1069
- if (rootFiles.includes(".windsurfrules")) {
1070
- context.detectedIAs.push("Windsurf");
1071
- }
1072
- if (rootFiles.includes(".aider.instructions.md") || rootFiles.includes(".aider.conf.yml")) {
1073
- context.detectedIAs.push("Aider");
1074
- }
1075
- if (rootDirs.includes(".agents")) {
1076
- context.detectedIAs.push("Antigravity");
1077
- }
1086
+ this.addDetectedIA(context, rootDirs.includes(".cursor") || rootFiles.includes(".cursorrules"), "Cursor");
1087
+ this.addDetectedIA(context, rootDirs.includes(".windsurf") || rootFiles.includes(".windsurfrules"), "Windsurf");
1088
+ this.addDetectedIA(context, rootFiles.includes(".aider.instructions.md") || rootFiles.includes(".aider.conf.yml"), "Aider");
1089
+ this.addDetectedIA(context, rootDirs.includes(".agents"), "Antigravity");
1090
+ this.addDetectedIA(context, rootDirs.includes(".codex"), "Codex");
1091
+ this.addDetectedIA(context, rootDirs.includes(".opencode") || rootFiles.includes("opencode.json"), "Opencode");
1092
+ this.addDetectedIA(context, rootDirs.includes(".claude") || rootFiles.includes("CLAUDE.md"), "Claude");
1078
1093
  if (context.detectedIAs.length === 0) {
1079
- context.detectedIAs = ["Cursor", "Windsurf", "Aider", "Antigravity"];
1094
+ context.detectedIAs = ["Cursor", "Windsurf", "Aider", "Antigravity", "Codex", "Opencode", "Claude"];
1080
1095
  }
1081
1096
  if (rootFiles.includes("package.json")) {
1082
1097
  const pkgPath = path12.join(this.cwd, "package.json");
1083
- const pkg = await fs12.readJson(pkgPath);
1098
+ const pkg2 = await fs12.readJson(pkgPath);
1084
1099
  const allDeps = {
1085
- ...pkg.dependencies || {},
1086
- ...pkg.devDependencies || {}
1100
+ ...pkg2.dependencies || {},
1101
+ ...pkg2.devDependencies || {}
1087
1102
  };
1088
1103
  for (const sig of TECHNOLOGY_SIGNATURES) {
1089
1104
  let matched = false;
1090
1105
  if (sig.deps && sig.deps.some((dep) => allDeps[dep])) {
1091
1106
  matched = true;
1092
1107
  }
1093
- if (sig.files && sig.files.some((f) => rootFiles.includes(f) || rootDirs.includes(f))) {
1094
- matched = true;
1108
+ if (sig.files) {
1109
+ for (const marker of sig.files) {
1110
+ if (await this.matchesFileMarker(marker, rootFiles, rootDirs)) {
1111
+ matched = true;
1112
+ break;
1113
+ }
1114
+ }
1095
1115
  }
1096
1116
  if (matched) {
1097
1117
  this.categorizeAndAdd(sig, context);
@@ -1132,6 +1152,17 @@ var ProjectScanner = class {
1132
1152
  context.wikiTemplatesToInject.push(sig.wikiTemplate);
1133
1153
  }
1134
1154
  }
1155
+ addDetectedIA(context, condition, name) {
1156
+ if (condition && !context.detectedIAs.includes(name)) {
1157
+ context.detectedIAs.push(name);
1158
+ }
1159
+ }
1160
+ async matchesFileMarker(marker, rootFiles, rootDirs) {
1161
+ if (!marker.includes("/") && !marker.includes("\\")) {
1162
+ return rootFiles.includes(marker) || rootDirs.includes(marker);
1163
+ }
1164
+ return fs12.pathExists(path12.join(this.cwd, marker));
1165
+ }
1135
1166
  };
1136
1167
 
1137
1168
  // src/features/init/init.command.ts
@@ -1420,7 +1451,7 @@ var DoctorService = class {
1420
1451
  });
1421
1452
  }
1422
1453
  }
1423
- const targets = registered?.aiTargets || ["Cursor", "Windsurf", "Aider", "Antigravity"];
1454
+ const targets = manifest?.config?.aiTargets || registered?.aiTargets || ["Cursor", "Windsurf", "Aider", "Antigravity", "Codex", "Opencode", "Claude"];
1424
1455
  for (const target of targets) {
1425
1456
  try {
1426
1457
  const adapters = AdapterRegistry.resolve([target]);
@@ -1611,8 +1642,10 @@ async function runUninstallCommand(options) {
1611
1642
  }
1612
1643
 
1613
1644
  // src/index.ts
1645
+ var require2 = createRequire(import.meta.url);
1646
+ var pkg = require2("../package.json");
1614
1647
  var program = new Command();
1615
- program.name("sauron").description("Sauron CLI - Framework para resolu\xE7\xE3o de Amn\xE9sia de Contexto em IAs").version("1.2.0");
1648
+ program.name("sauron").description("Sauron CLI - Framework para resolu\xE7\xE3o de Amn\xE9sia de Contexto em IAs").version(pkg.version || "0.0.0");
1616
1649
  program.command("init").description("Inicializa o Sauron Memory System no projeto atual").option("-y, --yes", "Pula os prompts interativos e usa os valores padr\xE3o (N\xE3o-interativo)").option("--json", "Sa\xEDda do resultado em formato JSON estruturado").option("--conflict <resolution>", "Estrat\xE9gia de resolu\xE7\xE3o de conflitos autom\xE1tica (ours | theirs)").action((options) => runInitCommand(options));
1617
1650
  program.command("doctor").description("Executa uma auditoria de integridade e conformidade estrutural das regras e wiki").option("--json", "Sa\xEDda do relat\xF3rio em formato JSON estruturado").action((options) => runDoctorCommand(options));
1618
1651
  program.command("uninstall").description("Remove as vincula\xE7\xF5es do Sauron CLI e regras de assistentes locais").option("--purge", "Remove fisicamente a pasta .sauron/ incluindo a wiki de documenta\xE7\xE3o").option("-y, --yes", "Pula os prompts de confirma\xE7\xE3o de desinstala\xE7\xE3o").option("--json", "Sa\xEDda do resultado em formato JSON estruturado").action((options) => runUninstallCommand(options));
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "sauron-cli",
3
- "version": "1.4.5",
3
+ "version": "1.4.7",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
- "sauron": "./dist/index.js"
7
+ "sauron": "dist/index.js"
8
8
  },
9
9
  "files": [
10
10
  "dist",