create-harness-btp 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,78 @@
1
+ <# Verificación de fuentes oficiales del harness BTP (PowerShell 5.1).
2
+ Uso:
3
+ powershell -ExecutionPolicy Bypass -File AI/scripts/check-docs.ps1
4
+ - Comprueba cada URL de AI/docs/fuentes-oficiales.md con UN solo intento
5
+ HTTP GET (timeout 15 s, sin reintentos ni bucles).
6
+ - Emite OK / ROTO / PENDIENTE por fuente + fecha.
7
+ - OK: HTTP 2xx-3xx. ROTO: HTTP 4xx-5xx confirmado. PENDIENTE: sin respuesta
8
+ (timeout/DNS; avisa pero no falla: re-verificar y actualizar la fecha).
9
+ - exit 1 si alguna fuente REQUERIDA está ROTA. exit 0 en otro caso.
10
+ - Cero secretos: solo peticiones GET anónimas, sin credenciales. #>
11
+
12
+ $ErrorActionPreference = "Continue"
13
+ $Fecha = (Get-Date).ToString("yyyy-MM-dd")
14
+ $FallosReq = 0
15
+
16
+ function Test-Doc {
17
+ param([string]$Nombre, [string]$Url, [string]$Nivel)
18
+ try {
19
+ $r = Invoke-WebRequest -Uri $Url -UseBasicParsing -TimeoutSec 15 -MaximumRedirection 5
20
+ $code = [int]$r.StatusCode
21
+ if ($code -ge 200 -and $code -lt 400) {
22
+ Write-Output ("{0} | OK | {1} | {2}" -f $Nombre, $Fecha, $Url)
23
+ } else {
24
+ Write-Output ("{0} | ROTO (HTTP {1}) | {2} | {3}" -f $Nombre, $code, $Fecha, $Url)
25
+ if ($Nivel -eq "REQ") { $script:FallosReq++ }
26
+ }
27
+ } catch {
28
+ $resp = $_.Exception.Response
29
+ if ($resp -ne $null) {
30
+ try { $code = [int]$resp.StatusCode } catch { $code = 0 }
31
+ # .NET Framework (PS 5.1) no sigue HTTP 308 automáticamente aunque se pida
32
+ # -MaximumRedirection: se sigue la redirección UNA sola vez, sin bucles.
33
+ if ($code -eq 308) {
34
+ try {
35
+ $loc = $resp.Headers["Location"]
36
+ if ($loc -notmatch "^https?://") {
37
+ $base = ([System.Uri]$Url).GetLeftPart([System.UriPartial]::Authority)
38
+ $loc = $base + $loc
39
+ }
40
+ $r2 = Invoke-WebRequest -Uri $loc -UseBasicParsing -TimeoutSec 15 -MaximumRedirection 5
41
+ $code2 = [int]$r2.StatusCode
42
+ if ($code2 -ge 200 -and $code2 -lt 400) {
43
+ Write-Output ("{0} | OK (redirige HTTP 308 a {1}) | {2} | {3}" -f $Nombre, $loc, $Fecha, $Url)
44
+ } else {
45
+ Write-Output ("{0} | ROTO (HTTP {1} tras 308) | {2} | {3}" -f $Nombre, $code2, $Fecha, $Url)
46
+ if ($Nivel -eq "REQ") { $script:FallosReq++ }
47
+ }
48
+ } catch {
49
+ Write-Output ("{0} | PENDIENTE (308 sin destino legible) | {1} | {2}" -f $Nombre, $Fecha, $Url)
50
+ }
51
+ } else {
52
+ Write-Output ("{0} | ROTO (HTTP {1}) | {2} | {3}" -f $Nombre, $code, $Fecha, $Url)
53
+ if ($Nivel -eq "REQ") { $script:FallosReq++ }
54
+ }
55
+ } else {
56
+ Write-Output ("{0} | PENDIENTE (sin respuesta: timeout/DNS) | {1} | {2}" -f $Nombre, $Fecha, $Url)
57
+ }
58
+ }
59
+ }
60
+
61
+ Write-Output ""
62
+ Write-Output ("Fuentes oficiales del harness BTP ({0})" -f $Fecha)
63
+ Test-Doc "cf-cli" "https://docs.cloudfoundry.org/cf-cli/install-go-cli.html" "REQ"
64
+ Test-Doc "mbt" "https://github.com/SAP/cloud-mta-build-tool" "REQ"
65
+ Test-Doc "cap" "https://cap.cloud.sap/docs/get-started/" "REQ"
66
+ Test-Doc "ui5-cli" "https://ui5.github.io/cli/" "REQ"
67
+ Test-Doc "opencode" "https://docs.opencode.ai/docs" "REQ"
68
+ Test-Doc "npm-trusted-publishers" "https://docs.npmjs.com/trusted-publishers/" "REQ"
69
+ Test-Doc "op-1password" "https://developer.1password.com/docs/cli/get-started/" "OPT"
70
+ Write-Output ""
71
+
72
+ if ($FallosReq -gt 0) {
73
+ Write-Output ("RESULTADO: {0} fuente(s) REQUERIDA(s) ROTA(s). Revisa AI/docs/fuentes-oficiales.md y actualiza la fecha tras corregir." -f $FallosReq)
74
+ exit 1
75
+ } else {
76
+ Write-Output "RESULTADO: ninguna fuente REQUERIDA rota. Actualiza la columna de fecha en AI/docs/fuentes-oficiales.md."
77
+ exit 0
78
+ }
@@ -0,0 +1,42 @@
1
+ #!/bin/sh
2
+ # Verificación de fuentes oficiales del harness BTP (POSIX sh).
3
+ # Uso: sh AI/scripts/check-docs.sh
4
+ # - Comprueba cada URL de AI/docs/fuentes-oficiales.md con UN solo intento
5
+ # HTTP GET (timeout 15 s, --retry 0, sin reintentos ni bucles).
6
+ # - Emite OK / ROTO / PENDIENTE por fuente + fecha.
7
+ # - OK: HTTP 2xx-3xx. ROTO: HTTP 4xx-5xx confirmado. PENDIENTE: sin respuesta
8
+ # (timeout/DNS; avisa pero no falla: re-verificar y actualizar la fecha).
9
+ # - exit 1 si alguna fuente REQUERIDA está ROTA. exit 0 en otro caso.
10
+ # - Cero secretos: solo peticiones GET anónimas, sin credenciales.
11
+ FECHA=$(date +%F)
12
+ FALLOS_REQ=0
13
+ # check_doc <nombre> <url> <nivel>: un solo intento, sin bucles.
14
+ check_doc() {
15
+ _code=$(curl -s -o /dev/null -w "%{http_code}" -L --max-time 15 --retry 0 "$2" 2>/dev/null)
16
+ _rc=$?
17
+ if [ $_rc -ne 0 ]; then
18
+ echo "$1 | PENDIENTE (sin respuesta: timeout/DNS) | $FECHA | $2"
19
+ elif [ "$_code" -ge 200 ] && [ "$_code" -lt 400 ]; then
20
+ echo "$1 | OK | $FECHA | $2"
21
+ else
22
+ echo "$1 | ROTO (HTTP $_code) | $FECHA | $2"
23
+ if [ "$3" = "REQ" ]; then FALLOS_REQ=$((FALLOS_REQ + 1)); fi
24
+ fi
25
+ }
26
+ echo ""
27
+ echo "Fuentes oficiales del harness BTP ($FECHA)"
28
+ check_doc "cf-cli" "https://docs.cloudfoundry.org/cf-cli/install-go-cli.html" "REQ"
29
+ check_doc "mbt" "https://github.com/SAP/cloud-mta-build-tool" "REQ"
30
+ check_doc "cap" "https://cap.cloud.sap/docs/get-started/" "REQ"
31
+ check_doc "ui5-cli" "https://ui5.github.io/cli/" "REQ"
32
+ check_doc "opencode" "https://docs.opencode.ai/docs" "REQ"
33
+ check_doc "npm-trusted-publishers" "https://docs.npmjs.com/trusted-publishers/" "REQ"
34
+ check_doc "op-1password" "https://developer.1password.com/docs/cli/get-started/" "OPT"
35
+ echo ""
36
+ if [ "$FALLOS_REQ" -gt 0 ]; then
37
+ echo "RESULTADO: $FALLOS_REQ fuente(s) REQUERIDA(s) ROTA(s). Revisa AI/docs/fuentes-oficiales.md y actualiza la fecha tras corregir."
38
+ exit 1
39
+ else
40
+ echo "RESULTADO: ninguna fuente REQUERIDA rota. Actualiza la columna de fecha en AI/docs/fuentes-oficiales.md."
41
+ exit 0
42
+ fi
@@ -0,0 +1,129 @@
1
+ <# Verificación de prerrequisitos del harness BTP (PowerShell 5.1).
2
+ Uso:
3
+ powershell -ExecutionPolicy Bypass -File AI/scripts/check-prereqs.ps1 [-WarnOnly] [-NeedMtar] [-NeedJava] [-NeedCds] [-NeedGh] [-NeedOp]
4
+ - Sin parámetros: comprueba REQUERIDO siempre + OPCIONAL como aviso.
5
+ - -NeedMtar/-NeedJava/-NeedCds/-NeedGh/-NeedOp: promocionan ese opcional a
6
+ REQUERIDO (usar cuando la spec del MVP lo exija).
7
+ - -WarnOnly: nunca falla (exit 0); lo usan install.ps1/install.sh al final.
8
+ NUNCA imprime secretos: solo ejecuta "<comando> --version" y cuenta archivos.
9
+ REQUERIDO faltante -> exit 1 (salvo -WarnOnly). Solo opcionales -> exit 0. #>
10
+ param(
11
+ [switch]$WarnOnly,
12
+ [switch]$NeedMtar,
13
+ [switch]$NeedJava,
14
+ [switch]$NeedCds,
15
+ [switch]$NeedGh,
16
+ [switch]$NeedOp
17
+ )
18
+
19
+ $ErrorActionPreference = "Continue"
20
+ $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
21
+ $HarnessRoot = Split-Path -Parent (Split-Path -Parent $ScriptDir)
22
+
23
+ $rows = New-Object System.Collections.ArrayList
24
+ function Add-Row($tool, $need, $level, $state, $detail, $url) {
25
+ [void]$rows.Add([pscustomobject]@{
26
+ Herramienta = $tool; NecesariaPara = $need; Nivel = $level
27
+ Estado = $state; Detalle = $detail; Instalacion = $url
28
+ })
29
+ }
30
+
31
+ function Test-Tool($name, $versionArgs) {
32
+ try {
33
+ $cmd = Get-Command $name -ErrorAction Stop
34
+ try {
35
+ $out = & $cmd.Source @versionArgs 2>&1 | Select-Object -First 1
36
+ if ($out) { $out = "$out".Trim() } else { $out = "instalado" }
37
+ } catch { $out = "instalado (version no legible)" }
38
+ return @{ Found = $true; Detail = $out }
39
+ } catch { return @{ Found = $false; Detail = "no encontrado en PATH" } }
40
+ }
41
+
42
+ # --- REQUERIDO siempre ---
43
+ $r = Test-Tool "git" @("--version")
44
+ Add-Row "git" "control de versiones del MVP" "REQ" $(if ($r.Found) { "OK" } else { "FALTA" }) $r.Detail "https://git-scm.com/downloads"
45
+
46
+ $node = Test-Tool "node" @("--version")
47
+ $nodeOk = $false
48
+ if ($node.Found) {
49
+ try {
50
+ $m = [regex]::Match($node.Detail, "v?(\d+)\.")
51
+ if ($m.Success -and [int]$m.Groups[1].Value -ge 18) { $nodeOk = $true }
52
+ else { $node.Detail = "$($node.Detail) (se requiere Node 18+)" }
53
+ } catch { $node.Detail = "$($node.Detail) (no se pudo verificar major >= 18)" }
54
+ }
55
+ Add-Row "node 18+" "CAP, UI5, mbt, scripts del harness" "REQ" $(if ($nodeOk) { "OK" } else { "FALTA" }) $node.Detail "https://nodejs.org/"
56
+
57
+ $r = Test-Tool "cf" @("--version")
58
+ $cfState = if ($r.Found) { "OK" } else { "FALTA" }
59
+ if ($r.Found -and ($r.Detail -notmatch "(?i)cf version|cloudfoundry")) {
60
+ $r.Detail = "$($r.Detail) (AVISO: no parece el CLI de Cloud Foundry; si 'cf' es otra herramienta, define un alias al CLI real)"
61
+ $cfState = "FALTA"
62
+ }
63
+ Add-Row "cf" "despliegues y lecturas Cloud Foundry" "REQ" $cfState $r.Detail "https://docs.cloudfoundry.org/cf-cli/install-go-cli.html"
64
+
65
+ $agentsOk = (Test-Path (Join-Path $HarnessRoot "AI\AGENTS.md")) -and ((Test-Path (Join-Path $HarnessRoot "AGENTS.md")) -or (Test-Path (Join-Path $HarnessRoot "templates\AGENTS.pointer.md")))
66
+ Add-Row "cliente agentico" "leer AGENTS.md y orquestar el flujo" "REQ" $(if ($agentsOk) { "OK" } else { "FALTA" }) $(if ($agentsOk) { "AGENTS.md + AI/AGENTS.md presentes; verifica que tu cliente los lea" } else { "falta AGENTS.md o AI/AGENTS.md (reinstala con install.ps1)" }) "https://docs.opencode.ai/ (o tu cliente agéntico)"
67
+
68
+ # --- OPCIONAL según MVP (promocionable con -Need*) ---
69
+ function Opt-Level($flag) { if ($flag) { "REQ" } else { "OPT" } }
70
+
71
+ $r = Test-Tool "mbt" @("--version")
72
+ Add-Row "mbt" "construir MTAR (solo si el MVP lo exige)" (Opt-Level $NeedMtar) $(if ($r.Found) { "OK" } else { "FALTA" }) $r.Detail "https://github.com/SAP/cloud-mta-build-tool"
73
+
74
+ $r = Test-Tool "make" @("--version")
75
+ Add-Row "make" "requerido por mbt en el SO" $(if ($NeedMtar) { "REQ" } else { "OPT" }) $(if ($r.Found) { "OK" } else { "FALTA" }) $r.Detail "https://www.gnu.org/software/make/"
76
+
77
+ $r = Test-Tool "java" @("-version")
78
+ Add-Row "java" "builds MTA Java (solo si la spec los pide)" (Opt-Level $NeedJava) $(if ($r.Found) { "OK" } else { "FALTA" }) $r.Detail "https://adoptium.net/"
79
+
80
+ $r = Test-Tool "cds" @("--version")
81
+ if (-not $r.Found) { $r.Detail = "no global; valido via npx -p @sap/cds-dk (solo si la spec exige CAP)" }
82
+ Add-Row "cds" "proyectos CAP (solo si la spec lo exige)" (Opt-Level $NeedCds) $(if ($r.Found) { "OK" } else { "FALTA" }) $r.Detail "https://cap.cloud.sap/docs/get-started/"
83
+
84
+ $r = Test-Tool "ui5" @("--version")
85
+ Add-Row "ui5" "proyectos UI5/Fiori (solo si la spec lo exige)" $(if ($NeedCds) { "REQ" } else { "OPT" }) $(if ($r.Found) { "OK" } else { "FALTA" }) $r.Detail "https://ui5.github.io/cli/"
86
+
87
+ $r = Test-Tool "gh" @("--version")
88
+ Add-Row "gh" "repo remoto/PR (solo si la spec pide remoto)" (Opt-Level $NeedGh) $(if ($r.Found) { "OK" } else { "FALTA" }) $r.Detail "https://cli.github.com/"
89
+
90
+ $r = Test-Tool "op" @("--version")
91
+ Add-Row "op (1Password)" "secretos de equipo (solo si el equipo lo adopta)" (Opt-Level $NeedOp) $(if ($r.Found) { "OK" } else { "FALTA" }) $r.Detail "https://developer.1password.com/docs/cli/get-started/"
92
+
93
+ # --- Harness: skills, agentes, fragmento MCP (presencia de archivos) ---
94
+ $skills = @()
95
+ $skillsDir = Join-Path $HarnessRoot "AI\.opencode\skills"
96
+ if (Test-Path $skillsDir) { $skills = Get-ChildItem $skillsDir -Directory | Where-Object { Test-Path (Join-Path $_.FullName "SKILL.md") } }
97
+ Add-Row "skills" "capacidades del harness (cf-cli, mta-build, ...)" "OPT" $(if ($skills.Count -gt 0) { "OK" } else { "FALTA" }) "$($skills.Count) skills con SKILL.md" "(vienen con AI/; reinstala con install.ps1 si FALTA)"
98
+
99
+ $agents = @()
100
+ $agentsDir = Join-Path $HarnessRoot "AI\.opencode\agents"
101
+ if (Test-Path $agentsDir) { $agents = Get-ChildItem $agentsDir -Filter "*.md" }
102
+ Add-Row "agents" "orquestador y especialistas" "OPT" $(if ($agents.Count -gt 0) { "OK" } else { "FALTA" }) "$($agents.Count) agentes .md" "(vienen con AI/; reinstala con install.ps1 si FALTA)"
103
+
104
+ $frag = Test-Path (Join-Path $HarnessRoot "AI\opencode.fragment.jsonc")
105
+ Add-Row "fragmento MCP" "plantilla MCP del proyecto destino" "OPT" $(if ($frag) { "OK" } else { "FALTA" }) $(if ($frag) { "AI/opencode.fragment.jsonc presente" } else { "no encontrado" }) "(viene con AI/; reinstala con install.ps1 si FALTA)"
106
+
107
+ # --- Tabla ---
108
+ Write-Output ""
109
+ Write-Output "Prerrequisitos del harness BTP (harness: $HarnessRoot)"
110
+ Write-Output ("{0,-14} | {1,-42} | {2,-5} | {3,-6} | {4}" -f "Herramienta", "Necesaria para", "Nivel", "Estado", "Detalle / Instalacion")
111
+ $rows | ForEach-Object {
112
+ Write-Output ("{0,-14} | {1,-42} | {2,-5} | {3,-6} | {4} [{5}]" -f $_.Herramienta, $_.NecesariaPara, $_.Nivel, $_.Estado, $_.Detalle, $_.Instalacion)
113
+ }
114
+ Write-Output ""
115
+ Write-Output "NOTA MCPs (no detectables desde shell): tu cliente agentico debe tener configurados"
116
+ Write-Output "sus propios MCPs: context7, codebase-memory, github, playwright, eslint, chrome-devtools."
117
+ Write-Output "Detalle y docs oficiales: AI/docs/prerequisitos.md"
118
+
119
+ $reqMissing = @($rows | Where-Object { $_.Nivel -eq "REQ" -and $_.Estado -eq "FALTA" })
120
+ $optMissing = @($rows | Where-Object { $_.Nivel -eq "OPT" -and $_.Estado -eq "FALTA" })
121
+ if ($reqMissing.Count -gt 0) {
122
+ Write-Output ("RESULTADO: FALTAN {0} REQUERIDOS ({1}). Instala y re-ejecuta este script." -f $reqMissing.Count, (($reqMissing | ForEach-Object { $_.Herramienta }) -join ", "))
123
+ if ($WarnOnly) { exit 0 } else { exit 1 }
124
+ } else {
125
+ if ($optMissing.Count -gt 0) {
126
+ Write-Output ("RESULTADO: OK en requeridos. Avisos opcionales ({0}): {1}." -f $optMissing.Count, (($optMissing | ForEach-Object { $_.Herramienta }) -join ", "))
127
+ } else { Write-Output "RESULTADO: todo OK (requeridos + opcionales presentes)." }
128
+ exit 0
129
+ }
@@ -0,0 +1,136 @@
1
+ #!/bin/sh
2
+ # Verificación de prerrequisitos del harness BTP (POSIX sh).
3
+ # Uso: ./check-prereqs.sh [--warn-only] [--need-mtar] [--need-java] [--need-cds] [--need-gh] [--need-op]
4
+ # --need-*: promociona ese opcional a REQUERIDO (cuando la spec del MVP lo exija).
5
+ # --warn-only: nunca falla (exit 0); lo usan install.ps1/install.sh al final.
6
+ # NUNCA imprime secretos: solo ejecuta "<comando> --version" y cuenta archivos.
7
+ # REQUERIDO faltante -> exit 1 (salvo --warn-only). Solo opcionales -> exit 0.
8
+ WARN_ONLY=0; NEED_MTAR=0; NEED_JAVA=0; NEED_CDS=0; NEED_GH=0; NEED_OP=0
9
+ for a in "$@"; do
10
+ case "$a" in
11
+ --warn-only) WARN_ONLY=1 ;;
12
+ --need-mtar) NEED_MTAR=1 ;;
13
+ --need-java) NEED_JAVA=1 ;;
14
+ --need-cds) NEED_CDS=1 ;;
15
+ --need-gh) NEED_GH=1 ;;
16
+ --need-op) NEED_OP=1 ;;
17
+ *) echo "ABORT: opción desconocida $a"; exit 1 ;;
18
+ esac
19
+ done
20
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
21
+ HARNESS_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
22
+
23
+ N_REQ_MISSING=""; N_OPT_MISSING=0; OPT_NAMES=""
24
+ row() { printf '%-14s | %-42s | %-5s | %-6s | %s [%s]\n' "$1" "$2" "$3" "$4" "$5" "$6"; }
25
+ record() {
26
+ # record <nivel> <estado> <nombre>
27
+ if [ "$1" = "REQ" ] && [ "$2" = "FALTA" ]; then
28
+ if [ -z "$N_REQ_MISSING" ]; then N_REQ_MISSING="$3"; else N_REQ_MISSING="$N_REQ_MISSING, $3"; fi
29
+ elif [ "$1" = "OPT" ] && [ "$2" = "FALTA" ]; then
30
+ N_OPT_MISSING=$((N_OPT_MISSING + 1))
31
+ if [ -z "$OPT_NAMES" ]; then OPT_NAMES="$3"; else OPT_NAMES="$OPT_NAMES, $3"; fi
32
+ fi
33
+ }
34
+ check_cmd() {
35
+ # check_cmd <nombre> <args...>: imprime "versión" o "no encontrado en PATH"
36
+ name="$1"; shift
37
+ if command -v "$name" >/dev/null 2>&1; then
38
+ v=$("$name" "$@" 2>&1 | head -n 1)
39
+ [ -z "$v" ] && v="instalado"
40
+ printf '%s' "$v"
41
+ return 0
42
+ fi
43
+ printf 'no encontrado en PATH'
44
+ return 1
45
+ }
46
+ opt_level() { if [ "$1" -eq 1 ]; then printf 'REQ'; else printf 'OPT'; fi; }
47
+
48
+ echo ""
49
+ echo "Prerrequisitos del harness BTP (harness: $HARNESS_ROOT)"
50
+ printf '%-14s | %-42s | %-5s | %-6s | %s\n' "Herramienta" "Necesaria para" "Nivel" "Estado" "Detalle / Instalacion"
51
+
52
+ if v=$(check_cmd git --version); then S=OK; else S=FALTA; fi
53
+ row "git" "control de versiones del MVP" "REQ" "$S" "$v" "https://git-scm.com/downloads"; record REQ "$S" git
54
+
55
+ if v=$(check_cmd node --version); then
56
+ major=$(printf '%s' "$v" | sed -n 's/^v\?\([0-9][0-9]*\).*/\1/p')
57
+ if [ -n "$major" ] && [ "$major" -ge 18 ]; then S=OK; else S=FALTA; v="$v (se requiere Node 18+)"; fi
58
+ else S=FALTA; fi
59
+ row "node 18+" "CAP, UI5, mbt, scripts del harness" "REQ" "$S" "$v" "https://nodejs.org/"; record REQ "$S" "node 18+"
60
+
61
+ if v=$(check_cmd cf --version); then
62
+ case "$v" in *[Cc][Ff]*version*|*[Cc]loud*[Ff]oundry*) S=OK ;; *) S=FALTA; v="$v (AVISO: no parece el CLI de Cloud Foundry; si 'cf' es otra herramienta, define un alias al CLI real)" ;; esac
63
+ else S=FALTA; fi
64
+ row "cf" "despliegues y lecturas Cloud Foundry" "REQ" "$S" "$v" "https://docs.cloudfoundry.org/cf-cli/install-go-cli.html"; record REQ "$S" cf
65
+
66
+ if [ -f "$HARNESS_ROOT/AI/AGENTS.md" ] && { [ -f "$HARNESS_ROOT/AGENTS.md" ] || [ -f "$HARNESS_ROOT/templates/AGENTS.pointer.md" ]; }; then
67
+ S=OK; v="AGENTS.md + AI/AGENTS.md presentes; verifica que tu cliente los lea"
68
+ else
69
+ S=FALTA; v="falta AGENTS.md o AI/AGENTS.md (reinstala con install.sh)"
70
+ fi
71
+ row "cliente agentico" "leer AGENTS.md y orquestar el flujo" "REQ" "$S" "$v" "https://docs.opencode.ai/ (o tu cliente agéntico)"; record REQ "$S" "cliente agentico"
72
+
73
+ LVL=$(opt_level $NEED_MTAR)
74
+ if v=$(check_cmd mbt --version); then S=OK; else S=FALTA; fi
75
+ row "mbt" "construir MTAR (solo si el MVP lo exige)" "$LVL" "$S" "$v" "https://github.com/SAP/cloud-mta-build-tool"; record "$LVL" "$S" mbt
76
+
77
+ if [ "$NEED_MTAR" -eq 1 ]; then LVL=REQ; else LVL=OPT; fi
78
+ if v=$(check_cmd make --version); then S=OK; else S=FALTA; fi
79
+ row "make" "requerido por mbt" "$LVL" "$S" "$v" "https://www.gnu.org/software/make/"; record "$LVL" "$S" make
80
+
81
+ LVL=$(opt_level $NEED_JAVA)
82
+ if v=$(check_cmd java -version); then S=OK; else S=FALTA; fi
83
+ row "java" "builds MTA Java (solo si la spec los pide)" "$LVL" "$S" "$v" "https://adoptium.net/"; record "$LVL" "$S" java
84
+
85
+ LVL=$(opt_level $NEED_CDS)
86
+ if v=$(check_cmd cds --version); then S=OK; else S=FALTA; v="no global; valido via npx -p @sap/cds-dk (solo si la spec exige CAP)"; fi
87
+ row "cds" "proyectos CAP (solo si la spec lo exige)" "$LVL" "$S" "$v" "https://cap.cloud.sap/docs/get-started/"; record "$LVL" "$S" cds
88
+
89
+ if [ "$NEED_CDS" -eq 1 ]; then LVL=REQ; else LVL=OPT; fi
90
+ if v=$(check_cmd ui5 --version); then S=OK; else S=FALTA; fi
91
+ row "ui5" "proyectos UI5/Fiori (solo si la spec lo exige)" "$LVL" "$S" "$v" "https://ui5.github.io/cli/"; record "$LVL" "$S" ui5
92
+
93
+ LVL=$(opt_level $NEED_GH)
94
+ if v=$(check_cmd gh --version); then S=OK; else S=FALTA; fi
95
+ row "gh" "repo remoto/PR (solo si la spec pide remoto)" "$LVL" "$S" "$v" "https://cli.github.com/"; record "$LVL" "$S" gh
96
+
97
+ LVL=$(opt_level $NEED_OP)
98
+ if v=$(check_cmd op --version); then S=OK; else S=FALTA; fi
99
+ row "op (1Password)" "secretos de equipo (solo si el equipo lo adopta)" "$LVL" "$S" "$v" "https://developer.1password.com/docs/cli/get-started/"; record "$LVL" "$S" "op (1Password)"
100
+
101
+ NSKILLS=0
102
+ if [ -d "$HARNESS_ROOT/AI/.opencode/skills" ]; then
103
+ for d in "$HARNESS_ROOT"/AI/.opencode/skills/*/; do
104
+ [ -f "${d}SKILL.md" ] && NSKILLS=$((NSKILLS + 1))
105
+ done
106
+ fi
107
+ if [ "$NSKILLS" -gt 0 ]; then S=OK; else S=FALTA; fi
108
+ row "skills" "capacidades del harness (cf-cli, mta-build, ...)" "OPT" "$S" "$NSKILLS skills con SKILL.md" "(vienen con AI/; reinstala con install.sh si FALTA)"; record OPT "$S" skills
109
+
110
+ NAGENTS=0
111
+ if [ -d "$HARNESS_ROOT/AI/.opencode/agents" ]; then
112
+ # shellcheck disable=SC2012
113
+ NAGENTS=$(ls "$HARNESS_ROOT"/AI/.opencode/agents/*.md 2>/dev/null | wc -l | tr -d ' ')
114
+ fi
115
+ if [ "$NAGENTS" -gt 0 ]; then S=OK; else S=FALTA; fi
116
+ row "agents" "orquestador y especialistas" "OPT" "$S" "$NAGENTS agentes .md" "(vienen con AI/; reinstala con install.sh si FALTA)"; record OPT "$S" agents
117
+
118
+ if [ -f "$HARNESS_ROOT/AI/opencode.fragment.jsonc" ]; then S=OK; v="AI/opencode.fragment.jsonc presente"; else S=FALTA; v="no encontrado"; fi
119
+ row "fragmento MCP" "plantilla MCP del proyecto destino" "OPT" "$S" "$v" "(viene con AI/; reinstala con install.sh si FALTA)"; record OPT "$S" "fragmento MCP"
120
+
121
+ echo ""
122
+ echo "NOTA MCPs (no detectables desde shell): tu cliente agéntico debe tener configurados"
123
+ echo "sus propios MCPs: context7, codebase-memory, github, playwright, eslint, chrome-devtools."
124
+ echo "Detalle y docs oficiales: AI/docs/prerequisitos.md"
125
+
126
+ if [ -n "$N_REQ_MISSING" ]; then
127
+ echo "RESULTADO: FALTAN REQUERIDOS ($N_REQ_MISSING). Instala y re-ejecuta este script."
128
+ if [ "$WARN_ONLY" -eq 1 ]; then exit 0; else exit 1; fi
129
+ else
130
+ if [ "$N_OPT_MISSING" -gt 0 ]; then
131
+ echo "RESULTADO: OK en requeridos. Avisos opcionales ($N_OPT_MISSING): $OPT_NAMES."
132
+ else
133
+ echo "RESULTADO: todo OK (requeridos + opcionales presentes)."
134
+ fi
135
+ exit 0
136
+ fi
@@ -6,7 +6,7 @@
6
6
  faltan -> asigna rol solo si falta. Emite SKIP: si existe, CREATE: si crea.
7
7
  Allowlist cerrada: target, spaces, space-users, services, marketplace,
8
8
  create-space, create-service, set-space-role.
9
- PROHIBIDO: delete-*, unbind-*, purge-*, restage-*. Usa sap_cf (nunca cf).
9
+ PROHIBIDO: delete-*, unbind-*, purge-*, restage-*. Usa cf.
10
10
  Cero secretos en repo: solo nombres. #>
11
11
  param(
12
12
  [string]$Space = "TODO(<paisaje>)",
@@ -17,7 +17,7 @@ param(
17
17
  $ErrorActionPreference = "Stop"
18
18
 
19
19
  function Target-Ok {
20
- $t = & sap_cf target 2>&1 | Out-String
20
+ $t = & cf target 2>&1 | Out-String
21
21
  if ($t -notmatch [regex]::Escape($ExpectedApi)) { Write-Output "ABORT: endpoint no coincide (esperado $ExpectedApi)"; return $false }
22
22
  if ($t -notmatch [regex]::Escape($ExpectedOrg)) { Write-Output "ABORT: org no coincide (esperada $ExpectedOrg)"; return $false }
23
23
  return $true
@@ -26,19 +26,19 @@ function Target-Ok {
26
26
  if (-not (Target-Ok)) { exit 1 }
27
27
 
28
28
  # 1. Espacio: crear solo si falta
29
- $spaces = & sap_cf spaces 2>&1 | Out-String
29
+ $spaces = & cf spaces 2>&1 | Out-String
30
30
  if ($spaces -match "(?m)^\s*$([regex]::Escape($Space))\s*$") {
31
31
  Write-Output "SKIP: space $Space ya existe"
32
32
  } else {
33
- & sap_cf create-space $Space
33
+ & cf create-space $Space
34
34
  Write-Output "CREATE: space $Space"
35
35
  }
36
- & sap_cf target -s $Space | Out-Null
36
+ & cf target -s $Space | Out-Null
37
37
 
38
38
  # 2. Guardia de marketplace: aborta antes de crear si falta un offering
39
39
  # TODO: lista los offerings requeridos, p. ej. @("xsuaa", "destination")
40
40
  $RequiredOfferings = @()
41
- $market = & sap_cf marketplace 2>&1 | Out-String
41
+ $market = & cf marketplace 2>&1 | Out-String
42
42
  foreach ($o in $RequiredOfferings) {
43
43
  if ($market -notmatch [regex]::Escape($o)) {
44
44
  Write-Output "ABORT: offering $o no disponible en marketplace"
@@ -49,12 +49,12 @@ foreach ($o in $RequiredOfferings) {
49
49
  # 3. Instancias: crear solo si faltan
50
50
  # TODO: anadir una entrada por instancia: @{ Name="TODO"; Offering="TODO"; Plan="TODO" }
51
51
  $Instances = @()
52
- $services = & sap_cf services 2>&1 | Out-String
52
+ $services = & cf services 2>&1 | Out-String
53
53
  foreach ($i in $Instances) {
54
54
  if ($services -match [regex]::Escape($i.Name)) {
55
55
  Write-Output ("SKIP: service {0} ya existe" -f $i.Name)
56
56
  } else {
57
- & sap_cf create-service $i.Offering $i.Plan $i.Name
57
+ & cf create-service $i.Offering $i.Plan $i.Name
58
58
  Write-Output ("CREATE: service {0}" -f $i.Name)
59
59
  }
60
60
  }
@@ -62,11 +62,11 @@ foreach ($i in $Instances) {
62
62
  # 4. Rol: asignar solo si falta
63
63
  # TODO: fijar usuario, p. ej. $User = "TODO"
64
64
  $User = "TODO"
65
- $users = & sap_cf space-users $ExpectedOrg $Space 2>&1 | Out-String
65
+ $users = & cf space-users $ExpectedOrg $Space 2>&1 | Out-String
66
66
  if ($users -match [regex]::Escape($User)) {
67
67
  Write-Output "SKIP: rol de $User ya asignado"
68
68
  } else {
69
- & sap_cf set-space-role $User $ExpectedOrg $Space SpaceDeveloper
69
+ & cf set-space-role $User $ExpectedOrg $Space SpaceDeveloper
70
70
  Write-Output "CREATE: rol SpaceDeveloper para $User"
71
71
  }
72
72