@ingeniomaps/cauce 0.34.0 → 0.35.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/CHANGELOG.md +37 -0
- package/README.md +5 -1
- package/automatization/runners/antigravity/skills/onboard/SKILL.md +23 -3
- package/automatization/runners/codex/AGENTS.md +6 -0
- package/automatization/runners/gemini/GEMINI.md +6 -0
- package/engine/cli/args.js +1 -0
- package/engine/cli/ops.js +108 -2
- package/engine/planning/contracts.js +10 -0
- package/package.json +1 -1
- package/template/Makefile +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,43 @@ desde este repositorio no va, porque el que lee no puede actuar sobre eso. Cuand
|
|
|
14
14
|
unas pocas líneas casi siempre es porque cuenta cómo se descubrió el problema o por qué se eligió el
|
|
15
15
|
diseño — eso vive en el commit y en el código.
|
|
16
16
|
|
|
17
|
+
## [0.35.0] - 2026-08-19
|
|
18
|
+
|
|
19
|
+
### Añadido
|
|
20
|
+
|
|
21
|
+
- **`ops destroy <ops-root>`: sacar una instancia entera, en un comando.** Enumera qué se pierde
|
|
22
|
+
—épicas, cola, trabajo terminado con su evidencia, acciones humanas pendientes, el contexto escrito— y
|
|
23
|
+
para. Sólo un segundo intento con `--force` desinstala cada runner cableado y después borra la
|
|
24
|
+
instancia. El orden no es negociable: borrar la carpeta antes que el wiring deja al runner ejecutando
|
|
25
|
+
guards que ya no existen, que es exactamente lo que pasaba haciéndolo a mano. También como
|
|
26
|
+
`make destroy`, que muestra el resumen sin borrar.
|
|
27
|
+
|
|
28
|
+
### Corregido
|
|
29
|
+
|
|
30
|
+
- **Una épica que nadie va a leer deja de pasar por válida.** Una corrida real escribió
|
|
31
|
+
`roadmap/epic-001.md`, sin slug: el parser busca `epic-NNN-<slug>.md`, así que `check` respondía
|
|
32
|
+
«planning válido: 0 épica(s)» con la épica ahí, y `autobuild` nunca habría encontrado trabajo en ella.
|
|
33
|
+
Renombrarla destapó dos errores que el silencio tapaba —un `status` inválido y un criterio sin historia
|
|
34
|
+
que lo cubriera—. Ahora cualquier archivo del roadmap que se llame como una épica y el parser no vaya a
|
|
35
|
+
leer es un error que dice cómo nombrarlo.
|
|
36
|
+
|
|
37
|
+
- **`check` avisa cuando una dimensión del molde desapareció de `organization/`.** Un agente que reescribe
|
|
38
|
+
esos archivos se queda con el contenido y pierde la estructura: el resultado se lee entero y completo, y
|
|
39
|
+
la dimensión que falta no la va a reclamar nadie. Va como advertencia —esos archivos son de la empresa y
|
|
40
|
+
reestructurarlos a propósito es legítimo—, y agregar secciones propias no dice nada.
|
|
41
|
+
|
|
42
|
+
- **Volver a una versión anterior deja de anunciarse como una actualización.** `upgrade --check` decía
|
|
43
|
+
«hay una versión más nueva: 0.33.0» contra una instancia en 0.34.0. Ahora dice que volvés, y te imprime
|
|
44
|
+
las entradas que dejás de tener en vez de las que ganarías.
|
|
45
|
+
|
|
46
|
+
### Cambiado
|
|
47
|
+
|
|
48
|
+
- **Los runners sin recorrido ejecutable llevan una lista de salida.** Codex, Gemini y Antigravity operan
|
|
49
|
+
el arranque leyendo instrucciones, y una corrida real falló cinco puntos de una vez: preguntas en
|
|
50
|
+
formulario, una épica sin slug, `organization/` reestructurado, `HUMAN_ACTIONS.md` vacío y `ops` listado
|
|
51
|
+
como servicio del producto. Todos del mismo lado: lo que no deja un archivo visible. La lista dice qué
|
|
52
|
+
se comprueba mirando el disco, que es lo que la prosa pidiendo cuidado no consigue.
|
|
53
|
+
|
|
17
54
|
## [0.34.0] - 2026-08-19
|
|
18
55
|
|
|
19
56
|
### Añadido
|
package/README.md
CHANGED
|
@@ -177,6 +177,7 @@ Lee [template/planning/PROTOCOL.md](template/planning/PROTOCOL.md) para el contr
|
|
|
177
177
|
| `ops tree <planning>` | Muestra roadmap, backlog, WIP, inbox y done sin mutar nada. |
|
|
178
178
|
| `ops context <planning>` | Emite el contexto mínimo de la tarea vigente para un runner. |
|
|
179
179
|
| `ops upgrade <ops-root>` | Actualiza `system/` y el runtime sin tocar lo del proyecto. |
|
|
180
|
+
| `ops destroy <ops-root>` | Enumera qué se pierde y, con `--force`, saca wiring e instancia. |
|
|
180
181
|
| `ops archive <planning> <NNN>` | Archiva el DONE de una épica cerrada de forma idempotente. |
|
|
181
182
|
| `ops agents list [ops-root]` | Lista los cargos visibles resolviendo la precedencia. |
|
|
182
183
|
| `ops agents fork <cargo>` | Copia un cargo del catálogo a la empresa, que pasa a mantenerlo. |
|
|
@@ -301,7 +302,10 @@ La instalación fusiona la configuración propia del runner y conserva las entra
|
|
|
301
302
|
reemplaza los guards que el propio toolkit había registrado sueltos por el grupo que ahora los cubre, y
|
|
302
303
|
lista cuáles quitó. Nada que no haya escrito el toolkit se toca.
|
|
303
304
|
|
|
304
|
-
Para
|
|
305
|
+
Para sacar una instancia entera —wiring incluido— está `ops destroy`, que primero enumera qué se pierde
|
|
306
|
+
y sólo borra si se lo repite con `--force`: el orden importa, porque borrar la carpeta antes que el
|
|
307
|
+
wiring deja al runner ejecutando guards que ya no existen. Para sacar sólo el wiring y conservar la
|
|
308
|
+
instancia, `automation uninstall` quita exactamente lo que Cauce entregó y sigue igual que como lo
|
|
305
309
|
entregó: los guards de la configuración del runner, los workflows, los punteros a cargos. Lo que no
|
|
306
310
|
escribió —tus hooks, tus workflows, tus skills— queda donde está, y un archivo suyo que hayas editado se
|
|
307
311
|
conserva y se nombra en la salida. Borrar la carpeta ops sin esto deja al runner ejecutando guards que ya
|
|
@@ -38,7 +38,27 @@ El arranque tiene tres objetivos y ninguno más: entender qué es el proyecto, d
|
|
|
38
38
|
para él y que la primera tarea pueda empezar. El análisis profundo viene después, cuando la persona pida
|
|
39
39
|
algo concreto.
|
|
40
40
|
|
|
41
|
-
Cerrá escribiendo
|
|
41
|
+
Cerrá escribiendo la épica en `{{OPS_DIR}}planning/roadmap/`: su resultado es que una tarea pueda
|
|
42
42
|
atravesar el ciclo entero, y sus criterios salen de lo que hoy falta —contexto sin supuestos, cada
|
|
43
|
-
comando en verde, el guard de límites probado en las dos direcciones, una tarea piloto en DONE—.
|
|
44
|
-
|
|
43
|
+
comando en verde, el guard de límites probado en las dos direcciones, una tarea piloto en DONE—.
|
|
44
|
+
**Nunca promuevas al BACKLOG**: esa firma es humana.
|
|
45
|
+
|
|
46
|
+
## Antes de decir que terminaste
|
|
47
|
+
|
|
48
|
+
Esta lista no es un resumen de lo de arriba: es lo que se comprueba mirando el disco. Una corrida real
|
|
49
|
+
falló los cinco puntos sin darse cuenta, y todos del mismo lado —lo que no produce un archivo visible—.
|
|
50
|
+
|
|
51
|
+
1. **Una pregunta por vez.** Si mandaste dos o más juntas, numeradas, hiciste un formulario. La segunda
|
|
52
|
+
pregunta depende de la primera respuesta: por eso se hacen de a una.
|
|
53
|
+
2. **`epic-NNN-<slug>.md`**, con slug en el nombre y `status: open`. `epic-001.md` no lo lee nadie: ni
|
|
54
|
+
`check`, ni `tree`, ni el runner que busca trabajo. Existe y no existe a la vez.
|
|
55
|
+
3. **Las secciones de `{{OPS_DIR}}organization/` son las del molde.** Escribí adentro de ellas; agregá las tuyas
|
|
56
|
+
abajo si hacen falta. Reemplazar la estructura pierde dimensiones que nadie va a reclamar después,
|
|
57
|
+
porque el archivo se lee completo.
|
|
58
|
+
4. **`HUMAN_ACTIONS.md` tiene filas.** Una por credencial nombrada en el inventario, una por sistema
|
|
59
|
+
externo o MCP, una por la autoridad de push. Si quedó vacío, no es que no hubiera nada: es que lo que
|
|
60
|
+
no te corresponde se perdió en vez de quedar escrito para alguien.
|
|
61
|
+
5. **`ops` no es un servicio del producto.** No va en el mapa real: es la instancia desde la que trabajás.
|
|
62
|
+
|
|
63
|
+
Recién ahí, `node {{OPS_DIR}}tools/ops.js check planning`. Si sale con advertencias, leelas: son
|
|
64
|
+
exactamente estas cosas.
|
|
@@ -53,6 +53,12 @@ El arranque tiene tres objetivos y ninguno más: entender qué es el proyecto, d
|
|
|
53
53
|
para él y que la primera tarea pueda empezar. El análisis profundo viene después, cuando la persona pida
|
|
54
54
|
algo concreto.
|
|
55
55
|
|
|
56
|
+
Antes de darlo por terminado, comprobá cinco cosas mirando el disco: preguntaste de a una y no en
|
|
57
|
+
formulario; la épica se llama `epic-NNN-<slug>.md` con `status: open` —`epic-001.md` no lo lee nadie—;
|
|
58
|
+
las secciones de `{{OPS_DIR}}organization/` siguen siendo las del molde y lo tuyo se agregó adentro;
|
|
59
|
+
`{{OPS_DIR}}planning/HUMAN_ACTIONS.md` tiene una fila por credencial, por externo y por la autoridad de
|
|
60
|
+
push; y `ops` no figura como servicio del producto en el mapa.
|
|
61
|
+
|
|
56
62
|
## Los equipos
|
|
57
63
|
|
|
58
64
|
Un equipo es una secuencia de cargos con etapas y exit gates, para evaluar una intención antes de que
|
|
@@ -46,6 +46,12 @@ El arranque tiene tres objetivos y ninguno más: entender qué es el proyecto, d
|
|
|
46
46
|
para él y que la primera tarea pueda empezar. El análisis profundo viene después, cuando la persona pida
|
|
47
47
|
algo concreto.
|
|
48
48
|
|
|
49
|
+
Antes de darlo por terminado, comprobá cinco cosas mirando el disco: preguntaste de a una y no en
|
|
50
|
+
formulario; la épica se llama `epic-NNN-<slug>.md` con `status: open` —`epic-001.md` no lo lee nadie—;
|
|
51
|
+
las secciones de `{{OPS_DIR}}organization/` siguen siendo las del molde y lo tuyo se agregó adentro;
|
|
52
|
+
`{{OPS_DIR}}planning/HUMAN_ACTIONS.md` tiene una fila por credencial, por externo y por la autoridad de
|
|
53
|
+
push; y `ops` no figura como servicio del producto en el mapa.
|
|
54
|
+
|
|
49
55
|
Nunca omitas aprobaciones, inventes credenciales, escribas remoto, hagas push/deploy o promociones
|
|
50
56
|
trabajo desde INBOX.
|
|
51
57
|
|
package/engine/cli/args.js
CHANGED
package/engine/cli/ops.js
CHANGED
|
@@ -47,6 +47,7 @@ function usage() {
|
|
|
47
47
|
ops tree <planning-dir> [--no-color] [--json]
|
|
48
48
|
ops context <planning-dir> [--json]
|
|
49
49
|
ops upgrade <ops-root> [--check] [--force]
|
|
50
|
+
ops destroy <ops-root> [--force]
|
|
50
51
|
ops archive <planning-dir> <NNN>
|
|
51
52
|
ops integration list <ops-root>
|
|
52
53
|
ops integration enable <ops-root> <provider>
|
|
@@ -440,6 +441,30 @@ function onboard(rootArg, cli, runner = '') {
|
|
|
440
441
|
console.log(' Con tus respuestas escribe organization/, el mapa real de AGENTS.md y la primera épica.')
|
|
441
442
|
}
|
|
442
443
|
|
|
444
|
+
// Qué dimensiones enumera el molde de `organization/` y cuáles dejaron de estar. Un agente que reescribe
|
|
445
|
+
// esos archivos tiende a quedarse con el contenido y perder la estructura: el resultado se lee entero y
|
|
446
|
+
// completo, y nadie va a pedir después la dimensión que falta porque nada indica que faltaba.
|
|
447
|
+
//
|
|
448
|
+
// Va como advertencia y no como error: la empresa es dueña de esos archivos y puede reestructurarlos a
|
|
449
|
+
// propósito. Lo que no puede pasar es que una dimensión desaparezca sin que se vea.
|
|
450
|
+
function seccionesPerdidas(root) {
|
|
451
|
+
const avisos = []
|
|
452
|
+
const molde = path.join(PROJECT_ROOT, 'template', 'organization')
|
|
453
|
+
for (const name of ['company.md', 'product.md']) {
|
|
454
|
+
const propio = path.join(root, 'organization', name)
|
|
455
|
+
if (!fs.existsSync(propio) || !fs.existsSync(path.join(molde, name))) continue
|
|
456
|
+
const titulos = (text) => new Set((text.match(/^##\s+(.+)$/gm) || []).map((line) => line.trim()))
|
|
457
|
+
const esperadas = titulos(fs.readFileSync(path.join(molde, name), 'utf8'))
|
|
458
|
+
const presentes = titulos(fs.readFileSync(propio, 'utf8'))
|
|
459
|
+
const faltan = [...esperadas].filter((titulo) => !presentes.has(titulo))
|
|
460
|
+
if (!faltan.length) continue
|
|
461
|
+
// Reescrito entero, faltan todas: enumerarlas hace una línea ilegible y el número dice más.
|
|
462
|
+
const lista = faltan.length > 3 ? `${faltan.slice(0, 3).join(', ')} y ${faltan.length - 3} más` : faltan.join(', ')
|
|
463
|
+
avisos.push(`organization/${name}: sin ${lista} — el molde las trae y acá no están`)
|
|
464
|
+
}
|
|
465
|
+
return avisos
|
|
466
|
+
}
|
|
467
|
+
|
|
443
468
|
function check(dir, cli) {
|
|
444
469
|
const root = path.resolve(dir || '.')
|
|
445
470
|
const errors = []
|
|
@@ -552,6 +577,8 @@ function check(dir, cli) {
|
|
|
552
577
|
const FK = require('../agents/fork')
|
|
553
578
|
for (const entry of FK.drift(path.resolve(root, '..'))) warnings.push(FK.driftLine(entry))
|
|
554
579
|
|
|
580
|
+
warnings.push(...seccionesPerdidas(path.resolve(root, '..')))
|
|
581
|
+
|
|
555
582
|
if (cli.has('--json')) {
|
|
556
583
|
console.log(JSON.stringify({
|
|
557
584
|
ok: !errors.length,
|
|
@@ -732,6 +759,76 @@ function instanceVersion(root) {
|
|
|
732
759
|
} catch { return '' }
|
|
733
760
|
}
|
|
734
761
|
|
|
762
|
+
// Qué se pierde al borrar una instancia. Se cuenta antes de tocar nada porque es lo único que vuelve
|
|
763
|
+
// reversible la decisión: quien lee esto todavía puede no seguir.
|
|
764
|
+
// Lo cuenta el mismo parser que usan `check` y `tree`, no una expresión regular propia: los moldes traen
|
|
765
|
+
// ejemplos comentados, y contarlos a mano anunciaba una tarea en cola y otra terminada en una instancia
|
|
766
|
+
// recién creada. Un aviso que exagera lo que se pierde se deja de leer igual que uno que lo minimiza.
|
|
767
|
+
function loQueSePierde(root) {
|
|
768
|
+
const planning = path.join(root, 'planning')
|
|
769
|
+
const cola = P.readBacklog(planning).reduce((total, hito) => total + (hito.tasks || []).length, 0)
|
|
770
|
+
const acciones = (() => {
|
|
771
|
+
try {
|
|
772
|
+
const texto = fs.readFileSync(path.join(planning, 'HUMAN_ACTIONS.md'), 'utf8')
|
|
773
|
+
return (texto.match(/^\| (?!Tarea|---)/gm) || []).length
|
|
774
|
+
} catch { return 0 }
|
|
775
|
+
})()
|
|
776
|
+
return {
|
|
777
|
+
epicas: P.readEpics(planning).length,
|
|
778
|
+
hechas: (P.readDone(planning).entries || []).length,
|
|
779
|
+
enCola: cola,
|
|
780
|
+
acciones,
|
|
781
|
+
contexto: !OB.guide(root).fresh,
|
|
782
|
+
runners: [...new Set(Object.keys(M.readRunners(root)).map((key) => key.split('/')[0]))],
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// Saca la instancia entera y el wiring que dejó en cada runner. Existe porque la alternativa era una
|
|
787
|
+
// lista de pasos a mano —desinstalar cada runner y después `rm -rf`—, y una lista se ejecuta a medias:
|
|
788
|
+
// el orden importa, y borrar primero la carpeta deja al runner ejecutando guards que ya no existen.
|
|
789
|
+
//
|
|
790
|
+
// Nunca borra sin que alguien lo haya pedido dos veces. Lo que hay adentro —planning, organization, la
|
|
791
|
+
// evidencia de lo hecho— es del proyecto y no lo repone ningún `init`.
|
|
792
|
+
function destroy(dir, cli) {
|
|
793
|
+
const root = path.resolve(dir || '.')
|
|
794
|
+
if (!fs.existsSync(path.join(root, 'ops.config.json'))) {
|
|
795
|
+
fail(`${root} no es una instancia de Cauce: falta ops.config.json.`, 2)
|
|
796
|
+
}
|
|
797
|
+
if (O.mode(root) === 'toolkit') fail(`${root} es el toolkit: acá se fabrica Cauce, no se lo borra.`, 2)
|
|
798
|
+
|
|
799
|
+
const perdida = loQueSePierde(root)
|
|
800
|
+
const lineas = [
|
|
801
|
+
perdida.epicas && `${perdida.epicas} épica(s) en el roadmap`,
|
|
802
|
+
perdida.enCola && `${perdida.enCola} tarea(s) en la cola`,
|
|
803
|
+
perdida.hechas && `${perdida.hechas} tarea(s) terminada(s) con su evidencia`,
|
|
804
|
+
perdida.acciones && `${perdida.acciones} acción(es) humana(s) pendiente(s)`,
|
|
805
|
+
perdida.contexto && 'el contexto escrito en organization/',
|
|
806
|
+
].filter(Boolean)
|
|
807
|
+
|
|
808
|
+
if (!cli.has('--force')) {
|
|
809
|
+
console.log(`Borrar ${root} se lleva:`)
|
|
810
|
+
for (const linea of lineas) console.log(` − ${linea}`)
|
|
811
|
+
if (!lineas.length) console.log(' − nada escrito todavía: la instancia está como salió de init')
|
|
812
|
+
if (perdida.runners.length) {
|
|
813
|
+
console.log(` y saca el wiring de: ${perdida.runners.join(', ')} (lo tuyo queda donde está)`)
|
|
814
|
+
}
|
|
815
|
+
console.log('\nNada de esto lo repone un init. Si es lo que querés: repetí con --force.')
|
|
816
|
+
process.exit(1)
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
for (const runner of perdida.runners) {
|
|
820
|
+
try { A.uninstall(root, runner, console) } catch (error) { console.error(` ${runner}: ${error.message}`) }
|
|
821
|
+
}
|
|
822
|
+
// El orden no es negociable: primero el wiring, después la carpeta. Al revés, cada llamada de
|
|
823
|
+
// herramienta del runner queda ejecutando un guard que ya no está.
|
|
824
|
+
const adentro = process.cwd() === root || process.cwd().startsWith(`${root}${path.sep}`)
|
|
825
|
+
fs.rmSync(root, { recursive: true, force: true })
|
|
826
|
+
console.log(`✓ ${root} borrado`)
|
|
827
|
+
// Correrlo desde adentro es lo natural —ahí está `tools/ops.js`— y deja la terminal en un directorio
|
|
828
|
+
// que ya no existe: el próximo comando falla con un `getcwd` que no dice nada de esto.
|
|
829
|
+
if (adentro) console.log(' tu terminal quedó en esa carpeta: hacé "cd .." antes del próximo comando.')
|
|
830
|
+
}
|
|
831
|
+
|
|
735
832
|
// Actualiza sólo lo que el toolkit declara suyo. Todo lo demás —planning, organization, reglas
|
|
736
833
|
// propias, agentes editados— queda intacto por construcción, no por comparación.
|
|
737
834
|
function upgrade(dir, cli) {
|
|
@@ -760,8 +857,16 @@ function upgrade(dir, cli) {
|
|
|
760
857
|
console.log(`= ${to}: la instancia está al día con el motor instalado`)
|
|
761
858
|
return console.log(' para traer una versión más nueva: npm install --save-dev @ingeniomaps/cauce@latest')
|
|
762
859
|
}
|
|
763
|
-
|
|
764
|
-
|
|
860
|
+
// Hacia atrás también es legítimo —una versión rompió algo y se vuelve—, pero anunciarlo como «hay
|
|
861
|
+
// una versión más nueva» era mentir con el número a la vista. Y lo que corresponde imprimir es lo
|
|
862
|
+
// contrario: no lo que se gana, sino lo que se deja.
|
|
863
|
+
if (CL.compare(to, from) < 0) {
|
|
864
|
+
console.log(`↩ volvés a ${to} desde ${from}. Esto es lo que dejás de tener:`)
|
|
865
|
+
printChangelog(to, from)
|
|
866
|
+
} else {
|
|
867
|
+
console.log(`⚠ hay una versión más nueva: ${to} (la instancia tiene ${from || 'una previa'})`)
|
|
868
|
+
printChangelog(from, to)
|
|
869
|
+
}
|
|
765
870
|
for (const file of changed) console.log(` editado localmente: ${file}`)
|
|
766
871
|
process.exit(1)
|
|
767
872
|
}
|
|
@@ -1263,6 +1368,7 @@ async function run(cli) {
|
|
|
1263
1368
|
else if (command === 'tree') tree(arg[1], cli)
|
|
1264
1369
|
else if (command === 'context') context(arg[1], cli)
|
|
1265
1370
|
else if (command === 'upgrade') upgrade(arg[1], cli)
|
|
1371
|
+
else if (command === 'destroy') destroy(arg[1], cli)
|
|
1266
1372
|
else if (command === 'agents') agents(arg[1], arg[2], arg[3], cli)
|
|
1267
1373
|
else if (command === 'archive') archive(arg[1], arg[2])
|
|
1268
1374
|
else if (command === 'integration') {
|
|
@@ -64,6 +64,16 @@ function validateRoadmapStructure(dir) {
|
|
|
64
64
|
try { entries = fs.readdirSync(roadmap, { withFileTypes: true }) } catch { return ['falta roadmap/'] }
|
|
65
65
|
const errors = []
|
|
66
66
|
for (const entry of entries) {
|
|
67
|
+
// Un archivo que se llama como una épica y no cumple el patrón no lo lee nadie: ni `check`, ni
|
|
68
|
+
// `tree`, ni el runner que busca trabajo. Ignorarlo en silencio es peor que rechazarlo, porque el
|
|
69
|
+
// planning se reporta válido mientras la épica que alguien escribió no existe para el sistema.
|
|
70
|
+
if (/^epic-/.test(entry.name) && !/^epic-\d{3}-/.test(entry.name)) {
|
|
71
|
+
errors.push(
|
|
72
|
+
`roadmap/${entry.name}: nadie lo lee. Una épica se nombra epic-NNN-<slug>.md, `
|
|
73
|
+
+ 'o un directorio epic-NNN-<slug>/ con spec.md adentro.',
|
|
74
|
+
)
|
|
75
|
+
continue
|
|
76
|
+
}
|
|
67
77
|
if (!entry.isDirectory() || !/^epic-\d{3}-/.test(entry.name)) continue
|
|
68
78
|
const epicDir = path.join(roadmap, entry.name)
|
|
69
79
|
if (!fs.existsSync(path.join(epicDir, 'spec.md'))) {
|
package/package.json
CHANGED
package/template/Makefile
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
.DEFAULT_GOAL := help
|
|
2
2
|
|
|
3
|
-
.PHONY: help check tree context upgrade automation-check
|
|
3
|
+
.PHONY: help check tree context upgrade destroy automation-check
|
|
4
4
|
.PHONY: integration-check integration-sync require-key integration-promote
|
|
5
5
|
.PHONY: require-agent agent-learn agent-propose agent-evaluate require-team team-check team-show
|
|
6
6
|
.PHONY: install-claude install-codex install-gemini install-antigravity
|
|
@@ -25,6 +25,9 @@ context: ## Muestra el contexto mínimo de la tarea vigente
|
|
|
25
25
|
|
|
26
26
|
# `init` fija la versión exacta del motor, así que `npm update` no la mueve: hay que pedir @latest.
|
|
27
27
|
# Sin este primer paso `upgrade` compara contra el motor instalado y contesta «al día» para siempre.
|
|
28
|
+
destroy: ## Muestra qué se pierde al borrar esta instancia (borrar exige --force a mano)
|
|
29
|
+
@node tools/ops.js destroy .
|
|
30
|
+
|
|
28
31
|
upgrade: ## Trae la última versión de Cauce y la aplica, sin tocar lo del proyecto
|
|
29
32
|
@npm install --save-dev @ingeniomaps/cauce@latest
|
|
30
33
|
@node tools/ops.js upgrade .
|