ozali 0.2.0 → 0.3.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/README.md CHANGED
@@ -65,7 +65,9 @@ ozali sync # lleva el histórico (docs + Engram) al repo de conocimiento de
65
65
 
66
66
  `init` también escribe un **perfil base de permisos** (`.claude/settings.json` para Claude Code,
67
67
  `opencode.json` para opencode) para reducir confirmaciones: deja libres comandos seguros y bloquea
68
- los destructivos. Es un template — tus reglas se conservan al re-correr `init`.
68
+ los destructivos. Es un template — tus reglas se conservan al re-correr `init`. Como Claude Code
69
+ **ignora** los permisos de un proyecto hasta confiar en él, `init` ofrece marcar el workspace como
70
+ confiable (`hasTrustDialogAccepted` en `~/.claude.json`); usa `--no-trust` para omitirlo.
69
71
 
70
72
  `init` también **instala Engram** y registra su MCP con `engram setup <agente>`: en modo
71
73
  interactivo te pregunta (default sí), y con `--yes` lo instala automáticamente. Usa brew en
@@ -73,9 +75,9 @@ macOS/Linux, `go install` en Windows, con binario precompilado como fallback. Si
73
75
  instalarlo, pasa `--no-engram` (arranca en modo `docs`). Opcionalmente habilita **Engram Cloud**
74
76
  (réplica de equipo opt-in) además del git-sync.
75
77
 
76
- Flags útiles: `--yes` (no interactivo), `--dry-run` (init sin escribir), `--no-engram`, `--agent`,
77
- `--scope`, `--knowledge-repo`, `--import`/`--push`/`--cloud` (sync). Modelo mental completo en
78
- [docs/intended-usage.md](docs/intended-usage.md).
78
+ Flags útiles: `--yes` (no interactivo), `--dry-run` (init sin escribir), `--no-engram`, `--no-trust`,
79
+ `--agent`, `--scope`, `--knowledge-repo`, `--import`/`--push`/`--cloud` (sync). Modelo mental completo
80
+ en [docs/intended-usage.md](docs/intended-usage.md).
79
81
 
80
82
  ## Agentes soportados
81
83
 
package/cli/bin/ozali.mjs CHANGED
@@ -24,7 +24,8 @@ ${c.bold("Opciones comunes:")}
24
24
  --agent <a> (init) claude-code | opencode | both.
25
25
  --scope <s> (init) project | global.
26
26
  --knowledge-repo <p> (init) Ruta del repo de conocimiento.
27
- --no-engram (init) No instalar Engram; arranca en modo docs.
27
+ --no-engram (init) No usar Engram; arranca en modo docs.
28
+ --no-trust (init) No marcar el workspace como confiable en Claude Code.
28
29
  --import (sync) Importa del repo de conocimiento a local.
29
30
  --push (sync) Hace push al remoto del repo de conocimiento.
30
31
  --cloud (sync) Replica también a Engram Cloud (si está habilitado).
@@ -46,6 +47,7 @@ function parseArgs(argv) {
46
47
  else if (a === "--push") opts.push = true;
47
48
  else if (a === "--cloud") opts.cloud = true;
48
49
  else if (a === "--no-engram") opts.noEngram = true;
50
+ else if (a === "--no-trust") opts.noTrust = true;
49
51
  else if (a === "--agent") opts.agent = argv[++i];
50
52
  else if (a === "--scope") opts.scope = argv[++i];
51
53
  else if (a === "--knowledge-repo") opts.knowledgeRepo = argv[++i];
@@ -49,15 +49,16 @@ export async function init(cwd, opts) {
49
49
 
50
50
  // Engram
51
51
  let memoryMode = "docs";
52
- if (env.engram.available) {
52
+ if (opts.noEngram) {
53
+ info("--no-engram: arranco en modo " + c.bold("docs") + " (sin usar Engram).");
54
+ } else if (env.engram.available) {
53
55
  memoryMode = "hybrid";
54
56
  ok(`Engram disponible (${env.engram.bin}). Modo de memoria: ${c.bold("hybrid")} (docs + Engram).`);
55
57
  } else {
56
58
  warn("Engram no está instalado.");
57
- // Decisión de instalar: --no-engram/--dry-run nunca instalan; --yes usa el default (sí);
58
- // interactivo pregunta.
59
- if (opts.dryRun && !opts.noEngram) info("(dry-run) Aquí instalaría y configuraría Engram.");
60
- const installNow = (opts.noEngram || opts.dryRun) ? false
59
+ // --dry-run no instala; --yes usa el default (sí); interactivo pregunta.
60
+ if (opts.dryRun) info("(dry-run) Aquí instalaría y configuraría Engram.");
61
+ const installNow = opts.dryRun ? false
61
62
  : (opts.yes ? true : await confirm("¿Instalo y configuro Engram ahora?", true));
62
63
  if (installNow) {
63
64
  if (opts.yes) info("Modo no interactivo: instalando Engram automáticamente…");
@@ -103,6 +104,8 @@ export async function init(cwd, opts) {
103
104
  // 2) perfiles base de permisos (idempotentes, merge mínimo) por agente
104
105
  if (agent === "claude-code" || agent === "both") {
105
106
  ensureClaudeCodeProfile(cwd, scope);
107
+ // Claude Code ignora los permisos de un .claude/settings.json de proyecto hasta confiar en él.
108
+ if (scope === "project" && !opts.noTrust) await ensureClaudeWorkspaceTrust(cwd, opts);
106
109
  }
107
110
  if (agent === "opencode" || agent === "both") {
108
111
  ensureOpencodeProfile(cwd);
@@ -283,6 +286,34 @@ function ensureClaudeCodeProfile(cwd, scope) {
283
286
  }
284
287
  }
285
288
 
289
+ // Marca el proyecto como confiable en Claude Code (~/.claude.json). Sin esto, Claude Code
290
+ // ignora los permisos de un .claude/settings.json de proyecto ("workspace not trusted").
291
+ async function ensureClaudeWorkspaceTrust(cwd, opts) {
292
+ const p = path.join(HOME, ".claude.json");
293
+ if (!exists(p)) {
294
+ info("Claude Code aún no tiene ~/.claude.json; al abrirlo aquí, acepta el diálogo de confianza.");
295
+ return;
296
+ }
297
+ let cfg;
298
+ try { cfg = JSON.parse(fs.readFileSync(p, "utf8")); }
299
+ catch { warn("No pude leer ~/.claude.json; acepta el diálogo de confianza de Claude Code manualmente."); return; }
300
+ cfg.projects = cfg.projects || {};
301
+ cfg.projects[cwd] = cfg.projects[cwd] || {};
302
+ if (cfg.projects[cwd].hasTrustDialogAccepted === true) {
303
+ info("Claude Code ya confía en este workspace.");
304
+ return;
305
+ }
306
+ const doTrust = opts.yes ? true
307
+ : await confirm("¿Marcar este proyecto como confiable en Claude Code? (necesario para que apliquen los permisos)", true);
308
+ if (!doTrust) {
309
+ info("Workspace no marcado como confiable: Claude Code ignorará los permisos hasta que aceptes su diálogo.");
310
+ return;
311
+ }
312
+ cfg.projects[cwd].hasTrustDialogAccepted = true;
313
+ fs.writeFileSync(p, JSON.stringify(cfg, null, 2)); // formato que usa Claude Code (indent 2, sin newline final)
314
+ ok("Workspace marcado como confiable en Claude Code (los permisos de .claude/settings.json ya aplican).");
315
+ }
316
+
286
317
  function ensureOpencodeProfile(cwd) {
287
318
  const p = path.join(cwd, "opencode.json");
288
319
  const base = readJSON(p, {});
@@ -57,7 +57,7 @@ test("doctor en proyecto vacío reporta pendientes (exit 1)", () => {
57
57
  test("init --yes instala la skill, aísla el histórico y escribe config", () => {
58
58
  const dir = tmpProject();
59
59
  try {
60
- run(["init", "--yes", "--no-engram", "--agent", "claude-code", "--scope", "project", "--knowledge-repo", path.join(dir, ".k")], dir);
60
+ run(["init", "--yes", "--no-engram", "--no-trust", "--agent", "claude-code", "--scope", "project", "--knowledge-repo", path.join(dir, ".k")], dir);
61
61
  assert.ok(fs.existsSync(path.join(dir, ".claude", "skills", "ozali", "SKILL.md")), "SKILL.md instalada");
62
62
  assert.ok(fs.existsSync(path.join(dir, ".ozali", "config.json")), "config escrita");
63
63
  const cfg = JSON.parse(fs.readFileSync(path.join(dir, ".ozali", "config.json"), "utf8"));
@@ -101,6 +101,11 @@ Es **un punto de partida, no una jaula**: puedes editar ese archivo y añadir lo
101
101
  necesite. Si vuelves a correr `ozali init`, tus reglas **se conservan** (no se borran ni se
102
102
  duplican).
103
103
 
104
+ > **Confianza del workspace (Claude Code):** por seguridad, Claude Code **ignora** los permisos de
105
+ > un proyecto hasta que confías en él (verás un aviso *"this workspace has not been trusted"*).
106
+ > `init` te ofrece marcarlo como confiable automáticamente; si prefieres hacerlo tú, abre Claude
107
+ > Code en la carpeta y acepta el diálogo de confianza una vez. Con `--no-trust` ozali no lo toca.
108
+
104
109
  Ejemplo — permitir Docker además de lo de fábrica:
105
110
 
106
111
  ```json
@@ -151,6 +156,11 @@ Lo corriste con `dlx`/`npx`, que es temporal. Instálalo global: `pnpm add -g oz
151
156
  **¿Esto ensucia mi repositorio?**
152
157
  No. El histórico y la memoria se aíslan (`.ozali/`, `.engram/` van al `.gitignore`).
153
158
 
159
+ **Veo "this workspace has not been trusted" y mis permisos no aplican.**
160
+ Es el aviso de seguridad de Claude Code: ignora los permisos del proyecto hasta confiar en él.
161
+ Deja que `init` lo marque como confiable, o abre Claude Code en la carpeta y acepta el diálogo una
162
+ vez. Tras eso, el aviso desaparece y los permisos surten efecto.
163
+
154
164
  **¿Funciona en Windows?**
155
165
  Sí. Los permisos base incluyen variantes PowerShell, y Engram se instala con `go install` o un
156
166
  binario descargable.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ozali",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Bootstrap interactivo de IA por equipo: calibra el proyecto, genera la skill de ejecución (cdk) con TDD/SDD, y mantiene memoria de equipo (Engram) con histórico aislado.",
5
5
  "type": "module",
6
6
  "bin": {