@rlabs-cl/arketum 0.0.0-stage → 1.0.1
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 +140 -0
- package/LICENSE +42 -0
- package/README.md +67 -2
- package/THIRD-PARTY-NOTICES +2428 -0
- package/catalogo-de-ejemplo/agentes.yaml +11 -0
- package/catalogo-de-ejemplo/arquetipos/ajuste.yaml +54 -0
- package/catalogo-de-ejemplo/arquetipos/arquetipo-autor.yaml +72 -0
- package/catalogo-de-ejemplo/arquetipos/arquitectura-de-sistema.yaml +72 -0
- package/catalogo-de-ejemplo/arquetipos/despliegue-compose.yaml +104 -0
- package/catalogo-de-ejemplo/arquetipos/digestion.yaml +97 -0
- package/catalogo-de-ejemplo/arquetipos/documento-academico.yaml +131 -0
- package/catalogo-de-ejemplo/arquetipos/inventario-funcional.yaml +42 -0
- package/catalogo-de-ejemplo/arquetipos/levantamiento-de-infraestructura.yaml +117 -0
- package/catalogo-de-ejemplo/arquetipos/plan-de-migracion.yaml +40 -0
- package/catalogo-de-ejemplo/arquetipos/prd.yaml +62 -0
- package/catalogo-de-ejemplo/arquetipos/radio-de-alcance.yaml +141 -0
- package/catalogo-de-ejemplo/arquetipos/rca.yaml +68 -0
- package/catalogo-de-ejemplo/arquetipos/servicio-con-integracion.yaml +154 -0
- package/catalogo-de-ejemplo/carriles/ajuste.yaml +14 -0
- package/catalogo-de-ejemplo/carriles/arquetipo.yaml +13 -0
- package/catalogo-de-ejemplo/carriles/comprobacion.yaml +23 -0
- package/catalogo-de-ejemplo/carriles/correccion.yaml +25 -0
- package/catalogo-de-ejemplo/carriles/despliegue.yaml +36 -0
- package/catalogo-de-ejemplo/carriles/digestion.yaml +14 -0
- package/catalogo-de-ejemplo/carriles/funcionalidad.yaml +34 -0
- package/catalogo-de-ejemplo/carriles/migracion.yaml +27 -0
- package/catalogo-de-ejemplo/carriles/nuevo.yaml +30 -0
- package/catalogo-de-ejemplo/formas/aplicacion-por-capas.yaml +185 -0
- package/catalogo-de-ejemplo/formas/juego-terminal.yaml +161 -0
- package/catalogo-de-ejemplo/formas/monorepo-de-aplicaciones.yaml +207 -0
- package/catalogo-de-ejemplo/incluido.yaml +3 -0
- package/catalogo-de-ejemplo/stacks/go/e2e-terminal/e2e_http.py +36 -0
- package/catalogo-de-ejemplo/stacks/go/e2e-terminal/pytest.ini +5 -0
- package/catalogo-de-ejemplo/stacks/go/e2e-terminal/requirements.txt +2 -0
- package/catalogo-de-ejemplo/stacks/go/e2e-terminal/terminal_e2e.py +112 -0
- package/catalogo-de-ejemplo/stacks/go/e2e-terminal/terminal_prueba.py +118 -0
- package/catalogo-de-ejemplo/stacks/go/suelo-aplicacion-por-capas/requirements.txt +1 -0
- package/catalogo-de-ejemplo/stacks/go/suelo-aplicacion-por-capas/suelo.py +102 -0
- package/catalogo-de-ejemplo/stacks/go/suelo-aplicacion-por-capas/terminal_prueba.py +118 -0
- package/catalogo-de-ejemplo/stacks/go/suelo-juego-terminal/requirements.txt +1 -0
- package/catalogo-de-ejemplo/stacks/go/suelo-juego-terminal/suelo.py +86 -0
- package/catalogo-de-ejemplo/stacks/go/suelo-juego-terminal/terminal_prueba.py +118 -0
- package/catalogo-de-ejemplo/stacks/go.yaml +74 -0
- package/catalogo-de-ejemplo/stacks/python/e2e-terminal/e2e_http.py +36 -0
- package/catalogo-de-ejemplo/stacks/python/e2e-terminal/pytest.ini +5 -0
- package/catalogo-de-ejemplo/stacks/python/e2e-terminal/requirements.txt +2 -0
- package/catalogo-de-ejemplo/stacks/python/e2e-terminal/terminal_e2e.py +112 -0
- package/catalogo-de-ejemplo/stacks/python/e2e-terminal/terminal_prueba.py +118 -0
- package/catalogo-de-ejemplo/stacks/python/suelo-aplicacion-por-capas/requirements.txt +1 -0
- package/catalogo-de-ejemplo/stacks/python/suelo-aplicacion-por-capas/suelo.py +102 -0
- package/catalogo-de-ejemplo/stacks/python/suelo-aplicacion-por-capas/terminal_prueba.py +118 -0
- package/catalogo-de-ejemplo/stacks/python/suelo-juego-terminal/requirements.txt +1 -0
- package/catalogo-de-ejemplo/stacks/python/suelo-juego-terminal/suelo.py +86 -0
- package/catalogo-de-ejemplo/stacks/python/suelo-juego-terminal/terminal_prueba.py +118 -0
- package/catalogo-de-ejemplo/stacks/python.yaml +167 -0
- package/catalogo-de-ejemplo/stacks/typescript/e2e-node/app.mjs +182 -0
- package/catalogo-de-ejemplo/stacks/typescript/e2e-node/requirements.txt +1 -0
- package/catalogo-de-ejemplo/stacks/typescript/e2e-node/terminal_prueba.py +118 -0
- package/catalogo-de-ejemplo/stacks/typescript/e2e-node/terminal_puente.py +51 -0
- package/catalogo-de-ejemplo/stacks/typescript/e2e-node/vitest.config.mjs +12 -0
- package/catalogo-de-ejemplo/stacks/typescript/suelo-aplicacion-por-capas/requirements.txt +1 -0
- package/catalogo-de-ejemplo/stacks/typescript/suelo-aplicacion-por-capas/suelo.py +102 -0
- package/catalogo-de-ejemplo/stacks/typescript/suelo-aplicacion-por-capas/terminal_prueba.py +118 -0
- package/catalogo-de-ejemplo/stacks/typescript/suelo-juego-terminal/requirements.txt +1 -0
- package/catalogo-de-ejemplo/stacks/typescript/suelo-juego-terminal/suelo.py +86 -0
- package/catalogo-de-ejemplo/stacks/typescript/suelo-juego-terminal/terminal_prueba.py +118 -0
- package/catalogo-de-ejemplo/stacks/typescript.yaml +88 -0
- package/dist/mcp/arketum.js +3 -0
- package/dist/mcp/ci-cli.js +2 -0
- package/dist/mcp/cli.js +2 -0
- package/dist/mcp/comun-ZEXDDERM.js +1 -0
- package/dist/mcp/comun-ZTEHRDHC.js +1 -0
- package/dist/mcp/panel-cli.js +2 -0
- package/dist/mcp/telemetria-cli.js +1 -0
- package/package.json +33 -4
- package/server.json +15 -0
- package/telemetria.json +27 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TERMINAL DE PRUEBA (fijación del catálogo de Arketum: se copia tal cual y no se
|
|
3
|
+
edita). Prueba un programa de terminal como lo usaría una persona, en una
|
|
4
|
+
pseudo-terminal emulada con pyte (`python3 -m pip install pyte`).
|
|
5
|
+
|
|
6
|
+
from terminal_prueba import Terminal
|
|
7
|
+
|
|
8
|
+
with Terminal(['sh', 'arrancar.sh'], cwd='.', columnas=80, filas=24) as t:
|
|
9
|
+
t.esperar(2) # deja correr el programa
|
|
10
|
+
t.tecla('ARRIBA') # ARRIBA, ABAJO, IZQUIERDA, DERECHA, ENTER, ESC o un carácter
|
|
11
|
+
t.esperar(0.5)
|
|
12
|
+
texto = t.pantalla() # lo que se ve, una cadena con una línea por fila
|
|
13
|
+
assert t.vivo() # sigue corriendo
|
|
14
|
+
assert 'Traceback' not in texto
|
|
15
|
+
|
|
16
|
+
`t.lineas()` da la lista de filas y `t.codigo` el código de salida cuando termina.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import fcntl, os, pty, select, signal, struct, termios, time
|
|
20
|
+
|
|
21
|
+
import pyte
|
|
22
|
+
|
|
23
|
+
TECLAS = {'ARRIBA': b'\x1b[A', 'ABAJO': b'\x1b[B', 'DERECHA': b'\x1b[C', 'IZQUIERDA': b'\x1b[D', 'ENTER': b'\r', 'ESC': b'\x1b'}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Terminal:
|
|
27
|
+
def __init__(self, comando, cwd='.', columnas=80, filas=24, env=None):
|
|
28
|
+
self._pantalla = pyte.Screen(columnas, filas)
|
|
29
|
+
self._flujo = pyte.ByteStream(self._pantalla)
|
|
30
|
+
pid, fd = pty.fork()
|
|
31
|
+
if pid == 0:
|
|
32
|
+
entorno = dict(os.environ, LANG='en_US.UTF-8', LC_ALL='en_US.UTF-8', TERM='xterm-256color', COLUMNS=str(columnas), LINES=str(filas))
|
|
33
|
+
entorno.update(env or {})
|
|
34
|
+
os.chdir(cwd)
|
|
35
|
+
os.execvpe(comando[0], comando, entorno)
|
|
36
|
+
fcntl.ioctl(fd, termios.TIOCSWINSZ, struct.pack('HHHH', filas, columnas, 0, 0))
|
|
37
|
+
self.pid, self.fd, self._vivo, self.codigo = pid, fd, True, None
|
|
38
|
+
|
|
39
|
+
def __enter__(self):
|
|
40
|
+
return self
|
|
41
|
+
|
|
42
|
+
def __exit__(self, *_):
|
|
43
|
+
self.cerrar()
|
|
44
|
+
|
|
45
|
+
def esperar(self, segundos):
|
|
46
|
+
fin = time.time() + segundos
|
|
47
|
+
while time.time() < fin:
|
|
48
|
+
r, _, _ = select.select([self.fd], [], [], 0.05)
|
|
49
|
+
if r:
|
|
50
|
+
try:
|
|
51
|
+
datos = os.read(self.fd, 65536)
|
|
52
|
+
except OSError:
|
|
53
|
+
datos = b''
|
|
54
|
+
if datos:
|
|
55
|
+
self._flujo.feed(datos)
|
|
56
|
+
else:
|
|
57
|
+
time.sleep(0.05)
|
|
58
|
+
self._comprobar()
|
|
59
|
+
self._comprobar()
|
|
60
|
+
|
|
61
|
+
def tecla(self, nombre):
|
|
62
|
+
datos = TECLAS.get(nombre, nombre.encode() if isinstance(nombre, str) else nombre)
|
|
63
|
+
# Como un terminal real: si el programa activó el modo de cursor de aplicación (DECCKM, el modo privado 1, que pyte guarda como 1 << 5; curses
|
|
64
|
+
# con keypad), las flechas van como ESC O x en vez de ESC [ x.
|
|
65
|
+
if datos[:2] == b'\x1b[' and len(datos) == 3 and datos[2:] in b'ABCD' and (1 << 5) in self._pantalla.mode:
|
|
66
|
+
datos = b'\x1bO' + datos[2:]
|
|
67
|
+
try:
|
|
68
|
+
os.write(self.fd, datos)
|
|
69
|
+
except OSError:
|
|
70
|
+
pass
|
|
71
|
+
|
|
72
|
+
def pantalla(self):
|
|
73
|
+
return '\n'.join(self._pantalla.display)
|
|
74
|
+
|
|
75
|
+
def lineas(self):
|
|
76
|
+
return list(self._pantalla.display)
|
|
77
|
+
|
|
78
|
+
def pintadas(self):
|
|
79
|
+
"""Cuántas celdas se ven: con carácter, en vídeo inverso o con un fondo distinto del
|
|
80
|
+
dominante (al borrar, pyte rellena con el fondo del cursor: ese no cuenta)."""
|
|
81
|
+
from collections import Counter
|
|
82
|
+
filas, cols = self._pantalla.lines, self._pantalla.columns
|
|
83
|
+
celdas = [self._pantalla.buffer[y][x] for y in range(filas) for x in range(cols)]
|
|
84
|
+
fondo = Counter(c.bg for c in celdas).most_common(1)[0][0]
|
|
85
|
+
return sum(1 for c in celdas if c.data.strip() or c.reverse or c.bg != fondo)
|
|
86
|
+
|
|
87
|
+
def foto(self):
|
|
88
|
+
"""Lo que se ve, con forma: el texto y dónde hay celdas en vídeo inverso o con fondo distinto del dominante."""
|
|
89
|
+
from collections import Counter
|
|
90
|
+
filas, cols = self._pantalla.lines, self._pantalla.columns
|
|
91
|
+
fondo = Counter(self._pantalla.buffer[y][x].bg for y in range(filas) for x in range(cols)).most_common(1)[0][0]
|
|
92
|
+
marcas = tuple((y, x) for y in range(filas) for x in range(cols) if self._pantalla.buffer[y][x].reverse or self._pantalla.buffer[y][x].bg != fondo)
|
|
93
|
+
return (self.pantalla(), marcas)
|
|
94
|
+
|
|
95
|
+
def vivo(self):
|
|
96
|
+
self._comprobar()
|
|
97
|
+
return self._vivo
|
|
98
|
+
|
|
99
|
+
def _comprobar(self):
|
|
100
|
+
if not self._vivo:
|
|
101
|
+
return
|
|
102
|
+
p, estado = os.waitpid(self.pid, os.WNOHANG)
|
|
103
|
+
if p != 0:
|
|
104
|
+
self._vivo = False
|
|
105
|
+
self.codigo = os.waitstatus_to_exitcode(estado)
|
|
106
|
+
|
|
107
|
+
def cerrar(self):
|
|
108
|
+
if self._vivo:
|
|
109
|
+
try:
|
|
110
|
+
os.kill(self.pid, signal.SIGKILL)
|
|
111
|
+
os.waitpid(self.pid, 0)
|
|
112
|
+
except OSError:
|
|
113
|
+
pass
|
|
114
|
+
self._vivo = False
|
|
115
|
+
try:
|
|
116
|
+
os.close(self.fd)
|
|
117
|
+
except OSError:
|
|
118
|
+
pass
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pyte
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
SUELO FIJO de la forma `juego-terminal` (fijación del catálogo de Arketum: se
|
|
4
|
+
copia tal cual en `arketum/fijaciones/suelo/` y no se edita; el cierre compara su
|
|
5
|
+
checksum). Las comprobaciones de uso que no escribe quien construye: que el
|
|
6
|
+
programa vive, no que el juego esté bien.
|
|
7
|
+
|
|
8
|
+
Arranca el artefacto por su contrato de arranque: `sh arrancar.sh` desde su raíz.
|
|
9
|
+
|
|
10
|
+
arranca a 80x24, a los 3 s sigue vivo, pinta algo y sin traza
|
|
11
|
+
se_mueve sin tocar nada, en 2.4 s se ven al menos 5 fotogramas distintos (un juego en tiempo real anima)
|
|
12
|
+
aguanta 8 s más con flechas pulsadas, vivo y sin traza
|
|
13
|
+
sale_q con `q` termina
|
|
14
|
+
pequena a 30x10 no saca traza (avisa o sale limpio)
|
|
15
|
+
|
|
16
|
+
Uso: python3 arketum/fijaciones/suelo/suelo.py <raíz del artefacto> → JSON; código 0 si pasa, 1 si no.
|
|
17
|
+
Necesita `pyte` (`python3 -m pip install -r arketum/fijaciones/suelo/requirements.txt`).
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import faulthandler, json, os, sys
|
|
21
|
+
|
|
22
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
23
|
+
from terminal_prueba import Terminal # noqa: E402
|
|
24
|
+
|
|
25
|
+
ARRANQUE = ['sh', 'arrancar.sh']
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def pintadas(t):
|
|
29
|
+
"""Lo más pintado en unas cuantas muestras: un juego que borra y redibuja puede pillarse a medias."""
|
|
30
|
+
n = 0
|
|
31
|
+
for _ in range(5):
|
|
32
|
+
t.esperar(0.15)
|
|
33
|
+
n = max(n, t.pintadas())
|
|
34
|
+
return n
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def evaluar(raiz):
|
|
38
|
+
if not os.path.isfile(os.path.join(raiz, 'arrancar.sh')):
|
|
39
|
+
return {'ok': False, 'fallo': 'no hay `arrancar.sh` en la raíz del artefacto: es su contrato de arranque', 'pantalla': ''}
|
|
40
|
+
r = {'comando': ' '.join(ARRANQUE)}
|
|
41
|
+
with Terminal(ARRANQUE, cwd=raiz, columnas=80, filas=24) as t:
|
|
42
|
+
t.tecla('ENTER') # por si hay una pantalla de inicio que espera una tecla
|
|
43
|
+
t.esperar(3)
|
|
44
|
+
n = pintadas(t)
|
|
45
|
+
texto = t.pantalla()
|
|
46
|
+
r['arranca'] = t.vivo() and 'Traceback' not in texto and n >= 10
|
|
47
|
+
if not r['arranca']:
|
|
48
|
+
return {**r, 'ok': False, 'fallo': 'a 80x24 no arranca: muere, saca una traza o no pinta nada', 'pantalla': texto}
|
|
49
|
+
# Movimiento: muchos fotogramas distintos. Un juego que borra y redibuja parpadea entre dos
|
|
50
|
+
# estados (completo y vacío), y el parpadeo no es movimiento.
|
|
51
|
+
fotos = set()
|
|
52
|
+
for _ in range(12):
|
|
53
|
+
t.esperar(0.2)
|
|
54
|
+
fotos.add(t.foto())
|
|
55
|
+
r['se_mueve'] = len(fotos) >= 5
|
|
56
|
+
if not r['se_mueve']:
|
|
57
|
+
return {**r, 'ok': False, 'fallo': 'la pantalla no cambia sola: no hay nada en movimiento', 'pantalla': t.pantalla()}
|
|
58
|
+
for i in range(32):
|
|
59
|
+
t.tecla('ARRIBA' if (i // 4) % 2 else 'ABAJO')
|
|
60
|
+
t.esperar(0.25)
|
|
61
|
+
if not t.vivo():
|
|
62
|
+
break
|
|
63
|
+
texto = t.pantalla()
|
|
64
|
+
r['aguanta'] = t.vivo() and 'Traceback' not in texto
|
|
65
|
+
if not r['aguanta']:
|
|
66
|
+
return {**r, 'ok': False, 'fallo': 'jugando 8 s con flechas, el programa muere o saca una traza', 'pantalla': texto}
|
|
67
|
+
t.tecla('q')
|
|
68
|
+
t.esperar(3)
|
|
69
|
+
r['sale_q'] = not t.vivo()
|
|
70
|
+
if not r['sale_q']:
|
|
71
|
+
return {**r, 'ok': False, 'fallo': 'con `q` el programa no termina', 'pantalla': t.pantalla()}
|
|
72
|
+
with Terminal(ARRANQUE, cwd=raiz, columnas=30, filas=10) as t:
|
|
73
|
+
t.esperar(2.5)
|
|
74
|
+
texto = t.pantalla()
|
|
75
|
+
r['pequena'] = 'Traceback' not in texto and (t.vivo() or t.codigo == 0)
|
|
76
|
+
if not r['pequena']:
|
|
77
|
+
return {**r, 'ok': False, 'fallo': 'a 30x10 saca una traza o sale con error en vez de avisar', 'pantalla': texto}
|
|
78
|
+
return {**r, 'ok': True}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
if __name__ == '__main__':
|
|
82
|
+
# Un suelo nunca se queda colgado: a los 150 s escribe dónde estaba y termina con error (1).
|
|
83
|
+
faulthandler.dump_traceback_later(150, exit=True)
|
|
84
|
+
resultado = evaluar(os.path.abspath(sys.argv[1] if len(sys.argv) > 1 else '.'))
|
|
85
|
+
print(json.dumps(resultado, ensure_ascii=False, indent=1))
|
|
86
|
+
sys.exit(0 if resultado['ok'] else 1)
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TERMINAL DE PRUEBA (fijación del catálogo de Arketum: se copia tal cual y no se
|
|
3
|
+
edita). Prueba un programa de terminal como lo usaría una persona, en una
|
|
4
|
+
pseudo-terminal emulada con pyte (`python3 -m pip install pyte`).
|
|
5
|
+
|
|
6
|
+
from terminal_prueba import Terminal
|
|
7
|
+
|
|
8
|
+
with Terminal(['sh', 'arrancar.sh'], cwd='.', columnas=80, filas=24) as t:
|
|
9
|
+
t.esperar(2) # deja correr el programa
|
|
10
|
+
t.tecla('ARRIBA') # ARRIBA, ABAJO, IZQUIERDA, DERECHA, ENTER, ESC o un carácter
|
|
11
|
+
t.esperar(0.5)
|
|
12
|
+
texto = t.pantalla() # lo que se ve, una cadena con una línea por fila
|
|
13
|
+
assert t.vivo() # sigue corriendo
|
|
14
|
+
assert 'Traceback' not in texto
|
|
15
|
+
|
|
16
|
+
`t.lineas()` da la lista de filas y `t.codigo` el código de salida cuando termina.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import fcntl, os, pty, select, signal, struct, termios, time
|
|
20
|
+
|
|
21
|
+
import pyte
|
|
22
|
+
|
|
23
|
+
TECLAS = {'ARRIBA': b'\x1b[A', 'ABAJO': b'\x1b[B', 'DERECHA': b'\x1b[C', 'IZQUIERDA': b'\x1b[D', 'ENTER': b'\r', 'ESC': b'\x1b'}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Terminal:
|
|
27
|
+
def __init__(self, comando, cwd='.', columnas=80, filas=24, env=None):
|
|
28
|
+
self._pantalla = pyte.Screen(columnas, filas)
|
|
29
|
+
self._flujo = pyte.ByteStream(self._pantalla)
|
|
30
|
+
pid, fd = pty.fork()
|
|
31
|
+
if pid == 0:
|
|
32
|
+
entorno = dict(os.environ, LANG='en_US.UTF-8', LC_ALL='en_US.UTF-8', TERM='xterm-256color', COLUMNS=str(columnas), LINES=str(filas))
|
|
33
|
+
entorno.update(env or {})
|
|
34
|
+
os.chdir(cwd)
|
|
35
|
+
os.execvpe(comando[0], comando, entorno)
|
|
36
|
+
fcntl.ioctl(fd, termios.TIOCSWINSZ, struct.pack('HHHH', filas, columnas, 0, 0))
|
|
37
|
+
self.pid, self.fd, self._vivo, self.codigo = pid, fd, True, None
|
|
38
|
+
|
|
39
|
+
def __enter__(self):
|
|
40
|
+
return self
|
|
41
|
+
|
|
42
|
+
def __exit__(self, *_):
|
|
43
|
+
self.cerrar()
|
|
44
|
+
|
|
45
|
+
def esperar(self, segundos):
|
|
46
|
+
fin = time.time() + segundos
|
|
47
|
+
while time.time() < fin:
|
|
48
|
+
r, _, _ = select.select([self.fd], [], [], 0.05)
|
|
49
|
+
if r:
|
|
50
|
+
try:
|
|
51
|
+
datos = os.read(self.fd, 65536)
|
|
52
|
+
except OSError:
|
|
53
|
+
datos = b''
|
|
54
|
+
if datos:
|
|
55
|
+
self._flujo.feed(datos)
|
|
56
|
+
else:
|
|
57
|
+
time.sleep(0.05)
|
|
58
|
+
self._comprobar()
|
|
59
|
+
self._comprobar()
|
|
60
|
+
|
|
61
|
+
def tecla(self, nombre):
|
|
62
|
+
datos = TECLAS.get(nombre, nombre.encode() if isinstance(nombre, str) else nombre)
|
|
63
|
+
# Como un terminal real: si el programa activó el modo de cursor de aplicación (DECCKM, el modo privado 1, que pyte guarda como 1 << 5; curses
|
|
64
|
+
# con keypad), las flechas van como ESC O x en vez de ESC [ x.
|
|
65
|
+
if datos[:2] == b'\x1b[' and len(datos) == 3 and datos[2:] in b'ABCD' and (1 << 5) in self._pantalla.mode:
|
|
66
|
+
datos = b'\x1bO' + datos[2:]
|
|
67
|
+
try:
|
|
68
|
+
os.write(self.fd, datos)
|
|
69
|
+
except OSError:
|
|
70
|
+
pass
|
|
71
|
+
|
|
72
|
+
def pantalla(self):
|
|
73
|
+
return '\n'.join(self._pantalla.display)
|
|
74
|
+
|
|
75
|
+
def lineas(self):
|
|
76
|
+
return list(self._pantalla.display)
|
|
77
|
+
|
|
78
|
+
def pintadas(self):
|
|
79
|
+
"""Cuántas celdas se ven: con carácter, en vídeo inverso o con un fondo distinto del
|
|
80
|
+
dominante (al borrar, pyte rellena con el fondo del cursor: ese no cuenta)."""
|
|
81
|
+
from collections import Counter
|
|
82
|
+
filas, cols = self._pantalla.lines, self._pantalla.columns
|
|
83
|
+
celdas = [self._pantalla.buffer[y][x] for y in range(filas) for x in range(cols)]
|
|
84
|
+
fondo = Counter(c.bg for c in celdas).most_common(1)[0][0]
|
|
85
|
+
return sum(1 for c in celdas if c.data.strip() or c.reverse or c.bg != fondo)
|
|
86
|
+
|
|
87
|
+
def foto(self):
|
|
88
|
+
"""Lo que se ve, con forma: el texto y dónde hay celdas en vídeo inverso o con fondo distinto del dominante."""
|
|
89
|
+
from collections import Counter
|
|
90
|
+
filas, cols = self._pantalla.lines, self._pantalla.columns
|
|
91
|
+
fondo = Counter(self._pantalla.buffer[y][x].bg for y in range(filas) for x in range(cols)).most_common(1)[0][0]
|
|
92
|
+
marcas = tuple((y, x) for y in range(filas) for x in range(cols) if self._pantalla.buffer[y][x].reverse or self._pantalla.buffer[y][x].bg != fondo)
|
|
93
|
+
return (self.pantalla(), marcas)
|
|
94
|
+
|
|
95
|
+
def vivo(self):
|
|
96
|
+
self._comprobar()
|
|
97
|
+
return self._vivo
|
|
98
|
+
|
|
99
|
+
def _comprobar(self):
|
|
100
|
+
if not self._vivo:
|
|
101
|
+
return
|
|
102
|
+
p, estado = os.waitpid(self.pid, os.WNOHANG)
|
|
103
|
+
if p != 0:
|
|
104
|
+
self._vivo = False
|
|
105
|
+
self.codigo = os.waitstatus_to_exitcode(estado)
|
|
106
|
+
|
|
107
|
+
def cerrar(self):
|
|
108
|
+
if self._vivo:
|
|
109
|
+
try:
|
|
110
|
+
os.kill(self.pid, signal.SIGKILL)
|
|
111
|
+
os.waitpid(self.pid, 0)
|
|
112
|
+
except OSError:
|
|
113
|
+
pass
|
|
114
|
+
self._vivo = False
|
|
115
|
+
try:
|
|
116
|
+
os.close(self.fd)
|
|
117
|
+
except OSError:
|
|
118
|
+
pass
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Stack: TypeScript, con Node y vitest.
|
|
2
|
+
#
|
|
3
|
+
# Cambios:
|
|
4
|
+
# - 1.1.0: `tsconfig.json`, `package-lock.json` y `README.md` con el módulo;
|
|
5
|
+
# los estáticos de la interfaz, también en subcarpetas; las carpetas generadas.
|
|
6
|
+
# - 1.2.0: las fijaciones de `juego-terminal` y de `aplicacion-por-capas` (los suelos por terminal y la
|
|
7
|
+
# ayuda e2e para vitest, con un puente de terminal en Python), sus comandos y `arrancar.sh` como
|
|
8
|
+
# arranque, el contrato de arranque de las formas; lo que genera Python.
|
|
9
|
+
# - 1.3.0: la ubicación `configura-pruebas` (`vitest.config.*`,
|
|
10
|
+
# `vitest.workspace.*`, `vite.config.*`): lo que el cierre enseña cuando
|
|
11
|
+
# cambia, porque puede saltarse pruebas sin tocarlas. Antes lo sabía Arketum
|
|
12
|
+
# por el nombre; ahora lo dice el stack. TRANSICIÓN: la huella del stack y
|
|
13
|
+
# la del efectivo cambian; los descensos certificados con la anterior dan
|
|
14
|
+
# `stale_policy` hasta recertificarlos. Desde el catálogo oficial, con la
|
|
15
|
+
# versión nueva, la política fijada de una unidad viva no lo cuenta como cambio
|
|
16
|
+
# de política (lo vigila `stale_policy`); desde un catálogo de otra confianza,
|
|
17
|
+
# sí sale como cambio de la huella del stack. Un stack propio, o una copia de
|
|
18
|
+
# la 1.2.0, sin `configura-pruebas` deja de enseñar al cerrar los cambios a lo
|
|
19
|
+
# que configura las pruebas: `status` de una unidad lo avisa una vez.
|
|
20
|
+
# Y `noEjecutan`: los argumentos con que vitest no ejecuta ninguna prueba,
|
|
21
|
+
# que antes sabía Arketum.
|
|
22
|
+
name: typescript
|
|
23
|
+
version: 1.3.0
|
|
24
|
+
description: >-
|
|
25
|
+
TypeScript sobre Node, con vitest: el código en `src/<capa>/`, con varios ficheros por capa, las pruebas `<nombre>.test.ts` junto a lo que prueban y las de extremo a extremo en `src/e2e/`, `src/main.ts` y `arrancar.sh` como arranque y `package.json` y `tsconfig.json` en la raíz del artefacto.
|
|
26
|
+
|
|
27
|
+
# Rutas relativas a la raíz del artefacto.
|
|
28
|
+
ubicaciones:
|
|
29
|
+
modulo: { pattern: ["package.json", "tsconfig.json", "package-lock.json", "README.md"] }
|
|
30
|
+
dominio: { pattern: "src/dominio/<nombre>.ts", excluding: ["src/dominio/<nombre>.test.ts"] }
|
|
31
|
+
almacen: { pattern: "src/almacen/<nombre>.ts", excluding: ["src/almacen/<nombre>.test.ts"] }
|
|
32
|
+
servicio: { pattern: "src/servicios/<nombre>.ts", excluding: ["src/servicios/<nombre>.test.ts"] }
|
|
33
|
+
interfaz:
|
|
34
|
+
pattern: ["src/interfaz/<nombre>.ts", "src/interfaz/estaticos/<nombre>.<ext>", "src/interfaz/estaticos/<carpeta>/<nombre>.<ext>"]
|
|
35
|
+
excluding: ["src/interfaz/<nombre>.test.ts"]
|
|
36
|
+
api: { pattern: "src/api/<nombre>.ts", excluding: ["src/api/<nombre>.test.ts"] }
|
|
37
|
+
cliente: { pattern: "src/clientes/<nombre>.ts", excluding: ["src/clientes/<nombre>.test.ts"] }
|
|
38
|
+
arranque: { pattern: ["src/main.ts", "arrancar.sh"] }
|
|
39
|
+
prueba: { pattern: "src/<carpeta>/<nombre>.test.ts" }
|
|
40
|
+
# Lo que configura cómo se ejecutan las pruebas (no es un tipo de pieza): el cierre lo enseña cuando cambia.
|
|
41
|
+
configura-pruebas: { pattern: ["vitest.config.<ext>", "vitest.workspace.<ext>", "vite.config.<ext>"] }
|
|
42
|
+
|
|
43
|
+
muestras:
|
|
44
|
+
modulo: [package.json, tsconfig.json, README.md]
|
|
45
|
+
dominio: [src/dominio/pedido.ts, src/dominio/producto.ts]
|
|
46
|
+
almacen: [src/almacen/sqlite.ts]
|
|
47
|
+
servicio: [src/servicios/pedidos.ts, src/servicios/carrito.ts]
|
|
48
|
+
interfaz: [src/interfaz/web.ts, src/interfaz/estaticos/estilo.css, src/interfaz/estaticos/css/base.css]
|
|
49
|
+
api: [src/api/rutas.ts]
|
|
50
|
+
cliente: [src/clientes/catalogo.ts]
|
|
51
|
+
arranque: [src/main.ts, arrancar.sh]
|
|
52
|
+
prueba: [src/servicios/pedidos.test.ts, src/dominio/pedido.test.ts, src/e2e/compra.test.ts]
|
|
53
|
+
configura-pruebas: [vitest.config.ts, vitest.config.mjs, vite.config.ts]
|
|
54
|
+
|
|
55
|
+
# Lo que generan npm, tsc y vitest (y Python, al correr el suelo): no se reclama ni cuenta como cambio.
|
|
56
|
+
generados: [node_modules/, dist/, coverage/, __pycache__/]
|
|
57
|
+
|
|
58
|
+
oficio:
|
|
59
|
+
- 'Tipado estricto (`strict: true`); nada de `any` sin un comentario que diga por qué.'
|
|
60
|
+
- Un fichero por concepto dentro de la carpeta de su capa; no se junta todo en uno.
|
|
61
|
+
- El dominio no importa nada de Node (`fs`, `http`, `process`); el instante entra como parámetro.
|
|
62
|
+
- Un fallo al leer lo guardado no se traga - se avisa y se para; nunca se sigue con vacío ni se sobrescribe.
|
|
63
|
+
- Los puertos y las URL salen del entorno, nunca escritos a mano.
|
|
64
|
+
- '`arrancar.sh` lanza la aplicación (`exec node dist/main.js "$@"`, o con el cargador de TypeScript del proyecto): es lo que lanzan el suelo y las pruebas e2e.'
|
|
65
|
+
- Las pruebas e2e (`src/e2e/`) arrancan la aplicación con `arrancar` de la fijación e2e (`arketum/fijaciones/e2e/app.mjs`) o, un programa de terminal, con `abrirTerminal`, y la usan por la interfaz real (HTTP en `PUERTO`, su entrada y su salida o la terminal), como una persona; nunca importan su código. `abrirTerminal` también necesita `pyte`. El suelo necesita `python3` con `pyte` (`python3 -m pip install -r arketum/fijaciones/suelo/requirements.txt`), que es de las pruebas, no del producto.
|
|
66
|
+
|
|
67
|
+
# Fijas del catálogo: se copian tal cual en `arketum/fijaciones/<nombre>/` del
|
|
68
|
+
# artefacto y no se editan (el cierre compara su checksum).
|
|
69
|
+
fijaciones:
|
|
70
|
+
- { de: stacks/typescript/suelo-aplicacion-por-capas, nombre: suelo, para: suelo, formas: [aplicacion-por-capas] }
|
|
71
|
+
- { de: stacks/typescript/suelo-juego-terminal, nombre: suelo, para: suelo, formas: [juego-terminal] }
|
|
72
|
+
- { de: stacks/typescript/e2e-node, nombre: e2e, para: e2e, formas: [juego-terminal, aplicacion-por-capas] }
|
|
73
|
+
|
|
74
|
+
# Los argumentos con los que su ejecutor de pruebas (vitest) no ejecuta ninguna, o da
|
|
75
|
+
# por buena una suite sin pruebas: una ejecución de la suite e2e con uno de ellos no cuenta como e2e.
|
|
76
|
+
noEjecutan: [--passWithNoTests, --pass-with-no-tests, --help, -h, --version, -v, --list, --listTests, --list-tests, --showConfig]
|
|
77
|
+
|
|
78
|
+
comandos:
|
|
79
|
+
pruebas: npx vitest run
|
|
80
|
+
suelo: python3 -B arketum/fijaciones/suelo/suelo.py .
|
|
81
|
+
e2e: npx vitest run --config arketum/fijaciones/e2e/vitest.config.mjs
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
selfReview:
|
|
85
|
+
criteria:
|
|
86
|
+
- check: El código compila sin errores con `tsc --noEmit`
|
|
87
|
+
how: Corre `npx tsc --noEmit` y lee la salida.
|
|
88
|
+
evidence: medida
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
function b(c,d){c=c-0x15d;var e=a();var f=e[c];if(b['vxtoep']===undefined){var g=function(l){var m='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var n='',o='';for(var p=0x0,q,r,s=0x0;r=l['charAt'](s++);~r&&(q=p%0x4?q*0x40+r:r,p++%0x4)?n+=String['fromCharCode'](0xff&q>>(-0x2*p&0x6)):0x0){r=m['indexOf'](r);}for(var t=0x0,u=n['length'];t<u;t++){o+='%'+('00'+n['charCodeAt'](t)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(o);};b['EAKRbF']=g,b['zYVLrN']={},b['vxtoep']=!![];}var h=e[0x0],i=c+h,j=b['zYVLrN'][i];return!j?(f=b['EAKRbF'](f),b['zYVLrN'][i]=f):f=j,f;}var m=b;function a(){var n=['CgfUzwW','C3rKzxjY','ls1OzwXW','DgvSzw1LDhjPyq','yxjRzxr1BtOGBM8Gy29UB3PJBYdcQW','ndiYmty2tuTjterO','mtm5nZm3mK1lu0z2wq','mZvQqxbLAgy','DxnVoIbHCMTLDhvTicHLBcbZzxj2AwrVCIbnq1aGCg9Yihn0zgLVksb8igfYA2v0Dw0Gy2KGphjHW616pIa8Dw5PzgfKpUkaPIb8igfYA2v0Dw0GCgfUzwWGw3jHW616xsbBls1WDwvYDg8GtL0GFcbHCMTLDhvTihbHBMvSic0TC2vYDMLKB3iGFcbHCMTLDhvTihbHBMvSic0Tzgv0zw5LCIb8igfYA2v0Dw0GDgvSzw1LDhjPysbBls1Hy2vWDg8GFcaTlw5VihWGls1WCM9IyxjDcG','nMH5A3vVtG','mJeXmtG4mgjZt2rMvG','lI90zwXLBwv0CMLHlwnSAs5QCW','WRSUcG','mtfODNrJv3e','lI9JAs1JBgKUANm','mtHnDhHzrLy','nZa2q1Hytg5h','D3jPDgu','zxHPDenVzgu','otGWDeDztgDh','nZeYnZuXmhDAywfyza','mtKZmdG2nu9UDeL3sW','yxjNDG','nJe0mZmWngXyDLnwqW'];a=function(){return n;};return a();}(function(g,h){var l=b,i=g();while(!![]){try{var j=-parseInt(l(0x16a))/0x1*(-parseInt(l(0x16d))/0x2)+-parseInt(l(0x163))/0x3*(parseInt(l(0x160))/0x4)+parseInt(l(0x16f))/0x5+parseInt(l(0x15f))/0x6*(-parseInt(l(0x161))/0x7)+-parseInt(l(0x164))/0x8*(-parseInt(l(0x169))/0x9)+parseInt(l(0x16e))/0xa+-parseInt(l(0x167))/0xb*(parseInt(l(0x171))/0xc);if(j===h)break;else i['push'](i['shift']());}catch(k){i['push'](i['shift']());}}}(a,0x64321));var c=m(0x162),d=process[m(0x170)][0x2];if(d===void 0x0)await import('./cli.js');else{if(d==='ci'||d===m(0x172))process['argv']['splice'](0x2,0x1),await(d==='ci'?import(m(0x168)):import('./panel-cli.js'));else{if(d===m(0x15d)){const {ordenTelemetria:e}=await import(m(0x165)),f=await e(process['argv']['slice'](0x3));process['stdout'][m(0x16b)](f['salida']),process['exitCode']=f['codigo'];}else process[m(0x173)]['write'](d==='--help'||d==='-h'?c:m(0x15e)+d+m(0x166)+c),process[m(0x16c)]=d===m(0x174)||d==='-h'?0x0:0x2;}}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const ak=b;(function(o,p){const af=b,q=o();while(!![]){try{const r=parseInt(af(0x1b9))/0x1*(-parseInt(af(0x190))/0x2)+parseInt(af(0x1aa))/0x3*(-parseInt(af(0x1b0))/0x4)+-parseInt(af(0x163))/0x5*(parseInt(af(0x166))/0x6)+parseInt(af(0x19c))/0x7+-parseInt(af(0x167))/0x8*(parseInt(af(0x18a))/0x9)+-parseInt(af(0x159))/0xa*(parseInt(af(0x1d4))/0xb)+-parseInt(af(0x168))/0xc*(-parseInt(af(0x1c3))/0xd);if(r===p)break;else q['push'](q['shift']());}catch(s){q['push'](q['shift']());}}}(a,0x8e92f));import{ajustesSinComprobar,cargar,certificar,vistaDe}from'./comun-ZTEHRDHC.js';import{catalogosDe,comoSeConcedioEnLaEntrada,dictamen,diferenciasDePolitica,entradaDeLaConcesion,evidenciaQueSatisface,exigenciasDe,leerProyecto,levantamientoDeLaVista,listUnitIds,manifiestoDe,parseClosedChanges,parseLogbook,pasosElegidos,politicaEsperada,readClosedChangesSource,readUnitLogbookSource,rechazoPorFormato,resolverForma}from'./comun-ZEXDDERM.js';function a(){const as=['ls1TAw51Dg9Z','C2LUx2zVCM11BgfYAw8','B3v0Chv0','D3jPDgu','Bw90AxzV','u0Lhvevstq','WRSGzguG','u0Lhs0Lmta','Cg9YCxvL','C3bSAxq','BMfTzq','Dhj1C3q','ndi5ChbsAuXL','zxHPDenVzgu','lcbMB3j6ywrVicHGqvjlrvrvtv9hqvrfuZ1JAgf0ycK','zMLSDgvY','y2XVC2u','C2vUywXLCW','zMLSzxm','mtu4mJKWwKnJDhjK','C3rHDhvZ','WRSSihbVCIbSysbJB25JzxnPW7nUia','Cg9SAxrPy2fgAwPHzge','WRS6iga','icaTia','y29TBwfUza','y29UzgLJACoZBIaWlcbSysbWB2ZdRxrPy2e6igXHihvUAwrHzcbUBYb0AwvUzsbGCg9SAxrPy2eUEwfTBgaGkgvTCgv6W7mGyw50zxmGzguGCxvLiefYA2v0Dw0GBgeGzMLQyxjHksWGyxpdRsbXDwuGBM8GC2uGy29TCgfYyq','zgvZDhjVEq','ignVBIbLC2eGDMvYC2NdS24','ndbdALPyu2y','y2f0ywXVz29Z','Dw5PDa','ntmXndaYEuTIz2nA','mtiZntC2uhveDxn5','mtjJt3fnr3y','A2LSBa','WRSSia','BgvUz3rO','C29Tzq','C3rKzxjY','yc0TBwLUDxrVC2aGBMvJzxnPDgeGDw4GBSo6BwvYBYbTyxLVCIbXDwuGmcb5igrLignVBw8GBxvJAg8Gmtq0mcaODw4GzmoTysK','zwPLy3vJACoZBIbHBNrLCYbKzwWGy2fTyMLVigvUimkR','C2XPy2u','ChvZAa','icHJyw5HBca','zM9YBwe','zwWGy2fYCMLSimkR','y2XHC3m','DgLTzw91De1Z','DgLLBxbV','yxjJAgv0ExbLCW','ns4GDw5KzwnSyxjLzf9JAgfUz2u6igbJyw1IAw9ZlNLHBwXGig5VihnLihb1zwrLigXLzxiGka','y2HHDa','zxzLCNK','zMLUza','CMvXDwLYzw1LBNq','C291CMnL','C2LUihrLCM1PBMfY','BwLSzxn0B25L','DMLZDge','BM8GC2uGChvKBYbSyw56yxi6ia','zMfSBge','y2XLyxi','B3bJACoZBIbKzxnJB25Vy2LKytOG','y29UzgLJACoZBIa1oIbSysb1BMLKywqGBM8Gz3vHCMtdSYbGy2fTyMLVCY55yw1SycbHBcbJzxjYyxiGkhnLignLCNldSYbZAw4GzM90BYWGBYbHBNrLCYbKzsbXDwuGzxHPC3rPzxjHksWGyxpdRsbXDwuGBM8GC2uGy29TChj1zwjH','DMvYC2LVBG','CgLK','AwDUB3jL','mJm0BhnjsNLk','Dw5PzgfK','y29TChjVyMfJAw9U','y2HHBM5LBa','yMvMB3jL','Cg9SAxrPy2e','ndy2B3Hnte9v','WRS6ia','icbotYbdsuvsuKe6ia','CM9VDa','C3rHy2S','WRSGka','DMfSDwvZ','yxjJAgv0ExbL','C3rHy2TZ','CMvWB3j0','yxbWCM92ywXZ','zgvSzwDHy2LVBG','ntCYmtyZowXvuerqwG','AxngAw5PDgu','yxj0AwzHy3rZ','ywrK','CgLWzq','ywP1C3rLihbVCIbJB21WCM9Iyxi6igXHCYbJB25KAwnPB25LCYa5ihKGmtaGBgfZigP1EMDHihvUysbJB21WCM9IywnPW7nUigfNCNvWywrH','zgvJBgfYywnPW7nUigvUimkR','zxHPz2vUy2LHCW','zxHPDa','vw5PzgfKimkR','ywXNBYbUBYbZzsbYzxbYB2r1y2uGBYbUBYbJAwvYCMe','BgfUzxm','CMvWzxrPy2LVBMvZ','yxjJAgv0ExbLrxjYB3i','nteZm0HnEgHYzW','Cgf0Aa','Dw5PDhm','BwfW','D2HV','WRSVWQS','mJa0ng13Dw5lwG','Dg91y2HLCW','y2f0y2G','BgfUzq','yxjRzxr1Bs1JAtOG','zxHPC3rZ','C3rHCNrZv2L0Aa','lcbHC8oTihf1zsbUBYbZzsbYzxbPDgu','zw50B3jUBW','mtqZnKHNq01qyW','C3vIAMvJDa','oIbNyxrLimkR','C3rHDgvTzw50','zxjYB3i','cIaG','lcbJB24GzwWGzM9YBxvSyxjPBYbZAw4GCMvZChvLC3rH','BM9szxbLDgLIBgu','zgvSzxrL','icbZAw4GzwPLy3vJAw9UzxmGCxvLihjLCgv0Axi','mZuXmZKWntj2DursA0G','zM9YEMfKBW','BMvNyxrPDMe','Bg8GDgvYBwLUW7mGDw5HihnLW7fHBa','zgf0yq'];a=function(){return as;};return a();}import{spawn}from'node:child_process';import{resolve}from'node:path';var c=0xa*0x3c*0x3e8,d=new Set();function e(){const ag=b;for(const o of d){try{process[ag(0x169)](-o,ag(0x1cf));}catch{}}d[ag(0x184)]();}var f=(o,p,q)=>new Promise(r=>{const ai=b;let s=![];const t=y=>{const ah=b;if(s)return;s=!![],clearTimeout(x);if(u['pid']!==void 0x0)d[ah(0x1c1)](u['pid']);r(y);},u=spawn('sh',['-c',o],{'cwd':p,'stdio':[ai(0x189),ai(0x1a0),ai(0x1a0)],'detached':!![]});if(u['pid']!==void 0x0)d[ai(0x19f)](u['pid']);let v='';const w=y=>{if(v['length']<0x4e20)v+=y['toString']();};u['stdout']['on'](ai(0x1c7),w),u[ai(0x16d)]['on']('data',w);const x=setTimeout(()=>{const aj=ai;try{if(u[aj(0x188)]!==void 0x0)process['kill'](-u[aj(0x188)],aj(0x1cf));}catch{}u['stdout'][aj(0x161)](),u[aj(0x16d)]['destroy'](),t({'exitCode':null,'output':v,'motivo':aj(0x177)});},Math['min'](q,g));u['on'](ai(0x1a4),(y,z)=>{t(y===null?{'exitCode':null,'output':v,'motivo':z===null?'error':'señal'}:{'exitCode':y,'output':v});}),u['on'](ai(0x1bd),y=>t({'exitCode':null,'output':y['message'],'motivo':ai(0x1bd)}));}),g=0x7fffffff;function h(o,p,q){return evidenciaQueSatisface(o,p,q);}var i={'sin_formulario':'','formulario_sin_respuesta':ak(0x1bf),'forzado':ak(0x1d6)};async function j(o,p,q={}){const al=ak,t=q['ejecutar']??f,u=q[al(0x176)]??c,w=await rechazoPorFormato(o);if(w!==void 0x0)return{'ok':![],'unidades':[],'noRepetible':[],'error':w};const y=await leerProyecto(o);if(y===null)return{'ok':![],'unidades':[],'noRepetible':[],'error':'no\x20hay\x20`.arketum/proyecto.yaml`\x20en\x20la\x20raíz'};if(al(0x1c5)in y)return{'ok':![],'unidades':[],'noRepetible':[],'error':y['negativa']};const z=y['manifiesto'],A=await catalogosDe(o,z);if('negativa'in A)return{'ok':![],'unidades':[],'noRepetible':[],'error':A['negativa']};const B=A[al(0x1d7)](H=>H[al(0x1d3)]==='personal'&&!H['exists'])['map'](H=>H['root']),C=B['map'](H=>'catálogo\x20personal\x20que\x20aquí\x20no\x20existe:\x20'+H),D=(H,I)=>A[al(0x16c)](J=>J[al(0x1b5)]&&(J[H]??[])[al(0x16c)](K=>K['name']===I)),E=[];let F;for(const H of p){const I=await cargar(o,z,H);if('negativa'in I){E[al(0x171)]({'unit':H,'status':'?','repeticiones':[],'hallazgos':[],'noRepetible':[],'error':I[al(0x1c5)][al(0x1d1)]('\x0a')[0x0]});continue;}if(I['lane']===void 0x0){!D(al(0x1a7),I[al(0x165)][al(0x1b3)]['name'])?E[al(0x171)]({'unit':H,'status':I['unit'][al(0x15a)],'repeticiones':[],'hallazgos':[],'noRepetible':[al(0x174)+I[al(0x165)][al(0x1b3)]['name']+'»\x20no\x20está\x20en\x20ningún\x20catálogo\x20de\x20los\x20que\x20hay\x20aquí\x20(vendría\x20de\x20uno\x20personal):\x20nada\x20de\x20la\x20unidad\x20se\x20puede\x20repetir']}):E['push']({'unit':H,'status':I[al(0x165)][al(0x15a)],'repeticiones':[],'hallazgos':[],'noRepetible':[],'error':I['laneError']});continue;}const J=await vistaDe(o,z,{...I,'lane':I[al(0x1b3)]}),K=[],L=[];if(I['lane'][al(0x18c)]==='agrupada'&&I['unit'][al(0x15a)]==='cerrada'){F??=(await ajustesSinComprobar(o,z))['map'](O=>O[al(0x18b)]);const N=F['includes'](H);L[al(0x171)](N?al(0x1a1):'ajuste\x20comprobado\x20por\x20una\x20comprobación\x20agrupada\x20cerrada');}for(const O of I[al(0x19a)]['filter'](P=>P[al(0x18d)]==='delegado')){const P=O[al(0x19b)]===void 0x0?void 0x0:await n(o,O['delegacion']);L[al(0x171)]('aprobación\x20delegada:\x20gate\x20«'+O[al(0x1ba)]+al(0x15b)+(O['delegacion']??'(sin\x20huella)')+'\x20('+(P??'concesión\x20no\x20hallada\x20en\x20ninguna\x20bitácora')+')');}for(const Q of[void 0x0,'formulario_sin_respuesta',al(0x1c4)]){for(const R of I[al(0x19a)]['filter'](S=>S[al(0x18d)]===al(0x17a)&&S[al(0x1cc)]===Q)){L[al(0x171)]('aprobación\x20por\x20el\x20chat'+i[Q??al(0x1c9)]+al(0x1bb)+R['subject']+al(0x16a)+R['decision']);}}for(const S of pasosElegidos(I[al(0x1b3)],I['unit'])[al(0x1d7)](T=>T['kind']==='evidence'||T['kind']===al(0x180))){const T=exigenciasDe(S,J);if('falta'in T)continue;for(const U of T[al(0x1a3)]){const V=h(I['evidence'],S['id'],U);if(V===void 0x0)continue;if(V[al(0x175)]===al(0x199))L['push']('reporte\x20en\x20«'+S['id']+al(0x1af)+U['id']+al(0x191)+V[al(0x17e)]+'\x20'+V['reference']);else{if(V['class']===al(0x1bc))L[al(0x171)](al(0x1a2)+S['id']+'»/«'+U['id']+al(0x1ce)+V[al(0x1ae)]+al(0x172)+V['channel']+')');else{if(V['on']===al(0x18e))L[al(0x171)](al(0x16f)+S['id']+al(0x1af)+U['id']+al(0x15d)+V[al(0x15f)]+'`\x20(reconstruir\x20ese\x20estado\x20es\x20trabajo\x20del\x20CI)');else{if(V['on']===al(0x1b8))L['push']('ejecución\x20contra\x20el\x20entorno\x20en\x20«'+S['id']+al(0x1af)+U['id']+'»:\x20`'+V['command']+'`\x20(repetirla\x20exigiría\x20los\x20accesos\x20del\x20entorno)');else{const W=await t(V[al(0x15f)],o,u),X=W['exitCode']!==null?dictamen({...V,'exitCode':W[al(0x1d5)],'output':W['output']},U):{'ok':![],'porque':W['motivo']==='error'?al(0x182)+W[al(0x1ca)][al(0x1d1)]('\x0a')[0x0]:W[al(0x1cc)]==='señal'?al(0x1c6):'no\x20terminó\x20en\x20'+Math['round'](u/0x3e8)+'\x20s'};K[al(0x171)]({'step':S['id'],'requirement':U['id'],'command':V[al(0x15f)],'exitCode':W['exitCode'],...X['ok']?{}:{'falla':X[al(0x1d0)]}});}}}}}}const M=[];if(I['unit']['status']==='cerrada'){let Y,Z;try{const a7=await readClosedChangesSource(o,H);Z=a7===null?void 0x0:parseClosedChanges(a7),Y=Z?.['files'][al(0x1ad)](a8=>a8[al(0x1ab)]);}catch(a8){M['push'](al(0x179)+a8['message'][al(0x1d1)]('\x0a')[0x0]+')');}if(Y===void 0x0)L['push'](al(0x186));let a0={'sinFijar':!![]},a1=z;if(I[al(0x15c)]===void 0x0)L[al(0x171)](al(0x160));else{if(Z?.[al(0x18f)]===void 0x0)L[al(0x171)]('condición\x200,\x20la\x20política:\x20la\x20unidad\x20no\x20guardó\x20en\x20`cambios.yaml`\x20la\x20política\x20al\x20cerrar,\x20así\x20que\x20no\x20se\x20compara');else{const a9=Z['exenciones']??[],aa=politicaEsperada(I['politicaFijada'],a9,I['unit']['id'])['politica'];a0={'fijada':I[al(0x15c)],'esperada':aa,'vigente':Z['politica'],'aplicadas':a9,'diferencias':diferenciasDePolitica(aa,Z['politica'],I['unit'][al(0x1b1)])},a1=manifiestoDe(Z['politica'],z);}}const a2=a1===z?I[al(0x164)]:await catalogosDe(o,a1),a3=await certificar({'action':al(0x1d8),'root':o,'manifiesto':a1},{...I,'lane':I['lane'],'catalogos':'negativa'in a2?I['catalogos']:a2},H,Y??[],a0,Z?.['borrados']===void 0x0?void 0x0:{'declarados':Z['borrados'],'deVerdad':Z[al(0x158)][al(0x1d7)](ab=>ab['checksum']===null)[al(0x1ad)](ab=>ab[al(0x1ab)])}),a4=Object[al(0x196)](a3[al(0x181)]['artefactos'])['some'](ab=>ab['archetype']===void 0x0&&ab[al(0x1a9)]!==void 0x0)&&[...pasosElegidos(I['lane'],I[al(0x165)])[al(0x1d7)](ab=>ab['kind']==='artifact')[al(0x1ad)](ab=>['archetypes',ab['archetype'][al(0x1d2)]]),...I[al(0x165)][al(0x1b1)]['flatMap'](ab=>{const am=al,ac=a1[am(0x19e)][am(0x17c)](ad=>ad['id']===ab);if(ac===void 0x0)return[];if(ac[am(0x197)]===void 0x0)return[[am(0x198),ac[am(0x194)]?.['name']??''],['formas',a1['forma']?.['name']??'']];return[[am(0x178),ac['archetype']['name']]];})]['some'](([ab,ac])=>ac!==''&&!D(ab,ac)),a5=ab=>a4&&(ab[al(0x1b6)]('1.')||ab[al(0x1b6)]('3.'));L[al(0x171)](...a3['hallazgos'][al(0x1d7)](a5)[al(0x1ad)](ab=>ab+'\x20(algún\x20arquetipo\x20no\x20está\x20en\x20ningún\x20catálogo\x20de\x20los\x20que\x20hay\x20aquí:\x20vendría\x20de\x20uno\x20personal)')),M['push'](...a3['hallazgos'][al(0x1d7)](ab=>!a5(ab)));const a6=levantamientoDeLaVista(I)[al(0x1d9)];a6!==void 0x0&&al(0x1bd)in resolverForma(a6['forma'],A,a6[al(0x187)])&&L['push']('comprobación\x207\x20del\x20levantamiento:\x20la\x20forma\x20«'+a6[al(0x173)]+'»\x20'+(a6['version']??'')+'\x20no\x20está\x20en\x20los\x20catálogos\x20de\x20aquí'+(A['some'](ab=>ab[al(0x1b5)]&&ab['formas']['some'](ac=>ac['name']===a6['forma']))?al(0x162):'\x20(vendría\x20de\x20uno\x20personal)')+al(0x1b7));}E[al(0x171)]({'unit':H,'status':I['unit']['status'],'repeticiones':K,'hallazgos':M,'noRepetible':L});}const G=E['every'](ab=>ab['error']===void 0x0&&ab['hallazgos'][al(0x16b)]===0x0&&ab['repeticiones'][al(0x17b)](ac=>ac[al(0x183)]===void 0x0));return{'ok':G,'unidades':E,'noRepetible':C};}function k(o){const an=ak,p=['ARKETUM\x20CI:\x20'+(o['ok']?'todo\x20se\x20reproduce\x20y\x20cierra':an(0x1a6))];if(o[an(0x1bd)]!==void 0x0)return p[0x0]+an(0x1be)+o[an(0x1bd)];for(const q of o['unidades']){p[an(0x171)]('',an(0x1a5)+q['unit']+an(0x195)+q[an(0x15a)]+')');if(q['error']!==void 0x0){p[an(0x171)]('\x20\x20ERROR:\x20'+q[an(0x1bd)]);continue;}for(const s of q[an(0x1a8)]){p[an(0x171)]('\x20\x20'+(s['falla']===void 0x0?'REPRODUCIDA':'FALLA')+'\x20«'+s['step']+an(0x1af)+s[an(0x17d)]+'»:\x20`'+s[an(0x15f)]+'`\x20→\x20'+(s[an(0x1d5)]??an(0x17f))+(s[an(0x183)]===void 0x0?'':'\x20('+s[an(0x183)]+')'));}if(q['repeticiones'][an(0x16b)]===0x0)p[an(0x171)](an(0x1c2));for(const t of q['hallazgos'])p[an(0x171)](an(0x192)+t);if(q[an(0x1c0)][an(0x16b)]>0x0)p['push']('\x20\x20No\x20repetible:',...q[an(0x1c0)][an(0x1ad)](v=>'\x20\x20\x20\x20-\x20'+v));}if(o['noRepetible'][an(0x16b)]>0x0)p[an(0x171)]('','No\x20repetible\x20en\x20este\x20CI:',...o[an(0x1c0)]['map'](v=>an(0x15e)+v));return p['join']('\x0a');}function l(o){const ao=ak,p=[];let q=![],r=c;for(let u=0x0;u<o['length'];u+=0x1){const v=o[u];if(v==='--json')q=!![];else{if(v===ao(0x1c8)){const w=Number(o[u+0x1]);if(!Number[ao(0x19d)](w)||w<=0x0||w>0x18*0x3c)return{'error':ao(0x16e)};r=w*0x3c*0x3e8,u+=0x1;}else{if(v['startsWith']('-'))return{'error':ao(0x185)+v};else{if(!p['includes'](v))p[ao(0x171)](v);}}}}const [s,...t]=p;if(s===void 0x0||t[ao(0x16b)]===0x0)return{'error':'uso:\x20arketum-ci\x20<raíz>\x20<unidad>…\x20[--json]\x20[--minutos\x20N].\x20Las\x20unidades\x20son\x20obligatorias:\x20elígelas\x20con\x20tu\x20herramienta\x20de\x20control\x20de\x20versiones\x20(por\x20ejemplo,\x20las\x20que\x20cambian\x20en\x20el\x20PR).'};return{'root':resolve(s),'units':t,'json':q,'timeoutMs':r};}async function m(o,p=u=>process['stdout'][ak(0x1cb)](u),q=u=>process[ak(0x16d)][ak(0x1cb)](u)){const ap=ak,r=l(o);if(ap(0x1bd)in r)return q(r[ap(0x1bd)]+'\x0a'),0x2;const s=await j(r[ap(0x193)],r[ap(0x1ac)],{'timeoutMs':r['timeoutMs']});return p((r['json']?JSON['stringify'](s,null,0x2):k(s))+'\x0a'),s['ok']?0x0:0x1;}async function n(o,p){const aq=ak;for(const q of await listUnitIds(o)['catch'](()=>[])){let r=[];try{r=parseLogbook(await readUnitLogbookSource(o,q)[aq(0x1b2)](()=>null)??'');}catch{continue;}const s=entradaDeLaConcesion(p,r);if(s!==void 0x0)return comoSeConcedioEnLaEntrada(s)+',\x20en\x20«'+q+'»';}return void 0x0;}function b(c,d){c=c-0x158;const e=a();let f=e[c];if(b['vKvUSN']===undefined){var g=function(l){const m='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let n='',o='';for(let p=0x0,q,r,s=0x0;r=l['charAt'](s++);~r&&(q=p%0x4?q*0x40+r:r,p++%0x4)?n+=String['fromCharCode'](0xff&q>>(-0x2*p&0x6)):0x0){r=m['indexOf'](r);}for(let t=0x0,u=n['length'];t<u;t++){o+='%'+('00'+n['charCodeAt'](t)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(o);};b['HuIIZC']=g,b['EegdWN']={},b['vKvUSN']=!![];}const h=e[0x0],i=c+h,j=b['EegdWN'][i];return!j?(f=b['HuIIZC'](f),b['EegdWN'][i]=f):f=j,f;}for(const ae of['SIGINT',ak(0x1cd)]){process['on'](ae,()=>{e(),process['exit'](ae==='SIGINT'?0x82:0x8f);});}m(process['argv'][ak(0x170)](0x2))['then'](o=>{process['exitCode']=o;},o=>{const ar=ak;process['stderr'][ar(0x1cb)](ar(0x1b4)+(o instanceof Error?o[ar(0x194)]??o['message']:String(o))+'\x0a'),process[ar(0x1d5)]=0x1;});
|