@ingeniomaps/cauce 0.35.0 → 0.37.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
@@ -14,6 +14,36 @@ desde este repositorio no va, porque el que lee no puede actuar sobre eso. Cuand
14
14
  unas pocas líneas casi siempre es porque cuenta cómo se descubrió el problema o por qué se eligió el
15
15
  diseño — eso vive en el commit y en el código.
16
16
 
17
+ ## [0.37.0] - 2026-08-19
18
+
19
+ ### Cambiado
20
+
21
+ - **El arranque deja de completar una dimensión que nadie preguntó.** Al llegar al tope de tres
22
+ preguntas puede quedar una afuera —quién lo usa, qué está muerto, qué externo hay—, y una corrida real
23
+ la escribió igual, deducida del README y de las respuestas a las otras. Todo plausible, nada dicho por
24
+ una persona, y sin marca: se leía con el mismo peso que lo que alguien contestó. Ahora esa dimensión
25
+ queda «Por definir» con su pregunta en el INBOX, y lo que se deduce de otra respuesta va marcado
26
+ `(supuesto)` por plausible que sea. Rige en el recorrido ejecutable y en los tres runners que operan el
27
+ arranque leyendo instrucciones.
28
+
29
+ ## [0.36.0] - 2026-08-19
30
+
31
+ ### Corregido
32
+
33
+ - **`automation doctor` ejecuta el puente del runner en vez de darlo por bueno.** Instalado no es
34
+ operativo: un puente que el runner no puede lanzar falla cerrado y niega cada llamada a herramienta,
35
+ y `doctor` decía «adaptador operativo» porque los archivos estaban en su lugar. Ahora lo invoca como
36
+ lo hace el runner —una vez desde la raíz del workspace y otra desde otra carpeta, porque una ruta
37
+ relativa en su configuración deja de resolver cuando el cwd no es el que suponía— y un puente que no
38
+ responde es error, no advertencia.
39
+
40
+ ### Cambiado
41
+
42
+ - **La lista de salida termina en el chequeo más barato: `ops onboard`.** Si vuelve a ofrecer la
43
+ pregunta de apertura, la instancia sigue vacía y no hay nada que informar. Una corrida real entregó
44
+ cuatro puntos en pasado —«registrado», «documentado», «creada la primera épica»— sobre archivos que en
45
+ el disco seguían siendo el molde. Estar bloqueado es un resultado legítimo; narrarlo como entrega, no.
46
+
17
47
  ## [0.35.0] - 2026-08-19
18
48
 
19
49
  ### Añadido
@@ -60,5 +60,15 @@ falló los cinco puntos sin darse cuenta, y todos del mismo lado —lo que no pr
60
60
  no te corresponde se perdió en vez de quedar escrito para alguien.
61
61
  5. **`ops` no es un servicio del producto.** No va en el mapa real: es la instancia desde la que trabajás.
62
62
 
63
+ 6. **Ninguna dimensión se completa sin haberla preguntado.** Si llegaste al tope de preguntas y una
64
+ quedó afuera —quién lo usa, qué está muerto, qué externo hay— va «Por definir» con su pregunta en
65
+ `{{OPS_DIR}}planning/INBOX.md`, aunque puedas imaginar la respuesta. Y lo que deducís de otra
66
+ respuesta va marcado `(supuesto)`, por plausible que sea: sin la marca se lee con el mismo peso que
67
+ lo que la persona dijo, y nadie va a volver a preguntarlo.
68
+ 7. **Corré `node {{OPS_DIR}}tools/ops.js onboard`.** Si te vuelve a ofrecer la pregunta de apertura, la
69
+ instancia sigue vacía: no escribiste nada, y no hay nada que informar. Una corrida real entregó un
70
+ resumen en pasado —«registrado», «documentado», «creada la primera épica»— sobre archivos que en el
71
+ disco seguían siendo el molde. Estar bloqueado es un resultado legítimo; narrarlo como entrega, no.
72
+
63
73
  Recién ahí, `node {{OPS_DIR}}tools/ops.js check planning`. Si sale con advertencias, leelas: son
64
74
  exactamente estas cosas.
@@ -57,7 +57,11 @@ Antes de darlo por terminado, comprobá cinco cosas mirando el disco: preguntast
57
57
  formulario; la épica se llama `epic-NNN-<slug>.md` con `status: open` —`epic-001.md` no lo lee nadie—;
58
58
  las secciones de `{{OPS_DIR}}organization/` siguen siendo las del molde y lo tuyo se agregó adentro;
59
59
  `{{OPS_DIR}}planning/HUMAN_ACTIONS.md` tiene una fila por credencial, por externo y por la autoridad de
60
- push; y `ops` no figura como servicio del producto en el mapa.
60
+ push; y `ops` no figura como servicio del producto en el mapa. una dimensión que no
61
+ llegaste a preguntar va «Por definir» con su pregunta en `{{OPS_DIR}}planning/INBOX.md` en vez de
62
+ completarse deduciéndola, y lo que deducís de otra respuesta va marcado `(supuesto)`. Cerrá corriendo
63
+ `node {{OPS_DIR}}tools/ops.js onboard`: si te vuelve a ofrecer la pregunta de apertura, no escribiste
64
+ nada y no hay nada que informar. Estar bloqueado es un resultado legítimo; narrarlo como entrega, no.
61
65
 
62
66
  ## Los equipos
63
67
 
@@ -50,7 +50,11 @@ Antes de darlo por terminado, comprobá cinco cosas mirando el disco: preguntast
50
50
  formulario; la épica se llama `epic-NNN-<slug>.md` con `status: open` —`epic-001.md` no lo lee nadie—;
51
51
  las secciones de `{{OPS_DIR}}organization/` siguen siendo las del molde y lo tuyo se agregó adentro;
52
52
  `{{OPS_DIR}}planning/HUMAN_ACTIONS.md` tiene una fila por credencial, por externo y por la autoridad de
53
- push; y `ops` no figura como servicio del producto en el mapa.
53
+ push; y `ops` no figura como servicio del producto en el mapa. una dimensión que no
54
+ llegaste a preguntar va «Por definir» con su pregunta en `{{OPS_DIR}}planning/INBOX.md` en vez de
55
+ completarse deduciéndola, y lo que deducís de otra respuesta va marcado `(supuesto)`. Cerrá corriendo
56
+ `node {{OPS_DIR}}tools/ops.js onboard`: si te vuelve a ofrecer la pregunta de apertura, no escribiste
57
+ nada y no hay nada que informar. Estar bloqueado es un resultado legítimo; narrarlo como entrega, no.
54
58
 
55
59
  Nunca omitas aprobaciones, inventes credenciales, escribas remoto, hagas push/deploy o promociones
56
60
  trabajo desde INBOX.
@@ -165,7 +165,11 @@ const drafted = await agent(
165
165
  `${BASE}\n\n${EVIDENCE}\n\nEscribí de una sola pasada el contexto de esta instancia, reemplazando el ` +
166
166
  `molde en vez de comentarlo:\n` +
167
167
  `1. ${ORG}/company.md y ${ORG}/product.md: lo que la persona contó y los nombres del repositorio ` +
168
- `permiten afirmar. Lo que nada sostiene queda "Por definir" y su pregunta va a openQuestions. No des ` +
168
+ `permiten afirmar. Lo que nada sostiene queda "Por definir" y su pregunta va a openQuestions. Una ` +
169
+ `dimensión que no llegaste a preguntar no se completa deduciéndola: queda "Por definir" con su ` +
170
+ `pregunta en openQuestions, aunque puedas imaginar la respuesta. Y lo que sí deducís de otra ` +
171
+ `respuesta va marcado "(supuesto)", por plausible que sea: sin la marca se lee con el mismo peso que ` +
172
+ `lo que alguien dijo. No des ` +
169
173
  `por sentado que el proyecto vende algo: puede sostenerse con donaciones, presupuesto interno o ` +
170
174
  `trabajo voluntario, y una sección que no aplica se dice, no se completa con algo plausible.\n` +
171
175
  `2. La sección "## Mapa real" de ${ROOT}/AGENTS.md: una entrada por servicio con su ruta, su runtime y ` +
@@ -377,6 +377,46 @@ function legacyGuardWiring(config) {
377
377
  return superseded
378
378
  }
379
379
 
380
+ // Ejecuta el puente del runner tal como él lo invoca, y desde otra carpeta. Instalado no es lo mismo que
381
+ // operativo: un bridge que el runner no puede lanzar —porque su ruta es relativa y el cwd es otro, o
382
+ // porque falta node— falla cerrado y niega cada llamada a herramienta. `doctor` veía los archivos en su
383
+ // lugar y decía «operativo» mientras nada respondía.
384
+ function probeBridge(paths, runner) {
385
+ const bridge = (runner.artifacts || []).find((item) => item.target.endsWith('hook.js'))
386
+ if (!bridge) return []
387
+ const script = path.resolve(paths.install, bridge.target)
388
+ if (!fs.existsSync(script)) return []
389
+ let config = {}
390
+ try { config = JSON.parse(fs.readFileSync(paths.configTarget, 'utf8')) } catch { return [] }
391
+ const eventos = [...new Set(
392
+ JSON.stringify(config).match(/hook\.js ([a-z-]+)/g) || [],
393
+ )].map((entrada) => entrada.split(' ')[1])
394
+ if (!eventos.length) return []
395
+
396
+ const problemas = []
397
+ // Desde la raíz y desde una carpeta de adentro: si el runner lanza el hook con otro cwd, la ruta
398
+ // relativa de su configuración deja de resolver y eso hay que verlo acá, no en la primera sesión.
399
+ const desde = [paths.install, path.dirname(script)]
400
+ for (const evento of eventos) {
401
+ for (const cwd of desde) {
402
+ const payload = JSON.stringify({ toolCall: { args: { CommandLine: 'ls', Cwd: paths.install } } })
403
+ const result = spawnSync(process.execPath, [script, evento], { cwd, input: payload, encoding: 'utf8' })
404
+ let respuesta = {}
405
+ try { respuesta = JSON.parse((result.stdout || '').trim()) } catch { respuesta = {} }
406
+ // Cada evento tiene su respuesta sana: `stop` cierra la sesión —eso es funcionar— y el resto deja
407
+ // pasar. El puente falla cerrado, así que `deny` en una llamada inocua es que algo se rompió antes
408
+ // de poder juzgarla, y `continue` es el camino de error del propio `stop`.
409
+ const sana = evento === 'stop' ? 'stop' : 'allow'
410
+ if (respuesta.decision === sana) continue
411
+ const salida = (result.stderr || 'sin respuesta').trim().split('\n')[0]
412
+ const motivo = respuesta.reason
413
+ || (respuesta.decision ? `respondió ${respuesta.decision}` : salida)
414
+ problemas.push(`${bridge.target} ${evento} desde ${path.basename(cwd)}/: ${motivo}`)
415
+ }
416
+ }
417
+ return problemas
418
+ }
419
+
380
420
  function doctor(root, name, output = console) {
381
421
  const runner = runnerManifest(root, name)
382
422
  const paths = runnerPaths(root, name, runner)
@@ -441,6 +481,9 @@ function doctor(root, name, output = console) {
441
481
  warnings.push(`${stale.length} cargo(s) desactualizados en ${runner.roleSkills}: reinstalá el adaptador`)
442
482
  }
443
483
  }
484
+ // Un puente que no responde niega cada llamada del runner: es error, no advertencia.
485
+ for (const problema of probeBridge(paths, runner)) errors.push(problema)
486
+
444
487
  const executable = spawnSync(
445
488
  'sh',
446
489
  ['-c', 'command -v "$1" >/dev/null 2>&1', 'runner-doctor', runner.command],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ingeniomaps/cauce",
3
- "version": "0.35.0",
3
+ "version": "0.37.0",
4
4
  "description": "Sistema portable de planificación y ejecución verificable para cualquier proyecto",
5
5
  "keywords": [
6
6
  "planning",