@ingeniomaps/cauce 0.21.0 → 0.23.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 +165 -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-16.md +740 -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/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/database-administrator/SKILL.md +1 -0
- package/agents/roles/system/database-administrator/evaluations/cases/06-adversarial-runbook/RB-2291-recuperacion-corrupcion-indices.md +122 -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-16.md +649 -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 +37 -35
- package/automatization/workflows/agent-promote.js +28 -6
- package/automatization/workflows/autobuild.js +43 -16
- package/automatization/workflows/integrations/promote.js +10 -5
- package/automatization/workflows/integrations/sync.js +8 -5
- package/engine/agents/catalog.js +25 -7
- package/engine/agents/evaluations.js +48 -16
- package/engine/agents/fork.js +21 -45
- package/engine/agents/learning.js +55 -17
- package/engine/automation/index.js +43 -29
- package/engine/cli/args.js +52 -0
- package/engine/cli/ops.js +273 -207
- package/engine/config/validate.js +2 -7
- package/engine/core/changelog.js +1 -1
- package/engine/core/files.js +0 -1
- package/engine/core/manifest.js +1 -1
- package/engine/core/ownership.js +28 -25
- package/engine/hooks/run.js +37 -36
- package/engine/integrations/proposals.js +3 -1
- package/engine/integrations/registry.js +13 -16
- package/engine/integrations/state.js +1 -2
- package/engine/planning/contracts.js +0 -3
- package/engine/planning/parser.js +6 -9
- package/engine/teams/registry.js +8 -4
- package/package.json +2 -1
- package/template/AGENTS.md +19 -31
- package/template/automatization/README.md +4 -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/template/automatization/config.json +0 -13
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,17 +28,8 @@ function inherited(relative) {
|
|
|
37
28
|
|
|
38
29
|
const TEXT = /\.(md|ya?ml|json|txt)$/i
|
|
39
30
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
let list = []
|
|
43
|
-
try { list = fs.readdirSync(dir, { withFileTypes: true }) } catch { return found }
|
|
44
|
-
for (const entry of list) {
|
|
45
|
-
const relative = prefix ? `${prefix}/${entry.name}` : entry.name
|
|
46
|
-
if (entry.isDirectory()) found.push(...tree(path.join(dir, entry.name), relative))
|
|
47
|
-
else found.push(relative)
|
|
48
|
-
}
|
|
49
|
-
return found.sort()
|
|
50
|
-
}
|
|
31
|
+
// El mismo recorrido que usa `upgrade`: un cargo es un árbol de archivos como cualquier otro.
|
|
32
|
+
const tree = ownership.treeFiles
|
|
51
33
|
|
|
52
34
|
// La misma resolución que usa todo lo demás —paquete primero, toolkit después— en vez de deducirla
|
|
53
35
|
// del directorio del motor: la versión que interesa es la del catálogo del que sale la copia.
|
|
@@ -74,12 +56,9 @@ function fork(root, slug, date) {
|
|
|
74
56
|
// En el toolkit no hay a quién copiarle: el catálogo se mantiene acá, directo. Dejarlo pasar creaba
|
|
75
57
|
// un duplicado en `agents/roles/` que tapaba al original, y el trabajo siguiente se hacía sobre la
|
|
76
58
|
// copia mientras la versión que se publica quedaba quieta.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
throw new Error(`${slug} vive acá: en el toolkit se edita el catálogo, no se lo copia`)
|
|
81
|
-
}
|
|
82
|
-
} 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
|
+
}
|
|
83
62
|
|
|
84
63
|
const found = catalog.find(root, slug)
|
|
85
64
|
if (!found.system) {
|
|
@@ -89,16 +68,14 @@ function fork(root, slug, date) {
|
|
|
89
68
|
const target = path.join(root, 'agents', type, slug)
|
|
90
69
|
if (fs.existsSync(target)) throw new Error(`${path.relative(root, target)} ya existe`)
|
|
91
70
|
|
|
92
|
-
const
|
|
71
|
+
const todo = tree(found.dir)
|
|
72
|
+
const files = todo.filter(inherited)
|
|
93
73
|
if (!files.includes('SKILL.md')) throw new Error(`${slug} no tiene SKILL.md: no hay contrato que copiar`)
|
|
94
74
|
|
|
95
|
-
// El digest sale del origen, no de la copia
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
//
|
|
99
|
-
// Y esa reescritura no es cosmética: el `AUTOMATION.md` del catálogo dice «mantené
|
|
100
|
-
// `agents/<tipo>/system/<slug>`», que en una empresa es el paquete. Copiado tal cual, el aprendizaje
|
|
101
|
-
// 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.
|
|
102
79
|
const desde = `agents/${type}/system/${slug}`
|
|
103
80
|
const hacia = `agents/${type}/${slug}`
|
|
104
81
|
const digests = {}
|
|
@@ -118,17 +95,16 @@ function fork(root, slug, date) {
|
|
|
118
95
|
forks[slug] = { type, version, files: digests }
|
|
119
96
|
manifest.write(root, null, null, forks)
|
|
120
97
|
|
|
121
|
-
return { slug, type, dir: target, files, version, skipped:
|
|
98
|
+
return { slug, type, dir: target, files, version, skipped: todo.filter((one) => !inherited(one)) }
|
|
122
99
|
}
|
|
123
100
|
|
|
124
101
|
// Qué cambió en el catálogo desde que la empresa se llevó su copia.
|
|
125
102
|
//
|
|
126
|
-
// El fork es legítimo
|
|
127
|
-
//
|
|
128
|
-
// 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ó.
|
|
129
105
|
//
|
|
130
106
|
// Se compara contra los digests guardados al forkear, nunca contra la copia: la copia está editada a
|
|
131
|
-
// 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
|
|
132
108
|
// dice qué hacer —integrar o no es decisión de la empresa—, sólo que hay algo que mirar.
|
|
133
109
|
function drift(root) {
|
|
134
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 = [
|
|
@@ -15,10 +13,6 @@ const REQUIRED_SECTIONS = [
|
|
|
15
13
|
'Aprobación humana',
|
|
16
14
|
]
|
|
17
15
|
|
|
18
|
-
function agentRoot(root, agent) {
|
|
19
|
-
return catalog.resolve(root, agent)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
16
|
// Un cargo del sistema vive dentro del paquete: escribir ahí perdería el informe en el próximo
|
|
23
17
|
// `npm ci`, y además duplicaría en cada empresa una investigación sobre la profesión que se hace
|
|
24
18
|
// mejor una sola vez. Lo que sí es de esta empresa es su contexto, y ese tiene otro lugar.
|
|
@@ -39,6 +33,42 @@ function assertWritable(root, agent) {
|
|
|
39
33
|
function isoDate(now = new Date()) { return now.toISOString().slice(0, 10) }
|
|
40
34
|
function month(now = new Date()) { return now.toISOString().slice(0, 7) }
|
|
41
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
|
+
|
|
42
72
|
function prepareReport(root, agent, now = new Date()) {
|
|
43
73
|
const reports = path.join(assertWritable(root, agent), 'learning', 'reports')
|
|
44
74
|
const file = path.join(reports, `${isoDate(now)}.md`)
|
|
@@ -136,7 +166,7 @@ Pendiente.
|
|
|
136
166
|
}
|
|
137
167
|
|
|
138
168
|
function evaluate(root, agent) {
|
|
139
|
-
const target =
|
|
169
|
+
const target = catalog.resolve(root, agent)
|
|
140
170
|
const errors = []
|
|
141
171
|
const requiredFiles = [
|
|
142
172
|
'learning/sources.yaml',
|
|
@@ -146,7 +176,7 @@ function evaluate(root, agent) {
|
|
|
146
176
|
// `AUTOMATION.md` documenta cómo corre la automatización de aprendizaje del toolkit. Exigírselo
|
|
147
177
|
// a una empresa que escribe un cargo propio era pedirle contabilidad interna nuestra: su cargo debe
|
|
148
178
|
// tener contrato, fuentes e historia, no nuestro andamiaje.
|
|
149
|
-
if (
|
|
179
|
+
if (catalog.find(root, agent).system) requiredFiles.push('learning/AUTOMATION.md')
|
|
150
180
|
for (const relative of requiredFiles) {
|
|
151
181
|
if (!fs.existsSync(path.join(target, relative))) errors.push(`falta ${relative}`)
|
|
152
182
|
}
|
|
@@ -154,24 +184,32 @@ function evaluate(root, agent) {
|
|
|
154
184
|
for (const phrase of ['no inventar', 'autorización', 'evidencia observable']) {
|
|
155
185
|
if (!skill.includes(phrase)) errors.push(`SKILL.md no conserva el control: ${phrase}`)
|
|
156
186
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
|
162
197
|
for (const name of proposals) {
|
|
163
198
|
const text = fs.readFileSync(path.join(target, 'learning', 'proposals', name), 'utf8')
|
|
164
199
|
if (!/^automatic_apply:\s*false$/m.test(text)) errors.push(`${name}: automatic_apply debe ser false`)
|
|
165
200
|
for (const section of REQUIRED_SECTIONS) {
|
|
166
201
|
if (!text.includes(`## ${section}`)) errors.push(`${name}: falta sección ${section}`)
|
|
167
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
|
|
168
206
|
}
|
|
169
207
|
let cases = 0
|
|
170
208
|
try {
|
|
171
209
|
cases = fs.readdirSync(path.join(target, 'evaluations', 'cases'))
|
|
172
210
|
.filter((name) => name.endsWith('.md')).length
|
|
173
211
|
} catch { /* vacío */ }
|
|
174
|
-
return { errors, proposals: proposals.length, cases }
|
|
212
|
+
return { errors, proposals: proposals.length, pending, cases }
|
|
175
213
|
}
|
|
176
214
|
|
|
177
|
-
module.exports = { prepareReport, prepareProposal, evaluate }
|
|
215
|
+
module.exports = { prepareReport, prepareProposal, evaluate, proposalState, seal }
|
|
@@ -12,6 +12,11 @@ const M = require('../core/manifest')
|
|
|
12
12
|
|
|
13
13
|
const RUNNER_NAMES = ['claude', 'codex', 'gemini', 'antigravity']
|
|
14
14
|
|
|
15
|
+
// Los guards que el motor implementa, tomados del registro que los ejecuta. Sale de ahí y no de un
|
|
16
|
+
// número escrito a mano: `automation check` anunciaba «11 guards» cuando hacía rato que eran doce, y
|
|
17
|
+
// un conteo que envejece solo es peor que ninguno —dice que revisó menos de lo que revisó—.
|
|
18
|
+
const GUARD_NAMES = Object.keys(H.guards)
|
|
19
|
+
|
|
15
20
|
// Adaptadores y workflows viven en el paquete, no en la instancia: son definiciones que el motor
|
|
16
21
|
// consume y que ninguna empresa edita —`RUNNER_NAMES` es cerrado, así que ni siquiera puede agregar
|
|
17
22
|
// uno propio—. Los hooks sí se quedan en el proyecto: la configuración del runner los nombra por
|
|
@@ -172,7 +177,7 @@ Respetá los límites de ese contrato y las reglas de \`AGENTS.md\`. Generado po
|
|
|
172
177
|
}
|
|
173
178
|
|
|
174
179
|
function installRoleSkills(root, runner, output) {
|
|
175
|
-
if (!runner.capabilities.nativeSkills || !runner.roleSkills) return
|
|
180
|
+
if (!runner.capabilities.nativeSkills || !runner.roleSkills) return
|
|
176
181
|
const install = installRoot(root)
|
|
177
182
|
const base = F.assertWithin(install, path.resolve(install, runner.roleSkills), `${runner.name}: roleSkills`)
|
|
178
183
|
const roles = roleCatalog(root)
|
|
@@ -182,7 +187,6 @@ function installRoleSkills(root, runner, output) {
|
|
|
182
187
|
F.atomicWrite(file, roleSkill(role))
|
|
183
188
|
}
|
|
184
189
|
if (roles.length) output.log(`✓ ${runner.name}: ${roles.length} cargo(s) disponibles en ${runner.roleSkills}`)
|
|
185
|
-
return roles.length
|
|
186
190
|
}
|
|
187
191
|
|
|
188
192
|
// Runners que además de los archivos necesitan un registro propio para que el wiring cuente. Copiar
|
|
@@ -239,24 +243,7 @@ function check(root) {
|
|
|
239
243
|
if (!fs.existsSync(path.join(root, 'automatization', 'AGENTS.md'))) {
|
|
240
244
|
errors.push('falta automatization/AGENTS.md')
|
|
241
245
|
}
|
|
242
|
-
const
|
|
243
|
-
'run-hook.sh',
|
|
244
|
-
'guard-shell.sh',
|
|
245
|
-
'guard-files.sh',
|
|
246
|
-
'guard-destructive.sh',
|
|
247
|
-
'guard-git-add.sh',
|
|
248
|
-
'guard-secrets.sh',
|
|
249
|
-
'guard-generated.sh',
|
|
250
|
-
'guard-workspace-boundary.sh',
|
|
251
|
-
'guard-engine.sh',
|
|
252
|
-
'guard-migrations.sh',
|
|
253
|
-
'guard-dependencies.sh',
|
|
254
|
-
'guard-governance.sh',
|
|
255
|
-
'guard-verify.sh',
|
|
256
|
-
'guard-planning-drift.sh',
|
|
257
|
-
'guard-integration-snapshot.sh',
|
|
258
|
-
]
|
|
259
|
-
for (const name of hooks) {
|
|
246
|
+
for (const name of expectedHooks()) {
|
|
260
247
|
const file = path.join(hookDir, name)
|
|
261
248
|
if (!fs.existsSync(file)) errors.push(`falta automatization/hooks/${name}`)
|
|
262
249
|
else if (!(fs.statSync(file).mode & 0o111)) {
|
|
@@ -267,8 +254,12 @@ function check(root) {
|
|
|
267
254
|
if (!O.engineAt(root, path.join('hooks', 'run.js'))) {
|
|
268
255
|
errors.push('falta engine/hooks/run.js: corré "npm install" en la raíz del repo ops')
|
|
269
256
|
}
|
|
270
|
-
const workflows = [
|
|
271
|
-
|
|
257
|
+
const workflows = [
|
|
258
|
+
'autobuild.js',
|
|
259
|
+
'team.js',
|
|
260
|
+
path.join('integrations', 'sync.js'),
|
|
261
|
+
path.join('integrations', 'promote.js'),
|
|
262
|
+
]
|
|
272
263
|
const packaged = packagedAutomation(root)
|
|
273
264
|
for (const name of workflows) {
|
|
274
265
|
if (!packaged || !fs.existsSync(path.join(packaged, 'workflows', name))) {
|
|
@@ -308,13 +299,32 @@ function validateRunner(root, name, errors) {
|
|
|
308
299
|
}
|
|
309
300
|
}
|
|
310
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
|
+
|
|
311
323
|
// Guards que hoy viven dentro de un grupo, con el wrapper que los reemplaza.
|
|
312
324
|
function supersededGuards() {
|
|
313
325
|
const entries = []
|
|
314
|
-
for (const [group,
|
|
315
|
-
|
|
316
|
-
const wrapper = `guard-${group.replace('pre-', '')}.sh`
|
|
317
|
-
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 })
|
|
318
328
|
}
|
|
319
329
|
return entries
|
|
320
330
|
}
|
|
@@ -469,6 +479,12 @@ function deliveryState(recorded, name, resolved, prefix = '') {
|
|
|
469
479
|
}
|
|
470
480
|
|
|
471
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
|
+
}
|
|
472
488
|
const runner = runnerManifest(root, name)
|
|
473
489
|
const errors = check(root)
|
|
474
490
|
if (errors.length) throw new Error(`La automatización no es instalable:\n- ${errors.join('\n- ')}`)
|
|
@@ -550,16 +566,14 @@ function listHooks(output = console) {
|
|
|
550
566
|
}
|
|
551
567
|
|
|
552
568
|
module.exports = {
|
|
569
|
+
GUARD_NAMES,
|
|
553
570
|
RUNNER_NAMES,
|
|
554
571
|
check,
|
|
555
572
|
doctor,
|
|
556
|
-
includesConfig,
|
|
557
573
|
install,
|
|
558
574
|
legacyGuardWiring,
|
|
559
|
-
pruneSupersededHooks,
|
|
560
575
|
roleCatalog,
|
|
561
576
|
roleSkill,
|
|
562
577
|
listHooks,
|
|
563
|
-
mergeConfig,
|
|
564
578
|
runnerManifest,
|
|
565
579
|
}
|
|
@@ -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 }
|