kcreate-scaffolding-gcp-script 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +429 -2
- package/bin/build.js +70 -0
- package/bin/cli.js +441 -0
- package/package.json +36 -4
- package/skill/SKILL.md +262 -0
- package/skill/references/lessons-learned.md +706 -0
- package/skill/scripts/01_init_config.sh +151 -0
- package/skill/scripts/02_print_config.sh +60 -0
- package/skill/scripts/10_build_components.sh +596 -0
- package/skill/scripts/20_validate_file_parity.sh +107 -0
- package/skill/scripts/21_validate_project_pinning.sh +105 -0
- package/skill/scripts/22_validate_no_app_name_leftover.sh +62 -0
- package/skill/scripts/lib/common.sh +788 -0
- package/skill/scripts/run_tracking.sh +93 -0
- package/skill/templates/scaffolding.config.template +81 -0
- package/vendor/github-proyect-tracking/SKILL.md +180 -0
- package/vendor/github-proyect-tracking/references/api.md +185 -0
- package/vendor/github-proyect-tracking/references/architecture.md +171 -0
- package/vendor/github-proyect-tracking/scripts/tracking.py +214 -0
- package/vendor/github-proyect-tracking/scripts/tracking_core/__init__.py +1 -0
- package/vendor/github-proyect-tracking/scripts/tracking_core/commands.py +940 -0
- package/vendor/github-proyect-tracking/scripts/tracking_core/common.py +208 -0
- package/vendor/github-proyect-tracking/scripts/tracking_core/events.py +233 -0
- package/vendor/github-proyect-tracking/scripts/tracking_core/github.py +324 -0
- package/vendor/github-proyect-tracking/scripts/tracking_core/state.py +379 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Envoltura delgada sobre github-proyect-tracking para este skill. El agente
|
|
3
|
+
# nunca llama a tracking.py directamente — siempre a través de este script,
|
|
4
|
+
# para no tener que recordar flags ni rutas.
|
|
5
|
+
#
|
|
6
|
+
# Uso:
|
|
7
|
+
# run_tracking.sh init-plan <config_file> <plan.json>
|
|
8
|
+
# run_tracking.sh resume <config_file>
|
|
9
|
+
# run_tracking.sh step-start <config_file> "<nombre del paso>"
|
|
10
|
+
# run_tracking.sh step-done <config_file> "<nombre del paso>"
|
|
11
|
+
# run_tracking.sh step-error <config_file> "<nombre del paso>" "<detalle>"
|
|
12
|
+
# run_tracking.sh status <config_file>
|
|
13
|
+
# run_tracking.sh finalize <config_file> [archivo_de_resumen]
|
|
14
|
+
#
|
|
15
|
+
# `init-plan` manda siempre --process-name "/kcreate-scaffolding-gcp-script"
|
|
16
|
+
# y --process-inputs con SOURCE_ENV/NEW_ENV (requiere github-proyect-tracking
|
|
17
|
+
# >= 0.5.0/0.6.0 — ver vendor/VENDORED_FROM.md) — así el Issue de tracking
|
|
18
|
+
# dice de entrada QUÉ skill lo está usando y CON QUÉ parámetros, sin que el
|
|
19
|
+
# humano tenga que adivinarlo leyendo los comentarios de los pasos.
|
|
20
|
+
#
|
|
21
|
+
# `finalize` acepta opcionalmente la ruta a un archivo de texto con el
|
|
22
|
+
# resumen final de la ejecución (requiere github-proyect-tracking >= 0.7.0):
|
|
23
|
+
# si se da, ese resumen queda como un comentario APARTE en el Issue,
|
|
24
|
+
# después del de FINALIZADO y antes de cerrarlo — el mismo resumen que el
|
|
25
|
+
# agente ya le muestra al humano en pantalla, también en el Issue.
|
|
26
|
+
#
|
|
27
|
+
# Si github-proyect-tracking no está instalado junto a este skill, todos los
|
|
28
|
+
# subcomandos salen con error claro (código 3) en vez de fallar a medias.
|
|
29
|
+
|
|
30
|
+
set -euo pipefail
|
|
31
|
+
|
|
32
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
33
|
+
# shellcheck source=lib/common.sh
|
|
34
|
+
source "$SCRIPT_DIR/lib/common.sh"
|
|
35
|
+
|
|
36
|
+
SUBCOMMAND="${1:-}"
|
|
37
|
+
CONFIG_FILE="${2:-}"
|
|
38
|
+
[[ -n "$SUBCOMMAND" && -n "$CONFIG_FILE" ]] || ksc_die \
|
|
39
|
+
"uso: run_tracking.sh <subcomando> <config_file> [args...]"
|
|
40
|
+
[[ -f "$CONFIG_FILE" ]] || ksc_die "no existe el archivo de configuración: $CONFIG_FILE"
|
|
41
|
+
|
|
42
|
+
REPO_ROOT="$(ksc_repo_root)"
|
|
43
|
+
TRACKING_PY="$REPO_ROOT/.claude/skills/github-proyect-tracking/scripts/tracking.py"
|
|
44
|
+
[[ -f "$TRACKING_PY" ]] || { ksc_err "github-proyect-tracking no está instalado en este repo ($TRACKING_PY no existe). Reinstala con install.sh de KTerragruntScaffoldingScripts (sin --skip-tracking)."; exit 3; }
|
|
45
|
+
|
|
46
|
+
# shellcheck disable=SC1090
|
|
47
|
+
source "$CONFIG_FILE"
|
|
48
|
+
[[ -n "${TRACKING_GITHUB_PROJECT_URL:-}" ]] || ksc_die \
|
|
49
|
+
"TRACKING_GITHUB_PROJECT_URL no está definido en $CONFIG_FILE"
|
|
50
|
+
|
|
51
|
+
TP() { python3 "$TRACKING_PY" "$@" --url "$TRACKING_GITHUB_PROJECT_URL"; }
|
|
52
|
+
|
|
53
|
+
case "$SUBCOMMAND" in
|
|
54
|
+
init-plan)
|
|
55
|
+
PLAN_FILE="${3:-}"
|
|
56
|
+
[[ -n "$PLAN_FILE" && -f "$PLAN_FILE" ]] || ksc_die "init-plan requiere un archivo plan.json existente"
|
|
57
|
+
PROCESS_INPUTS="$(python3 -c 'import json,sys; print(json.dumps({"SOURCE_ENV": sys.argv[1], "NEW_ENV": sys.argv[2]}))' "$SOURCE_ENV" "$NEW_ENV")"
|
|
58
|
+
TP init --plan-file "$PLAN_FILE" \
|
|
59
|
+
--process-name "/kcreate-scaffolding-gcp-script" \
|
|
60
|
+
--process-inputs "$PROCESS_INPUTS"
|
|
61
|
+
;;
|
|
62
|
+
resume)
|
|
63
|
+
TP resume
|
|
64
|
+
;;
|
|
65
|
+
step-start)
|
|
66
|
+
NAME="${3:-}"; [[ -n "$NAME" ]] || ksc_die "step-start requiere el nombre del paso"
|
|
67
|
+
TP step-start --name "$NAME"
|
|
68
|
+
;;
|
|
69
|
+
step-done)
|
|
70
|
+
NAME="${3:-}"; [[ -n "$NAME" ]] || ksc_die "step-done requiere el nombre del paso"
|
|
71
|
+
TP step-done --name "$NAME"
|
|
72
|
+
;;
|
|
73
|
+
step-error)
|
|
74
|
+
NAME="${3:-}"; DETAILS="${4:-sin detalle}"
|
|
75
|
+
[[ -n "$NAME" ]] || ksc_die "step-error requiere el nombre del paso"
|
|
76
|
+
TP step-error --name "$NAME" --details "$DETAILS"
|
|
77
|
+
;;
|
|
78
|
+
status)
|
|
79
|
+
TP status --remote
|
|
80
|
+
;;
|
|
81
|
+
finalize)
|
|
82
|
+
SUMMARY_FILE="${3:-}"
|
|
83
|
+
if [[ -n "$SUMMARY_FILE" ]]; then
|
|
84
|
+
[[ -f "$SUMMARY_FILE" ]] || ksc_die "no existe el archivo de resumen: $SUMMARY_FILE"
|
|
85
|
+
TP finalize --summary-file "$SUMMARY_FILE"
|
|
86
|
+
else
|
|
87
|
+
TP finalize
|
|
88
|
+
fi
|
|
89
|
+
;;
|
|
90
|
+
*)
|
|
91
|
+
ksc_die "subcomando desconocido: $SUBCOMMAND"
|
|
92
|
+
;;
|
|
93
|
+
esac
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Archivo de configuración de kcreate-scaffolding-gcp-script
|
|
2
|
+
# Generado automáticamente por 01_init_config.sh — no es necesario crearlo a
|
|
3
|
+
# mano. Los campos marcados __PENDIENTE__ no se pudieron inferir del
|
|
4
|
+
# entorno fuente y deben llenarse antes de continuar. Los demás ya vienen
|
|
5
|
+
# autodetectados del entorno fuente (SOURCE_ENV) — revísalos, pero no es
|
|
6
|
+
# obligatorio tocarlos salvo que alguno esté mal.
|
|
7
|
+
#
|
|
8
|
+
# Formato: KEY="value", una por línea. Este archivo se `source`-ea
|
|
9
|
+
# directamente en bash — no agregues nada que no sea una asignación simple
|
|
10
|
+
# o un comentario.
|
|
11
|
+
|
|
12
|
+
# --- Identidad de la ejecución (fijos, no editar tras la primera corrida) ---
|
|
13
|
+
SOURCE_ENV="__SOURCE_ENV__"
|
|
14
|
+
NEW_ENV="__NEW_ENV__"
|
|
15
|
+
|
|
16
|
+
# --- Requeridos: no se pueden inferir del entorno fuente ---
|
|
17
|
+
|
|
18
|
+
# Nombre legible para GCP (project_name). Inferido de NEW_ENV con la
|
|
19
|
+
# convención <App-Con-Mayúscula-Inicial>-<QA|Prod> — confírmalo o corrígelo
|
|
20
|
+
# si el nombre de la app tiene una capitalización distinta a la obvia
|
|
21
|
+
# (ej. siglas, nombres compuestos).
|
|
22
|
+
PROJECT_NAME="__PENDIENTE__"
|
|
23
|
+
|
|
24
|
+
# Repo(s) de GitHub (formato owner/repo) que hacen `push` de imágenes
|
|
25
|
+
# Docker al Artifact Registry de este proyecto nuevo. Se asume que ya
|
|
26
|
+
# existen — este skill NO valida contra GitHub. Uno solo en el caso común;
|
|
27
|
+
# si la app tiene varios repos (como boletera-qa, que maneja 5), sepáralos
|
|
28
|
+
# con ";" — se genera un binding de github_workload_identity por cada uno.
|
|
29
|
+
APP_GITHUB_REPO="__PENDIENTE__"
|
|
30
|
+
|
|
31
|
+
# URL del repo de GitHub (https://github.com/{owner}/{repo}) usado por
|
|
32
|
+
# github-proyect-tracking para registrar el avance de esta ejecución como
|
|
33
|
+
# Issues/comentarios. Necesario para poder reanudar si el proceso se
|
|
34
|
+
# interrumpe.
|
|
35
|
+
TRACKING_GITHUB_PROJECT_URL="__PENDIENTE__"
|
|
36
|
+
|
|
37
|
+
# --- Autodetectados de SOURCE_ENV (verificar, normalmente no hace falta tocar) ---
|
|
38
|
+
|
|
39
|
+
ORG_ID="__PENDIENTE__"
|
|
40
|
+
ORG_BILLING_ACCOUNT="__PENDIENTE__"
|
|
41
|
+
REGION="__PENDIENTE__"
|
|
42
|
+
ZONE="__PENDIENTE__"
|
|
43
|
+
LABEL_OWNER="__PENDIENTE__"
|
|
44
|
+
|
|
45
|
+
# Organización de GitHub usada en github_workload_identity (local.github_organization).
|
|
46
|
+
GITHUB_ORGANIZATION="__PENDIENTE__"
|
|
47
|
+
|
|
48
|
+
# Entradas fijas (no "dev-<usuario>") de sql_postgres.authorized_networks en
|
|
49
|
+
# SOURCE_ENV, separadas por ";" como "nombre=ip/32;nombre2=ip2/32". Se
|
|
50
|
+
# copian tal cual al entorno nuevo — son IPs de oficina/admin compartidas
|
|
51
|
+
# entre entornos, no específicas de SOURCE_ENV.
|
|
52
|
+
FIXED_ADMIN_NETWORKS="__PENDIENTE__"
|
|
53
|
+
|
|
54
|
+
# --- Opcionales, con default vacío (no bloquean CONFIG_READY) -----------
|
|
55
|
+
|
|
56
|
+
# Componentes a incluir ADEMÁS de los base (la intersección real de todos
|
|
57
|
+
# los entornos de live/ — ver ksc_base_components). Por defecto NO se
|
|
58
|
+
# incluyen opcionales como cloud_armor/identity_platform/monitoring_alerts
|
|
59
|
+
# /secrets aunque SOURCE_ENV los tenga, siguiendo la guía (§1.2: "no
|
|
60
|
+
# incluir salvo pedido explícito"). Si NEW_ENV sí los necesita, lístalos
|
|
61
|
+
# aquí separados por ";", ej. "secrets;cloud_armor".
|
|
62
|
+
EXTRA_COMPONENTS=""
|
|
63
|
+
|
|
64
|
+
# Si sql_postgres de SOURCE_ENV usa dns_domain_name, da aquí el dominio
|
|
65
|
+
# real que NEW_ENV usa (ej. "xoloshop.mx."). Déjalo vacío para que el
|
|
66
|
+
# skill genere un valor por patrón (<app>.ninja., copiando la convención
|
|
67
|
+
# de SOURCE_ENV) marcado con [WARN] para confirmación humana — el dominio
|
|
68
|
+
# real registrado puede no coincidir con ese patrón visual.
|
|
69
|
+
DNS_DOMAIN=""
|
|
70
|
+
|
|
71
|
+
# --- Copiados de SOURCE_ENV pero marcados para verificación humana/del ---
|
|
72
|
+
# --- agente: no se puede confirmar que sigan siendo la versión más ---
|
|
73
|
+
# --- reciente sin consultar documentación externa en el momento. ---
|
|
74
|
+
|
|
75
|
+
# Versión de GKE (canal Stable). 10_build_components.sh usa este valor tal
|
|
76
|
+
# cual — si quieres la versión estable más reciente real (no la que ya
|
|
77
|
+
# usaba SOURCE_ENV), verifícala y corrígela aquí antes de construir.
|
|
78
|
+
GKE_VERSION_NEEDS_VERIFICATION="__PENDIENTE__"
|
|
79
|
+
|
|
80
|
+
# Versión mayor de Cloud SQL Postgres. Mismo criterio que GKE_VERSION.
|
|
81
|
+
DATABASE_VERSION_NEEDS_VERIFICATION="__PENDIENTE__"
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: github-proyect-tracking
|
|
3
|
+
description: Track process execution state in GitHub Issues with resume.
|
|
4
|
+
version: 0.7.0
|
|
5
|
+
author: Rommel (rommelmg), Hermes Agent
|
|
6
|
+
license: MIT
|
|
7
|
+
platforms: [linux, macos, windows]
|
|
8
|
+
metadata:
|
|
9
|
+
hermes:
|
|
10
|
+
tags: [github, tracking, state-machine, resume, issues]
|
|
11
|
+
category: software-development
|
|
12
|
+
related_skills: [github]
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# github-proyect-tracking Skill
|
|
16
|
+
|
|
17
|
+
Persiste el estado de ejecución de un proceso estructurado en un Issue de
|
|
18
|
+
GitHub (uno por ejecución) y lo reanuda tras interrupciones leyendo el
|
|
19
|
+
último comentario. No ejecuta los pasos del proceso: los instrumenta —
|
|
20
|
+
el agente hace el trabajo real y reporta cada transición con este skill.
|
|
21
|
+
Depende solo de Python 3.8+ (stdlib); `gh` es opcional (fuente de token).
|
|
22
|
+
|
|
23
|
+
**v0.4.0**: cada transición nueva lleva metadatos HTML con `transition_id`
|
|
24
|
+
UUID para reconciliar respuestas perdidas y 500/502/503/504 sin confundir
|
|
25
|
+
otro emisor.
|
|
26
|
+
El resultado CANCELADO se conserva en reintentos, `resume` y `adopt`; tras
|
|
27
|
+
ERROR se exige una reanudación explícita. El lock tiene heartbeat automático,
|
|
28
|
+
el estado usa esquema v2 con migración desde v1 y los instaladores restauran
|
|
29
|
+
el respaldo exacto ante fallos.
|
|
30
|
+
|
|
31
|
+
## When to Use
|
|
32
|
+
|
|
33
|
+
- El usuario pide rastrear/persistir la ejecución de un proceso con estados
|
|
34
|
+
verificables en GitHub (Issues como bitácora) y reanudar tras fallos.
|
|
35
|
+
- Un proceso se interrumpió (error, caída de sesión) y hay que continuar
|
|
36
|
+
exactamente donde quedó, usando el Issue como fuente de verdad.
|
|
37
|
+
- Contador: "trackea este proceso en GitHub", "reanuda donde quedó",
|
|
38
|
+
"registrando el avance del proceso".
|
|
39
|
+
|
|
40
|
+
Don't use for:
|
|
41
|
+
- Crear issues/PRs de mantenimiento sin seguimiento de proceso
|
|
42
|
+
(usa el skill `github`).
|
|
43
|
+
- Persistir secretos en el cuerpo de un Issue (los `Detalles` se
|
|
44
|
+
sanitizan por patrones, pero no guarantees absolutas: no metas
|
|
45
|
+
credenciales).
|
|
46
|
+
|
|
47
|
+
## Prerequisites
|
|
48
|
+
|
|
49
|
+
- `github_project_url` exacta: `https://github.com/{owner}/{repo}`
|
|
50
|
+
(obligatoria en `init`; owner/repo se normalizan a minúsculas).
|
|
51
|
+
- Token de GitHub con permisos de escritura sobre Issues (classic PAT
|
|
52
|
+
scope `repo`; fine-grained: Issues → Read and write). Resolución
|
|
53
|
+
automática: `--token` → `GITHUB_TRACKING_TOKEN` → `GITHUB_TOKEN` →
|
|
54
|
+
`GH_TOKEN` → `gh auth token` → archivo de estado (solo con
|
|
55
|
+
`--store-token`). Sin token → pídelo al usuario; nunca lo inventes.
|
|
56
|
+
- Python 3.8+ en PATH (`python3`).
|
|
57
|
+
|
|
58
|
+
## How to Run
|
|
59
|
+
|
|
60
|
+
Todo corre por `terminal` con un único JSON de respuesta por comando.
|
|
61
|
+
Ruta del script relativa a este skill: `scripts/tracking.py`:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
SKILL="$HOME/.hermes/profiles/<profile>/skills/software-development/github-proyect-tracking/scripts/tracking.py"
|
|
65
|
+
python3 "$SKILL" doctor --url https://github.com/OWNER/REPO --token "$GITHUB_TOKEN"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Quick Reference
|
|
69
|
+
|
|
70
|
+
| Comando | Efecto |
|
|
71
|
+
|---|---|
|
|
72
|
+
| `init --url URL [--plan JSON] [--store-token] [--process-name N]` | Valida URL+token, crea el Issue (título `[Process Tracking][N] Execution ID: …` si se da N), guarda `active_process_id` y `process_name` |
|
|
73
|
+
| `resume [--url URL]` | Lee el ÚLTIMO comentario y dicta cómo continuar |
|
|
74
|
+
| `step-start --name N` | Comenta `[STATUS: INICIANDO] - Paso: N` (valida orden del plan) |
|
|
75
|
+
| `step-done --name N` | Comenta `[STATUS: COMPLETADO] - Paso: N` (exige paso en vuelo) |
|
|
76
|
+
| `step-error --name N --details D` | Comenta `[STATUS: ERROR]` sanitizado y detiene |
|
|
77
|
+
| `finalize [--force]` | FINALIZADO, o CANCELADO con `--force`; cierra y limpia memoria |
|
|
78
|
+
| `status [--remote]` | Estado local (+ veredicto remoto) |
|
|
79
|
+
| `adopt --url URL --execution-id ID [--force]` | Recupera memoria desde un Issue remoto |
|
|
80
|
+
| `clear [--hard]` | Limpia `active_process_id` (o borra el archivo) |
|
|
81
|
+
| `doctor [--url URL]` | Diagnóstico de entorno y permisos (exit 0) |
|
|
82
|
+
|
|
83
|
+
Exit codes: `0` ok · `2` validación/transición inválida · `3` token sin
|
|
84
|
+
permiso · `4` sin token · `5` sin proceso activo · `6` Issue no
|
|
85
|
+
encontrado/ambiguo · `7` resume requerido · `8` conflicto con el estado
|
|
86
|
+
remoto (Issue cerrado externamente o finalize bloqueado). Excepciones
|
|
87
|
+
documentadas al contrato JSON: `--help`/`--version` (salida humana,
|
|
88
|
+
exit 0) y `KeyboardInterrupt` (130).
|
|
89
|
+
|
|
90
|
+
## Procedure
|
|
91
|
+
|
|
92
|
+
1. **Preparar.** `doctor --url URL`. Si `token` o `issues-write` falla,
|
|
93
|
+
pide el PAT al usuario. Criterio: JSON con `"ok": true` en checks
|
|
94
|
+
requeridos (gh es opcional y no rompe `ok`). Un rol demostrado de solo
|
|
95
|
+
lectura hace fallar `issues-write`; `UNVERIFIED` se reserva para permisos
|
|
96
|
+
granulares que la API no puede confirmar.
|
|
97
|
+
2. **Init.** `init --url URL --plan '["Paso 1: ...", ...]'` (plan
|
|
98
|
+
recomendado: nombres ÚNICOS; hace la reanudación determinista).
|
|
99
|
+
Si el proceso pertenece a un skill padre, añade
|
|
100
|
+
`--process-name "Mi Skill"`: el título del Issue pasa a
|
|
101
|
+
`[Process Tracking][Mi Skill] Execution ID: …` y el cuerpo incluye
|
|
102
|
+
`- **Proceso:** Mi Skill` — así el Issue identifica QUÉ se rastrea.
|
|
103
|
+
Para dejar constancia de CON QUÉ se ejecutó, añade `--process-inputs
|
|
104
|
+
'{"archivo":"x.csv","modo":"lint"}'` (objeto clave→valor; se publica
|
|
105
|
+
en la sección "Parámetros de entrada" del Issue, con secretos
|
|
106
|
+
redactados).
|
|
107
|
+
Si devuelve `RESUME_REQUIRED` (exit 7), NO crees otro Issue: ve al
|
|
108
|
+
paso 3. Criterio: `execution_id`, `process_name` e `issue_url` en la
|
|
109
|
+
salida.
|
|
110
|
+
3. **Reanudar (si aplica).** `resume` y sigue el `verdict.action`
|
|
111
|
+
(`RERUN_STEP`, `NEXT_STEP`, `START_FIRST`, `ALL_STEPS_DONE`/
|
|
112
|
+
`FINISH_CLEANUP` → finalize, `ABORTED_EXTERNALLY` → pregunta al
|
|
113
|
+
usuario, `NEXT_STEP_AGENT_DEFINED`). `NONE` y `FINISH_CLEANUP` llevan
|
|
114
|
+
`outcome=FINALIZADO|CANCELADO`; conserva ese resultado.
|
|
115
|
+
4. **Ejecutar pasos.** Por cada paso, en orden estricto: `step-start`
|
|
116
|
+
ANTES de trabajar; si el trabajo falla, `step-error` (el proceso se
|
|
117
|
+
detiene; reanudar exige `resume` y solo permite reintentar ese paso);
|
|
118
|
+
si triunfa, `step-done`. Con plan, el CLI rechaza pasos fuera de orden,
|
|
119
|
+
desconocidos, duplicados o sin `step-start` previo (exit 2). Criterio:
|
|
120
|
+
`comment_url` por transición.
|
|
121
|
+
5. **Finalizar.** Con todos los pasos COMPLETADO: `finalize` — rechaza
|
|
122
|
+
cerrar procesos incompletos (exit 8 `FINALIZE_BLOCKED`) salvo
|
|
123
|
+
`--force` (que registra CANCELADO, no éxito), y nunca un Issue cerrado
|
|
124
|
+
externamente. Sin plan exige al menos un COMPLETADO para éxito; sin
|
|
125
|
+
trabajo, `--force` cancela. Criterio: `issue_state: "closed"`,
|
|
126
|
+
`active_process_id: null` y `outcome` coherente.
|
|
127
|
+
6. **Fallos transitorios de red.** GET/PATCH reintentan solos. Si un POST
|
|
128
|
+
pierde la respuesta o recibe 500/502/503/504, se reconcilia por el UUID
|
|
129
|
+
del intento antes de reintentar UNA vez; otro emisor con el mismo texto
|
|
130
|
+
no lo confirma. `init` también busca el Issue por título con paginación.
|
|
131
|
+
|
|
132
|
+
Memoria interna: `~/.github-proyect-tracking/{owner}__{repo}.json`
|
|
133
|
+
(owner/repo en minúsculas; esquema v2, migración automática desde v1 al
|
|
134
|
+
guardar, escritura atómica con tmp único + fsync y permisos 0600). El candado
|
|
135
|
+
por repositorio mantiene heartbeat durante toda la operación y comprueba su
|
|
136
|
+
propiedad antes de efectos remotos y escrituras. `active_process_id` (número
|
|
137
|
+
de Issue; null si no hay proceso) y `github_token` (SOLO con `--store-token`;
|
|
138
|
+
enmascarado en salidas). Overridable con `GITHUB_TRACKING_STATE`.
|
|
139
|
+
|
|
140
|
+
## Pitfalls
|
|
141
|
+
|
|
142
|
+
- **Título exacto del Issue:** `[Process Tracking] Execution ID: {ID}` —
|
|
143
|
+
no lo edites; `adopt` exige igualdad canónica (IDs parciales se
|
|
144
|
+
rechazan).
|
|
145
|
+
- **Contrato de comentarios:** los formatos visibles `[STATUS: ...]` son
|
|
146
|
+
exactos. La línea HTML de metadatos no cambia ese contrato. Un comentario
|
|
147
|
+
manual que imite el formato se interpretará como evento (el modelo de
|
|
148
|
+
confianza es "cualquiera con acceso al repo puede comentar").
|
|
149
|
+
- **Sanitización de secretos:** `Detalles` y nombres de paso se redactan
|
|
150
|
+
por patrones (tokens GitHub/AWS, Authorization/Bearer, passwords,
|
|
151
|
+
URLs con credenciales) ANTES de publicar — no es una garantía
|
|
152
|
+
absoluta: revisa lo que envías.
|
|
153
|
+
- **`init` con proceso inconcluso** falla con exit 7 a propósito:
|
|
154
|
+
reanuda con `resume` o descarta con `clear`.
|
|
155
|
+
- **`step-error` detiene el proceso** (estado `ERROR`). Continuar exige
|
|
156
|
+
`resume` → `RERUN_STEP` (no se puede hacer `step-done` directo).
|
|
157
|
+
- **`finalize` exige plan completo** (o `--force`); sin plan requiere un
|
|
158
|
+
COMPLETADO para éxito. Un Issue cerrado por un humano nunca se convierte
|
|
159
|
+
en éxito (`ABORTED_EXTERNALLY`, exit 8).
|
|
160
|
+
- **Planes legados duplicados** producen `PLAN_AMBIGUOUS`; asigna nombres
|
|
161
|
+
únicos en el cuerpo del Issue, sin alterar los eventos.
|
|
162
|
+
- **Contexto ambiguo:** varios procesos activos exigen `--url`; `clear`
|
|
163
|
+
también lo exige con varios estados inactivos.
|
|
164
|
+
- **Token en el archivo de estado** solo con `--store-token` (opt-in);
|
|
165
|
+
prefiere variables de entorno o `gh auth token`. `adopt` sí puede usarlo.
|
|
166
|
+
- **Límite de comentarios:** un Issue con >10 000 comentarios produce
|
|
167
|
+
`COMMENTS_TOO_MANY` (error explícito, no veredicto truncado).
|
|
168
|
+
|
|
169
|
+
## Verification
|
|
170
|
+
|
|
171
|
+
- `doctor` → `"ok": true` (gh opcional no rompe el global).
|
|
172
|
+
- Tras `init`: `status` muestra `active_process_id` = número del Issue.
|
|
173
|
+
- Tras `finalize`: `status` → `process_state: "FINALIZED"` o `"CANCELADO"`
|
|
174
|
+
según `outcome`, `active_process_id: null`; `resume` responde `NONE` con el
|
|
175
|
+
mismo `outcome`.
|
|
176
|
+
- Reanudación determinista: tras `step-error`, `resume` →
|
|
177
|
+
`verdict.action == "RERUN_STEP"` con el mismo paso; `step-done` sin
|
|
178
|
+
`step-start` previo falla con `NO_STEP_IN_FLIGHT`.
|
|
179
|
+
- 141 pruebas descubiertas: `python3 tests/test_tracking.py` (140 offline;
|
|
180
|
+
la integración real opt-in se omite por defecto).
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Referencia de API (CLI) — github-proyect-tracking
|
|
2
|
+
|
|
3
|
+
`scripts/tracking.py` — stdlib only, Python 3.8+. Cada comando imprime
|
|
4
|
+
EXACTAMENTE un objeto JSON a stdout y usa un exit code documentado. Los
|
|
5
|
+
ejemplos suponen `PY="python3 <ruta-del-skill>/scripts/tracking.py"`.
|
|
6
|
+
|
|
7
|
+
## Contrato de respuesta
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{ "ok": true, "action": "INIT", "execution_id": "exec-...", "...": "..." }
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Error:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{ "ok": false, "error": { "code": "RESUME_REQUIRED", "message": "...",
|
|
17
|
+
"state": {...}, "next": ["resume"] } }
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
| Exit | code típico | Significado / acción del agente |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| 0 | — | Éxito |
|
|
23
|
+
| 1 | `NETWORK_ERROR`, `RATE_LIMITED`, `STATE_CORRUPT`, `COMMENTS_TOO_MANY`, `STATE_LOCKED`, `STATE_LOCK_LOST`… | Reintentar / diagnosticar / `resume` |
|
|
24
|
+
| 2 | `VALIDATION_ERROR`, `NO_STEP_IN_FLIGHT`, `STEP_OUT_OF_ORDER`, `STEP_NOT_IN_PLAN`, `STEP_ALREADY_DONE`, `STEP_IN_FLIGHT`, `CONTEXT_AMBIGUOUS` | Corregir argumentos o transición |
|
|
25
|
+
| 3 | `INVALID_TOKEN`, `INSUFFICIENT_SCOPE`, `NO_REPO_ACCESS`, `REPO_NOT_FOUND`, `ISSUES_WRITE_FAILED` | Token sin `issues:write` |
|
|
26
|
+
| 4 | `NO_TOKEN` | Pedir el token al usuario |
|
|
27
|
+
| 5 | `NO_STATE`, `NO_ACTIVE_PROCESS` | `init` primero |
|
|
28
|
+
| 6 | `ISSUE_NOT_FOUND`, `ISSUE_AMBIGUOUS` | Verificar número / `adopt` (ID EXACTO) |
|
|
29
|
+
| 7 | `RESUME_REQUIRED` (proceso inconcluso, estado `ERROR`, `adopt` sobre activo) | `resume` (o `adopt --force`) |
|
|
30
|
+
| 8 | `FINALIZE_BLOCKED`, `ABORTED_EXTERNALLY`, `ISSUE_CLOSED_EXTERNALLY`, `ALREADY_FINALIZED` | Conflicto con estado remoto |
|
|
31
|
+
|
|
32
|
+
`finalize --force` publica `[STATUS: CANCELADO] - El proceso fue cerrado
|
|
33
|
+
anticipadamente (--force).` con los pasos pendientes — distinguible del
|
|
34
|
+
éxito (`FINALIZADO`). `NONE` y `FINISH_CLEANUP` incluyen `outcome:
|
|
35
|
+
FINALIZADO|CANCELADO`; reintentar, reanudar o adoptar nunca reclasifica una
|
|
36
|
+
cancelación como éxito.
|
|
37
|
+
|
|
38
|
+
Los comentarios nuevos conservan exactamente esos formatos visibles y añaden
|
|
39
|
+
una línea HTML `<!-- github-proyect-tracking: {...} -->` con `execution_id`,
|
|
40
|
+
`sequence` y `transition_id` UUID. El parser ignora esos metadatos al leer el
|
|
41
|
+
texto y los usa para reconciliar únicamente el intento que originó el POST.
|
|
42
|
+
|
|
43
|
+
## Comandos
|
|
44
|
+
|
|
45
|
+
### `init --url URL [--plan JSON | --plan-file F] [--token T] [--prompt-token] [--store-token] [--process-name N] [--process-inputs JSON]`
|
|
46
|
+
|
|
47
|
+
- Valida la URL (regex, redactada en errores), resuelve el token, valida
|
|
48
|
+
`issues:write` ANTES de crear nada.
|
|
49
|
+
- Crea el Issue `[Process Tracking] Execution ID: {exec_id}` con el cuerpo
|
|
50
|
+
estándar (metadatos + plan numerado SANITIZADO) y guarda
|
|
51
|
+
`active_process_id`.
|
|
52
|
+
- `--plan` recomendado: lista JSON de cadenas (nombres únicos tras
|
|
53
|
+
normalizar: strip+sanitización; duplicados y colisiones se rechazan) →
|
|
54
|
+
`resume` determinista.
|
|
55
|
+
- `--store-token`: persistencia del token OPT-IN (por defecto NO se
|
|
56
|
+
guarda; `--no-store-token` quedó obsoleto).
|
|
57
|
+
- `--process-name N`: nombre del proceso/skill padre. Título resultante:
|
|
58
|
+
`[Process Tracking][N] Execution ID: {exec_id}`; el cuerpo incluye
|
|
59
|
+
`- **Proceso:** N`; estado y JSON llevan `process_name`. Sin `N`, se
|
|
60
|
+
conserva el formato legado `[Process Tracking] Execution ID: …`.
|
|
61
|
+
Un secreto en `N` se redacta; `[`/`]`/saltos → `VALIDATION_ERROR`.
|
|
62
|
+
- `--process-inputs JSON`: objeto clave→valor con los parámetros de
|
|
63
|
+
entrada del proceso. Se publican en la sección "Parámetros de entrada"
|
|
64
|
+
del cuerpo del Issue (ordenados por clave, valores entre backticks) y
|
|
65
|
+
se guardan en el estado (`process_inputs`) y en la salida de `init`
|
|
66
|
+
(`process_inputs`). Secretos en claves/valores se REDACTAN; límites:
|
|
67
|
+
50 pares, valores ≤ 2000 caracteres; claves vacías, JSON inválido o no
|
|
68
|
+
objeto → `VALIDATION_ERROR`. Sin la opción, el estado queda limpio
|
|
69
|
+
(`process_inputs: null`) y el cuerpo no tiene la sección.
|
|
70
|
+
- Salida de `init`: añade `process_name`, `process_inputs` e `issue_title`.
|
|
71
|
+
|
|
72
|
+
Salida: `execution_id`, `issue_number`, `issue_url`, `state_file`, `plan`,
|
|
73
|
+
`first_step`, `token_source`.
|
|
74
|
+
|
|
75
|
+
### `resume [--url URL] [--token T]`
|
|
76
|
+
|
|
77
|
+
- Trae Issue + TODOS los comentarios (paginación por `Link`), parsea
|
|
78
|
+
eventos, emite `verdict` (ver tabla en `references/architecture.md`).
|
|
79
|
+
- `--url` opcional si hay exactamente UN proceso activo; con varios
|
|
80
|
+
activos → `CONTEXT_AMBIGUOUS` (el error lista los repos activos).
|
|
81
|
+
- Registra `last_resume`: después de ERROR autoriza únicamente el reintento
|
|
82
|
+
del paso fallido. Un plan legado duplicado produce `PLAN_AMBIGUOUS` con
|
|
83
|
+
instrucciones para asignar nombres únicos en el cuerpo del Issue.
|
|
84
|
+
|
|
85
|
+
Salida: `issue_state`, `comment_count`, `verdict{action, outcome?,
|
|
86
|
+
resume_from_step, remaining_steps?, failed_step?, error_details?, reason}`.
|
|
87
|
+
|
|
88
|
+
### `step-start --name N` / `step-done --name N`
|
|
89
|
+
|
|
90
|
+
Publican exactamente:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
[STATUS: INICIANDO] - Paso: {N}
|
|
94
|
+
[STATUS: COMPLETADO] - Paso: {N}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### `step-error --name N (--details D | --details-file F)`
|
|
98
|
+
|
|
99
|
+
Publica `[STATUS: ERROR] - Paso: {N} - Detalles: {D}` y fija
|
|
100
|
+
`process_state: "ERROR"` — **el proceso se detiene aquí** (por diseño;
|
|
101
|
+
reanudar exige `resume`). `--details-file` ideal para stacktraces largos
|
|
102
|
+
(trunca a 60000 chars).
|
|
103
|
+
|
|
104
|
+
### `finalize [--url URL] [--token T] [--force] [--summary TEXT | --summary-file F]`
|
|
105
|
+
|
|
106
|
+
1. Verifica el veredicto remoto: rechaza procesos con pasos pendientes
|
|
107
|
+
(`FINALIZE_BLOCKED`, exit 8) y abortes externos. Sin plan permite éxito
|
|
108
|
+
después de un COMPLETADO; sin trabajo exige `--force`.
|
|
109
|
+
2. Sin `--force`: comenta `[STATUS: FINALIZADO] - El proceso concluyó
|
|
110
|
+
exitosamente.` (idempotente). Con `--force`: `[STATUS: CANCELADO] -
|
|
111
|
+
El proceso fue cerrado anticipadamente (--force).` con los pasos
|
|
112
|
+
pendientes (cierre anticipado distinguible, nunca éxito falso).
|
|
113
|
+
3. Si se dio `--summary`/`--summary-file` **y** la ruta es de éxito (no
|
|
114
|
+
`--force`): publica un comentario APARTE con ese texto (sanitizado y
|
|
115
|
+
truncado a 60000 chars, igual que `--details`), inmediatamente después
|
|
116
|
+
del de FINALIZADO. Sin marcador `[STATUS: ...]`, así que `COMMENT_RE`
|
|
117
|
+
lo ignora en lecturas futuras — no es parte de la máquina de estados,
|
|
118
|
+
solo queda como constancia legible en el Issue. `--summary`/
|
|
119
|
+
`--summary-file` vacío o en blanco no publica nada.
|
|
120
|
+
4. Cierra el Issue (PATCH state=closed) y **verifica re-leyendo**.
|
|
121
|
+
5. Limpia `active_process_id` (estado `FINALIZED`/`CANCELADO`) + historial
|
|
122
|
+
(con `outcome`). Un CANCELADO existente conserva ese resultado aunque el
|
|
123
|
+
reintento no lleve `--force`. La salida incluye
|
|
124
|
+
`summary_comment_posted`/`summary_comment_url`.
|
|
125
|
+
|
|
126
|
+
### `status [--url URL] [--remote]`
|
|
127
|
+
|
|
128
|
+
Estado local enmascarado (nunca imprime el token) y, con `--remote`,
|
|
129
|
+
veredicto fresco del Issue.
|
|
130
|
+
|
|
131
|
+
### `adopt --url URL --execution-id ID [--token T] [--force]`
|
|
132
|
+
|
|
133
|
+
Recuperación: busca el Issue por título canónico EXACTO (el ID completo;
|
|
134
|
+
parciales rechazados, ambigüedad → `ISSUE_AMBIGUOUS`), reconstruye el
|
|
135
|
+
archivo de estado local. Carga el estado candidato antes de resolver el
|
|
136
|
+
token, por lo que puede usar el guardado con `--store-token`. No sustituye
|
|
137
|
+
un proceso activo sin `--force` (que conserva token e historial). Si adopta
|
|
138
|
+
un ERROR, guarda `process_state=ERROR` y exige `resume`; conserva CANCELADO
|
|
139
|
+
y ABORTED según el Issue. Útil tras perder la máquina local o tras un
|
|
140
|
+
`clear --hard` accidental.
|
|
141
|
+
|
|
142
|
+
### `clear [--url URL] [--hard]`
|
|
143
|
+
|
|
144
|
+
Soft: `active_process_id := null`, `process_state := "CLEARED"` (conserva
|
|
145
|
+
token/historial). Hard: elimina el archivo. Si el proceso era inconcluso,
|
|
146
|
+
avisa: el Issue queda abierto en GitHub (recuperable con `adopt`). Sin URL,
|
|
147
|
+
varios estados locales —activos o inactivos— producen `CONTEXT_AMBIGUOUS`;
|
|
148
|
+
nunca se elige un archivo destructivamente por fecha.
|
|
149
|
+
|
|
150
|
+
### `doctor [--url URL] [--token T]`
|
|
151
|
+
|
|
152
|
+
Checks: python ≥ 3.8, directorio de estado escribible (crea el directorio
|
|
153
|
+
y un archivo de prueba — efecto de escritura declarado), token resuelto
|
|
154
|
+
(incluye el guardado con `--store-token` del repo de `--url`), GitHub API
|
|
155
|
+
+ rate limit, `gh` CLI (opcional), archivos de estado, URL válida y
|
|
156
|
+
`issues:write` (con `--url`). Siempre exit 0 — es un reporte.
|
|
157
|
+
|
|
158
|
+
## Variables de entorno
|
|
159
|
+
|
|
160
|
+
| Variable | Uso |
|
|
161
|
+
|---|---|
|
|
162
|
+
| `GITHUB_TRACKING_TOKEN` | Token (prioridad máxima de las fuentes automáticas) |
|
|
163
|
+
| `GITHUB_TOKEN` / `GH_TOKEN` | Fallbacks estándar |
|
|
164
|
+
| `GITHUB_TRACKING_STATE` | Directorio alternativo de archivos de estado |
|
|
165
|
+
|
|
166
|
+
## Detalles de la API REST usada
|
|
167
|
+
|
|
168
|
+
| Operación | Endpoint |
|
|
169
|
+
|---|---|
|
|
170
|
+
| Validación de repo/permisos | `GET /repos/{owner}/{repo}` |
|
|
171
|
+
| Crear Issue | `POST /repos/{owner}/{repo}/issues` |
|
|
172
|
+
| Leer Issue / cerrar Issue | `GET` / `PATCH /repos/{owner}/{repo}/issues/{n}` |
|
|
173
|
+
| Comentarios (paginado 100/pág) | `GET /repos/{owner}/{repo}/issues/{n}/comments` |
|
|
174
|
+
| Publicar comentario | `POST /repos/{owner}/{repo}/issues/{n}/comments` |
|
|
175
|
+
| Buscar Issue (adopt) | `GET /search/issues?q=...` |
|
|
176
|
+
| Rate limit (doctor) | `GET /rate_limit` |
|
|
177
|
+
|
|
178
|
+
Cabeceras: `Authorization: Bearer`, `Accept: application/vnd.github+json`,
|
|
179
|
+
`X-GitHub-Api-Version: 2022-11-28`, `User-Agent: github-proyect-tracking/{v}`.
|
|
180
|
+
Reintentos: GET/PATCH/5xx con backoff. Ante respuesta perdida o
|
|
181
|
+
500/502/503/504 en POST, se busca el `transition_id` UUID fuera de la línea
|
|
182
|
+
base y solo entonces se reconcilia; si no aparece, hay un único reintento con
|
|
183
|
+
el mismo UUID y una segunda reconciliación. La creación del Issue usa búsqueda
|
|
184
|
+
paginada por título exacto. Rate limit 403/429 con `X-RateLimit-Remaining: 0`
|
|
185
|
+
espera controlada (máx 90 s).
|