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.
@@ -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).