@ingeniomaps/cauce 0.7.1 → 0.7.3
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 +23 -0
- package/automatization/workflows/team.js +41 -25
- package/engine/cli/ops.js +30 -12
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,29 @@ esa operación sea confiable en vez de sólo cómoda: acá se lee qué cambió a
|
|
|
8
8
|
un cambio en el protocolo, en las reglas del sistema o en un guard es visible para el usuario y sube
|
|
9
9
|
minor aunque no toque una sola línea de código.
|
|
10
10
|
|
|
11
|
+
## [0.7.3] - 2026-08-15
|
|
12
|
+
|
|
13
|
+
### Corregido
|
|
14
|
+
|
|
15
|
+
- **Una bandera antes del último posicional se comía su lugar.** `agents list --json` tomaba `--json`
|
|
16
|
+
como la raíz ops y devolvía `[]` sin error: no había forma de distinguir "no hay cargos" de "te
|
|
17
|
+
contesté con nada". Lo destapó un agente del recorrido de `team`, que pedía ese JSON para resolver
|
|
18
|
+
dónde vive cada cargo y se quedaba sin dato.
|
|
19
|
+
- La ruta del contrato de cada cargo es obligatoria en el manifiesto que arma `team`. Siendo opcional
|
|
20
|
+
el agente la omitía, la etapa caía al camino de respaldo y salía a buscar el archivo igual.
|
|
21
|
+
|
|
22
|
+
## [0.7.2] - 2026-08-15
|
|
23
|
+
|
|
24
|
+
### Cambiado
|
|
25
|
+
|
|
26
|
+
- **`team` gastaba un cuarto del recorrido en transcribir salida determinista de un CLI.** Dos agentes
|
|
27
|
+
resolvían el equipo y leían su manifiesto; ahora es uno. El segundo además leía `organization/`
|
|
28
|
+
"como contexto para etapas siguientes", y cada etapa es un agente nuevo con su propio contexto: esa
|
|
29
|
+
lectura no llegaba a ninguna parte y sólo costaba tokens.
|
|
30
|
+
- Cada etapa recibe la ruta exacta del contrato de su cargo. Antes le pasaban
|
|
31
|
+
`agents/<tipo>/<slug>/SKILL.md` —con el `<tipo>` literal— y desde 0.4.0 el catálogo ni siquiera está
|
|
32
|
+
en el proyecto, así que el agente salía a buscarlo antes de poder empezar.
|
|
33
|
+
|
|
11
34
|
## [0.7.1] - 2026-08-15
|
|
12
35
|
|
|
13
36
|
### Corregido
|
|
@@ -40,8 +40,12 @@ const CANDIDATE = String(input.team || (prefix ? prefix[1] : '') || 'product-dev
|
|
|
40
40
|
const INTENT = (input.team || !prefix ? raw : prefix[2]).trim()
|
|
41
41
|
|
|
42
42
|
const MANIFEST = {
|
|
43
|
-
|
|
43
|
+
// `exists` es lo único obligatorio: el mismo agente responde "no hay tal equipo" sin poder llenar
|
|
44
|
+
// un manifiesto que no existe. El resto se exige después, cuando sí lo hay.
|
|
45
|
+
type: 'object', additionalProperties: false, required: ['exists'],
|
|
44
46
|
properties: {
|
|
47
|
+
exists: { type: 'boolean' },
|
|
48
|
+
teams: { type: 'array', items: { type: 'string' } },
|
|
45
49
|
name: { type: 'string' }, purpose: { type: 'string' },
|
|
46
50
|
outcome: { type: 'string', enum: ['epic', 'report'] },
|
|
47
51
|
entryAgent: { type: 'string' }, facilitator: { type: 'string' },
|
|
@@ -49,10 +53,17 @@ const MANIFEST = {
|
|
|
49
53
|
owners: { type: 'array', items: { type: 'object', additionalProperties: false, properties: {
|
|
50
54
|
domain: { type: 'string' }, agent: { type: 'string' },
|
|
51
55
|
} } },
|
|
52
|
-
stages: { type: 'array', items: { type: 'object', additionalProperties: false,
|
|
56
|
+
stages: { type: 'array', items: { type: 'object', additionalProperties: false,
|
|
57
|
+
// `skill` es obligatorio a propósito: siendo opcional el agente lo omitía, la etapa caía al
|
|
58
|
+
// camino de respaldo y salía a buscar el contrato igual. Un dato que se puede resolver una vez
|
|
59
|
+
// no debería depender de que alguien se acuerde de resolverlo.
|
|
60
|
+
required: ['id', 'agent', 'phase', 'skill'], properties: {
|
|
53
61
|
id: { type: 'string' }, agent: { type: 'string' }, exitGate: { type: 'string' },
|
|
54
62
|
phase: { type: 'string', enum: ['discovery', 'delivery'] },
|
|
55
63
|
produces: { type: 'array', items: { type: 'string' } },
|
|
64
|
+
// Resuelto acá una vez: sin esto cada etapa gasta llamadas buscando el contrato de su cargo,
|
|
65
|
+
// que además ya no vive en el proyecto sino en el paquete.
|
|
66
|
+
skill: { type: 'string' },
|
|
56
67
|
} } },
|
|
57
68
|
},
|
|
58
69
|
}
|
|
@@ -100,31 +111,35 @@ const BASE = `Nunca inventes clientes, métricas, restricciones ni decisiones. N
|
|
|
100
111
|
`haría falta averiguar. No promuevas trabajo al BACKLOG, no escribas en sistemas externos y no ` +
|
|
101
112
|
`declares validado nada sin evidencia observable.`
|
|
102
113
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
{ schema: { type: 'object', required: ['exists', 'teams'], properties: {
|
|
107
|
-
exists: { type: 'boolean' }, teams: { type: 'array', items: { type: 'string' } },
|
|
108
|
-
} }, label: 'team-resolve' },
|
|
109
|
-
)
|
|
110
|
-
if (!resolved) return stop('teams-unavailable', 'no se pudo listar los equipos')
|
|
111
|
-
if (!resolved.exists && input.team) {
|
|
112
|
-
return stop('equipo-inexistente', `${CANDIDATE} no existe. Disponibles: ${resolved.teams.join(', ')}`)
|
|
113
|
-
}
|
|
114
|
-
// El prefijo era parte de la intención, no un equipo: se recompone y sigue con el equipo por defecto.
|
|
115
|
-
const TEAM = resolved.exists ? CANDIDATE : 'product-development'
|
|
116
|
-
const GOAL = resolved.exists ? INTENT : raw
|
|
117
|
-
if (!resolved.exists && prefix) log(`"${CANDIDATE}" no es un equipo: se toma el texto completo como intención.`)
|
|
118
|
-
|
|
114
|
+
// Tres comandos deterministas en un solo agente. Eran dos agentes, y el segundo además leía
|
|
115
|
+
// `organization/` "como contexto para etapas siguientes": cada etapa es un agente nuevo con su
|
|
116
|
+
// propio contexto, así que esa lectura no llegaba a ninguna parte y sólo costaba tokens.
|
|
119
117
|
const contract = await agent(
|
|
120
|
-
`${BASE}\n\
|
|
121
|
-
`
|
|
122
|
-
`
|
|
123
|
-
`
|
|
124
|
-
|
|
118
|
+
`${BASE}\n\nFrom ${ROOT}, run exactly these commands and report only what they printed. Read no ` +
|
|
119
|
+
`other file.\n` +
|
|
120
|
+
`1. "node tools/ops.js team show ${CANDIDATE} --json".\n` +
|
|
121
|
+
` If it fails, run "node tools/ops.js team list", set exists=false, report teams, and stop.\n` +
|
|
122
|
+
`2. "node tools/ops.js agents list --json", which gives each role its resolved path.\n` +
|
|
123
|
+
`Report exists=true, the manifest fields —name, purpose, outcome, entryAgent, facilitator, ` +
|
|
124
|
+
`guardrails, stages with id, phase, agent, produces and exitGate, decisionOwners flattened into ` +
|
|
125
|
+
`owners as domain/agent pairs— and for every stage set skill to "<path>/SKILL.md" using the path ` +
|
|
126
|
+
`that command 2 printed for that stage's agent.`,
|
|
125
127
|
{ schema: MANIFEST, label: 'team-contract' },
|
|
126
128
|
)
|
|
127
|
-
if (!contract) return stop('contract-unavailable', `no se pudo leer el manifiesto de ${
|
|
129
|
+
if (!contract) return stop('contract-unavailable', `no se pudo leer el manifiesto de ${CANDIDATE}`)
|
|
130
|
+
if (contract.exists === false) {
|
|
131
|
+
if (input.team) {
|
|
132
|
+
return stop('equipo-inexistente', `${CANDIDATE} no existe. Disponibles: ${(contract.teams || []).join(', ')}`)
|
|
133
|
+
}
|
|
134
|
+
// El prefijo era parte de la intención, no un equipo: se recompone y se reintenta por defecto.
|
|
135
|
+
return stop('equipo-inexistente', `"${CANDIDATE}" no es un equipo. Repetí sin el prefijo: la ` +
|
|
136
|
+
`intención completa era "${raw}". Disponibles: ${(contract.teams || []).join(', ')}`)
|
|
137
|
+
}
|
|
138
|
+
if (!contract.name || !contract.stages || !contract.guardrails) {
|
|
139
|
+
return stop('contrato-incompleto', `el manifiesto de ${CANDIDATE} no trae nombre, etapas o guardrails`)
|
|
140
|
+
}
|
|
141
|
+
const TEAM = CANDIDATE
|
|
142
|
+
const GOAL = INTENT
|
|
128
143
|
|
|
129
144
|
const owners = (contract.owners || []).map((owner) => `${owner.domain}=${owner.agent}`).join(', ')
|
|
130
145
|
const RULES = `${BASE}\n\nEquipo ${contract.name}: ${contract.purpose}\n` +
|
|
@@ -147,7 +162,8 @@ for (const stage of discovery) {
|
|
|
147
162
|
|
|
148
163
|
const result = await agent(
|
|
149
164
|
`${RULES}\n\n${previous}\n\nActuá como ${stage.agent}, respetando su contrato en ` +
|
|
150
|
-
|
|
165
|
+
`${stage.skill || `${ROOT}/agents/roles/${stage.agent}/SKILL.md`} y sus límites. ` +
|
|
166
|
+
`Etapa "${stage.id}": producí ` +
|
|
151
167
|
`${(stage.produces || []).join(' y ')}. Distinguí hechos, evidencia, supuestos y preguntas ` +
|
|
152
168
|
`abiertas. El exit gate es: "${stage.exitGate}". Marcá gatePassed sólo si se cumple de verdad; ` +
|
|
153
169
|
`si no, explicá en missing qué falta y en humanAction la acción concreta que lo desbloquea.`,
|
package/engine/cli/ops.js
CHANGED
|
@@ -53,6 +53,23 @@ function usage() {
|
|
|
53
53
|
ops team show <team>`)
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
// Banderas que consumen el argumento siguiente: su valor no es un posicional.
|
|
57
|
+
const VALUED_FLAGS = new Set(['--name', '--mode', '--engine', '--fixture'])
|
|
58
|
+
|
|
59
|
+
// Los posicionales del comando, salteando banderas y sus valores. Leer `process.argv` crudo hacía
|
|
60
|
+
// que `agents list --json` tomara `--json` como la raíz: el catálogo salía vacío, sin error, y quien
|
|
61
|
+
// lo consumía —un agente, por ejemplo— no tenía cómo notar que le habían contestado con nada.
|
|
62
|
+
function positionals() {
|
|
63
|
+
const found = []
|
|
64
|
+
const argv = process.argv.slice(2)
|
|
65
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
66
|
+
const value = argv[index]
|
|
67
|
+
if (!value.startsWith('--')) { found.push(value); continue }
|
|
68
|
+
if (VALUED_FLAGS.has(value)) index += 1
|
|
69
|
+
}
|
|
70
|
+
return found
|
|
71
|
+
}
|
|
72
|
+
|
|
56
73
|
function option(name, fallback = '') {
|
|
57
74
|
const index = process.argv.indexOf(name)
|
|
58
75
|
return index >= 0 ? process.argv[index + 1] || fallback : fallback
|
|
@@ -790,20 +807,21 @@ function team(action, slug) {
|
|
|
790
807
|
async function main() {
|
|
791
808
|
const command = process.argv[2]
|
|
792
809
|
if (!command || ['help', '--help', '-h'].includes(command)) return usage()
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
else if (command === '
|
|
796
|
-
else if (command === '
|
|
797
|
-
else if (command === '
|
|
798
|
-
else if (command === '
|
|
799
|
-
else if (command === '
|
|
810
|
+
const arg = positionals()
|
|
811
|
+
if (command === 'init') init(arg[1])
|
|
812
|
+
else if (command === 'check') check(arg[1])
|
|
813
|
+
else if (command === 'tree') tree(arg[1])
|
|
814
|
+
else if (command === 'context') context(arg[1])
|
|
815
|
+
else if (command === 'upgrade') upgrade(arg[1])
|
|
816
|
+
else if (command === 'agents') agents(arg[1], arg[2])
|
|
817
|
+
else if (command === 'archive') archive(arg[1], arg[2])
|
|
800
818
|
else if (command === 'integration') {
|
|
801
|
-
await integration(
|
|
819
|
+
await integration(arg[1], arg[2], arg[3], arg[4])
|
|
802
820
|
}
|
|
803
|
-
else if (command === 'automation') automation(
|
|
804
|
-
else if (command === 'learn') learn(
|
|
805
|
-
else if (command === 'evaluate') evaluate(
|
|
806
|
-
else if (command === 'team') team(
|
|
821
|
+
else if (command === 'automation') automation(arg[1], arg[2], arg[3])
|
|
822
|
+
else if (command === 'learn') learn(arg[1])
|
|
823
|
+
else if (command === 'evaluate') evaluate(arg[1])
|
|
824
|
+
else if (command === 'team') team(arg[1], arg[2])
|
|
807
825
|
else { usage(); fail(`Comando desconocido: ${command}`, 2) }
|
|
808
826
|
}
|
|
809
827
|
|