sauron-cli 1.4.0 → 1.4.1

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.
@@ -0,0 +1,20 @@
1
+ # Prompt: Inteligência de Atualização e Proteção de Memória no Sauron CLI
2
+
3
+ ```markdown
4
+ Estamos desenvolvendo o Sauron CLI, uma ferramenta de CLI em Node.js (TypeScript) que injeta regras de governança e memória arquitetural em repositórios para otimizar o uso de IAs (Cursor, Windsurf, Aider).
5
+
6
+ Stack: Node.js, TypeScript, commander, @clack/prompts.
7
+
8
+ Atualmente, temos o comando `sauron init`, que executa um onboarding interativo com o usuário (perguntando as IAs que serão usadas, severidade das regras, contexto do projeto e stack tecnológica). Após coletar essas respostas, ele gera os arquivos de manifesto (`AGENTS.md`, `.sauron/.manifest.json` e a pasta `.agents/`).
9
+
10
+ O problema atual:
11
+ Quando o usuário roda `npx sauron-cli@latest init` para **atualizar** o Sauron em um projeto existente, a CLI refaz todas as perguntas do onboarding inicial do zero, ignorando as configurações que o usuário já respondeu na primeira instalação.
12
+
13
+ O que precisamos:
14
+ 1. **Detecção de Instalação Existente**: Antes de iniciar o onboarding do `@clack/prompts`, a CLI deve verificar se o `.sauron/.manifest.json` (ou `AGENTS.md`) já existe.
15
+ 2. **Reaproveitamento de Respostas**: Se existir, extrair os dados antigos (aiTargets, severity, projectContext, projectStack) e usá-los como `initialValue` nas perguntas do clack.
16
+ 3. **Opção de Bypass (Fast-track)**: Melhor ainda seria perguntar "Detectamos uma instalação anterior. Deseja manter as configurações atuais e pular o onboarding? (y/n)". Se 'y', pular as perguntas e apenas re-injetar os arquivos principais atualizados.
17
+ 4. **Proteção Rigorosa da Memória**: Garantir que a lógica de atualização **nunca** apague, sobrescreva ou modifique arquivos de documentação criados pelo usuário/IA dentro das subpastas de `.sauron/wiki/` (ex: `knowledge/`, `history/`, `modules/`). A atualização só pode atuar sobre a pasta `.agents/`, `AGENTS.md` e os arquivos base de configuração que vêm nos templates.
18
+
19
+ Como podemos implementar essa inteligência no nosso comando de init (provavelmente refatorando o `init.command.ts` e o fluxo do `init.service.ts`) de forma elegante, garantindo a idempotência e segurança absoluta dos dados da Wiki?
20
+ ```
package/dist/index.js CHANGED
@@ -10,10 +10,6 @@ import pc2 from "picocolors";
10
10
  import { fileURLToPath } from "url";
11
11
  import * as p2 from "@clack/prompts";
12
12
 
13
- // src/features/init/init.service.ts
14
- import fs8 from "fs-extra";
15
- import path8 from "path";
16
-
17
13
  // src/core/manifest.service.ts
18
14
  import crypto from "crypto";
19
15
  import fs from "fs-extra";
@@ -39,6 +35,10 @@ async function saveManifest(targetDir, manifest) {
39
35
  await fs.writeJson(manifestPath, manifest, { spaces: 2 });
40
36
  }
41
37
 
38
+ // src/features/init/init.service.ts
39
+ import fs8 from "fs-extra";
40
+ import path8 from "path";
41
+
42
42
  // src/core/merge.service.ts
43
43
  function checkConflict(localContent, newContent, manifestHash) {
44
44
  const localHash = generateHash(localContent);
@@ -410,6 +410,10 @@ var InitService = class {
410
410
  const targetPath = path8.join(target, file);
411
411
  const stat = await fs8.stat(sourcePath);
412
412
  if (stat.isDirectory()) {
413
+ const relativeToTarget = path8.relative(cwd, targetPath).replace(/\\/g, "/");
414
+ if (relativeToTarget === ".sauron/wiki" && await fs8.pathExists(targetPath)) {
415
+ continue;
416
+ }
413
417
  await fs8.ensureDir(targetPath);
414
418
  await processDirectory(sourcePath, targetPath);
415
419
  } else {
@@ -464,6 +468,12 @@ var InitService = class {
464
468
  modifiedFiles.push("AGENTS.md");
465
469
  }
466
470
  manifest.files["AGENTS.md"] = generateHash(agentsMdContent);
471
+ manifest.config = {
472
+ aiTargets: options.aiTargets,
473
+ severity: options.severity,
474
+ projectContext: options.projectContext,
475
+ projectStack: options.projectStack
476
+ };
467
477
  await saveManifest(cwd, manifest);
468
478
  modifiedFiles.push(".sauron/.manifest.json");
469
479
  const memoryFilePath = path8.join(cwd, ".agents", "rules", "memory.md");
@@ -929,7 +939,41 @@ async function runInitCommand(options) {
929
939
  ...scannedContext.styling
930
940
  ].filter(Boolean).join(", ");
931
941
  let projectStack = inferredStackString || "Node.js, TypeScript";
932
- if (session.interactive) {
942
+ let bypassOnboarding = false;
943
+ const manifestData = await getManifest(cwd);
944
+ if (manifestData) {
945
+ if (manifestData.config) {
946
+ aiTargets = manifestData.config.aiTargets;
947
+ severity = manifestData.config.severity;
948
+ projectContext = manifestData.config.projectContext;
949
+ projectStack = manifestData.config.projectStack;
950
+ } else {
951
+ const agentsMdPath = path10.join(cwd, "AGENTS.md");
952
+ if (await fs10.pathExists(agentsMdPath)) {
953
+ const content = await fs10.readFile(agentsMdPath, "utf8");
954
+ const targetsMatch = content.match(/\*\*Targets:\*\* (.*)/);
955
+ if (targetsMatch) aiTargets = targetsMatch[1].split(",").map((s) => s.trim());
956
+ const severityMatch = content.match(/\*\*Severity:\*\* (.*)/);
957
+ if (severityMatch) severity = severityMatch[1].trim();
958
+ const contextMatch = content.match(/## Project Context\n([\s\S]*?)\n## Tech Stack/);
959
+ if (contextMatch) projectContext = contextMatch[1].trim();
960
+ const stackMatch = content.match(/## Tech Stack\n([\s\S]*?)\n## Golden Rule/);
961
+ if (stackMatch) projectStack = stackMatch[1].trim();
962
+ }
963
+ }
964
+ if (session.interactive) {
965
+ const bypass = await p2.confirm({
966
+ message: "Detectamos uma instala\xE7\xE3o anterior. Deseja manter as configura\xE7\xF5es atuais e pular o onboarding?",
967
+ initialValue: true
968
+ });
969
+ if (p2.isCancel(bypass)) {
970
+ p2.cancel("Inicializa\xE7\xE3o abortada.");
971
+ process.exit(0);
972
+ }
973
+ bypassOnboarding = bypass;
974
+ }
975
+ }
976
+ if (session.interactive && !bypassOnboarding) {
933
977
  try {
934
978
  const config = await p2.group(
935
979
  {
@@ -1282,10 +1326,10 @@ async function runUninstallCommand(options) {
1282
1326
  p4.intro(pc4.bgRed(pc4.white(" Sauron Memory System - Desinstala\xE7\xE3o ")));
1283
1327
  }
1284
1328
  if (session.interactive) {
1285
- const confirm2 = await p4.confirm({
1329
+ const confirm3 = await p4.confirm({
1286
1330
  message: options.purge ? pc4.red("Tem certeza que deseja desinstalar o Sauron e PURGAR toda a wiki de documenta\xE7\xE3o f\xEDsica?") : "Tem certeza que deseja desinstalar o Sauron deste projeto (a wiki/ de documenta\xE7\xE3o ser\xE1 preservada)?"
1287
1331
  });
1288
- if (p4.isCancel(confirm2) || !confirm2) {
1332
+ if (p4.isCancel(confirm3) || !confirm3) {
1289
1333
  p4.cancel("Desinstala\xE7\xE3o abortada.");
1290
1334
  process.exit(0);
1291
1335
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sauron-cli",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "bin": {