@ingeniomaps/cauce 0.7.1 → 0.7.2

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 CHANGED
@@ -8,6 +8,18 @@ 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.2] - 2026-08-15
12
+
13
+ ### Cambiado
14
+
15
+ - **`team` gastaba un cuarto del recorrido en transcribir salida determinista de un CLI.** Dos agentes
16
+ resolvían el equipo y leían su manifiesto; ahora es uno. El segundo además leía `organization/`
17
+ "como contexto para etapas siguientes", y cada etapa es un agente nuevo con su propio contexto: esa
18
+ lectura no llegaba a ninguna parte y sólo costaba tokens.
19
+ - Cada etapa recibe la ruta exacta del contrato de su cargo. Antes le pasaban
20
+ `agents/<tipo>/<slug>/SKILL.md` —con el `<tipo>` literal— y desde 0.4.0 el catálogo ni siquiera está
21
+ en el proyecto, así que el agente salía a buscarlo antes de poder empezar.
22
+
11
23
  ## [0.7.1] - 2026-08-15
12
24
 
13
25
  ### 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
- type: 'object', additionalProperties: false, required: ['name', 'purpose', 'stages', 'guardrails'],
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' },
@@ -53,6 +57,9 @@ const MANIFEST = {
53
57
  id: { type: 'string' }, agent: { type: 'string' }, exitGate: { type: 'string' },
54
58
  phase: { type: 'string', enum: ['discovery', 'delivery'] },
55
59
  produces: { type: 'array', items: { type: 'string' } },
60
+ // Resuelto acá una vez: sin esto cada etapa gasta llamadas buscando el contrato de su cargo,
61
+ // que además ya no vive en el proyecto sino en el paquete.
62
+ skill: { type: 'string' },
56
63
  } } },
57
64
  },
58
65
  }
@@ -100,31 +107,35 @@ const BASE = `Nunca inventes clientes, métricas, restricciones ni decisiones. N
100
107
  `haría falta averiguar. No promuevas trabajo al BACKLOG, no escribas en sistemas externos y no ` +
101
108
  `declares validado nada sin evidencia observable.`
102
109
 
103
- const resolved = await agent(
104
- `${BASE}\n\nRun "node tools/ops.js team list" from ${ROOT}. Report whether "${CANDIDATE}" is one of ` +
105
- `the slugs it printed, and the full list. Do not guess: report only what the command printed.`,
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
-
110
+ // Tres comandos deterministas en un solo agente. Eran dos agentes, y el segundo además leía
111
+ // `organization/` "como contexto para etapas siguientes": cada etapa es un agente nuevo con su
112
+ // propio contexto, así que esa lectura no llegaba a ninguna parte y sólo costaba tokens.
119
113
  const contract = await agent(
120
- `${BASE}\n\nRun "node tools/ops.js team show ${TEAM} --json" from ${ROOT} and report only what it ` +
121
- `printed: name, purpose, outcome, entryAgent, facilitator, guardrails, the stages with id, phase, ` +
122
- `agent, ` +
123
- `produces and exitGate, and decisionOwners flattened into owners as domain/agent pairs. Then read ` +
124
- `${ROOT}/organization/ and report nothing from it: it is context for later stages, not output.`,
114
+ `${BASE}\n\nFrom ${ROOT}, run exactly these commands and report only what they printed. Read no ` +
115
+ `other file.\n` +
116
+ `1. "node tools/ops.js team show ${CANDIDATE} --json".\n` +
117
+ ` If it fails, run "node tools/ops.js team list", set exists=false, report teams, and stop.\n` +
118
+ `2. "node tools/ops.js agents list --json", which gives each role its resolved path.\n` +
119
+ `Report exists=true, the manifest fields —name, purpose, outcome, entryAgent, facilitator, ` +
120
+ `guardrails, stages with id, phase, agent, produces and exitGate, decisionOwners flattened into ` +
121
+ `owners as domain/agent pairs— and for every stage set skill to "<path>/SKILL.md" using the path ` +
122
+ `that command 2 printed for that stage's agent.`,
125
123
  { schema: MANIFEST, label: 'team-contract' },
126
124
  )
127
- if (!contract) return stop('contract-unavailable', `no se pudo leer el manifiesto de ${TEAM}`)
125
+ if (!contract) return stop('contract-unavailable', `no se pudo leer el manifiesto de ${CANDIDATE}`)
126
+ if (contract.exists === false) {
127
+ if (input.team) {
128
+ return stop('equipo-inexistente', `${CANDIDATE} no existe. Disponibles: ${(contract.teams || []).join(', ')}`)
129
+ }
130
+ // El prefijo era parte de la intención, no un equipo: se recompone y se reintenta por defecto.
131
+ return stop('equipo-inexistente', `"${CANDIDATE}" no es un equipo. Repetí sin el prefijo: la ` +
132
+ `intención completa era "${raw}". Disponibles: ${(contract.teams || []).join(', ')}`)
133
+ }
134
+ if (!contract.name || !contract.stages || !contract.guardrails) {
135
+ return stop('contrato-incompleto', `el manifiesto de ${CANDIDATE} no trae nombre, etapas o guardrails`)
136
+ }
137
+ const TEAM = CANDIDATE
138
+ const GOAL = INTENT
128
139
 
129
140
  const owners = (contract.owners || []).map((owner) => `${owner.domain}=${owner.agent}`).join(', ')
130
141
  const RULES = `${BASE}\n\nEquipo ${contract.name}: ${contract.purpose}\n` +
@@ -147,7 +158,8 @@ for (const stage of discovery) {
147
158
 
148
159
  const result = await agent(
149
160
  `${RULES}\n\n${previous}\n\nActuá como ${stage.agent}, respetando su contrato en ` +
150
- `agents/<tipo>/${stage.agent}/SKILL.md y sus límites. Etapa "${stage.id}": producí ` +
161
+ `${stage.skill || `${ROOT}/agents/roles/${stage.agent}/SKILL.md`} y sus límites. ` +
162
+ `Etapa "${stage.id}": producí ` +
151
163
  `${(stage.produces || []).join(' y ')}. Distinguí hechos, evidencia, supuestos y preguntas ` +
152
164
  `abiertas. El exit gate es: "${stage.exitGate}". Marcá gatePassed sólo si se cumple de verdad; ` +
153
165
  `si no, explicá en missing qué falta y en humanAction la acción concreta que lo desbloquea.`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ingeniomaps/cauce",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "description": "Sistema portable de planificación y ejecución verificable para cualquier proyecto",
5
5
  "type": "commonjs",
6
6
  "bin": {