ozali 0.5.0 → 0.6.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 +15 -7
- package/cli/bin/ozali.mjs +5 -4
- package/cli/lib/commands.mjs +74 -8
- package/cli/lib/util.mjs +1 -0
- package/cli/test/smoke.test.mjs +74 -0
- package/package.json +2 -1
- package/skill/SKILL.md +48 -3
- package/skill/references/cdk-contract.md +72 -0
- package/skill-commit/SKILL.md +81 -0
package/README.md
CHANGED
|
@@ -59,9 +59,9 @@ git clone <repo> && node ozali/cli/bin/ozali.mjs init
|
|
|
59
59
|
### Uso del CLI
|
|
60
60
|
|
|
61
61
|
```bash
|
|
62
|
-
ozali init # detecta agente, instala
|
|
63
|
-
ozali doctor # health-check read-only (fuente de verdad, Engram, Cloud, Strict TDD
|
|
64
|
-
ozali update # actualiza
|
|
62
|
+
ozali init # detecta agente, instala skills ozali + ozali-commit, aísla histórico, configura Engram
|
|
63
|
+
ozali doctor # health-check read-only (fuente de verdad, Engram, Cloud, versión de cdk, Strict TDD…)
|
|
64
|
+
ozali update # actualiza skills ozali + ozali-commit + ozali-jarvis + permisos; avisa si cdk quedó atrás
|
|
65
65
|
ozali sync # lleva el histórico (docs + Engram) al repo de conocimiento de equipo
|
|
66
66
|
ozali audit # navega/audita la memoria de Engram del proyecto (o general)
|
|
67
67
|
```
|
|
@@ -78,10 +78,17 @@ pnpm add -g ozali@<versión> # actualiza el CLI global (pinea la versión por
|
|
|
78
78
|
ozali update # en cada repo: refresca skill ozali + ozali-jarvis + permisos
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
`ozali update` también **crea ozali-jarvis**
|
|
82
|
-
`cdk` la **regenera tu agente** (no el CLI):
|
|
83
|
-
|
|
84
|
-
|
|
81
|
+
`ozali update` también **crea ozali-jarvis** y **instala la skill `ozali-commit`** en repos
|
|
82
|
+
inicializados con versiones anteriores. La skill `cdk` la **regenera/migra tu agente** (no el CLI):
|
|
83
|
+
`ozali update` **detecta la versión de contrato** de `cdk` y, si quedó atrás (o aún referencia
|
|
84
|
+
`copsis-commit` de versiones viejas), te avisa y te da los pasos manuales. Tras `ozali update`, abre
|
|
85
|
+
el agente y vuelve a correr la skill `ozali`: su **pre-flight** detecta el `cdk` existente, lo **migra
|
|
86
|
+
automáticamente** al contrato vigente (eliminando `copsis-commit` y cableando `ozali-commit`) y
|
|
87
|
+
estampa la versión — tus docs por hito y el plan congelado se conservan.
|
|
88
|
+
|
|
89
|
+
> **Commit del hito (`ozali-commit`):** `init`/`update` instalan la skill `ozali-commit`
|
|
90
|
+
> (`.claude/skills/ozali-commit/`), sucesora de `copsis-commit`. `cdk` la invoca al cerrar cada hito
|
|
91
|
+
> para generar el commit convencional (feat/fix/hotfix/refactor + scope) tras tu aprobación.
|
|
85
92
|
|
|
86
93
|
`init` también escribe un **perfil base de permisos** (`.claude/settings.json` para Claude Code,
|
|
87
94
|
`opencode.json` para opencode) para reducir confirmaciones: deja libres comandos seguros y bloquea
|
|
@@ -125,6 +132,7 @@ Claude Code y opencode (perfiles de permisos para ambos en
|
|
|
125
132
|
| Desplegar Engram Cloud (Google Cloud) | [docs/deploy-cloud-gcloud.md](docs/deploy-cloud-gcloud.md) |
|
|
126
133
|
| Skill bootstrap | [skill/SKILL.md](skill/SKILL.md) |
|
|
127
134
|
| Calibración de testing + TDD | [skill/references/calibration-blueprint.md](skill/references/calibration-blueprint.md) |
|
|
135
|
+
| Contrato y versión de `cdk` | [skill/references/cdk-contract.md](skill/references/cdk-contract.md) |
|
|
128
136
|
| Blueprint de agentes | [skill/references/agents-blueprint.md](skill/references/agents-blueprint.md) |
|
|
129
137
|
| Memoria híbrida (docs + Engram) | [skill/references/engram-convention.md](skill/references/engram-convention.md) |
|
|
130
138
|
|
package/cli/bin/ozali.mjs
CHANGED
|
@@ -12,10 +12,11 @@ ${c.bold("Uso:")}
|
|
|
12
12
|
ozali <comando> [opciones]
|
|
13
13
|
|
|
14
14
|
${c.bold("Comandos:")}
|
|
15
|
-
init Detecta el agente (Claude Code/opencode), instala
|
|
16
|
-
aísla el histórico, configura Engram y el repo de conocimiento.
|
|
17
|
-
doctor Health-check read-only del proyecto (fuente de verdad, Engram, TDD…).
|
|
18
|
-
update Actualiza la instalación (
|
|
15
|
+
init Detecta el agente (Claude Code/opencode), instala las skills ozali y
|
|
16
|
+
ozali-commit, aísla el histórico, configura Engram y el repo de conocimiento.
|
|
17
|
+
doctor Health-check read-only del proyecto (fuente de verdad, Engram, versión de cdk, TDD…).
|
|
18
|
+
update Actualiza la instalación (skills ozali + ozali-commit + ozali-jarvis + permisos)
|
|
19
|
+
al paquete y avisa si la skill cdk quedó desactualizada.
|
|
19
20
|
sync Sincroniza el histórico (docs + Engram) con el repo de conocimiento.
|
|
20
21
|
audit Navega/audita la memoria de Engram del proyecto (o general).
|
|
21
22
|
cloud Gestiona Engram Cloud: status, upgrade, repair, dashboard, config.
|
package/cli/lib/commands.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import os from "node:os";
|
|
5
5
|
import {
|
|
6
6
|
c, ok, warn, err, info, step,
|
|
7
|
-
SKILL_SRC, TEMPLATES_SRC, exists, ensureDir, copyDir, readJSON, writeJSON,
|
|
7
|
+
SKILL_SRC, COMMIT_SKILL_SRC, TEMPLATES_SRC, exists, ensureDir, copyDir, readJSON, writeJSON,
|
|
8
8
|
ensureGitignore, tryExec, spawnCmd, which, engramAssetName,
|
|
9
9
|
projectName, pkgVersion, DEFAULT_KNOWLEDGE, HOME, openURL,
|
|
10
10
|
} from "./util.mjs";
|
|
@@ -23,6 +23,11 @@ function skillTarget(cwd, scope) {
|
|
|
23
23
|
return path.join(base, "skills", "ozali");
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
function commitSkillTarget(cwd, scope) {
|
|
27
|
+
const base = scope === "global" ? path.join(process.env.HOME || "", ".claude") : path.join(cwd, ".claude");
|
|
28
|
+
return path.join(base, "skills", "ozali-commit");
|
|
29
|
+
}
|
|
30
|
+
|
|
26
31
|
function readTeamCloud(cwd) {
|
|
27
32
|
return readJSON(TEAM_CLOUD_PATH(cwd));
|
|
28
33
|
}
|
|
@@ -166,11 +171,14 @@ export async function init(cwd, opts) {
|
|
|
166
171
|
|
|
167
172
|
// --- acciones ---
|
|
168
173
|
step("Aplicando");
|
|
169
|
-
// 1) copiar skill
|
|
174
|
+
// 1) copiar skill ozali (bootstrap) + ozali-commit (commit convencional)
|
|
170
175
|
const target = skillTarget(cwd, scope);
|
|
171
176
|
ensureDir(path.dirname(target));
|
|
172
177
|
copyDir(SKILL_SRC, target);
|
|
173
178
|
ok(`Skill instalada en ${c.bold(path.relative(cwd, target) || target)}.`);
|
|
179
|
+
const commitTarget = commitSkillTarget(cwd, scope);
|
|
180
|
+
copyDir(COMMIT_SKILL_SRC, commitTarget);
|
|
181
|
+
ok(`Skill ${c.bold("ozali-commit")} instalada en ${c.bold(path.relative(cwd, commitTarget) || commitTarget)}.`);
|
|
174
182
|
|
|
175
183
|
// 2) perfiles base de permisos (idempotentes, merge mínimo) por agente
|
|
176
184
|
if (agent === "claude-code" || agent === "both") {
|
|
@@ -761,6 +769,19 @@ export function doctor(cwd) {
|
|
|
761
769
|
add("Node ≥ 16", env.node.ok, env.node.version);
|
|
762
770
|
add("Fuente de verdad", env.sot.found, env.sot.found ? `${env.sot.doc} + ${env.sot.dir}/` : "ausente (corre la skill 'ozali')");
|
|
763
771
|
add("Skill ozali instalada", env.skill.installed, env.skill.installed ? env.skill.paths.map((p) => path.relative(cwd, p) || p).join(", ") : "no instalada (ozali init)");
|
|
772
|
+
// Skill cdk (la genera el agente): versión de contrato vs. la vigente del paquete.
|
|
773
|
+
const cdkInfo = detectCdk(cwd);
|
|
774
|
+
const cdkN = cdkCanonicalVersion();
|
|
775
|
+
if (!cdkInfo.installed) {
|
|
776
|
+
add("Skill cdk", true, "no generada aún (corre la skill 'ozali' en tu agente)");
|
|
777
|
+
} else if (cdkInfo.version != null && cdkInfo.version >= cdkN && !cdkInfo.hasCopsis) {
|
|
778
|
+
add("Skill cdk", true, `contrato v${cdkInfo.version} (al día)`);
|
|
779
|
+
} else {
|
|
780
|
+
const reason = cdkInfo.hasCopsis ? "contiene copsis-commit → migra con la skill 'ozali'"
|
|
781
|
+
: cdkInfo.version == null ? "sin versión de contrato (legado) → migra con la skill 'ozali'"
|
|
782
|
+
: `contrato v${cdkInfo.version} < v${cdkN} → migra con la skill 'ozali'`;
|
|
783
|
+
add("Skill cdk", false, reason);
|
|
784
|
+
}
|
|
764
785
|
add("Engram", env.engram.available, env.engram.available ? env.engram.bin : "no instalado → modo docs");
|
|
765
786
|
if (env.engram.available) {
|
|
766
787
|
const online = tryExec("engram", ["doctor"], { cwd }) !== null;
|
|
@@ -899,10 +920,15 @@ export function update(cwd, opts = {}) {
|
|
|
899
920
|
}
|
|
900
921
|
|
|
901
922
|
// 1) Skill ozali (incluye las references: la base desde la que el agente regenera cdk)
|
|
923
|
+
// + ozali-commit (commit convencional) como skill hermana — la crea en repos previos.
|
|
902
924
|
if (env.skill.installed) {
|
|
903
925
|
for (const p of env.skill.paths) {
|
|
904
926
|
copyDir(SKILL_SRC, p);
|
|
905
927
|
ok(`Skill ozali actualizada: ${path.relative(cwd, p) || p} → v${pkgVersion()}`);
|
|
928
|
+
const commitDir = path.join(path.dirname(p), "ozali-commit");
|
|
929
|
+
const freshCommit = !exists(commitDir);
|
|
930
|
+
copyDir(COMMIT_SKILL_SRC, commitDir);
|
|
931
|
+
ok(`Skill ozali-commit ${freshCommit ? "instalada" : "actualizada"}: ${path.relative(cwd, commitDir) || commitDir}`);
|
|
906
932
|
}
|
|
907
933
|
} else {
|
|
908
934
|
warn("Skill ozali no instalada en esta ruta (corre " + c.bold("ozali init") + " para instalarla).");
|
|
@@ -926,13 +952,27 @@ export function update(cwd, opts = {}) {
|
|
|
926
952
|
if (agent === "opencode" || agent === "both") ensureJarvisOpencode(cwd);
|
|
927
953
|
}
|
|
928
954
|
|
|
929
|
-
// 4) Skill cdk: la genera el AGENTE (Fase 6)
|
|
955
|
+
// 4) Skill cdk: la genera/migra el AGENTE (Fase 0.5/6); el CLI solo detecta versión y guía.
|
|
930
956
|
const cdk = detectCdk(cwd);
|
|
957
|
+
const cdkN = cdkCanonicalVersion();
|
|
931
958
|
if (cdk.installed) {
|
|
932
959
|
step("Skill cdk (generada por el agente)");
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
960
|
+
const upToDate = cdk.version != null && cdk.version >= cdkN && !cdk.hasCopsis;
|
|
961
|
+
if (upToDate) {
|
|
962
|
+
ok(`cdk al día (contrato v${cdk.version}).`);
|
|
963
|
+
} else {
|
|
964
|
+
const reason = cdk.version == null ? "sin versión de contrato (cdk legado)"
|
|
965
|
+
: cdk.version < cdkN ? `contrato v${cdk.version} < v${cdkN} (desactualizado)`
|
|
966
|
+
: "contiene referencias a copsis-commit";
|
|
967
|
+
warn(`cdk desactualizada: ${reason}.`);
|
|
968
|
+
if (cdk.hasCopsis) warn("Detectadas referencias a " + c.bold("copsis-commit") + " (heredadas de versiones anteriores).");
|
|
969
|
+
info("El CLI no regenera cdk. Actualízala manualmente desde tu agente:");
|
|
970
|
+
info(" 1. Abre tu agente en este proyecto.");
|
|
971
|
+
info(" 2. Corre la skill " + c.bold("ozali") + " (escribe " + c.bold('"ozali"') + "): el pre-flight migra cdk al contrato " + c.bold("v" + cdkN) + ", elimina copsis-commit y cablea ozali-commit.");
|
|
972
|
+
info("Tus docs por hito (" + c.bold(".ozali/docs/cdk/") + ") y el plan congelado se conservan.");
|
|
973
|
+
}
|
|
974
|
+
} else {
|
|
975
|
+
info("cdk aún no generada en este repo. Corre la skill " + c.bold("ozali") + " en tu agente para crearla.");
|
|
936
976
|
}
|
|
937
977
|
|
|
938
978
|
// 5) versión del config
|
|
@@ -941,13 +981,39 @@ export function update(cwd, opts = {}) {
|
|
|
941
981
|
return 0;
|
|
942
982
|
}
|
|
943
983
|
|
|
944
|
-
/**
|
|
984
|
+
/**
|
|
985
|
+
* ¿Existe la skill cdk (generada por el agente)? Devuelve además la versión de contrato
|
|
986
|
+
* estampada en su frontmatter (`cdk_contract_version`) y si aún referencia `copsis-commit`.
|
|
987
|
+
* version === null ⇒ cdk legado (sin marcador de versión).
|
|
988
|
+
*/
|
|
945
989
|
function detectCdk(cwd) {
|
|
946
990
|
const paths = [
|
|
947
991
|
path.join(cwd, ".claude", "skills", "cdk", "SKILL.md"),
|
|
948
992
|
path.join(HOME, ".claude", "skills", "cdk", "SKILL.md"),
|
|
949
993
|
].filter(exists);
|
|
950
|
-
return { installed: paths
|
|
994
|
+
if (paths.length === 0) return { installed: false, paths: [], version: null, hasCopsis: false };
|
|
995
|
+
let version = null;
|
|
996
|
+
let hasCopsis = false;
|
|
997
|
+
for (const f of paths) {
|
|
998
|
+
const txt = fs.readFileSync(f, "utf8");
|
|
999
|
+
if (version === null) {
|
|
1000
|
+
const m = txt.match(/cdk_contract_version:\s*(\d+)/i);
|
|
1001
|
+
if (m) version = parseInt(m[1], 10);
|
|
1002
|
+
}
|
|
1003
|
+
if (/copsis-commit/i.test(txt)) hasCopsis = true;
|
|
1004
|
+
}
|
|
1005
|
+
return { installed: true, paths, version, hasCopsis };
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
/** Versión de contrato vigente de cdk (fuente única: skill/references/cdk-contract.md del paquete). */
|
|
1009
|
+
function cdkCanonicalVersion() {
|
|
1010
|
+
try {
|
|
1011
|
+
const txt = fs.readFileSync(path.join(SKILL_SRC, "references", "cdk-contract.md"), "utf8");
|
|
1012
|
+
const m = txt.match(/CDK_CONTRACT_VERSION:\s*(\d+)/i);
|
|
1013
|
+
return m ? parseInt(m[1], 10) : 1;
|
|
1014
|
+
} catch {
|
|
1015
|
+
return 1;
|
|
1016
|
+
}
|
|
951
1017
|
}
|
|
952
1018
|
|
|
953
1019
|
// ============================================================= sync ===========
|
package/cli/lib/util.mjs
CHANGED
|
@@ -10,6 +10,7 @@ import { execFileSync } from "node:child_process";
|
|
|
10
10
|
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
11
11
|
export const PKG_ROOT = path.resolve(HERE, "..", "..");
|
|
12
12
|
export const SKILL_SRC = path.join(PKG_ROOT, "skill");
|
|
13
|
+
export const COMMIT_SKILL_SRC = path.join(PKG_ROOT, "skill-commit");
|
|
13
14
|
export const TEMPLATES_SRC = path.join(PKG_ROOT, "templates");
|
|
14
15
|
|
|
15
16
|
export function pkgVersion() {
|
package/cli/test/smoke.test.mjs
CHANGED
|
@@ -133,6 +133,80 @@ test("update agrega ozali-jarvis en un repo que no lo tenía", () => {
|
|
|
133
133
|
}
|
|
134
134
|
});
|
|
135
135
|
|
|
136
|
+
function initRepo(dir) {
|
|
137
|
+
run(["init", "--yes", "--no-engram", "--no-trust", "--no-jarvis", "--agent", "claude-code", "--scope", "project", "--knowledge-repo", path.join(dir, ".k")], dir);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function writeCdkStub(dir, body) {
|
|
141
|
+
const f = path.join(dir, ".claude", "skills", "cdk", "SKILL.md");
|
|
142
|
+
fs.mkdirSync(path.dirname(f), { recursive: true });
|
|
143
|
+
fs.writeFileSync(f, body);
|
|
144
|
+
return f;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
test("init instala la skill ozali-commit", () => {
|
|
148
|
+
const dir = tmpProject();
|
|
149
|
+
try {
|
|
150
|
+
initRepo(dir);
|
|
151
|
+
assert.ok(fs.existsSync(path.join(dir, ".claude", "skills", "ozali-commit", "SKILL.md")), "ozali-commit SKILL.md instalada");
|
|
152
|
+
} finally {
|
|
153
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test("doctor marca cdk al día cuando la versión de contrato coincide", () => {
|
|
158
|
+
const dir = tmpProject();
|
|
159
|
+
try {
|
|
160
|
+
initRepo(dir);
|
|
161
|
+
writeCdkStub(dir, "---\nname: cdk\ncdk_contract_version: 1\n---\n# cdk\n");
|
|
162
|
+
const { stdout } = run(["doctor"], dir, true);
|
|
163
|
+
assert.match(stdout, /Skill cdk/, "doctor reporta la fila Skill cdk");
|
|
164
|
+
assert.match(stdout, /contrato v1 \(al día\)/, "doctor marca cdk al día");
|
|
165
|
+
} finally {
|
|
166
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test("doctor marca cdk desactualizada si referencia copsis-commit", () => {
|
|
171
|
+
const dir = tmpProject();
|
|
172
|
+
try {
|
|
173
|
+
initRepo(dir);
|
|
174
|
+
writeCdkStub(dir, "---\nname: cdk\ncdk_contract_version: 1\n---\n# cdk\ninvoca copsis-commit al cierre del hito\n");
|
|
175
|
+
const { stdout } = run(["doctor"], dir, true);
|
|
176
|
+
assert.match(stdout, /copsis-commit/, "doctor avisa de copsis-commit");
|
|
177
|
+
} finally {
|
|
178
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test("update avisa y da pasos manuales si cdk está desactualizada (legado)", () => {
|
|
183
|
+
const dir = tmpProject();
|
|
184
|
+
try {
|
|
185
|
+
initRepo(dir);
|
|
186
|
+
writeCdkStub(dir, "---\nname: cdk\n---\n# cdk legado que invoca copsis-commit\n");
|
|
187
|
+
const { stdout } = run(["update"], dir);
|
|
188
|
+
assert.match(stdout, /cdk desactualizada/, "update avisa de cdk desactualizada");
|
|
189
|
+
assert.match(stdout, /copsis-commit/, "update menciona la migración de copsis-commit");
|
|
190
|
+
assert.match(stdout, /skill ozali|pre-flight|migra/i, "update da pasos manuales");
|
|
191
|
+
} finally {
|
|
192
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test("update también instala ozali-commit en repos previos", () => {
|
|
197
|
+
const dir = tmpProject();
|
|
198
|
+
try {
|
|
199
|
+
initRepo(dir);
|
|
200
|
+
// Simula instalación previa sin ozali-commit.
|
|
201
|
+
fs.rmSync(path.join(dir, ".claude", "skills", "ozali-commit"), { recursive: true, force: true });
|
|
202
|
+
assert.ok(!fs.existsSync(path.join(dir, ".claude", "skills", "ozali-commit", "SKILL.md")), "precondición: sin ozali-commit");
|
|
203
|
+
run(["update"], dir);
|
|
204
|
+
assert.ok(fs.existsSync(path.join(dir, ".claude", "skills", "ozali-commit", "SKILL.md")), "update instala ozali-commit");
|
|
205
|
+
} finally {
|
|
206
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
|
|
136
210
|
test("init --dry-run no escribe nada", () => {
|
|
137
211
|
const dir = tmpProject();
|
|
138
212
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ozali",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.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": {
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"files": [
|
|
13
13
|
"cli/",
|
|
14
14
|
"skill/",
|
|
15
|
+
"skill-commit/",
|
|
15
16
|
"templates/",
|
|
16
17
|
"docs/",
|
|
17
18
|
"README.md",
|
package/skill/SKILL.md
CHANGED
|
@@ -30,6 +30,7 @@ produce documentación, la calibración, el plan y los artefactos de la skill `c
|
|
|
30
30
|
|
|
31
31
|
```
|
|
32
32
|
Fase 0 Identidad y registro → quién corre ozali (git/sesión)
|
|
33
|
+
Fase 0.5 Pre-flight de cdk → ¿existe cdk? ¿versión de contrato vigente? migrar si toca
|
|
33
34
|
Fase 1 Detección fuente de verdad → ¿existe AI.md/.ai o IA.md/.ia?
|
|
34
35
|
Fase 2 Generación conocimiento → si falta, evaluar el proyecto y generar AI.md + .ai/
|
|
35
36
|
Fase 3 Validación + ajustes → ¿coincide con la estructura real? ajustes mínimos
|
|
@@ -69,6 +70,45 @@ Guarda estos valores; se reutilizan en Fase 6 y en la documentación.
|
|
|
69
70
|
|
|
70
71
|
---
|
|
71
72
|
|
|
73
|
+
## Fase 0.5 — Pre-flight de `cdk` (versión de contrato + migración)
|
|
74
|
+
|
|
75
|
+
> Esta fase resuelve el caso de **un repo que ya tiene `cdk` instalada**: en vez de omitirla,
|
|
76
|
+
> `ozali` decide si está **al día**, **desactualizada** o **ausente**, y actúa en consecuencia.
|
|
77
|
+
> La **versión de contrato vigente** y las reglas de migración están en
|
|
78
|
+
> [`references/cdk-contract.md`](references/cdk-contract.md) — es la **fuente de verdad única**.
|
|
79
|
+
|
|
80
|
+
1. **Lee la versión de contrato vigente `N`** del marcador `CDK_CONTRACT_VERSION` en
|
|
81
|
+
[`references/cdk-contract.md`](references/cdk-contract.md).
|
|
82
|
+
2. **Busca el `cdk` instalado**: `.claude/skills/cdk/SKILL.md` (proyecto), luego
|
|
83
|
+
`~/.claude/skills/cdk/SKILL.md` (global). Si existe, lee `cdk_contract_version` de su frontmatter.
|
|
84
|
+
3. **Decide y registra** la decisión (se usa en las Fases 5 y 6):
|
|
85
|
+
|
|
86
|
+
| Estado del `cdk` instalado | Decisión |
|
|
87
|
+
|---|---|
|
|
88
|
+
| **No existe** | `GENERAR` — flujo normal: continúa el bootstrap hasta el GATE (Fase 5) y genera `cdk` en la Fase 6, estampando `cdk_contract_version: N`. |
|
|
89
|
+
| **Existe sin `cdk_contract_version`** (cdk legado) o con valor **`< N`** | `MIGRAR` — **migración automática** (sin GATE), ver abajo. |
|
|
90
|
+
| **Existe con `cdk_contract_version == N`** | `AL_DÍA` — no regenerar. Infórmalo y continúa el bootstrap solo para refrescar la calibración/documentación si el usuario lo pide. |
|
|
91
|
+
|
|
92
|
+
4. **Migración automática (`MIGRAR`)** — aplica los deltas del changelog de
|
|
93
|
+
[`references/cdk-contract.md`](references/cdk-contract.md) sobre el `cdk` instalado, **sin** pasar
|
|
94
|
+
por el GATE, porque preserva el `cdk` del usuario y solo actualiza el contrato:
|
|
95
|
+
- **Elimina toda referencia a `copsis-commit`** y reemplázala por **`ozali-commit`** (la skill de
|
|
96
|
+
commit vigente, instalada en `.claude/skills/ozali-commit/`).
|
|
97
|
+
- Aplica el resto de deltas del changelog (recall-first, telemetría, etc. según la versión).
|
|
98
|
+
- **Estampa** `cdk_contract_version: N` en el frontmatter del `cdk`.
|
|
99
|
+
- **Preserva** intactos `.ozali/docs/cdk/` (histórico por hito) y los planes congelados
|
|
100
|
+
(`02-plan-aprobado.md`).
|
|
101
|
+
- **Reporta** al usuario, en texto, qué cambió (referencias migradas, secciones actualizadas,
|
|
102
|
+
versión nueva).
|
|
103
|
+
- **Excepción → GATE:** si un delta exige **regeneración estructural** (reescribir subagentes,
|
|
104
|
+
cambiar el harness, rehacer el wiring de TDD), eso **no** es migración automática: preséntalo en
|
|
105
|
+
el plan del GATE (Fase 5) y regénéralo en la Fase 6.
|
|
106
|
+
|
|
107
|
+
> Sin `cdk` previo, esta fase no hace nada salvo registrar `GENERAR`. La calibración (Fase 3.5) y el
|
|
108
|
+
> resto del flujo continúan igual.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
72
112
|
## Fase 1 — Detección de la fuente de verdad
|
|
73
113
|
|
|
74
114
|
Busca en la raíz del repositorio, aceptando **ambas nomenclaturas**:
|
|
@@ -217,6 +257,9 @@ Solo tras la aprobación de la Fase 5. Genera:
|
|
|
217
257
|
- declarar en el frontmatter una **description con triggers ricos** (verbos y sustantivos
|
|
218
258
|
que el usuario usaría: "crea", "genera", "corrige", "refactoriza", método, clase,
|
|
219
259
|
endpoint, componente…) para mejorar la auto-invocación de la skill;
|
|
260
|
+
- **estampar en el frontmatter** `cdk_contract_version: N`, con `N` = la versión de contrato
|
|
261
|
+
vigente de [`references/cdk-contract.md`](references/cdk-contract.md). Esto permite que el
|
|
262
|
+
pre-flight (Fase 0.5) y `ozali doctor`/`ozali update` sepan si el `cdk` está al día;
|
|
220
263
|
- declarar que ayuda a **generar código** (nuevo componente, fix de bug, análisis de impacto)
|
|
221
264
|
respetando la fuente de verdad y los estándares del proyecto;
|
|
222
265
|
- orquestar los 8 subagentes según la fase del trabajo;
|
|
@@ -249,9 +292,11 @@ Solo tras la aprobación de la Fase 5. Genera:
|
|
|
249
292
|
resumen técnico, `state`) con naming determinista, según
|
|
250
293
|
[`references/engram-convention.md`](references/engram-convention.md), y al **iniciar** un
|
|
251
294
|
hito hacer `mem_search` del proyecto/hito para recuperar contexto previo;
|
|
252
|
-
- en el **cierre del hito**, invocar la skill **`ozali-commit`**
|
|
253
|
-
|
|
254
|
-
|
|
295
|
+
- en el **cierre del hito**, invocar la skill **`ozali-commit`** (instalada por el CLI en
|
|
296
|
+
`.claude/skills/ozali-commit/`; **nunca** `copsis-commit`, nombre heredado de versiones
|
|
297
|
+
anteriores) para generar el commit summary (feature→`feat`, bugfix→`fix`, hotfix→`hotfix`,
|
|
298
|
+
refactor→`refactor`; scope = módulo del hito). El GATE del mensaje es independiente del GATE
|
|
299
|
+
del plan.
|
|
255
300
|
2. `.claude/agents/<rol>.md` — un subagente real por cada uno de los 8 roles, con su system
|
|
256
301
|
prompt y herramientas, según [`references/agents-blueprint.md`](references/agents-blueprint.md).
|
|
257
302
|
3. `.claude/skills/cdk/verify-structure.mjs` — **harness del analista**: script Node sin
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<!-- CDK_CONTRACT_VERSION: 1 -->
|
|
2
|
+
|
|
3
|
+
# Contrato de la skill `cdk` — versión y migración
|
|
4
|
+
|
|
5
|
+
Esta es la **fuente de verdad única** de la versión del contrato con el que `ozali` genera (y
|
|
6
|
+
mantiene) la skill `cdk`. La lee el **agente** (en la Fase 0.5 y la Fase 6 de
|
|
7
|
+
[`../SKILL.md`](../SKILL.md)) y la parsea el **CLI** (`ozali doctor`/`ozali update`) del paquete.
|
|
8
|
+
Para subir el contrato: incrementa el número del marcador `CDK_CONTRACT_VERSION` de arriba y la
|
|
9
|
+
prosa de abajo, y agrega una entrada al changelog.
|
|
10
|
+
|
|
11
|
+
> **Versión de contrato vigente: `1`**
|
|
12
|
+
|
|
13
|
+
El número vive en **un solo lugar** (el marcador HTML de la primera línea, formato
|
|
14
|
+
`CDK_CONTRACT_VERSION: <entero>`). No lo dupliques en otros archivos.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Cómo se usa la versión
|
|
19
|
+
|
|
20
|
+
- El `cdk` generado **debe estampar** su versión de contrato en el frontmatter de su `SKILL.md`:
|
|
21
|
+
|
|
22
|
+
```yaml
|
|
23
|
+
---
|
|
24
|
+
name: cdk
|
|
25
|
+
description: <triggers ricos…>
|
|
26
|
+
cdk_contract_version: 1
|
|
27
|
+
---
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- En el **pre-flight** (Fase 0.5 de `ozali`), el agente compara la versión estampada en el `cdk`
|
|
31
|
+
instalado contra esta versión vigente **N**:
|
|
32
|
+
|
|
33
|
+
| Estado del `cdk` instalado | Acción |
|
|
34
|
+
|---|---|
|
|
35
|
+
| No existe | Generar `cdk` por el flujo normal (GATE Fase 5 → Fase 6), estampando `cdk_contract_version: N`. |
|
|
36
|
+
| Existe **sin** `cdk_contract_version`, o con un valor **< N** | **Desactualizado → migración automática** (sin GATE): aplica los deltas del changelog, estampa `N` y reporta los cambios. Si el delta exige **regeneración estructural** de subagentes, eso sí pasa por el GATE de la Fase 5. |
|
|
37
|
+
| Existe con `cdk_contract_version == N` | Al día → no regenerar; solo informarlo. |
|
|
38
|
+
|
|
39
|
+
> Un `cdk` **sin** el campo `cdk_contract_version` es un `cdk` **legado** (generado por una versión
|
|
40
|
+
> anterior de `ozali`). Trátalo como versión `0`: siempre desactualizado.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Regla de migración (todas las versiones)
|
|
45
|
+
|
|
46
|
+
Al migrar un `cdk` legado o desactualizado, **siempre**:
|
|
47
|
+
|
|
48
|
+
1. **Elimina toda referencia a `copsis-commit`** (nombre heredado de versiones anteriores) y
|
|
49
|
+
**reemplázala por `ozali-commit`** — la skill de commit vigente que `ozali init`/`ozali update`
|
|
50
|
+
instalan en `.claude/skills/ozali-commit/`.
|
|
51
|
+
2. **Preserva** el histórico por hito (`.ozali/docs/cdk/`) y los planes congelados
|
|
52
|
+
(`02-plan-aprobado.md`): la migración del contrato **nunca** los borra ni reescribe.
|
|
53
|
+
3. **Estampa** `cdk_contract_version: N` en el frontmatter del `cdk` migrado.
|
|
54
|
+
4. **Reporta** al usuario, en texto, qué cambió (referencias migradas, secciones actualizadas,
|
|
55
|
+
versión nueva).
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Changelog del contrato
|
|
60
|
+
|
|
61
|
+
### v1 — contrato base
|
|
62
|
+
Un `cdk` conforme a la v1 debe:
|
|
63
|
+
|
|
64
|
+
- Estampar `cdk_contract_version: 1` en su frontmatter.
|
|
65
|
+
- En el **cierre de hito**, invocar la skill **`ozali-commit`** (nunca `copsis-commit`) para
|
|
66
|
+
generar el commit summary convencional (feature→`feat`, bugfix→`fix`, hotfix→`hotfix`,
|
|
67
|
+
refactor→`refactor`; scope = módulo del hito).
|
|
68
|
+
- Operar **recall-first** (reusar memoria de Engram antes de releer/re-analizar) según
|
|
69
|
+
[`engram-convention.md`](engram-convention.md) §7.
|
|
70
|
+
- Espejar a Engram los artefactos clave del hito y escribir la telemetría de tokens
|
|
71
|
+
(`.ozali/metrics/token-metrics.json`, que lee `ozali doctor`).
|
|
72
|
+
- Respetar la calibración de Strict TDD (Fase 3.5) y el 🛑 GATE del plan.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ozali-commit
|
|
3
|
+
description: Genera un "commit summary" convencional (feat/fix/hotfix/refactor) con prefijo, scope y descripción a partir de los cambios EN STAGE y commitea tras tu aprobación. Úsala cuando el usuario quiera "commitea", "haz el commit", "genera el mensaje de commit", "cierra el hito con commit", o cuando otra skill (p. ej. cdk) cierre un hito. Sucesora de copsis-commit.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: ozali-commit
|
|
7
|
+
|
|
8
|
+
`ozali-commit` produce el **mensaje de commit** de un cambio siguiendo
|
|
9
|
+
[Conventional Commits](https://www.conventionalcommits.org/) y lo **commitea tras tu aprobación**.
|
|
10
|
+
Es la skill de commit vigente del ecosistema `ozali` (sucede a la antigua `copsis-commit`).
|
|
11
|
+
|
|
12
|
+
`cdk` la invoca en el **cierre de cada hito**, pero también puedes usarla suelta en cualquier repo.
|
|
13
|
+
|
|
14
|
+
> **Regla de oro:** nunca commitea sin tu aprobación explícita (🛑 **GATE de mensaje**). El GATE del
|
|
15
|
+
> mensaje es **independiente** del GATE del plan de `cdk`.
|
|
16
|
+
|
|
17
|
+
> **Cero dependencias:** usa `git` directo (ya habilitado en el perfil base de permisos de ozali:
|
|
18
|
+
> `Bash(git add *)`, `Bash(git commit *)`, `Bash(git status)`, `Bash(git diff *)`,
|
|
19
|
+
> `Bash(git log *)`). No requiere herramientas externas.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Flujo
|
|
24
|
+
|
|
25
|
+
### 1. Inspecciona el stage
|
|
26
|
+
- `git status --short` — qué hay staged vs sin stage.
|
|
27
|
+
- `git diff --cached` — el contenido **EN STAGE** (la fuente de verdad del mensaje).
|
|
28
|
+
- Si **no hay nada en stage**: dilo y pregunta si quieres que haga `git add` de archivos concretos
|
|
29
|
+
(o `git add -A`). **No** hagas `add -A` por tu cuenta sin confirmación.
|
|
30
|
+
- Lee el commit anterior con `git log -1 --pretty=%s` para mantener el estilo del repo.
|
|
31
|
+
|
|
32
|
+
### 2. Determina el tipo y el scope
|
|
33
|
+
A partir del diff EN STAGE, clasifica el cambio:
|
|
34
|
+
|
|
35
|
+
| Tipo | Cuándo |
|
|
36
|
+
|---|---|
|
|
37
|
+
| `feat` | nueva funcionalidad / capacidad |
|
|
38
|
+
| `fix` | corrección de bug |
|
|
39
|
+
| `hotfix` | corrección urgente en caliente |
|
|
40
|
+
| `refactor` | reestructura sin cambiar comportamiento |
|
|
41
|
+
| `docs` | solo documentación |
|
|
42
|
+
| `test` | solo pruebas |
|
|
43
|
+
| `chore` | mantenimiento (deps, config, build) |
|
|
44
|
+
|
|
45
|
+
- **Scope** = módulo/área tocada del repo (derívalo de las rutas en stage; ej. `cobranza`, `cli`,
|
|
46
|
+
`auth`). Si abarca varias áreas, usa la más representativa o un scope general.
|
|
47
|
+
- Si la skill que invoca aporta tipo/scope (p. ej. `cdk` mapea feature→`feat`, bugfix→`fix`,
|
|
48
|
+
hotfix→`hotfix`, refactor→`refactor`), **respétalos**.
|
|
49
|
+
|
|
50
|
+
### 3. Redacta el mensaje
|
|
51
|
+
Formato: `tipo(scope): descripción en imperativo, ≤ 72 chars`. Cuerpo opcional (qué/por qué, no el
|
|
52
|
+
cómo). No inventes cambios que no estén en el diff. Idioma: el del repo (mira `git log`).
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
feat(cobranza): agrega validación de RFC en alta de cotización
|
|
56
|
+
|
|
57
|
+
- valida formato y dígito verificador antes de persistir
|
|
58
|
+
- cubre el caso de RFC genérico (XAXX010101000)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 4. 🛑 GATE de mensaje
|
|
62
|
+
Presenta el mensaje completo **como texto visible** y espera aprobación. Si el usuario pide ajustes,
|
|
63
|
+
itera. **No commitees** hasta el "ok".
|
|
64
|
+
|
|
65
|
+
### 5. Commitea
|
|
66
|
+
Tras la aprobación:
|
|
67
|
+
```bash
|
|
68
|
+
git commit -m "tipo(scope): descripción" [-m "cuerpo…"]
|
|
69
|
+
```
|
|
70
|
+
- Commitea **solo lo que está en stage** (no añadas archivos no aprobados).
|
|
71
|
+
- **No** hagas `git push` (es destructivo/saliente y está denegado por defecto): si el usuario lo
|
|
72
|
+
quiere, recuérdaselo para que lo haga él.
|
|
73
|
+
- Reporta el hash corto resultante (`git rev-parse --short HEAD`).
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Notas
|
|
78
|
+
- Si el repo usa una convención propia (gitmoji, prefijos de ticket), detéctala desde `git log` y
|
|
79
|
+
síguela.
|
|
80
|
+
- Si el cambio es demasiado grande/heterogéneo para un solo mensaje coherente, **sugiere** dividir
|
|
81
|
+
en varios commits (pero no lo hagas sin aprobación).
|