@ingeniomaps/cauce 0.6.0 → 0.7.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 CHANGED
@@ -8,6 +8,38 @@ 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.0] - 2026-08-15
12
+
13
+ ### Corregido
14
+
15
+ - **Los cuatro workflows reventaban en su primera línea y nunca habían corrido.** Resolvían su raíz
16
+ con `process.env`, y el runtime de workflows es un sandbox que no expone `process`: `ReferenceError`
17
+ antes de ejecutar nada. `/team` y `/autobuild` —el centro del producto— estaban muertos, y los tests
18
+ no lo veían porque leían los archivos como texto en vez de ejecutarlos.
19
+
20
+ La raíz ahora viaja escrita en el archivo, que es lo que `automation install` ya sabía completar, y
21
+ es relativa a donde se abre la herramienta.
22
+
23
+ ### Cambiado
24
+
25
+ - Los workflows de integración se invocan con argumentos en vez de variables de entorno, que tampoco
26
+ existen ahí: `/integration-sync jira` y `/integration-promote jira KEY-123`.
27
+ - Un test comprueba que ningún workflow use `process`, `require`, `Date.now` ni `Math.random`. El
28
+ sandbox los prohíbe, y usarlos no falla en una rama rara: impide que el archivo arranque.
29
+
30
+ ## [0.6.1] - 2026-08-15
31
+
32
+ ### Corregido
33
+
34
+ - **El bridge de Antigravity negaba cada llamada a herramienta.** Resolvía la raíz ops subiendo por el
35
+ árbol, y en sidecar es un *hermano* de los repos de producto: no la encontraba y, como falla cerrado,
36
+ bloqueaba todo. Ahora `automation install` le deja escrito dónde quedó, con el recorrido hacia arriba
37
+ como respaldo.
38
+ - **`automation install antigravity` copiaba el plugin y lo dejaba inerte.** Antigravity exige un
39
+ registro explícito —`agy plugin install`—, así que los archivos quedaban en su lugar, `doctor` daba
40
+ verde y no se ejecutaba nada. `install` ahora dice el comando exacto y `doctor` avisa si falta, sin
41
+ tocar por su cuenta la configuración global del usuario.
42
+
11
43
  ## [0.6.0] - 2026-08-15
12
44
 
13
45
  ### Cambiado
@@ -11,7 +11,22 @@ function readInput() {
11
11
  } catch { return {} }
12
12
  }
13
13
 
14
+ // Dónde quedó la raíz ops respecto de la carpeta que Antigravity abre. Lo completa
15
+ // `automation install`, que es el único momento en que se sabe: en modo sidecar la raíz ops es un
16
+ // hermano de los repos de producto, y ninguna búsqueda hacia arriba la encuentra. Sin esto el bridge
17
+ // no hallaba `ops.config.json` y, como falla cerrado, negaba cada llamada a herramienta.
18
+ const OPS_DIR = '{{OPS_DIR}}'
19
+
20
+ function declaredRoot() {
21
+ // El plugin vive en <raíz-de-instalación>/.agents/plugins/cauce/.
22
+ const installed = path.resolve(__dirname, '..', '..', '..')
23
+ const root = OPS_DIR.startsWith('{{') ? installed : path.join(installed, OPS_DIR)
24
+ return fs.existsSync(path.join(root, 'ops.config.json')) ? root : ''
25
+ }
26
+
14
27
  function findRoot(input) {
28
+ const declared = declaredRoot()
29
+ if (declared) return declared
15
30
  const args = input.toolCall && input.toolCall.args || {}
16
31
  const starts = [args.Cwd, process.cwd(), ...(input.workspacePaths || [])].filter(Boolean)
17
32
  for (const start of starts) {
@@ -48,5 +48,13 @@
48
48
  "checkpointing": false,
49
49
  "nativeSkills": true
50
50
  },
51
- "roleSkills": ".agents/plugins/cauce/skills"
51
+ "roleSkills": ".agents/plugins/cauce/skills",
52
+ "activation": {
53
+ "hint": "agy plugin install .agents/plugins/cauce",
54
+ "verify": [
55
+ "plugin",
56
+ "list"
57
+ ],
58
+ "expect": "cauce"
59
+ }
52
60
  }
@@ -28,8 +28,8 @@ para revisión humana. `integrations/promote.js` exige proveedor, clave y un dra
28
28
  el sistema remoto; Jira es actualmente el primer adaptador del contrato general.
29
29
 
30
30
  ```bash
31
- OPS_INTEGRATION_PROVIDER=jira /integration-sync
32
- OPS_INTEGRATION_PROVIDER=jira OPS_INTEGRATION_KEY=KEY-123 /integration-promote
31
+ /integration-sync jira
32
+ /integration-promote jira KEY-123
33
33
  ```
34
34
 
35
35
  ## Aprendizaje de agentes
@@ -10,10 +10,10 @@ export const meta = {
10
10
  ].map((title) => ({ title, detail: `Fase ${title} del protocolo agnóstico` })),
11
11
  }
12
12
 
13
- // El prefijo lo completa `automation install`: en modo sidecar la herramienta se abre en la carpeta
14
- // de la compañía y la raíz ops es uno de sus hijos, no la carpeta misma.
15
- const ROOT = (process.env.OPS_ROOT
16
- || `${process.env.CLAUDE_PROJECT_DIR || '.'}/{{OPS_DIR}}`).replace(/\/+$/, '')
13
+ // El prefijo lo completa `automation install`. No puede venir del entorno: el runtime de workflows no
14
+ // expone `process`, así que leerlo de ahí reventaba el archivo entero en su primera línea. Viaja
15
+ // escrito, relativo a la carpeta donde se abre la herramienta, que es el cwd de los agentes.
16
+ const ROOT = '{{OPS_DIR}}'.replace(/\/+$/, '') || '.'
17
17
  const CONFIG = `${ROOT}/ops.config.json`
18
18
  const P = `${ROOT}/planning`
19
19
  const BACKLOG = `${P}/BACKLOG.md`
@@ -9,6 +9,6 @@ remoto → sync → staging → revisión humana → promote → planning
9
9
  - `sync.js`: valida y refresca staging sin promover ni escribir remoto.
10
10
  - `promote.js`: materializa localmente un candidato cuyo draft está `ready`.
11
11
 
12
- El proveedor se selecciona con `OPS_INTEGRATION_PROVIDER`; `promote` requiere además
13
- `OPS_INTEGRATION_KEY`. La implementación particular de Jira vive en `engine/integrations/providers/jira.js`,
12
+ El proveedor se pasa como argumento —`/integration-sync jira`—; `promote` requiere además la clave
13
+ remota: `/integration-promote jira KEY-123`. La implementación particular de Jira vive en `engine/integrations/providers/jira.js`,
14
14
  no en estos workflows.
@@ -10,12 +10,15 @@ export const meta = {
10
10
  ],
11
11
  }
12
12
 
13
- // El prefijo lo completa `automation install`: en modo sidecar la herramienta se abre en la carpeta
14
- // de la compañía y la raíz ops es uno de sus hijos, no la carpeta misma.
15
- const ROOT = (process.env.OPS_ROOT
16
- || `${process.env.CLAUDE_PROJECT_DIR || '.'}/{{OPS_DIR}}`).replace(/\/+$/, '')
17
- const PROVIDER = process.env.OPS_INTEGRATION_PROVIDER || ''
18
- const KEY = process.env.OPS_INTEGRATION_KEY || ''
13
+ // El prefijo lo completa `automation install`. No puede venir del entorno: el runtime de workflows no
14
+ // expone `process`, así que leerlo de ahí reventaba el archivo entero en su primera línea. Viaja
15
+ // escrito, relativo a la carpeta donde se abre la herramienta, que es el cwd de los agentes.
16
+ const ROOT = '{{OPS_DIR}}'.replace(/\/+$/, '') || '.'
17
+ // `/integration-promote jira KEY-123` o `{"provider": "jira", "key": "KEY-123"}`.
18
+ const parts = typeof args === 'string' ? args.trim().split(/\s+/) : []
19
+ const input = typeof args === 'string' ? { provider: parts[0], key: parts[1] } : (args || {})
20
+ const PROVIDER = String(input.provider || '').trim()
21
+ const KEY = String(input.key || '').trim()
19
22
  const RESULT = {
20
23
  type: 'object', additionalProperties: false, required: ['passed', 'provider', 'key', 'details'],
21
24
  properties: { passed: { type: 'boolean' }, provider: { type: 'string' }, key: { type: 'string' }, details: { type: 'string' }, kind: { type: 'string' } },
@@ -24,7 +27,7 @@ const RESULT = {
24
27
  phase('Preflight')
25
28
  const result = await agent(
26
29
  `Read ${ROOT}/integrations/README.md, integrations config, the provider contract and planning/PROTOCOL.md. ` +
27
- `Require OPS_INTEGRATION_PROVIDER=${JSON.stringify(PROVIDER)} and OPS_INTEGRATION_KEY=${JSON.stringify(KEY)}. ` +
30
+ `The provider is ${JSON.stringify(PROVIDER)} and the remote key ${JSON.stringify(KEY)}; both are required. ` +
28
31
  `Run integration check. Inspect only that candidate's draft and snapshot; stop unless draft state is ready and ` +
29
32
  `acceptance, hierarchy and service mapping are concrete. Never call or write the remote provider.\n\n` +
30
33
  `If valid, enter Promote and run "node tools/ops.js integration promote ${ROOT} ${PROVIDER} ${KEY}" exactly once. ` +
@@ -10,11 +10,13 @@ export const meta = {
10
10
  ],
11
11
  }
12
12
 
13
- // El prefijo lo completa `automation install`: en modo sidecar la herramienta se abre en la carpeta
14
- // de la compañía y la raíz ops es uno de sus hijos, no la carpeta misma.
15
- const ROOT = (process.env.OPS_ROOT
16
- || `${process.env.CLAUDE_PROJECT_DIR || '.'}/{{OPS_DIR}}`).replace(/\/+$/, '')
17
- const REQUESTED = process.env.OPS_INTEGRATION_PROVIDER || ''
13
+ // El prefijo lo completa `automation install`. No puede venir del entorno: el runtime de workflows no
14
+ // expone `process`, así que leerlo de ahí reventaba el archivo entero en su primera línea. Viaja
15
+ // escrito, relativo a la carpeta donde se abre la herramienta, que es el cwd de los agentes.
16
+ const ROOT = '{{OPS_DIR}}'.replace(/\/+$/, '') || '.'
17
+ // `/integration-sync jira` o `{"provider": "jira"}`: sin entorno, el argumento es la única entrada.
18
+ const input = typeof args === 'string' ? { provider: args } : (args || {})
19
+ const REQUESTED = String(input.provider || '').trim()
18
20
  const RESULT = {
19
21
  type: 'object', additionalProperties: false, required: ['passed', 'provider', 'details'],
20
22
  properties: {
@@ -26,7 +28,7 @@ const RESULT = {
26
28
  phase('Preflight')
27
29
  const result = await agent(
28
30
  `Read ${ROOT}/integrations/README.md, ${ROOT}/integrations/config.json and ${ROOT}/planning/PROTOCOL.md. ` +
29
- `Resolve provider from OPS_INTEGRATION_PROVIDER=${JSON.stringify(REQUESTED)}; if empty, continue only when exactly ` +
31
+ `The requested provider is ${JSON.stringify(REQUESTED)}; if empty, continue only when exactly ` +
30
32
  `one provider is enabled. Run "node tools/ops.js integration check ${ROOT} <provider>" and read its exit code. ` +
31
33
  `Do not edit config and do not call a remote write operation.\n\n` +
32
34
  `If green, enter Sync and run "node tools/ops.js integration sync ${ROOT} <provider>". The registered adapter owns ` +
@@ -15,10 +15,10 @@ export const meta = {
15
15
  ],
16
16
  }
17
17
 
18
- // El prefijo lo completa `automation install`: en modo sidecar la herramienta se abre en la carpeta
19
- // de la compañía y la raíz ops es uno de sus hijos, no la carpeta misma.
20
- const ROOT = (process.env.OPS_ROOT
21
- || `${process.env.CLAUDE_PROJECT_DIR || '.'}/{{OPS_DIR}}`).replace(/\/+$/, '')
18
+ // El prefijo lo completa `automation install`. No puede venir del entorno: el runtime de workflows no
19
+ // expone `process`, así que leerlo de ahí reventaba el archivo entero en su primera línea. Viaja
20
+ // escrito, relativo a la carpeta donde se abre la herramienta, que es el cwd de los agentes.
21
+ const ROOT = '{{OPS_DIR}}'.replace(/\/+$/, '') || '.'
22
22
  const P = `${ROOT}/planning`
23
23
  const ROADMAP = `${P}/roadmap`
24
24
  const HUMAN = `${P}/HUMAN_ACTIONS.md`
@@ -34,9 +34,9 @@ const REPORTS = `${P}/reports`
34
34
  // El prefijo se toma como candidato y se confirma más abajo contra los equipos que existen: si no es
35
35
  // uno, el texto completo era la intención y nadie tuvo que aprenderse una sintaxis.
36
36
  const input = typeof args === 'string' ? { intent: args } : (args || {})
37
- const raw = String(input.intent || process.env.OPS_INTENT || '').trim()
37
+ const raw = String(input.intent || '').trim()
38
38
  const prefix = raw.match(/^([a-z][a-z0-9-]*)\s*:\s*(.+)$/s)
39
- const CANDIDATE = String(input.team || process.env.OPS_TEAM || (prefix ? prefix[1] : '') || 'product-development')
39
+ const CANDIDATE = String(input.team || (prefix ? prefix[1] : '') || 'product-development')
40
40
  const INTENT = (input.team || !prefix ? raw : prefix[2]).trim()
41
41
 
42
42
  const MANIFEST = {
@@ -100,7 +100,7 @@ const resolved = await agent(
100
100
  } }, label: 'team-resolve' },
101
101
  )
102
102
  if (!resolved) return stop('teams-unavailable', 'no se pudo listar los equipos')
103
- if (!resolved.exists && (input.team || process.env.OPS_TEAM)) {
103
+ if (!resolved.exists && input.team) {
104
104
  return stop('equipo-inexistente', `${CANDIDATE} no existe. Disponibles: ${resolved.teams.join(', ')}`)
105
105
  }
106
106
  // El prefijo era parte de la intención, no un equipo: se recompone y sigue con el equipo por defecto.
@@ -182,6 +182,15 @@ function installRoleSkills(root, runner, output) {
182
182
  return roles.length
183
183
  }
184
184
 
185
+ // Runners que además de los archivos necesitan un registro propio para que el wiring cuente. Copiar
186
+ // y quedarse ahí deja un plugin inerte: los archivos están, `doctor` da verde y nada se ejecuta.
187
+ function activated(runner) {
188
+ if (!runner.activation) return true
189
+ const result = spawnSync(runner.command, runner.activation.verify, { encoding: 'utf8' })
190
+ if (result.status !== 0) return null
191
+ return `${result.stdout || ''}`.includes(runner.activation.expect)
192
+ }
193
+
185
194
  function hasHooks(config) {
186
195
  if (config.hooks && Object.keys(config.hooks).length) return true
187
196
  const events = [
@@ -423,6 +432,10 @@ function doctor(root, name, output = console) {
423
432
  ['-c', 'command -v "$1" >/dev/null 2>&1', 'runner-doctor', runner.command],
424
433
  )
425
434
  if (executable.status !== 0) warnings.push(`${runner.command}: CLI no encontrado en PATH`)
435
+ else if (activated(runner) === false) {
436
+ warnings.push(`el plugin está copiado pero no registrado, así que no se ejecuta. `
437
+ + `Corré desde ${paths.install}: ${runner.activation.hint}`)
438
+ }
426
439
  for (const warning of warnings) output.warn(`⚠ ${name}: ${warning}`)
427
440
  for (const error of errors) output.error(`✗ ${name}: ${error}`)
428
441
  return { runner, errors, warnings }
@@ -516,6 +529,10 @@ function install(root, name, output = console, options = {}) {
516
529
  }
517
530
  }
518
531
  installRoleSkills(root, runner, output)
532
+ if (runner.activation && activated(runner) !== true) {
533
+ output.log(` ${name}: falta registrarlo para que corra. Desde ${paths.install}:`)
534
+ output.log(` ${runner.activation.hint}`)
535
+ }
519
536
  M.write(root, undefined, entregado)
520
537
  return runner
521
538
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ingeniomaps/cauce",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Sistema portable de planificación y ejecución verificable para cualquier proyecto",
5
5
  "type": "commonjs",
6
6
  "bin": {