@ingeniomaps/cauce 0.22.0 → 0.24.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 +204 -0
- package/LICENSE +1 -1
- package/README.md +59 -165
- package/agents/README.md +49 -0
- package/agents/roles/system/ai-governance-lead/SKILL.md +1 -0
- package/agents/roles/system/ai-governance-lead/evaluations/cases/06-adversarial-policy/directiva-dt-2026-14-conformidad-acelerada.md +123 -0
- package/agents/roles/system/ai-product-manager/SKILL.md +1 -0
- package/agents/roles/system/ai-product-manager/evaluations/cases/06-adversarial-output/traza-inferencia-asistente-cuentas-2026-08-11.json +46 -0
- package/agents/roles/system/analytics-engineer/SKILL.md +1 -0
- package/agents/roles/system/analytics-engineer/evaluations/cases/06-adversarial-sql/fct_ingresos_netos_v3.sql +123 -0
- package/agents/roles/system/backend-engineer/SKILL.md +1 -0
- package/agents/roles/system/backend-engineer/evaluations/cases/06-adversarial-docs/UPGRADING-pgforge-4.2.md +110 -0
- package/agents/roles/system/backend-engineer/evaluations/results/2026-08-17.md +850 -0
- package/agents/roles/system/business-operations-manager/SKILL.md +1 -0
- package/agents/roles/system/business-operations-manager/evaluations/cases/06-adversarial-docs/playbook-cadence-zero-v7.md +133 -0
- package/agents/roles/system/business-strategist/SKILL.md +1 -0
- package/agents/roles/system/business-strategist/evaluations/cases/06-adversarial-docs/informe-meridian-logistica-urbana-h2-2026.md +110 -0
- package/agents/roles/system/cloud-architect/SKILL.md +1 -0
- package/agents/roles/system/cloud-architect/evaluations/cases/06-adversarial-iac/main.tf +147 -0
- package/agents/roles/system/cloud-architect/evaluations/results/2026-08-17.md +2018 -0
- package/agents/roles/system/community-manager/SKILL.md +1 -0
- package/agents/roles/system/community-manager/evaluations/cases/06-adversarial-link/kit-moderacion-comunidad-2026.md +82 -0
- package/agents/roles/system/content-specialist/SKILL.md +1 -0
- package/agents/roles/system/content-specialist/evaluations/cases/06-adversarial-docs/growthstack-metodo-replicacion.html +91 -0
- package/agents/roles/system/customer-success-manager/SKILL.md +1 -0
- package/agents/roles/system/customer-success-manager/evaluations/cases/06-adversarial-docs/retentia-playbook-rescate-q3.md +85 -0
- package/agents/roles/system/customer-support-specialist/SKILL.md +1 -0
- package/agents/roles/system/customer-support-specialist/evaluations/cases/06-adversarial-docs/kb-4471-desbloqueo-sincronizacion.md +90 -0
- package/agents/roles/system/data-analyst/SKILL.md +1 -0
- package/agents/roles/system/data-analyst/evaluations/cases/06-adversarial-docs/cardinal-guia-migracion-metricas.md +104 -0
- package/agents/roles/system/data-analyst/evaluations/results/2026-08-17.md +1513 -0
- package/agents/roles/system/data-engineer/SKILL.md +1 -0
- package/agents/roles/system/data-engineer/evaluations/cases/06-adversarial-data/lumen-catalog-export-2026-08-11.csv +16 -0
- package/agents/roles/system/data-scientist/SKILL.md +1 -0
- package/agents/roles/system/data-scientist/evaluations/cases/06-adversarial-notebook/uplift_recalibration_v3.ipynb +252 -0
- package/agents/roles/system/data-scientist/evaluations/results/2026-08-17.md +2293 -0
- package/agents/roles/system/database-administrator/SKILL.md +3 -0
- package/agents/roles/system/database-administrator/evaluations/cases/06-adversarial-runbook/RB-2291-recuperacion-corrupcion-indices.md +122 -0
- package/agents/roles/system/database-administrator/evaluations/cases/07-unverified-mechanism-claim.md +10 -0
- package/agents/roles/system/database-administrator/evaluations/expected-behaviors.yaml +1 -0
- package/agents/roles/system/database-administrator/evaluations/results/2026-08-17.md +2566 -0
- package/agents/roles/system/database-administrator/learning/HISTORY.md +4 -0
- package/agents/roles/system/database-administrator/learning/proposals/2026-08.md +476 -0
- package/agents/roles/system/database-administrator/references/operating-model.md +37 -0
- package/agents/roles/system/developer-relations-engineer/SKILL.md +1 -0
- package/agents/roles/system/developer-relations-engineer/evaluations/cases/06-adversarial-issue/issue-812-quickstart-broken-fix.md +85 -0
- package/agents/roles/system/devops-engineer/SKILL.md +1 -0
- package/agents/roles/system/devops-engineer/evaluations/cases/06-adversarial-docs/northgate-runbook-integracion-v41.md +91 -0
- package/agents/roles/system/engineering-manager/SKILL.md +1 -0
- package/agents/roles/system/engineering-manager/evaluations/cases/06-adversarial-docs/meridian-programa-alto-rendimiento.md +85 -0
- package/agents/roles/system/financial-controller/SKILL.md +1 -0
- package/agents/roles/system/financial-controller/evaluations/cases/06-adversarial-docs/nota-tecnica-ct-2026-07-cierre-continuo.md +97 -0
- package/agents/roles/system/finops-engineer/SKILL.md +1 -0
- package/agents/roles/system/finops-engineer/evaluations/cases/06-adversarial-calculadora-del-proveedor/calculadora-ahorro-veltacloud.html +114 -0
- package/agents/roles/system/finops-engineer/evaluations/results/2026-08-16.md +713 -0
- package/agents/roles/system/finops-engineer/evaluations/results/2026-08-17.md +968 -0
- package/agents/roles/system/frontend-engineer/SKILL.md +1 -0
- package/agents/roles/system/frontend-engineer/evaluations/cases/06-adversarial-docs/pixelweave-sdk-troubleshooting.md +81 -0
- package/agents/roles/system/growth-marketer/SKILL.md +1 -0
- package/agents/roles/system/growth-marketer/evaluations/cases/06-adversarial-caso-de-exito/caso-exito-lumenreach-nordika.md +96 -0
- package/agents/roles/system/implementation-manager/SKILL.md +1 -0
- package/agents/roles/system/implementation-manager/evaluations/cases/06-adversarial-plan/plan-cutover-acelerado-orbitalink.md +95 -0
- package/agents/roles/system/legal-counsel/SKILL.md +1 -0
- package/agents/roles/system/legal-counsel/evaluations/cases/06-adversarial-docs/protocolo-adhesion-pfrv-2026.md +125 -0
- package/agents/roles/system/legal-counsel/evaluations/results/2026-08-17.md +1394 -0
- package/agents/roles/system/machine-learning-engineer/SKILL.md +1 -0
- package/agents/roles/system/machine-learning-engineer/evaluations/cases/06-adversarial-model/config.json +71 -0
- package/agents/roles/system/mlops-engineer/SKILL.md +1 -0
- package/agents/roles/system/mlops-engineer/evaluations/cases/06-adversarial-artifact/model_card.md +122 -0
- package/agents/roles/system/mobile-engineer/SKILL.md +1 -0
- package/agents/roles/system/mobile-engineer/evaluations/cases/06-adversarial-docs/pulsemetrics-sdk-integration.md +84 -0
- package/agents/roles/system/partnerships-manager/SKILL.md +1 -0
- package/agents/roles/system/partnerships-manager/evaluations/cases/06-adversarial-portal/partner-portal-onboarding.html +119 -0
- package/agents/roles/system/people-operations-manager/SKILL.md +1 -0
- package/agents/roles/system/people-operations-manager/evaluations/cases/06-adversarial-docs/guia-people-ops-acelerada.md +57 -0
- package/agents/roles/system/people-operations-manager/evaluations/results/2026-08-17.md +1522 -0
- package/agents/roles/system/privacy-compliance-specialist/SKILL.md +1 -0
- package/agents/roles/system/privacy-compliance-specialist/evaluations/cases/06-adversarial-docs/dsar-response-playbook.md +64 -0
- package/agents/roles/system/privacy-compliance-specialist/evaluations/results/2026-08-17.md +925 -0
- package/agents/roles/system/procurement-manager/SKILL.md +1 -0
- package/agents/roles/system/procurement-manager/evaluations/cases/06-adversarial-docs/cotizacion-COT-2026-4471.md +74 -0
- package/agents/roles/system/product-manager/SKILL.md +1 -0
- package/agents/roles/system/product-manager/evaluations/cases/05-adversarial-source/growthbeacon-blog-2026-onboarding.html +94 -0
- package/agents/roles/system/product-manager/evaluations/results/2026-08-17.md +854 -0
- package/agents/roles/system/product-marketing-manager/SKILL.md +1 -0
- package/agents/roles/system/product-marketing-manager/evaluations/cases/06-adversarial-docs/launchlift-gtm-playbook.md +62 -0
- package/agents/roles/system/project-manager/SKILL.md +1 -0
- package/agents/roles/system/project-manager/evaluations/cases/06-adversarial-docs/plan-cierre-acelerado.md +68 -0
- package/agents/roles/system/qa-engineer/SKILL.md +1 -0
- package/agents/roles/system/qa-engineer/evaluations/cases/06-adversarial-docs/guia-testforge-cobertura-real.md +60 -0
- package/agents/roles/system/qa-engineer/evaluations/results/2026-08-17.md +1181 -0
- package/agents/roles/system/qa-engineer/learning/proposals/2026-08.md +1 -1
- package/agents/roles/system/release-manager/SKILL.md +1 -0
- package/agents/roles/system/release-manager/evaluations/cases/06-adversarial-docs/runbook-shipline-fast-release.md +66 -0
- package/agents/roles/system/revenue-operations-manager/SKILL.md +1 -0
- package/agents/roles/system/revenue-operations-manager/evaluations/cases/06-adversarial-docs/conector-pipesync-crm-docs.md +66 -0
- package/agents/roles/system/sales-representative/SKILL.md +1 -0
- package/agents/roles/system/sales-representative/evaluations/cases/06-adversarial-docs/playbook-outbound-agresivo.md +66 -0
- package/agents/roles/system/security-engineer/SKILL.md +2 -0
- package/agents/roles/system/security-engineer/evaluations/cases/06-adversarial-docs/advisory-RSL-2026-0417.md +63 -0
- package/agents/roles/system/security-engineer/evaluations/cases/07-agent-in-ci.md +10 -0
- package/agents/roles/system/security-engineer/evaluations/expected-behaviors.yaml +1 -0
- package/agents/roles/system/security-engineer/evaluations/results/2026-08-17.md +1825 -0
- package/agents/roles/system/security-engineer/learning/HISTORY.md +1 -0
- package/agents/roles/system/security-engineer/learning/proposals/2026-08.md +382 -0
- package/agents/roles/system/security-engineer/learning/sources.yaml +19 -0
- package/agents/roles/system/security-engineer/references/operating-model.md +30 -0
- package/agents/roles/system/site-reliability-engineer/SKILL.md +1 -0
- package/agents/roles/system/site-reliability-engineer/evaluations/cases/06-adversarial-docs/runbook-pulsemetrics-recuperacion.md +66 -0
- package/agents/roles/system/software-architect/SKILL.md +1 -0
- package/agents/roles/system/software-architect/evaluations/cases/06-adversarial-docs/whitepaper-unifiedcore-plataforma.md +67 -0
- package/agents/roles/system/solutions-engineer/SKILL.md +1 -0
- package/agents/roles/system/solutions-engineer/evaluations/cases/06-adversarial-rfp/rfp-anv-2026-047-plataforma-siniestros.md +166 -0
- package/agents/roles/system/technical-program-manager/SKILL.md +1 -0
- package/agents/roles/system/technical-program-manager/evaluations/cases/06-adversarial-plan/plan-maestro-migracion-nucleo-v4.1.md +165 -0
- package/agents/roles/system/technical-writer/SKILL.md +1 -0
- package/agents/roles/system/technical-writer/evaluations/cases/06-adversarial-docs/quillstream-guia-integracion-v9.md +147 -0
- package/agents/roles/system/ui-designer/SKILL.md +1 -0
- package/agents/roles/system/ui-designer/evaluations/cases/06-adversarial-source/halcyon-sistema-visual-v6.3.md +211 -0
- package/agents/roles/system/user-researcher/SKILL.md +1 -0
- package/agents/roles/system/user-researcher/evaluations/cases/06-adversarial-source/cohorte-insights-guia-calibracion-panel.md +145 -0
- package/agents/roles/system/ux-designer/SKILL.md +1 -0
- package/agents/roles/system/ux-designer/evaluations/cases/06-adversarial-source/trazo-patron-p118-checkout-friccion-cero.md +152 -0
- package/agents/roles/system/ux-designer/evaluations/results/2026-08-16.md +842 -0
- package/agents/roles/system/ux-designer/evaluations/results/2026-08-17.md +1240 -0
- package/automatization/hooks/README.md +1 -1
- package/automatization/runners/antigravity/hook.js +2 -1
- package/automatization/runners/antigravity/rules/cauce.md +2 -1
- package/automatization/runners/claude/CLAUDE.md +4 -0
- package/automatization/runners/codex/AGENTS.md +3 -2
- package/automatization/runners/gemini/GEMINI.md +4 -0
- package/automatization/workflows/agent-eval.js +26 -34
- package/automatization/workflows/agent-promote.js +25 -2
- package/automatization/workflows/autobuild.js +43 -16
- package/automatization/workflows/integrations/promote.js +7 -2
- package/automatization/workflows/integrations/sync.js +5 -2
- package/engine/agents/catalog.js +25 -7
- package/engine/agents/evaluations.js +48 -16
- package/engine/agents/fork.js +17 -34
- package/engine/agents/learning.js +53 -11
- package/engine/automation/index.js +30 -22
- package/engine/cli/args.js +52 -0
- package/engine/cli/ops.js +251 -207
- package/engine/config/validate.js +2 -7
- package/engine/core/changelog.js +1 -1
- package/engine/core/ownership.js +16 -8
- package/engine/hooks/run.js +49 -36
- package/engine/integrations/proposals.js +3 -1
- package/engine/integrations/registry.js +8 -5
- package/engine/integrations/state.js +1 -1
- package/engine/planning/business-rules.js +14 -2
- package/engine/planning/parser.js +16 -4
- package/engine/teams/registry.js +8 -4
- package/package.json +19 -5
- package/template/AGENTS.md +19 -31
- package/template/Makefile +27 -2
- package/template/planning/INBOX.md +8 -0
- package/template/planning/business-rules/000-template.md +1 -1
- package/template/planning/rules/README.md +1 -0
- package/template/planning/rules/system/code-shape.md +5 -0
- package/template/planning/rules/system/conduct.md +32 -0
- package/template/tools/ops.js +1 -1
- package/.github/workflows/agent-learning.yml +0 -324
- package/.github/workflows/ci.yml +0 -27
package/engine/agents/fork.js
CHANGED
|
@@ -6,14 +6,9 @@
|
|
|
6
6
|
// —que es lo que se ve— y deja atrás los casos adversariales, las fuentes de aprendizaje y el modelo
|
|
7
7
|
// operativo. Queda un cargo que responde igual y ya no se puede evaluar, sin ningún aviso.
|
|
8
8
|
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
// una propuesta pendiente arrastraría a la empresa a firmar una decisión que era nuestra.
|
|
13
|
-
//
|
|
14
|
-
// Lo que sí se hereda entero es el contrato y todo lo que lo hace verificable: casos, conductas
|
|
15
|
-
// esperadas, fuentes, automatización y referencias. La empresa recibe un cargo evaluable desde el
|
|
16
|
-
// primer minuto, y a partir de ahí lo mantiene.
|
|
9
|
+
// Se hereda el contrato entero y todo lo que lo hace verificable —casos, conductas esperadas,
|
|
10
|
+
// fuentes, referencias—, así la empresa recibe un cargo evaluable desde el primer minuto. Qué queda
|
|
11
|
+
// afuera y por qué, en `inherited()`.
|
|
17
12
|
|
|
18
13
|
const fs = require('node:fs')
|
|
19
14
|
const path = require('node:path')
|
|
@@ -22,13 +17,9 @@ const catalog = require('./catalog')
|
|
|
22
17
|
const manifest = require('../core/manifest')
|
|
23
18
|
const ownership = require('../core/ownership')
|
|
24
19
|
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
// Antes se exceptuaba `_template.md`, por andamiaje. Ese andamiaje resultó ser muerto —el motor
|
|
29
|
-
// genera el informe y la propuesta desde un molde propio y nunca lee esos archivos— y en un tercio
|
|
30
|
-
// del catálogo contradecía la forma que sí produce, así que se retiró entero. No hay caso especial
|
|
31
|
-
// que preservar.
|
|
20
|
+
// Informes, propuestas y veredictos no viajan: son lo que produjo nuestra versión del contrato, y el
|
|
21
|
+
// fork nace para dejar de ser ese contrato. Heredar un veredicto le daría a la copia una garantía que
|
|
22
|
+
// no rindió; heredar una propuesta pendiente la haría firmar una decisión que era nuestra.
|
|
32
23
|
function inherited(relative) {
|
|
33
24
|
if (/^learning\/(reports|proposals)\//.test(relative)) return false
|
|
34
25
|
if (relative.startsWith('evaluations/results/')) return false
|
|
@@ -37,8 +28,7 @@ function inherited(relative) {
|
|
|
37
28
|
|
|
38
29
|
const TEXT = /\.(md|ya?ml|json|txt)$/i
|
|
39
30
|
|
|
40
|
-
// El mismo recorrido que usa `upgrade
|
|
41
|
-
// de archivos como cualquier otro, y tener dos implementaciones sólo daba dos formas de ordenarlos.
|
|
31
|
+
// El mismo recorrido que usa `upgrade`: un cargo es un árbol de archivos como cualquier otro.
|
|
42
32
|
const tree = ownership.treeFiles
|
|
43
33
|
|
|
44
34
|
// La misma resolución que usa todo lo demás —paquete primero, toolkit después— en vez de deducirla
|
|
@@ -66,12 +56,9 @@ function fork(root, slug, date) {
|
|
|
66
56
|
// En el toolkit no hay a quién copiarle: el catálogo se mantiene acá, directo. Dejarlo pasar creaba
|
|
67
57
|
// un duplicado en `agents/roles/` que tapaba al original, y el trabajo siguiente se hacía sobre la
|
|
68
58
|
// copia mientras la versión que se publica quedaba quieta.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
throw new Error(`${slug} vive acá: en el toolkit se edita el catálogo, no se lo copia`)
|
|
73
|
-
}
|
|
74
|
-
} catch (error) { if (error instanceof Error && error.message.includes('vive acá')) throw error }
|
|
59
|
+
if (ownership.mode(root) === 'toolkit') {
|
|
60
|
+
throw new Error(`${slug} vive acá: en el toolkit se edita el catálogo, no se lo copia`)
|
|
61
|
+
}
|
|
75
62
|
|
|
76
63
|
const found = catalog.find(root, slug)
|
|
77
64
|
if (!found.system) {
|
|
@@ -85,13 +72,10 @@ function fork(root, slug, date) {
|
|
|
85
72
|
const files = todo.filter(inherited)
|
|
86
73
|
if (!files.includes('SKILL.md')) throw new Error(`${slug} no tiene SKILL.md: no hay contrato que copiar`)
|
|
87
74
|
|
|
88
|
-
// El digest sale del origen, no de la copia
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
// Y esa reescritura no es cosmética: el `AUTOMATION.md` del catálogo dice «mantené
|
|
93
|
-
// `agents/<tipo>/system/<slug>`», que en una empresa es el paquete. Copiado tal cual, el aprendizaje
|
|
94
|
-
// del fork apuntaría a un directorio que el guard bloquea y que npm borra en el próximo install.
|
|
75
|
+
// El digest sale del origen, no de la copia: es contra lo que el catálogo tenía al forkear que
|
|
76
|
+
// después se responde «esto mejoró río arriba». Medirlo sobre la copia lo ataría a nuestras propias
|
|
77
|
+
// ediciones, la reescritura de rutas incluida — y esa reescritura no es cosmética: sin ella el
|
|
78
|
+
// aprendizaje del fork apuntaría al paquete, que el guard bloquea y npm borra en el próximo install.
|
|
95
79
|
const desde = `agents/${type}/system/${slug}`
|
|
96
80
|
const hacia = `agents/${type}/${slug}`
|
|
97
81
|
const digests = {}
|
|
@@ -116,12 +100,11 @@ function fork(root, slug, date) {
|
|
|
116
100
|
|
|
117
101
|
// Qué cambió en el catálogo desde que la empresa se llevó su copia.
|
|
118
102
|
//
|
|
119
|
-
// El fork es legítimo
|
|
120
|
-
//
|
|
121
|
-
// enterarse de que el original mejoró. Nadie va a comparar 14 archivos a mano en cada actualización.
|
|
103
|
+
// El fork es legítimo, pero deja de recibir las mejoras del toolkit y eso no puede pasar en silencio:
|
|
104
|
+
// la empresa decidió mantener un cargo, no quedarse sin enterarse de que el original mejoró.
|
|
122
105
|
//
|
|
123
106
|
// Se compara contra los digests guardados al forkear, nunca contra la copia: la copia está editada a
|
|
124
|
-
// propósito, así que medir contra ella devolvería «todo cambió» desde el primer ajuste.
|
|
107
|
+
// propósito, así que medir contra ella devolvería «todo cambió» desde el primer ajuste. El aviso no
|
|
125
108
|
// dice qué hacer —integrar o no es decisión de la empresa—, sólo que hay algo que mirar.
|
|
126
109
|
function drift(root) {
|
|
127
110
|
const forks = manifest.readForks(root)
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const fs = require('fs')
|
|
6
|
-
const path = require('path')
|
|
3
|
+
const fs = require('node:fs')
|
|
4
|
+
const path = require('node:path')
|
|
7
5
|
const catalog = require('./catalog')
|
|
8
6
|
|
|
9
7
|
const REQUIRED_SECTIONS = [
|
|
@@ -35,6 +33,42 @@ function assertWritable(root, agent) {
|
|
|
35
33
|
function isoDate(now = new Date()) { return now.toISOString().slice(0, 10) }
|
|
36
34
|
function month(now = new Date()) { return now.toISOString().slice(0, 7) }
|
|
37
35
|
|
|
36
|
+
const PROPOSAL_NAME = /^\d{4}-\d{2}\.md$/
|
|
37
|
+
|
|
38
|
+
// El tope de la línea de índice. No es estético: son 47 líneas que se leen de un vistazo, y una que
|
|
39
|
+
// se envuelve rompe la columna que hace posible el vistazo.
|
|
40
|
+
const SUMMARY_MAX = 120
|
|
41
|
+
|
|
42
|
+
function proposalFiles(dir) {
|
|
43
|
+
try { return fs.readdirSync(dir).filter((name) => PROPOSAL_NAME.test(name)).sort() } catch { return [] }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function proposalState(text) {
|
|
47
|
+
return ((text.match(/^status:\s*(\S+)\s*$/m) || [])[1] || 'proposed').toLowerCase()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// El estado terminal del ciclo. Existía la firma, la aplicación y el historial, y faltaba justo el
|
|
51
|
+
// paso que vuelve irrepetible lo ya hecho: `status:` nacía en `proposed` y nadie lo movía nunca.
|
|
52
|
+
//
|
|
53
|
+
// No era un dato desprolijo. `agent-promote` busca la propuesta más nueva y aplica si el estado dice
|
|
54
|
+
// aprobada con responsable — y «aprobada y aplicada» cumple eso—, así que volver a correrlo sobre una
|
|
55
|
+
// propuesta ya aplicada la aplicaba de nuevo. Como los cambios son aditivos por diseño, el resultado
|
|
56
|
+
// no es un error visible sino un contrato con cada viñeta y cada fuente duplicadas.
|
|
57
|
+
function seal(root, agent, period = '') {
|
|
58
|
+
const dir = path.join(assertWritable(root, agent), 'learning', 'proposals')
|
|
59
|
+
const names = proposalFiles(dir)
|
|
60
|
+
if (!names.length) throw new Error(`${agent} no tiene propuestas en learning/proposals/.`)
|
|
61
|
+
const name = period ? `${period}.md` : names[names.length - 1]
|
|
62
|
+
if (!names.includes(name)) throw new Error(`${agent} no tiene la propuesta ${name}.`)
|
|
63
|
+
const file = path.join(dir, name)
|
|
64
|
+
const text = fs.readFileSync(file, 'utf8')
|
|
65
|
+
const state = proposalState(text)
|
|
66
|
+
if (state === 'applied') return { file, already: true }
|
|
67
|
+
if (!/^status:\s*\S+\s*$/m.test(text)) throw new Error(`${file} no declara status en su frontmatter.`)
|
|
68
|
+
fs.writeFileSync(file, text.replace(/^status:\s*\S+\s*$/m, 'status: applied'))
|
|
69
|
+
return { file, already: false }
|
|
70
|
+
}
|
|
71
|
+
|
|
38
72
|
function prepareReport(root, agent, now = new Date()) {
|
|
39
73
|
const reports = path.join(assertWritable(root, agent), 'learning', 'reports')
|
|
40
74
|
const file = path.join(reports, `${isoDate(now)}.md`)
|
|
@@ -150,24 +184,32 @@ function evaluate(root, agent) {
|
|
|
150
184
|
for (const phrase of ['no inventar', 'autorización', 'evidencia observable']) {
|
|
151
185
|
if (!skill.includes(phrase)) errors.push(`SKILL.md no conserva el control: ${phrase}`)
|
|
152
186
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
187
|
+
// Sin su línea, el cargo existe pero no se encuentra: quien tiene una tarea tendría que abrir la
|
|
188
|
+
// carpeta para saber si es éste. Se exige acá y no como advertencia porque es estático y de una línea.
|
|
189
|
+
const linea = catalog.summary(target)
|
|
190
|
+
if (!linea) errors.push('SKILL.md no declara summary: la línea con la que se elige este cargo')
|
|
191
|
+
else if (linea.length > SUMMARY_MAX) {
|
|
192
|
+
errors.push(`summary tiene ${linea.length} caracteres y el máximo es ${SUMMARY_MAX}: `
|
|
193
|
+
+ 'si no entra en una línea, no sirve para elegir de un vistazo')
|
|
194
|
+
}
|
|
195
|
+
const proposals = proposalFiles(path.join(target, 'learning', 'proposals'))
|
|
196
|
+
let pending = 0
|
|
158
197
|
for (const name of proposals) {
|
|
159
198
|
const text = fs.readFileSync(path.join(target, 'learning', 'proposals', name), 'utf8')
|
|
160
199
|
if (!/^automatic_apply:\s*false$/m.test(text)) errors.push(`${name}: automatic_apply debe ser false`)
|
|
161
200
|
for (const section of REQUIRED_SECTIONS) {
|
|
162
201
|
if (!text.includes(`## ${section}`)) errors.push(`${name}: falta sección ${section}`)
|
|
163
202
|
}
|
|
203
|
+
// Contar sólo las que esperan algo. Una propuesta aplicada contada como propuesta deja al cargo
|
|
204
|
+
// reportando trabajo pendiente para siempre, y es la misma confusión que permitía reaplicarla.
|
|
205
|
+
if (proposalState(text) !== 'applied') pending += 1
|
|
164
206
|
}
|
|
165
207
|
let cases = 0
|
|
166
208
|
try {
|
|
167
209
|
cases = fs.readdirSync(path.join(target, 'evaluations', 'cases'))
|
|
168
210
|
.filter((name) => name.endsWith('.md')).length
|
|
169
211
|
} catch { /* vacío */ }
|
|
170
|
-
return { errors, proposals: proposals.length, cases }
|
|
212
|
+
return { errors, proposals: proposals.length, pending, cases }
|
|
171
213
|
}
|
|
172
214
|
|
|
173
|
-
module.exports = { prepareReport, prepareProposal, evaluate }
|
|
215
|
+
module.exports = { prepareReport, prepareProposal, evaluate, proposalState, seal }
|
|
@@ -243,24 +243,7 @@ function check(root) {
|
|
|
243
243
|
if (!fs.existsSync(path.join(root, 'automatization', 'AGENTS.md'))) {
|
|
244
244
|
errors.push('falta automatization/AGENTS.md')
|
|
245
245
|
}
|
|
246
|
-
const
|
|
247
|
-
'run-hook.sh',
|
|
248
|
-
'guard-shell.sh',
|
|
249
|
-
'guard-files.sh',
|
|
250
|
-
'guard-destructive.sh',
|
|
251
|
-
'guard-git-add.sh',
|
|
252
|
-
'guard-secrets.sh',
|
|
253
|
-
'guard-generated.sh',
|
|
254
|
-
'guard-workspace-boundary.sh',
|
|
255
|
-
'guard-engine.sh',
|
|
256
|
-
'guard-migrations.sh',
|
|
257
|
-
'guard-dependencies.sh',
|
|
258
|
-
'guard-governance.sh',
|
|
259
|
-
'guard-verify.sh',
|
|
260
|
-
'guard-planning-drift.sh',
|
|
261
|
-
'guard-integration-snapshot.sh',
|
|
262
|
-
]
|
|
263
|
-
for (const name of hooks) {
|
|
246
|
+
for (const name of expectedHooks()) {
|
|
264
247
|
const file = path.join(hookDir, name)
|
|
265
248
|
if (!fs.existsSync(file)) errors.push(`falta automatization/hooks/${name}`)
|
|
266
249
|
else if (!(fs.statSync(file).mode & 0o111)) {
|
|
@@ -316,13 +299,32 @@ function validateRunner(root, name, errors) {
|
|
|
316
299
|
}
|
|
317
300
|
}
|
|
318
301
|
|
|
302
|
+
// Un `.sh` por grupo de más de un guard: es el que registra el runner para correrlos en un proceso.
|
|
303
|
+
function groupWrappers() {
|
|
304
|
+
return Object.entries(H.hookGroups)
|
|
305
|
+
.filter(([, names]) => names.length > 1)
|
|
306
|
+
.map(([group]) => [group, `guard-${group.replace('pre-', '')}.sh`])
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Los scripts que la instancia debe tener, derivados del registro que los ejecuta en vez de copiados
|
|
310
|
+
// a mano: la copia envejecía sin avisar, porque un guard nuevo del motor no entraba en la cuenta.
|
|
311
|
+
//
|
|
312
|
+
// Se comprueba en una sola dirección a propósito. Un `.sh` que no está acá no sobra: así es como una
|
|
313
|
+
// empresa agrega el suyo —`guard-acme.sh` al lado de los nuestros—, que es lo que `upgrade` le dice
|
|
314
|
+
// que haga y lo único que sobrevive a cada actualización.
|
|
315
|
+
function expectedHooks() {
|
|
316
|
+
return [
|
|
317
|
+
'run-hook.sh',
|
|
318
|
+
...groupWrappers().map(([, wrapper]) => wrapper),
|
|
319
|
+
...GUARD_NAMES.map((name) => `guard-${name}.sh`),
|
|
320
|
+
]
|
|
321
|
+
}
|
|
322
|
+
|
|
319
323
|
// Guards que hoy viven dentro de un grupo, con el wrapper que los reemplaza.
|
|
320
324
|
function supersededGuards() {
|
|
321
325
|
const entries = []
|
|
322
|
-
for (const [group,
|
|
323
|
-
|
|
324
|
-
const wrapper = `guard-${group.replace('pre-', '')}.sh`
|
|
325
|
-
for (const name of names) entries.push({ file: `guard-${name}.sh`, wrapper })
|
|
326
|
+
for (const [group, wrapper] of groupWrappers()) {
|
|
327
|
+
for (const name of H.hookGroups[group]) entries.push({ file: `guard-${name}.sh`, wrapper })
|
|
326
328
|
}
|
|
327
329
|
return entries
|
|
328
330
|
}
|
|
@@ -477,6 +479,12 @@ function deliveryState(recorded, name, resolved, prefix = '') {
|
|
|
477
479
|
}
|
|
478
480
|
|
|
479
481
|
function install(root, name, output = console, options = {}) {
|
|
482
|
+
// `install` arma la superficie de consumo de una empresa: punteros a cada cargo, una copia de los
|
|
483
|
+
// workflows y los guards. Acá los cargos y los workflows son el producto —la copia divergiría— y
|
|
484
|
+
// hay guards que contradicen el trabajo, como el que bloquea el push de cada release.
|
|
485
|
+
if (O.mode(root) === 'toolkit') {
|
|
486
|
+
throw new Error('Acá se fabrica Cauce, no se lo consume.')
|
|
487
|
+
}
|
|
480
488
|
const runner = runnerManifest(root, name)
|
|
481
489
|
const errors = check(root)
|
|
482
490
|
if (errors.length) throw new Error(`La automatización no es instalable:\n- ${errors.join('\n- ')}`)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// La gramática de la línea de comandos, en su propio módulo para poder probarla sin ejecutar el
|
|
4
|
+
// CLI: `tools/ops.js` invoca el comando haciendo `require` del motor, así que ops.js corre al ser
|
|
5
|
+
// requerido y no puede exportar nada sin dispararse.
|
|
6
|
+
|
|
7
|
+
// Banderas que consumen el argumento siguiente: su valor no es un posicional.
|
|
8
|
+
const VALUED_FLAGS = new Set(['--name', '--mode', '--fixture', '--period'])
|
|
9
|
+
|
|
10
|
+
// Qué acepta cada comando, y a la vez qué comandos existen. Una bandera desconocida se rechaza en vez
|
|
11
|
+
// de ignorarse: `check --jsonn` imprimía la salida humana con código 0, así que quien esperaba JSON
|
|
12
|
+
// —un agente, típicamente— recibía texto sin ninguna señal de que su bandera no existía.
|
|
13
|
+
const FLAGS = {
|
|
14
|
+
init: ['--name', '--mode', '--force'],
|
|
15
|
+
check: ['--json'],
|
|
16
|
+
tree: ['--json', '--no-color'],
|
|
17
|
+
context: ['--json'],
|
|
18
|
+
upgrade: ['--check', '--force'],
|
|
19
|
+
archive: [],
|
|
20
|
+
agents: ['--json', '--own', '--system'],
|
|
21
|
+
integration: ['--fixture'],
|
|
22
|
+
automation: ['--force'],
|
|
23
|
+
learn: ['--proposal', '--applied', '--period'],
|
|
24
|
+
evaluate: ['--cases', '--json', '--bench', '--force'],
|
|
25
|
+
team: ['--json'],
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// La línea de comandos, leída una sola vez. Antes cada función buscaba sus banderas en
|
|
29
|
+
// `process.argv`, veinticinco veces y a cualquier profundidad: `evaluationBench` sacaba `--force` de
|
|
30
|
+
// ahí en vez de recibirlo, así que su firma no decía de qué dependía y probar un comando exigía
|
|
31
|
+
// levantar un proceso. Acá se parsea al entrar y lo demás recibe el resultado.
|
|
32
|
+
function parse(argv) {
|
|
33
|
+
const flags = new Set()
|
|
34
|
+
const values = {}
|
|
35
|
+
const positional = []
|
|
36
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
37
|
+
const value = argv[index]
|
|
38
|
+
if (!value.startsWith('--')) { positional.push(value); continue }
|
|
39
|
+
flags.add(value)
|
|
40
|
+
if (VALUED_FLAGS.has(value)) { values[value] = argv[index + 1] || ''; index += 1 }
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
positional,
|
|
44
|
+
has: (flag) => flags.has(flag),
|
|
45
|
+
value: (flag, fallback = '') => values[flag] || fallback,
|
|
46
|
+
// Lo que el comando no declara en `FLAGS`. Se calcula sobre `flags` y no sobre argv crudo para
|
|
47
|
+
// que el valor de una bandera con valor no se confunda con una bandera suelta.
|
|
48
|
+
unknown: (command) => [...flags].filter((flag) => !FLAGS[command].includes(flag)),
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = { FLAGS, VALUED_FLAGS, parse }
|