ozali 0.7.1 → 0.8.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 +11 -0
- package/cli/bin/ozali.mjs +5 -0
- package/cli/lib/commands.mjs +63 -1
- package/cli/lib/detect.mjs +15 -3
- package/cli/test/smoke.test.mjs +47 -0
- package/docs/compilado-local.md +182 -0
- package/docs/guia-de-uso.md +50 -0
- package/docs/workspaces.md +19 -5
- package/package.json +1 -1
- package/skill/SKILL.md +22 -0
- package/templates/ozali-workspace-jarvis.md +57 -13
package/README.md
CHANGED
|
@@ -80,7 +80,10 @@ referencian entre sí, corre **una vez** en esa raíz:
|
|
|
80
80
|
```bash
|
|
81
81
|
ozali workspace # escanea repos hijos, remedia los que faltan y escribe la config conjunta
|
|
82
82
|
ozali workspace --dry-run # solo muestra el inventario y el plan, sin escribir
|
|
83
|
+
ozali workspace --yes # no interactivo: acepta defaults y todas las referencias detectadas
|
|
83
84
|
ozali workspace --depth 2 # busca repos hasta 2 niveles (para raíces con subcarpetas de grupo)
|
|
85
|
+
ozali workspace --doctor # health-check de TODOS los repos miembros + resumen (solo CLI)
|
|
86
|
+
ozali workspace --update # actualiza skills/permisos/jarvis de TODOS los repos miembros (solo CLI)
|
|
84
87
|
```
|
|
85
88
|
|
|
86
89
|
Qué hace, en orden: (1) **escanea** los repos hijos y reporta su estado —`✔ listo`, `⚠ sin calibrar`
|
|
@@ -93,6 +96,13 @@ contigo; y (4) escribe la config para **trabajar en conjunto**:
|
|
|
93
96
|
- `<carpeta>.code-workspace` — workspace multi-root que abre todos los repos juntos.
|
|
94
97
|
- Orquestador **`ozali-workspace-jarvis`** en `CLAUDE.md`/`AGENTS.md` de la raíz: coordina los repos
|
|
95
98
|
según el manifiesto y delega la ejecución en el `cdk` de cada uno.
|
|
99
|
+
- La skill **`ozali`** en la raíz (`.claude/skills/ozali/`) para **calibrar los miembros desde el
|
|
100
|
+
workspace** (modo target), sin abrir cada proyecto.
|
|
101
|
+
|
|
102
|
+
**Operar todo desde la raíz:** `ozali workspace --doctor` y `--update` corren el health-check y la
|
|
103
|
+
actualización sobre **todos** los repos miembros (solo CLI). Y para calibrar los `⚠ sin calibrar`,
|
|
104
|
+
abre el agente en la raíz y pídele a `ozali-workspace-jarvis` que *"calibre los repos pendientes"*: los
|
|
105
|
+
recorre uno por uno (con su GATE) sin que cambies de proyecto.
|
|
96
106
|
|
|
97
107
|
Es **idempotente**: re-córrelo cuando agregues repos o cambien las referencias. Detalle completo en
|
|
98
108
|
[`docs/workspaces.md`](docs/workspaces.md).
|
|
@@ -152,6 +162,7 @@ Claude Code y opencode (perfiles de permisos para ambos en
|
|
|
152
162
|
|---|---|
|
|
153
163
|
| Guía de uso (usuarios generales) | [docs/guia-de-uso.md](docs/guia-de-uso.md) |
|
|
154
164
|
| Uso previsto (modelo mental) | [docs/intended-usage.md](docs/intended-usage.md) |
|
|
165
|
+
| Compilado y uso local (repo clonado) | [docs/compilado-local.md](docs/compilado-local.md) |
|
|
155
166
|
| Seguridad del instalador (npx/pnpm) | [docs/security.md](docs/security.md) |
|
|
156
167
|
| Histórico aislado y memoria de equipo | [docs/team-history.md](docs/team-history.md) |
|
|
157
168
|
| Desplegar Engram Cloud (VPS) | [docs/deploy-cloud-vps.md](docs/deploy-cloud-vps.md) |
|
package/cli/bin/ozali.mjs
CHANGED
|
@@ -16,6 +16,7 @@ ${c.bold("Comandos:")}
|
|
|
16
16
|
ozali-commit, aísla el histórico, configura Engram y el repo de conocimiento.
|
|
17
17
|
workspace Multi-repo: escanea los repos de la carpeta raíz, remedia los que no tienen
|
|
18
18
|
ozali init, guía la calibración y escribe la config para trabajar en conjunto.
|
|
19
|
+
Con --doctor / --update opera sobre TODOS los repos miembros desde la raíz.
|
|
19
20
|
doctor Health-check read-only del proyecto (fuente de verdad, Engram, versión de cdk, TDD…).
|
|
20
21
|
update Actualiza la instalación (skills ozali + ozali-commit + ozali-jarvis + permisos)
|
|
21
22
|
al paquete y avisa si la skill cdk quedó desactualizada.
|
|
@@ -29,6 +30,8 @@ ${c.bold("Opciones comunes:")}
|
|
|
29
30
|
--agent <a> (init) claude-code | opencode | both.
|
|
30
31
|
--scope <s> (init) project | global.
|
|
31
32
|
--depth <n> (workspace) Niveles a escanear bajo la raíz (default 1).
|
|
33
|
+
--doctor (workspace) Health-check de TODOS los repos miembros + resumen.
|
|
34
|
+
--update (workspace) Actualiza (skills/permisos/jarvis) TODOS los repos miembros.
|
|
32
35
|
--knowledge-repo <p> (init) Ruta del repo de conocimiento.
|
|
33
36
|
--no-engram (init) No usar Engram; arranca en modo docs.
|
|
34
37
|
--no-trust (init) No marcar el workspace como confiable en Claude Code.
|
|
@@ -73,6 +76,8 @@ function parseArgs(argv) {
|
|
|
73
76
|
else if (a === "--agent") opts.agent = argv[++i];
|
|
74
77
|
else if (a === "--scope") opts.scope = argv[++i];
|
|
75
78
|
else if (a === "--depth") opts.depth = argv[++i];
|
|
79
|
+
else if (a === "--doctor") opts.wsDoctor = true;
|
|
80
|
+
else if (a === "--update") opts.wsUpdate = true;
|
|
76
81
|
else if (a === "--knowledge-repo") opts.knowledgeRepo = argv[++i];
|
|
77
82
|
else if (a === "-h" || a === "--help") opts.help = true;
|
|
78
83
|
else if (a === "-v" || a === "--version") opts.version = true;
|
package/cli/lib/commands.mjs
CHANGED
|
@@ -793,6 +793,10 @@ export async function workspace(cwd, opts = {}) {
|
|
|
793
793
|
step("Repos detectados");
|
|
794
794
|
printMembers(ws.members);
|
|
795
795
|
|
|
796
|
+
// Modos batch (Track 1): operan sobre los miembros del workspace ya existente y salen.
|
|
797
|
+
if (opts.wsDoctor) return workspaceDoctor(ws.members);
|
|
798
|
+
if (opts.wsUpdate) return workspaceUpdate(ws.members, opts);
|
|
799
|
+
|
|
796
800
|
// Fase B — remediación de los que no tienen ozali init
|
|
797
801
|
const missing = ws.members.filter((m) => m.status === "missing-init");
|
|
798
802
|
if (missing.length && opts.dryRun) {
|
|
@@ -836,6 +840,7 @@ export async function workspace(cwd, opts = {}) {
|
|
|
836
840
|
const agent = manifest.agent;
|
|
837
841
|
if (agent === "claude-code" || agent === "both") {
|
|
838
842
|
ensureWorkspaceJarvisClaudeCode(cwd);
|
|
843
|
+
ensureWorkspaceOzaliSkill(cwd); // Track 2: skill ozali en la raíz → calibrar miembros desde el workspace
|
|
839
844
|
if (!opts.noTrust) await ensureClaudeWorkspaceTrust(cwd, opts);
|
|
840
845
|
}
|
|
841
846
|
if (agent === "opencode" || agent === "both") ensureWorkspaceJarvisOpencode(cwd);
|
|
@@ -849,11 +854,68 @@ export async function workspace(cwd, opts = {}) {
|
|
|
849
854
|
step("Siguientes pasos");
|
|
850
855
|
const wsFile = `${path.basename(cwd)}.code-workspace`;
|
|
851
856
|
console.log(` 1. Abre el workspace en tu editor: ${c.bold(wsFile)} ${c.dim("(VSCode/Antigravity → Open Workspace).")}`);
|
|
852
|
-
if (needCal.length)
|
|
857
|
+
if (needCal.length) {
|
|
858
|
+
console.log(` 2. Calibra los pendientes (${c.bold(needCal.map((m) => m.dir).join(", "))}) ${c.dim("sin salir del workspace:")}`);
|
|
859
|
+
console.log(` ${c.dim("abre el agente en la raíz y pide a")} ${c.bold("ozali-workspace-jarvis")} ${c.dim('que "calibre los repos pendientes"')}`);
|
|
860
|
+
console.log(` ${c.dim("(usa la skill")} ${c.bold("ozali")} ${c.dim("en modo target, repo por repo con su GATE).")}`);
|
|
861
|
+
}
|
|
862
|
+
console.log(` ${c.dim("• Salud de todos los repos:")} ${c.bold("ozali workspace --doctor")}`);
|
|
863
|
+
console.log(` ${c.dim("• Actualizar todos los repos:")} ${c.bold("ozali workspace --update")}`);
|
|
853
864
|
console.log(` ${c.dim("Re-corre")} ${c.bold("ozali workspace")} ${c.dim("cuando agregues repos o cambien las referencias (es idempotente).")}`);
|
|
854
865
|
return 0;
|
|
855
866
|
}
|
|
856
867
|
|
|
868
|
+
/** Track 1 — health-check de todos los miembros (doctor por repo) + resumen consolidado. */
|
|
869
|
+
function workspaceDoctor(members) {
|
|
870
|
+
const results = [];
|
|
871
|
+
for (const m of members) {
|
|
872
|
+
console.log("");
|
|
873
|
+
console.log(c.bold(c.magenta(`── ${m.dir} ──`)));
|
|
874
|
+
if (m.status === "missing-init") {
|
|
875
|
+
warn(`Sin ozali init → córrelo (o re-corre ${c.bold("ozali workspace")}).`);
|
|
876
|
+
results.push({ dir: m.dir, ok: false, note: "sin init" });
|
|
877
|
+
continue;
|
|
878
|
+
}
|
|
879
|
+
const code = doctor(m.path);
|
|
880
|
+
results.push({ dir: m.dir, ok: code === 0, note: code === 0 ? "todo en orden" : "puntos a atender" });
|
|
881
|
+
}
|
|
882
|
+
step("Resumen del workspace");
|
|
883
|
+
const pad = Math.max(4, ...members.map((m) => m.dir.length));
|
|
884
|
+
for (const r of results) {
|
|
885
|
+
console.log(` ${r.ok ? c.green("✔") : c.yellow("✖")} ${r.dir.padEnd(pad)} ${c.dim(r.note)}`);
|
|
886
|
+
}
|
|
887
|
+
return results.every((r) => r.ok) ? 0 : 1;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
/** Track 1 — update de todos los miembros ozali (skills/permisos/jarvis) + resumen. */
|
|
891
|
+
function workspaceUpdate(members, opts) {
|
|
892
|
+
const results = [];
|
|
893
|
+
let failed = 0;
|
|
894
|
+
for (const m of members) {
|
|
895
|
+
console.log("");
|
|
896
|
+
console.log(c.bold(c.magenta(`── ${m.dir} ──`)));
|
|
897
|
+
if (m.status === "missing-init") {
|
|
898
|
+
warn("Sin ozali init → nada que actualizar (córrelo primero).");
|
|
899
|
+
results.push({ dir: m.dir, mark: c.yellow("—"), note: "sin init (saltado)" });
|
|
900
|
+
continue;
|
|
901
|
+
}
|
|
902
|
+
const code = update(m.path, opts);
|
|
903
|
+
if (code !== 0) failed++;
|
|
904
|
+
results.push({ dir: m.dir, mark: code === 0 ? c.green("✔") : c.yellow("✖"), note: code === 0 ? "actualizado" : "revisar" });
|
|
905
|
+
}
|
|
906
|
+
step("Resumen del workspace");
|
|
907
|
+
const pad = Math.max(4, ...members.map((m) => m.dir.length));
|
|
908
|
+
for (const r of results) console.log(` ${r.mark} ${r.dir.padEnd(pad)} ${c.dim(r.note)}`);
|
|
909
|
+
info(`La skill ${c.bold("cdk")} la regenera el agente. Re-corre ${c.bold("ozali workspace")} para refrescar estados.`);
|
|
910
|
+
return failed > 0 ? 1 : 0;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
/** Track 2 — instala la skill `ozali` en la raíz para calibrar miembros desde el workspace. */
|
|
914
|
+
function ensureWorkspaceOzaliSkill(root) {
|
|
915
|
+
copyDir(SKILL_SRC, path.join(root, ".claude", "skills", "ozali"));
|
|
916
|
+
ok(`Skill ${c.bold("ozali")} instalada en la raíz (${c.bold(".claude/skills/ozali")}) para calibrar miembros desde el workspace.`);
|
|
917
|
+
}
|
|
918
|
+
|
|
857
919
|
/** Primer .ozali/config.json entre los miembros ya inicializados (para heredar defaults). */
|
|
858
920
|
function inheritedConfig(members) {
|
|
859
921
|
for (const m of members) {
|
package/cli/lib/detect.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// detect.mjs — detección read-only del entorno del proyecto destino.
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { exists, which, gitInfo, nodeMajor, HOME, readJSON, projectName, DEFAULT_KNOWLEDGE } from "./util.mjs";
|
|
4
|
+
import { exists, which, gitInfo, tryExec, nodeMajor, HOME, readJSON, projectName, DEFAULT_KNOWLEDGE } from "./util.mjs";
|
|
5
5
|
|
|
6
6
|
/** Variante de fuente de verdad: {found, doc, dir, variant} */
|
|
7
7
|
export function detectSourceOfTruth(cwd) {
|
|
@@ -121,9 +121,21 @@ function isKnowledgeRepo(dir) {
|
|
|
121
121
|
return d === k || d.startsWith(k + path.sep);
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
/**
|
|
125
|
+
* ¿`dir` es la RAÍZ de su propio repo git? No basta con estar dentro de un work tree
|
|
126
|
+
* (una subcarpeta de un repo también lo está): exigimos que el toplevel de git sea `dir`.
|
|
127
|
+
* Así, correr `ozali workspace` dentro de un repo NO trata sus subcarpetas como miembros.
|
|
128
|
+
*/
|
|
129
|
+
function isRepoRoot(dir) {
|
|
130
|
+
const top = tryExec("git", ["-C", dir, "rev-parse", "--show-toplevel"]);
|
|
131
|
+
if (!top) return false;
|
|
132
|
+
try { return fs.realpathSync(top) === fs.realpathSync(dir); } catch { return false; }
|
|
133
|
+
}
|
|
134
|
+
|
|
124
135
|
/**
|
|
125
136
|
* Junta las rutas de repos git bajo `root` hasta `depth` niveles. Un directorio que
|
|
126
|
-
* ES repo git se trata como hoja (no se desciende dentro). Salta
|
|
137
|
+
* ES la raíz de su propio repo git se trata como hoja (no se desciende dentro). Salta
|
|
138
|
+
* ocultos/ignorados.
|
|
127
139
|
*/
|
|
128
140
|
function collectRepoDirs(root, depth, level = 1, acc = []) {
|
|
129
141
|
let entries;
|
|
@@ -133,7 +145,7 @@ function collectRepoDirs(root, depth, level = 1, acc = []) {
|
|
|
133
145
|
if (e.name.startsWith(".") || IGNORE_DIRS.has(e.name)) continue;
|
|
134
146
|
const full = path.join(root, e.name);
|
|
135
147
|
if (isKnowledgeRepo(full)) continue;
|
|
136
|
-
if (
|
|
148
|
+
if (isRepoRoot(full)) { acc.push(full); continue; } // repo propio = hoja
|
|
137
149
|
if (level < depth) collectRepoDirs(full, depth, level + 1, acc);
|
|
138
150
|
}
|
|
139
151
|
return acc;
|
package/cli/test/smoke.test.mjs
CHANGED
|
@@ -257,6 +257,8 @@ test("workspace escribe manifiesto + .code-workspace + jarvis y es idempotente",
|
|
|
257
257
|
assert.ok(fs.existsSync(wsFile), ".code-workspace escrito");
|
|
258
258
|
assert.equal(JSON.parse(fs.readFileSync(wsFile, "utf8")).folders.length, 2, "multi-root con 2 folders");
|
|
259
259
|
assert.match(fs.readFileSync(path.join(root, "CLAUDE.md"), "utf8"), /ozali-workspace-jarvis:start/, "bloque jarvis en CLAUDE.md");
|
|
260
|
+
// Track 2: la skill ozali queda instalada en la raíz para calibrar miembros desde el workspace
|
|
261
|
+
assert.ok(fs.existsSync(path.join(root, ".claude", "skills", "ozali", "SKILL.md")), "skill ozali en la raíz");
|
|
260
262
|
|
|
261
263
|
// idempotencia: re-correr no duplica
|
|
262
264
|
run(["workspace", "--yes", "--no-trust"], root);
|
|
@@ -268,6 +270,51 @@ test("workspace escribe manifiesto + .code-workspace + jarvis y es idempotente",
|
|
|
268
270
|
}
|
|
269
271
|
});
|
|
270
272
|
|
|
273
|
+
test("workspace --doctor revisa cada miembro y saca resumen consolidado", () => {
|
|
274
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "ozali-ws-"));
|
|
275
|
+
try {
|
|
276
|
+
wsRepo(root, "api", { config: true, cdk: true, pkg: { name: "api", version: "1.0.0" } });
|
|
277
|
+
wsRepo(root, "web", { config: true, cdk: true, pkg: { name: "web" } });
|
|
278
|
+
const { stdout } = run(["workspace", "--doctor"], root, true); // exit 1 esperado (repos sin sot/engram)
|
|
279
|
+
assert.match(stdout, /health-check/i, "corre doctor por repo");
|
|
280
|
+
assert.match(stdout, /Resumen del workspace/, "imprime el resumen consolidado");
|
|
281
|
+
assert.match(stdout, /api/, "menciona el repo api en el resumen");
|
|
282
|
+
assert.match(stdout, /web/, "menciona el repo web en el resumen");
|
|
283
|
+
assert.ok(!fs.existsSync(path.join(root, "ozali-workspace.json")), "--doctor no escribe config");
|
|
284
|
+
} finally {
|
|
285
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
test("workspace --update actualiza cada miembro y salta los sin init", () => {
|
|
290
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "ozali-ws-"));
|
|
291
|
+
try {
|
|
292
|
+
wsRepo(root, "api", { config: true, cdk: true, pkg: { name: "api", version: "1.0.0" } });
|
|
293
|
+
wsRepo(root, "bare", { pkg: { name: "bare" } }); // missing-init → se salta
|
|
294
|
+
const { stdout } = run(["workspace", "--update", "--yes", "--no-jarvis"], root);
|
|
295
|
+
assert.match(stdout, /Resumen del workspace/, "imprime el resumen consolidado");
|
|
296
|
+
assert.match(stdout, /Sin ozali init/, "salta el repo sin init");
|
|
297
|
+
assert.ok(!fs.existsSync(path.join(root, "ozali-workspace.json")), "--update no escribe config");
|
|
298
|
+
} finally {
|
|
299
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
test("workspace no trata subcarpetas de un repo como miembros (solo repos propios)", () => {
|
|
304
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "ozali-ws-"));
|
|
305
|
+
try {
|
|
306
|
+
execFileSync("git", ["init", "-q"], { cwd: root }); // la raíz ES un repo git
|
|
307
|
+
fs.mkdirSync(path.join(root, "src")); // subcarpeta simple, NO repo propio
|
|
308
|
+
fs.writeFileSync(path.join(root, "src", "index.js"), "//\n");
|
|
309
|
+
wsRepo(root, "pkg", { config: true, cdk: true, pkg: { name: "pkg", version: "1.0.0" } }); // repo propio anidado
|
|
310
|
+
const { stdout } = run(["workspace", "--dry-run"], root);
|
|
311
|
+
assert.match(stdout, /\bpkg\b/, "incluye el repo propio anidado");
|
|
312
|
+
assert.doesNotMatch(stdout, /\bsrc\b/, "no incluye la subcarpeta que no es repo propio");
|
|
313
|
+
} finally {
|
|
314
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
|
|
271
318
|
test("init --dry-run no escribe nada", () => {
|
|
272
319
|
const dir = tmpProject();
|
|
273
320
|
try {
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# Compilado y uso local (para probar el repo clonado)
|
|
2
|
+
|
|
3
|
+
← [README](../README.md)
|
|
4
|
+
|
|
5
|
+
Guía para cuando **clonas este repositorio** y quieres compilarlo/empaquetarlo y **probarlo en local**
|
|
6
|
+
antes de publicarlo o para desarrollar sobre él.
|
|
7
|
+
|
|
8
|
+
> **Aclaración importante — no hay "compilación".** `ozali` es un CLI **Node de cero dependencias y
|
|
9
|
+
> ESM puro** (solo usa módulos `node:*`). **No hay build step**, ni TypeScript que transpilar, ni
|
|
10
|
+
> `dist/`. "Compilar" aquí significa una de dos cosas: (a) **correrlo tal cual** desde el fuente, o
|
|
11
|
+
> (b) **empaquetar el artefacto distribuible** (`npm pack` → un `.tgz`, el "archivo base") para
|
|
12
|
+
> instalarlo y probarlo como lo haría un usuario final.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Requisitos
|
|
17
|
+
|
|
18
|
+
- **Node ≥ 16** (`node --version`). Es lo único imprescindible.
|
|
19
|
+
- **git** (el CLI lee identidad/estado del repo).
|
|
20
|
+
- **pnpm** o **npm** (opcional; solo para `test`, `pack`, `link` o instalación global). No hay `npm
|
|
21
|
+
install` que correr: **el repo no tiene dependencias**.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
git clone https://github.com/jimmybathrooms/ozali.git
|
|
25
|
+
cd ozali
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 1. Correr desde el fuente (sin instalar nada)
|
|
31
|
+
|
|
32
|
+
Como no hay dependencias ni build, el CLI corre directo:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
node cli/bin/ozali.mjs --version # imprime la versión de package.json (p. ej. 0.8.0)
|
|
36
|
+
node cli/bin/ozali.mjs --help # lista de comandos
|
|
37
|
+
node cli/bin/ozali.mjs doctor # health-check en el cwd
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Esta es la forma **más auditable**: ejecutas exactamente el código que ves, sin capa de instalación.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 2. Correr la batería de pruebas
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm test # (o: pnpm test) → node --test cli/test/*.test.mjs
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Debe salir todo en verde. Los tests son `node:test` puro (sin dependencias) y cubren init, doctor,
|
|
51
|
+
update, workspace, seguridad del paquete y los helpers de release de Engram.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 3. Empaquetar el "archivo base" (tarball distribuible)
|
|
56
|
+
|
|
57
|
+
El artefacto que se publicaría en npm es un tarball `.tgz`. Se genera con:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npm pack # (o: pnpm pack)
|
|
61
|
+
# → crea ozali-<version>.tgz en la raíz del repo (el cwd)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Para tu versión actual produce, por ejemplo, **`ozali-0.8.0.tgz`**. Es **idéntico** a lo que recibiría
|
|
65
|
+
un usuario desde npm: incluye solo lo declarado en `package.json > files` (`cli/`, `skill/`,
|
|
66
|
+
`skill-commit/`, `templates/`, `docs/`, `README.md`, `LICENSE`).
|
|
67
|
+
|
|
68
|
+
Para **ver qué contiene sin generar el archivo**:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npm pack --dry-run # lista archivos, tamaño y nombre del tarball, sin escribir nada
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
> El `.tgz` es un artefacto temporal: **no lo commitees**. Bórralo tras probar (o añádelo a
|
|
75
|
+
> `.gitignore` como `ozali-*.tgz`).
|
|
76
|
+
|
|
77
|
+
### Extraer / inspeccionar el tarball
|
|
78
|
+
|
|
79
|
+
El tarball es un `.tar.gz` estándar. Para extraerlo y revisar el "archivo base" tal como quedaría
|
|
80
|
+
instalado:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
tar -xzf ozali-0.8.0.tgz # crea una carpeta package/ con el contenido publicable
|
|
84
|
+
ls -R package # inspecciona la estructura
|
|
85
|
+
tar -tzf ozali-0.8.0.tgz # o solo LISTA el contenido, sin extraer
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
La carpeta `package/` es exactamente lo que npm coloca en `node_modules/ozali` al instalar.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 4. Usarlo en local para pruebas
|
|
93
|
+
|
|
94
|
+
Tres formas, de la más cómoda para desarrollar a la más fiel al usuario final:
|
|
95
|
+
|
|
96
|
+
### a) `npm link` — bucle de desarrollo (refleja tus cambios al instante)
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npm link # (o: pnpm link --global)
|
|
100
|
+
# ahora 'ozali' está en tu PATH, apuntando al clon local
|
|
101
|
+
ozali --version
|
|
102
|
+
ozali doctor
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Como es un symlink al repo, cualquier edición que hagas en `cli/` se ve de inmediato (no hace falta
|
|
106
|
+
re-linkear). Para deshacer: `npm unlink -g ozali` (o `npm rm -g ozali`).
|
|
107
|
+
|
|
108
|
+
### b) Instalar el tarball global — prueba el artefacto real
|
|
109
|
+
|
|
110
|
+
Instala el `.tgz` como lo haría un usuario, para validar el paquete exacto que publicarías:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
npm i -g ./ozali-0.8.0.tgz # (o: pnpm add -g ./ozali-0.8.0.tgz)
|
|
114
|
+
ozali --version
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Para desinstalar: `npm rm -g ozali`.
|
|
118
|
+
|
|
119
|
+
### c) Efímero, sin instalar en el PATH — como `npx`/`pnpm dlx`
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
npx ./ozali-0.8.0.tgz init # corre init desde el tarball, sin dejar 'ozali' instalado
|
|
123
|
+
pnpm dlx ./ozali-0.8.0.tgz init # equivalente con pnpm
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
> **Nota de seguridad:** el flag `--ignore-scripts` que recomendamos para instalar desde npm es
|
|
127
|
+
> irrelevante aquí, porque `ozali` **no tiene dependencias ni lifecycle scripts** (nada que ejecutar
|
|
128
|
+
> en install). Detalle en [security.md](security.md).
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 5. Probar en un proyecto sandbox
|
|
133
|
+
|
|
134
|
+
Crea un repo de juguete y corre el flujo real sin ensuciar nada:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
mkdir /tmp/ozali-sandbox && cd /tmp/ozali-sandbox && git init
|
|
138
|
+
|
|
139
|
+
# opción sin instalar: apunta al bin del clon
|
|
140
|
+
node /ruta/al/clon/ozali/cli/bin/ozali.mjs init --dry-run # muestra el plan, no escribe
|
|
141
|
+
node /ruta/al/clon/ozali/cli/bin/ozali.mjs init --yes --no-engram # init real, sin instalar Engram
|
|
142
|
+
node /ruta/al/clon/ozali/cli/bin/ozali.mjs doctor # verifica el resultado
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Para probar **workspaces multi-repo**, crea una carpeta con varios repos git dentro y corre:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
node /ruta/al/clon/ozali/cli/bin/ozali.mjs workspace --dry-run # inventario + plan, sin escribir
|
|
149
|
+
node /ruta/al/clon/ozali/cli/bin/ozali.mjs workspace --doctor # health-check de todos los miembros
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
(Si hiciste `npm link`, sustituye todo lo anterior por simplemente `ozali <comando>`.)
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## 6. Verificar y limpiar
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
ozali --version # debe coincidir con la "version" de package.json
|
|
160
|
+
npm rm -g ozali # desinstala el global (link o tarball)
|
|
161
|
+
rm -f ozali-*.tgz # borra el tarball de prueba
|
|
162
|
+
rm -rf package/ # borra la extracción del tarball, si la hiciste
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Resumen
|
|
168
|
+
|
|
169
|
+
| Quiero… | Comando |
|
|
170
|
+
|---|---|
|
|
171
|
+
| Correr sin instalar | `node cli/bin/ozali.mjs <cmd>` |
|
|
172
|
+
| Correr los tests | `npm test` |
|
|
173
|
+
| Empaquetar el distribuible | `npm pack` → `ozali-<version>.tgz` |
|
|
174
|
+
| Ver el contenido del paquete | `npm pack --dry-run` |
|
|
175
|
+
| Extraer el tarball | `tar -xzf ozali-<version>.tgz` → `package/` |
|
|
176
|
+
| Desarrollar con `ozali` en PATH | `npm link` |
|
|
177
|
+
| Probar el artefacto real | `npm i -g ./ozali-<version>.tgz` |
|
|
178
|
+
| Probar efímero | `npx ./ozali-<version>.tgz init` |
|
|
179
|
+
|
|
180
|
+
> ¿Buscas **publicar** una versión nueva (no solo probar)? Eso es otro flujo: bump de `version` en
|
|
181
|
+
> `package.json` → commit → tag `vX.Y.Z` → push; el tag dispara la publicación a npm con provenance
|
|
182
|
+
> vía GitHub Actions.
|
package/docs/guia-de-uso.md
CHANGED
|
@@ -81,6 +81,7 @@ Lleva el histórico y la memoria al repo de conocimiento del equipo. Tus compañ
|
|
|
81
81
|
| Comando | Qué hace |
|
|
82
82
|
|---|---|
|
|
83
83
|
| `ozali init` | Prepara el proyecto (lo corres una vez por repo). |
|
|
84
|
+
| `ozali workspace` | Configura varios repos de una carpeta para trabajar en conjunto (lo corres en la carpeta raíz). |
|
|
84
85
|
| `ozali doctor` | Revisa que todo esté bien. Es solo lectura, no cambia nada. |
|
|
85
86
|
| `ozali update` | Actualiza skill ozali + ozali-jarvis + permisos (y guía cómo regenerar cdk). |
|
|
86
87
|
| `ozali sync` | Sube el histórico/memoria al repo de equipo. |
|
|
@@ -171,6 +172,51 @@ Atajos: `ozali audit --tui` abre un navegador interactivo de la memoria; `ozali
|
|
|
171
172
|
busca un término; `ozali audit --general` fuerza el alcance general. Si no tienes Engram, audita el
|
|
172
173
|
histórico local de `.ozali/docs/`.
|
|
173
174
|
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Trabajar con varios repos a la vez (`ozali workspace`)
|
|
178
|
+
|
|
179
|
+
¿Tienes una carpeta que agrupa **varios repositorios que se hablan entre sí** (una API, su front, una
|
|
180
|
+
librería compartida) y quieres que tu agente trabaje con todos juntos? Corre **una vez** en esa
|
|
181
|
+
carpeta raíz:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
ozali workspace # escanea los repos hijos, prepara los que falten y arma la config conjunta
|
|
185
|
+
ozali workspace --dry-run # solo te muestra el inventario y el plan, sin escribir nada
|
|
186
|
+
ozali workspace --yes # sin preguntas: acepta los defaults y las referencias detectadas
|
|
187
|
+
ozali workspace --depth 2 # busca repos hasta 2 niveles (si están en subcarpetas de grupo)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Qué hace, en orden:
|
|
191
|
+
|
|
192
|
+
1. **Revisa** cada repo y te dice cómo está: `✔ listo`, `⚠ sin calibrar` (le falta correr la skill
|
|
193
|
+
`ozali`) o `✖ sin init` (nunca se preparó).
|
|
194
|
+
2. **Prepara** los que están `✖ sin init` corriendo `ozali init` por ti, y te **guía** para calibrar
|
|
195
|
+
los que están `⚠ sin calibrar` (abrir ese repo y escribir *"diagnostica el proyecto"* — eso lo
|
|
196
|
+
hace tu agente, no el comando).
|
|
197
|
+
3. **Detecta las referencias** entre repos (dependencias npm cruzadas, submódulos, `docker-compose`) y
|
|
198
|
+
te pide confirmarlas.
|
|
199
|
+
4. **Escribe la configuración** para trabajar en conjunto:
|
|
200
|
+
- `ozali-workspace.json` — el mapa de repos, su estado y sus referencias (esto **sí** se commitea).
|
|
201
|
+
- `<carpeta>.code-workspace` — ábrelo en VSCode/Antigravity y verás todos los repos juntos.
|
|
202
|
+
- **ozali-workspace-jarvis** en el `CLAUDE.md`/`AGENTS.md` de la raíz: un orquestador que coordina
|
|
203
|
+
los repos según ese mapa y delega el trabajo de código en el `cdk` de cada uno.
|
|
204
|
+
|
|
205
|
+
**Sin ir a cada proyecto:** desde la carpeta raíz puedes operar todos los repos de una vez:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
ozali workspace --doctor # revisa la salud de todos los repos y saca un resumen
|
|
209
|
+
ozali workspace --update # actualiza skills, permisos y jarvis de todos los repos
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Y para **calibrar** (generar `cdk`) los que estén `⚠ sin calibrar`, ya **no** abres cada proyecto:
|
|
213
|
+
abre tu agente en la carpeta raíz y pídele *"calibra los repos pendientes"* — el orquestador los
|
|
214
|
+
recorre **uno por uno** (cada uno con su aprobación) sin que cambies de proyecto.
|
|
215
|
+
|
|
216
|
+
Es **idempotente**: vuelve a correrlo cuando agregues un repo o cambien las referencias — no duplica
|
|
217
|
+
nada. Cada repo conserva su autonomía (su propio jarvis, su `cdk` y su memoria); el workspace solo
|
|
218
|
+
los **coordina**. Detalle completo en [workspaces.md](workspaces.md).
|
|
219
|
+
|
|
174
220
|
## Preguntas frecuentes
|
|
175
221
|
|
|
176
222
|
**¿Tengo que usar Engram?**
|
|
@@ -185,6 +231,10 @@ Lo corriste con `dlx`/`npx`, que es temporal. Instálalo global: `pnpm add -g oz
|
|
|
185
231
|
**¿Esto ensucia mi repositorio?**
|
|
186
232
|
No. El histórico y la memoria se aíslan (`.ozali/`, `.engram/` van al `.gitignore`).
|
|
187
233
|
|
|
234
|
+
**Tengo varios repos que dependen entre sí. ¿Los conecto?**
|
|
235
|
+
Sí: abre la carpeta que los agrupa y corre `ozali workspace`. Prepara los que falten y arma una
|
|
236
|
+
config para que tu agente trabaje con todos juntos. Ver [arriba](#trabajar-con-varios-repos-a-la-vez-ozali-workspace).
|
|
237
|
+
|
|
188
238
|
**Veo "this workspace has not been trusted" y mis permisos no aplican.**
|
|
189
239
|
Es el aviso de seguridad de Claude Code: ignora los permisos del proyecto hasta confiar en él.
|
|
190
240
|
Deja que `init` lo marque como confiable, o abre Claude Code en la carpeta y acepta el diálogo una
|
package/docs/workspaces.md
CHANGED
|
@@ -26,6 +26,18 @@ ozali workspace --no-trust # no marca la raíz como confiable en Claude Code
|
|
|
26
26
|
Un CLI **no puede auto-dispararse** con solo hacer `cd`; por eso es un comando explícito e
|
|
27
27
|
**idempotente**: re-córrelo cuando agregues repos o cambien las referencias.
|
|
28
28
|
|
|
29
|
+
### Operar todos los repos desde la raíz
|
|
30
|
+
|
|
31
|
+
Para no entrar repo por repo, dos modos batch corren un comando sobre **todos los miembros**:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
ozali workspace --doctor # health-check de cada repo miembro + resumen consolidado
|
|
35
|
+
ozali workspace --update # actualiza skills/permisos/jarvis de cada repo + avisa de cdk desfasado
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Ambos son **solo CLI** (no necesitan el agente) y saltan los repos `✖ sin init`. La **calibración**
|
|
39
|
+
(generar `cdk`) sí la hace el agente, pero también **sin cambiar de proyecto** — ver abajo.
|
|
40
|
+
|
|
29
41
|
## Qué hace, paso a paso
|
|
30
42
|
|
|
31
43
|
1. **Escaneo (read-only).** Enumera los repos git hijos y reporta el estado ozali de cada uno:
|
|
@@ -37,10 +49,11 @@ Un CLI **no puede auto-dispararse** con solo hacer `cd`; por eso es un comando e
|
|
|
37
49
|
instala skills, aísla histórico, configura Engram). Hereda `agent`/`scope`/`knowledge-repo` de un
|
|
38
50
|
repo ya inicializado para mantener el equipo consistente.
|
|
39
51
|
|
|
40
|
-
3. **Guía de calibración.** El CLI **no calibra** (eso lo hace el agente)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
52
|
+
3. **Guía de calibración.** El CLI **no calibra** (eso lo hace el agente), pero ya **no** tienes que
|
|
53
|
+
abrir cada repo por separado: `ozali workspace` instala la skill **`ozali`** en la **raíz**, y el
|
|
54
|
+
orquestador `ozali-workspace-jarvis` la usa **en modo target** para calibrar cada repo
|
|
55
|
+
`⚠ sin calibrar` **desde el workspace**, repo por repo y con su propio 🛑 GATE. Abre el agente en la
|
|
56
|
+
raíz y pídele *"calibra los repos pendientes"*.
|
|
44
57
|
|
|
45
58
|
4. **Referencias (auto-detección + confirmación).** Infiere aristas dirigidas `from → to`:
|
|
46
59
|
- `npm-dep` — el `name` de un repo aparece en `dependencies`/`devDependencies`/`peerDependencies` de otro.
|
|
@@ -58,6 +71,7 @@ En la carpeta raíz:
|
|
|
58
71
|
| `ozali-workspace.json` | Manifiesto: miembros (ruta, proyecto, estado, fuente de verdad), referencias, `knowledgeRepo`, cloud. Fuente de verdad del workspace. |
|
|
59
72
|
| `<carpeta>.code-workspace` | Workspace **multi-root** de VSCode/Antigravity: abre todos los repos juntos. Merge idempotente si ya existe. |
|
|
60
73
|
| `CLAUDE.md` / `AGENTS.md` (raíz) | Bloque marcado del orquestador **`ozali-workspace-jarvis`** + subagente / agente de opencode. |
|
|
74
|
+
| `.claude/skills/ozali/` (raíz) | La skill **`ozali`** instalada en la raíz para **calibrar miembros en modo target** sin cambiar de proyecto (solo Claude Code). |
|
|
61
75
|
|
|
62
76
|
Si la raíz es a su vez un repo git, se añade `.claude/`, `.engram/` y `.ozali/` a su `.gitignore`
|
|
63
77
|
(los artefactos locales del agente no se commitean). `ozali-workspace.json` y `.code-workspace` **sí**
|
|
@@ -78,5 +92,5 @@ miembros). Su trabajo:
|
|
|
78
92
|
## Fuera de alcance (por ahora)
|
|
79
93
|
|
|
80
94
|
- Auto-sugerencia al abrir la carpeta (tarea de editor/hook).
|
|
81
|
-
- `ozali
|
|
95
|
+
- `ozali sync` agregado a nivel workspace (`--doctor`/`--update` ya existen; falta `--sync`).
|
|
82
96
|
- Detección de referencias más allá de npm/submódulos/compose (imports TS/py, `go.work`).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ozali",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.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": {
|
package/skill/SKILL.md
CHANGED
|
@@ -26,6 +26,28 @@ produce documentación, la calibración, el plan y los artefactos de la skill `c
|
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
29
|
+
## Modo workspace — calibrar un repo miembro (target)
|
|
30
|
+
|
|
31
|
+
Normalmente `ozali` opera sobre el **repo actual** (cwd). Pero cuando te invocan desde la **raíz de un
|
|
32
|
+
workspace** (existe `ozali-workspace.json`) para calibrar un **repo miembro**, operas sobre un
|
|
33
|
+
**target de subcarpeta** en vez del cwd. En ese caso:
|
|
34
|
+
|
|
35
|
+
- **Todas las rutas son relativas al `<target>`**, no a la raíz: la fuente de verdad
|
|
36
|
+
(`<target>/AI.md` + `<target>/.ai/`, o su variante `IA.md` + `.ia/`), la skill que generas
|
|
37
|
+
(`<target>/.claude/skills/cdk/`), el histórico (`<target>/.ozali/docs/`) y
|
|
38
|
+
`<target>/.engram/config.json`.
|
|
39
|
+
- **Identidad git del miembro:** usa `git -C <target> …` (no la raíz).
|
|
40
|
+
- **Engram:** guarda con el `project_name` de `<target>/.engram/config.json` (equivale al
|
|
41
|
+
`members[].project` del manifiesto). **No mezcles** memoria entre repos.
|
|
42
|
+
- **Un target por corrida**, secuencial, con su **propio 🛑 GATE**. No calibres varios a la vez sin
|
|
43
|
+
aprobación.
|
|
44
|
+
- Al terminar, sugiere **re-correr `ozali workspace`** en la raíz para refrescar el estado del miembro
|
|
45
|
+
en el manifiesto (`needs-calibration` → `ready`).
|
|
46
|
+
|
|
47
|
+
Si te invocan sin target (uso normal en un solo repo), ignora esta sección y sigue con el cwd.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
29
51
|
## Flujo general (7 fases)
|
|
30
52
|
|
|
31
53
|
```
|
|
@@ -13,29 +13,73 @@ ejecución disciplinada dentro de cada uno.
|
|
|
13
13
|
> Cada repo miembro conserva su propia autonomía: su `ozali-jarvis`, su skill `cdk`, su fuente de
|
|
14
14
|
> verdad (`.ai/`/`.ia/`) y su memoria Engram. Tú **no** los reemplazas: los **coordinas**.
|
|
15
15
|
|
|
16
|
+
## El manifiesto (`ozali-workspace.json`) — tu única fuente de verdad
|
|
17
|
+
|
|
18
|
+
Léelo en la raíz **antes de cualquier cosa**. Es lo que `ozali workspace` escribió; su esquema:
|
|
19
|
+
|
|
20
|
+
- `members[]` — cada repo miembro:
|
|
21
|
+
- `path` — carpeta relativa a la raíz (el repo donde ejecutas).
|
|
22
|
+
- `project` — **nombre del proyecto en Engram** de ese repo. Úsalo para acotar la memoria (ver §1);
|
|
23
|
+
**no** dependas de `mem_current_project`, que detecta la raíz del workspace, no el miembro.
|
|
24
|
+
- `status` — `ready` / `needs-calibration` / `missing-init`. **Es una foto** del último
|
|
25
|
+
`ozali workspace`: puede haber quedado atrás (ver §2).
|
|
26
|
+
- `sot` — variante de fuente de verdad del repo (`ai`/`ia`/…) o `null` si no la tiene.
|
|
27
|
+
- `references[]` — aristas dirigidas `{ from, to, kind }` entre miembros (`from` consume a `to`):
|
|
28
|
+
- `kind: "npm-dep"` — `from` declara a `to` en sus dependencias npm.
|
|
29
|
+
- `kind: "git-submodule"` — `to` está montado como submódulo dentro de `from`.
|
|
30
|
+
- `kind: "compose"` — un servicio de `from` construye desde `to` (`docker-compose`).
|
|
31
|
+
- `knowledgeRepo` — repo de conocimiento **compartido** por el equipo (histórico + memoria sincronizada).
|
|
32
|
+
- `cloud` — config de Engram Cloud (réplica de equipo) si está habilitada.
|
|
33
|
+
- `agent` — agente objetivo (`claude-code` / `opencode` / `both`).
|
|
34
|
+
|
|
35
|
+
**No inventes** miembros ni referencias: si algo no está en el manifiesto, no lo asumas.
|
|
36
|
+
|
|
16
37
|
## 1. Al iniciar (recall-first, a nivel workspace)
|
|
17
|
-
- **Lee `ozali-workspace.json`**
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
cada repo con `mem_current_project` y usa `mem_search`/`mem_context` acotado a esos proyectos.
|
|
38
|
+
- **Lee `ozali-workspace.json`** y ubica la tarea: ¿qué repo(s) toca y, vía qué `references`, impacta a
|
|
39
|
+
otros?
|
|
40
|
+
- Recupera contexto de memoria **solo de los proyectos involucrados** (no de todos): para cada miembro
|
|
41
|
+
en juego usa su `members[].project` con `mem_search`/`mem_context` acotado a ese proyecto.
|
|
22
42
|
- **Recuperación selectiva:** nunca vuelques toda la memoria; trae solo lo necesario por repo.
|
|
23
43
|
|
|
24
44
|
## 2. Antes de tocar código — verifica que el repo esté listo
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
- Si un miembro está `
|
|
28
|
-
|
|
45
|
+
- El `status` del manifiesto es una foto; **confírmalo contra la realidad** antes de confiar en él: un
|
|
46
|
+
repo está calibrado si existe `<path>/.claude/skills/cdk/SKILL.md`.
|
|
47
|
+
- Si un miembro está `missing-init` (sin `.ozali/config.json`), dilo y sugiere `ozali init` en ese repo.
|
|
48
|
+
- Si está `needs-calibration` (tiene init pero **falta `cdk`**), **condúcelo** desde aquí (ver sección
|
|
49
|
+
siguiente): ya **no** hace falta abrir cada repo por separado.
|
|
50
|
+
- Si calibraste o inicializaste un repo desde aquí, el manifiesto quedó **desactualizado**: sugiere
|
|
51
|
+
re-correr `ozali workspace` en la raíz para refrescar estados y referencias.
|
|
52
|
+
|
|
53
|
+
## Calibrar o preparar miembros desde la raíz (sin cambiar de proyecto)
|
|
54
|
+
|
|
55
|
+
No abras cada repo por separado. Desde este workspace prepara y calibra en secuencia:
|
|
56
|
+
|
|
57
|
+
- **`missing-init`** (sin `.ozali/config.json`): pide correr `ozali init <path>` en ese miembro, o
|
|
58
|
+
`ozali workspace` en la raíz (que lo inicializa por ti).
|
|
59
|
+
- **`needs-calibration`** (falta `cdk`): invoca la skill **`ozali`** instalada en la raíz **en modo
|
|
60
|
+
target**, apuntando a `<path>` del miembro. Genera `AI.md`/`.ai/` y su `cdk` **dentro de esa
|
|
61
|
+
subcarpeta**, guardando en Engram con el `members[].project` de ese repo.
|
|
62
|
+
- Hazlo **repo por repo, secuencialmente**, respetando el 🛑 **GATE** de cada uno: nunca calibres
|
|
63
|
+
varios sin aprobación.
|
|
64
|
+
- Para **revisar** o **actualizar** todos de golpe (sin agente, solo CLI): `ozali workspace --doctor`
|
|
65
|
+
y `ozali workspace --update`.
|
|
66
|
+
- Tras inicializar/calibrar, sugiere **re-correr `ozali workspace`** en la raíz para refrescar los
|
|
67
|
+
estados del manifiesto.
|
|
29
68
|
|
|
30
69
|
## 3. Para ejecutar cambios → delega en el repo correcto
|
|
31
70
|
- Un cambio se ejecuta **dentro** del repo que le corresponde, usando **su** skill `cdk` (plan, GATE,
|
|
32
71
|
TDD, docs por hito). Tú preparas el contexto cruzado; el `cdk` del repo ejecuta.
|
|
33
|
-
- **Cambios que cruzan repos
|
|
34
|
-
|
|
35
|
-
|
|
72
|
+
- **Cambios que cruzan repos:** secuencia según las `references`, **primero el `to` (proveedor), luego
|
|
73
|
+
el `from` (consumidor)**. Según el `kind`:
|
|
74
|
+
- `npm-dep` — publica/enlaza el paquete de `to` antes de que `from` consuma la nueva versión.
|
|
75
|
+
- `git-submodule` — actualiza `to`, luego mueve el puntero del submódulo en `from` y verifícalo.
|
|
76
|
+
- `compose` — reconstruye el servicio de `to` antes de levantar `from`.
|
|
77
|
+
- Deja registrado en la memoria de **cada** repo qué cambió y por qué, enlazando ambos lados de la
|
|
78
|
+
referencia.
|
|
36
79
|
|
|
37
80
|
## 4. Al cerrar
|
|
38
|
-
- Resume por repo tocado con `mem_session_summary` (solo el agente top-level)
|
|
81
|
+
- Resume por repo tocado con `mem_session_summary` (solo el agente top-level), usando el `project` de
|
|
82
|
+
cada miembro.
|
|
39
83
|
- Si el cambio afectó una referencia entre repos, anótalo en **ambos** proyectos para que el recall
|
|
40
84
|
futuro lo encuentre desde cualquiera de los dos.
|
|
41
85
|
|