create-harness-btp 0.2.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AI/VERSION +1 -1
- package/AI/agents/analyst.md +30 -0
- package/AI/agents/architect.md +29 -0
- package/AI/agents/backend-cap.md +19 -0
- package/AI/agents/deploy-cf.md +26 -0
- package/AI/agents/documentarian.md +20 -0
- package/AI/agents/e2e-fiori.md +62 -0
- package/AI/agents/frontend-ui5.md +20 -0
- package/AI/agents/harness-evolution.md +38 -0
- package/AI/agents/orchestrator.md +41 -0
- package/AI/agents/qa-review.md +28 -0
- package/AI/agents/researcher.md +29 -0
- package/AI/clients/claude/agents/analyst.md +22 -0
- package/AI/clients/claude/agents/architect.md +21 -0
- package/AI/clients/claude/agents/backend-cap.md +18 -0
- package/AI/clients/claude/agents/deploy-cf.md +25 -0
- package/AI/clients/claude/agents/documentarian.md +15 -0
- package/AI/clients/claude/agents/e2e-fiori.md +61 -0
- package/AI/clients/claude/agents/frontend-ui5.md +19 -0
- package/AI/clients/claude/agents/harness-evolution.md +37 -0
- package/AI/clients/claude/agents/orchestrator.md +40 -0
- package/AI/clients/claude/agents/qa-review.md +27 -0
- package/AI/clients/claude/agents/researcher.md +21 -0
- package/AI/clients/claude/commands/flow.md +16 -0
- package/AI/clients/claude/commands/verify.md +18 -0
- package/AI/clients/claude/skills/cap-cli/SKILL.md +21 -0
- package/AI/clients/claude/skills/cf-cli/SKILL.md +41 -0
- package/AI/clients/claude/skills/mta-build/SKILL.md +45 -0
- package/AI/clients/claude/skills/sap-verify/SKILL.md +27 -0
- package/AI/clients/copilot/agents/analyst.agent.md +22 -0
- package/AI/clients/copilot/agents/architect.agent.md +21 -0
- package/AI/clients/copilot/agents/backend-cap.agent.md +18 -0
- package/AI/clients/copilot/agents/deploy-cf.agent.md +25 -0
- package/AI/clients/copilot/agents/documentarian.agent.md +15 -0
- package/AI/clients/copilot/agents/e2e-fiori.agent.md +61 -0
- package/AI/clients/copilot/agents/frontend-ui5.agent.md +19 -0
- package/AI/clients/copilot/agents/harness-evolution.agent.md +37 -0
- package/AI/clients/copilot/agents/orchestrator.agent.md +40 -0
- package/AI/clients/copilot/agents/qa-review.agent.md +27 -0
- package/AI/clients/copilot/agents/researcher.agent.md +21 -0
- package/AI/clients/copilot/prompts/flow.prompt.md +16 -0
- package/AI/clients/copilot/prompts/verify.prompt.md +18 -0
- package/AI/clients/copilot/skills/cap-cli/SKILL.md +21 -0
- package/AI/clients/copilot/skills/cf-cli/SKILL.md +41 -0
- package/AI/clients/copilot/skills/mta-build/SKILL.md +45 -0
- package/AI/clients/copilot/skills/sap-verify/SKILL.md +27 -0
- package/AI/clients/cursor/commands/flow.md +12 -0
- package/AI/clients/cursor/commands/verify.md +14 -0
- package/AI/clients/cursor/skills/cap-cli/SKILL.md +21 -0
- package/AI/clients/cursor/skills/cf-cli/SKILL.md +41 -0
- package/AI/clients/cursor/skills/mta-build/SKILL.md +45 -0
- package/AI/clients/cursor/skills/sap-verify/SKILL.md +27 -0
- package/AI/clients/opencode/agents/analyst.md +29 -0
- package/AI/clients/opencode/agents/architect.md +28 -0
- package/AI/clients/opencode/agents/backend-cap.md +18 -0
- package/AI/clients/opencode/agents/deploy-cf.md +25 -0
- package/AI/clients/opencode/agents/documentarian.md +19 -0
- package/AI/clients/opencode/agents/e2e-fiori.md +61 -0
- package/AI/clients/opencode/agents/frontend-ui5.md +19 -0
- package/AI/clients/opencode/agents/harness-evolution.md +37 -0
- package/AI/clients/opencode/agents/orchestrator.md +40 -0
- package/AI/clients/opencode/agents/qa-review.md +27 -0
- package/AI/clients/opencode/agents/researcher.md +28 -0
- package/AI/clients/opencode/commands/flow.md +16 -0
- package/AI/clients/opencode/commands/verify.md +18 -0
- package/AI/clients/opencode/skills/cap-cli/SKILL.md +21 -0
- package/AI/clients/opencode/skills/cf-cli/SKILL.md +41 -0
- package/AI/clients/opencode/skills/mta-build/SKILL.md +45 -0
- package/AI/clients/opencode/skills/sap-verify/SKILL.md +27 -0
- package/AI/commands/flow.md +16 -0
- package/AI/commands/verify.md +18 -0
- package/AI/skills/cap-cli/SKILL.md +21 -0
- package/AI/skills/cf-cli/SKILL.md +41 -0
- package/AI/skills/mta-build/SKILL.md +45 -0
- package/AI/skills/sap-verify/SKILL.md +27 -0
- package/README.md +54 -16
- package/VERSION +1 -1
- package/bin/harness-btp.js +87 -3
- package/install.ps1 +85 -2
- package/install.sh +95 -5
- package/package.json +1 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cf-cli
|
|
3
|
+
description: Uso estándar del CLI de Cloud Foundry (cf)
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CLI Cloud Foundry (`cf`)
|
|
7
|
+
|
|
8
|
+
El CLI de Cloud Foundry se invoca **siempre** como `cf` (instalación
|
|
9
|
+
estándar del CLI; adapta rutas según tu equipo). Si `cf` en tu máquina
|
|
10
|
+
corresponde a otra herramienta, define un alias propio y úsalo de forma
|
|
11
|
+
consistente donde el harness diga `cf`.
|
|
12
|
+
|
|
13
|
+
## Lectura segura (sin secretos)
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
cf target # endpoint / org / espacio actuales
|
|
17
|
+
cf api # endpoint y versión API
|
|
18
|
+
cf orgs # solo nombres
|
|
19
|
+
cf spaces # solo nombres
|
|
20
|
+
cf apps # estado observable (started/stopped, rutas)
|
|
21
|
+
cf services # instancias visibles
|
|
22
|
+
cf logs <app> --recent
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`target`, `api`, `orgs`, `spaces` y `app <nombre>` nunca muestran tokens.
|
|
26
|
+
Si una salida incluyera un secreto, redáctalo antes de citarla.
|
|
27
|
+
|
|
28
|
+
## Mutaciones (solo `deploy-cf`, con destino confirmado)
|
|
29
|
+
|
|
30
|
+
- Confirmar endpoint/org/espacio contra la spec **antes** de cada despliegue.
|
|
31
|
+
- `cf push` para apps simples; `cf deploy <archivo>.mtar` para MTA
|
|
32
|
+
(requiere plugin `multiapps`, no instalado: ver skill `mta-build`).
|
|
33
|
+
- Verificar después: `cf apps` + `cf logs <app> --recent` + URL.
|
|
34
|
+
|
|
35
|
+
## Denylist
|
|
36
|
+
|
|
37
|
+
- Borrar o renombrar orgs, espacios, apps o servicios fuera del MVP.
|
|
38
|
+
- `cf login`/re-autenticaciones no solicitadas (si la sesión caduca,
|
|
39
|
+
pedir al usuario el flujo interactivo, nunca credenciales en texto).
|
|
40
|
+
- `--var`/`--vars-file` con secretos en shell compartida; usar archivos ya
|
|
41
|
+
ignorados por Git y no citar sus valores.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mta-build
|
|
3
|
+
description: Construir y verificar artefactos MTAR con mbt en este equipo
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Build MTA (`mbt`)
|
|
7
|
+
|
|
8
|
+
`mbt` es Cloud MTA Build Tool 1.2.50 (verificado 2026-10-29). Invocarlo
|
|
9
|
+
siempre como `mbt`, nunca como `cf` ni rutas inventadas.
|
|
10
|
+
|
|
11
|
+
## Flujo
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
mbt build # requiere mta.yaml en la raíz del proyecto
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- El `.mtar` resultante queda en `mta_archives/` con el nombre/versión de
|
|
18
|
+
`mta.yaml`. Comprobar existencia y fecha antes de desplegar.
|
|
19
|
+
- Para módulos Node.js, `mbt` ejecuta `npm install`/`npm run build` según
|
|
20
|
+
`mta.yaml`; para Java necesita Maven (`mvn` no instalado: documentar como
|
|
21
|
+
pendiente si una spec lo exige).
|
|
22
|
+
- `mbt build --help` para flags (`--mtar`, `--platform=cf`).
|
|
23
|
+
|
|
24
|
+
## Despliegue del MTAR
|
|
25
|
+
|
|
26
|
+
`cf deploy <archivo>.mtar` requiere el **plugin multiapps**. Verificar
|
|
27
|
+
siempre con `cf plugins` antes de asumir su ausencia (2026-10-30 resultó
|
|
28
|
+
ya instalado contra lo documentado). Instalarlo solo cuando un MVP necesite
|
|
29
|
+
despliegue MTA:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
cf install-plugin -r CF-Community multiapps
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Alternativa sin plugin para MVPs simples: `cf push` por app según plan.
|
|
36
|
+
|
|
37
|
+
## Notas
|
|
38
|
+
|
|
39
|
+
- El binario `mbt.exe` se obtuvo con el propio `install.js` del paquete npm
|
|
40
|
+
(`node install.js cloud-mta-build-tool`). Si `mbt` vuelve a fallar tras
|
|
41
|
+
una actualización global, repetir ese comando en el directorio del paquete.
|
|
42
|
+
- Nunca versionar `mta_archives/*.mtar` ni `default-services.json` con claves.
|
|
43
|
+
- `mbt` exige `make` en `%PATH%` (ver `AGENTS.md` § Disciplina de shell y
|
|
44
|
+
CLIs): si falla `exec: "make": executable file not found`, anteponer el
|
|
45
|
+
`bin` de ezwinports/GnuWin32 al `$env:PATH` solo para el comando.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sap-verify
|
|
3
|
+
description: Clasificar disponibilidad, cuenta y coste de servicios SAP/BTP
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Verificación de dependencias externas SAP
|
|
7
|
+
|
|
8
|
+
Toda afirmación sobre un servicio, plan, API o capacidad BTP se clasifica en
|
|
9
|
+
una de estas categorías, con fuente y fecha:
|
|
10
|
+
|
|
11
|
+
| Categoría | Significado |
|
|
12
|
+
|---|---|
|
|
13
|
+
| **Documentado** | Docs oficiales vigentes + evidencia (comando, consola o enlace con fecha). |
|
|
14
|
+
| **Pendiente en cuenta** | Existe en docs pero sin comprobar en la subcuenta/destino real. |
|
|
15
|
+
| **Coste por cotizar** | Requiere plan de pago o métrica no verificada; no activar sin confirmación. |
|
|
16
|
+
|
|
17
|
+
## Reglas
|
|
18
|
+
|
|
19
|
+
- Desarrollo local y mocks primero; servicios reales solo con evidencia.
|
|
20
|
+
- Distinguir Windows local frente a BAS/dev space remoto: una instalación o
|
|
21
|
+
capacidad de un lado no implica la del otro.
|
|
22
|
+
- No afirmar que una integración está aprobada o disponible hasta comprobarla
|
|
23
|
+
con documentación y accesos vigentes.
|
|
24
|
+
- Costes: antes de activar cualquier recurso con coste, verificar precio y
|
|
25
|
+
documentarlo en la spec; capa gratuita por defecto.
|
|
26
|
+
- Bloqueos externos no paran el MVP: documentar evidencia y continuar con
|
|
27
|
+
mocks o adaptador local.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Ciclo completo spec-despliegue de un MVP SAP BTP
|
|
3
|
+
agent: orchestrator
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Ejecuta el flujo sobre la especificación: $ARGUMENTS
|
|
7
|
+
(p. ej. `/flow specs/mi-mvp.md`).
|
|
8
|
+
|
|
9
|
+
El orquestador recorre las etapas 0–10 de `AGENTS.md` con los especialistas
|
|
10
|
+
adecuados (`analyst`, `researcher`, `architect`, `frontend-ui5`,
|
|
11
|
+
`backend-cap`, `qa-review`, `deploy-cf`, `documentarian`). En MVPs pequeños
|
|
12
|
+
puede saltar etapas irrelevantes y registrarlo; ningún riesgo o
|
|
13
|
+
incertidumbre bloquea por sí solo: se investiga, se decide con evidencia y
|
|
14
|
+
se continúa con lo resoluble. La puerta de despliegue (etapa 7) es
|
|
15
|
+
obligatoria antes de desplegar. Al cerrar: qué se hizo, verificaciones con
|
|
16
|
+
comandos y resultado real, y qué quedó pendiente y por qué.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Puerta de despliegue CF sin desplegar
|
|
3
|
+
agent: orchestrator
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Ejecuta solo la puerta de despliegue (etapa 7) para $ARGUMENTS
|
|
7
|
+
(spec o nombre de app; si se omite, el MVP en curso).
|
|
8
|
+
|
|
9
|
+
Verificaciones (delegables en `qa-review` + `deploy-cf` en solo lectura):
|
|
10
|
+
|
|
11
|
+
1. `cf target` coincide con el destino de la spec (endpoint/org/espacio).
|
|
12
|
+
2. El artefacto existe y es reciente (`.mtar` en `mta_archives/` o bundle
|
|
13
|
+
para `push`).
|
|
14
|
+
3. Todos los criterios de aceptación están en verde con evidencia.
|
|
15
|
+
4. Diff/Git sin secretos ni archivos que debieran estar ignorados.
|
|
16
|
+
|
|
17
|
+
Veredicto: apto / no apto con motivos concretos. Este comando nunca
|
|
18
|
+
despliega ni muta nada en Cloud Foundry.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cap-cli
|
|
3
|
+
description: Invocación verificada del CLI de CAP y facets en este equipo
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CLI de CAP (`cds`)
|
|
7
|
+
|
|
8
|
+
Nombres verificados el 2026-10-29 (docs cap.cloud.sap vía `context7`;
|
|
9
|
+
paquete `@cap-js/cds-dk` **no existe** — el correcto es `@sap/cds-dk`):
|
|
10
|
+
|
|
11
|
+
- CLI solo vía `npx -p @sap/cds-dk cds ...` (el `node_modules` del proyecto
|
|
12
|
+
no incluye el ejecutable `cds`; `npx cds` a secas falla).
|
|
13
|
+
- Runtime del proyecto: `@sap/cds` v10 + `@cap-js/sqlite` v3 (SQLite solo
|
|
14
|
+
para dev local; sin persistencia en CF).
|
|
15
|
+
- Scaffold: `npx -p @sap/cds-dk cds init <nombre> --nodejs` (no global).
|
|
16
|
+
- Facets usadas en este harness: `mta xsuaa approuter html5-repo
|
|
17
|
+
destination ui5` (lista completa real con `cds add --help`, no de memoria).
|
|
18
|
+
- Tras `cds add`, siempre `npm install` antes del siguiente comando.
|
|
19
|
+
- `cds add` es aditivo y genera `mta.yaml`/`xs-security.json`: revisar el
|
|
20
|
+
diff antes de aceptar lo generado (nombres de instancia deben coincidir
|
|
21
|
+
con las existentes en la subcuenta).
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cf-cli
|
|
3
|
+
description: Uso estándar del CLI de Cloud Foundry (cf)
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CLI Cloud Foundry (`cf`)
|
|
7
|
+
|
|
8
|
+
El CLI de Cloud Foundry se invoca **siempre** como `cf` (instalación
|
|
9
|
+
estándar del CLI; adapta rutas según tu equipo). Si `cf` en tu máquina
|
|
10
|
+
corresponde a otra herramienta, define un alias propio y úsalo de forma
|
|
11
|
+
consistente donde el harness diga `cf`.
|
|
12
|
+
|
|
13
|
+
## Lectura segura (sin secretos)
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
cf target # endpoint / org / espacio actuales
|
|
17
|
+
cf api # endpoint y versión API
|
|
18
|
+
cf orgs # solo nombres
|
|
19
|
+
cf spaces # solo nombres
|
|
20
|
+
cf apps # estado observable (started/stopped, rutas)
|
|
21
|
+
cf services # instancias visibles
|
|
22
|
+
cf logs <app> --recent
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`target`, `api`, `orgs`, `spaces` y `app <nombre>` nunca muestran tokens.
|
|
26
|
+
Si una salida incluyera un secreto, redáctalo antes de citarla.
|
|
27
|
+
|
|
28
|
+
## Mutaciones (solo `deploy-cf`, con destino confirmado)
|
|
29
|
+
|
|
30
|
+
- Confirmar endpoint/org/espacio contra la spec **antes** de cada despliegue.
|
|
31
|
+
- `cf push` para apps simples; `cf deploy <archivo>.mtar` para MTA
|
|
32
|
+
(requiere plugin `multiapps`, no instalado: ver skill `mta-build`).
|
|
33
|
+
- Verificar después: `cf apps` + `cf logs <app> --recent` + URL.
|
|
34
|
+
|
|
35
|
+
## Denylist
|
|
36
|
+
|
|
37
|
+
- Borrar o renombrar orgs, espacios, apps o servicios fuera del MVP.
|
|
38
|
+
- `cf login`/re-autenticaciones no solicitadas (si la sesión caduca,
|
|
39
|
+
pedir al usuario el flujo interactivo, nunca credenciales en texto).
|
|
40
|
+
- `--var`/`--vars-file` con secretos en shell compartida; usar archivos ya
|
|
41
|
+
ignorados por Git y no citar sus valores.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mta-build
|
|
3
|
+
description: Construir y verificar artefactos MTAR con mbt en este equipo
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Build MTA (`mbt`)
|
|
7
|
+
|
|
8
|
+
`mbt` es Cloud MTA Build Tool 1.2.50 (verificado 2026-10-29). Invocarlo
|
|
9
|
+
siempre como `mbt`, nunca como `cf` ni rutas inventadas.
|
|
10
|
+
|
|
11
|
+
## Flujo
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
mbt build # requiere mta.yaml en la raíz del proyecto
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- El `.mtar` resultante queda en `mta_archives/` con el nombre/versión de
|
|
18
|
+
`mta.yaml`. Comprobar existencia y fecha antes de desplegar.
|
|
19
|
+
- Para módulos Node.js, `mbt` ejecuta `npm install`/`npm run build` según
|
|
20
|
+
`mta.yaml`; para Java necesita Maven (`mvn` no instalado: documentar como
|
|
21
|
+
pendiente si una spec lo exige).
|
|
22
|
+
- `mbt build --help` para flags (`--mtar`, `--platform=cf`).
|
|
23
|
+
|
|
24
|
+
## Despliegue del MTAR
|
|
25
|
+
|
|
26
|
+
`cf deploy <archivo>.mtar` requiere el **plugin multiapps**. Verificar
|
|
27
|
+
siempre con `cf plugins` antes de asumir su ausencia (2026-10-30 resultó
|
|
28
|
+
ya instalado contra lo documentado). Instalarlo solo cuando un MVP necesite
|
|
29
|
+
despliegue MTA:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
cf install-plugin -r CF-Community multiapps
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Alternativa sin plugin para MVPs simples: `cf push` por app según plan.
|
|
36
|
+
|
|
37
|
+
## Notas
|
|
38
|
+
|
|
39
|
+
- El binario `mbt.exe` se obtuvo con el propio `install.js` del paquete npm
|
|
40
|
+
(`node install.js cloud-mta-build-tool`). Si `mbt` vuelve a fallar tras
|
|
41
|
+
una actualización global, repetir ese comando en el directorio del paquete.
|
|
42
|
+
- Nunca versionar `mta_archives/*.mtar` ni `default-services.json` con claves.
|
|
43
|
+
- `mbt` exige `make` en `%PATH%` (ver `AGENTS.md` § Disciplina de shell y
|
|
44
|
+
CLIs): si falla `exec: "make": executable file not found`, anteponer el
|
|
45
|
+
`bin` de ezwinports/GnuWin32 al `$env:PATH` solo para el comando.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sap-verify
|
|
3
|
+
description: Clasificar disponibilidad, cuenta y coste de servicios SAP/BTP
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Verificación de dependencias externas SAP
|
|
7
|
+
|
|
8
|
+
Toda afirmación sobre un servicio, plan, API o capacidad BTP se clasifica en
|
|
9
|
+
una de estas categorías, con fuente y fecha:
|
|
10
|
+
|
|
11
|
+
| Categoría | Significado |
|
|
12
|
+
|---|---|
|
|
13
|
+
| **Documentado** | Docs oficiales vigentes + evidencia (comando, consola o enlace con fecha). |
|
|
14
|
+
| **Pendiente en cuenta** | Existe en docs pero sin comprobar en la subcuenta/destino real. |
|
|
15
|
+
| **Coste por cotizar** | Requiere plan de pago o métrica no verificada; no activar sin confirmación. |
|
|
16
|
+
|
|
17
|
+
## Reglas
|
|
18
|
+
|
|
19
|
+
- Desarrollo local y mocks primero; servicios reales solo con evidencia.
|
|
20
|
+
- Distinguir Windows local frente a BAS/dev space remoto: una instalación o
|
|
21
|
+
capacidad de un lado no implica la del otro.
|
|
22
|
+
- No afirmar que una integración está aprobada o disponible hasta comprobarla
|
|
23
|
+
con documentación y accesos vigentes.
|
|
24
|
+
- Costes: antes de activar cualquier recurso con coste, verificar precio y
|
|
25
|
+
documentarlo en la spec; capa gratuita por defecto.
|
|
26
|
+
- Bloqueos externos no paran el MVP: documentar evidencia y continuar con
|
|
27
|
+
mocks o adaptador local.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# harness-btp
|
|
2
2
|
|
|
3
|
-
[](https://github.com/horangelmillan/harness-btp/releases/tag/v0.3.0)
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
[](https://github.com/horangelmillan/harness-btp)
|
|
6
6
|
[](https://github.com/horangelmillan/harness-btp)
|
|
@@ -18,6 +18,7 @@ Para quien construye MVPs SAP BTP y quiere empezar cada proyecto con el mismo fl
|
|
|
18
18
|
- [Instalación asistida por agente](#instalación-asistida-por-agente)
|
|
19
19
|
- [Actualizar y desinstalar](#actualizar-y-desinstalar)
|
|
20
20
|
- [Adaptadores opcionales](#adaptadores-opcionales)
|
|
21
|
+
- [Multi-cliente](#multi-cliente)
|
|
21
22
|
- [Estructura del repo](#estructura-del-repo)
|
|
22
23
|
- [Cómo lo descubre el agente](#cómo-lo-descubre-el-agente)
|
|
23
24
|
- [Troubleshooting](#troubleshooting)
|
|
@@ -55,7 +56,7 @@ El camino de 30 segundos en un proyecto nuevo. Elige tu shell:
|
|
|
55
56
|
PowerShell (Windows):
|
|
56
57
|
|
|
57
58
|
```powershell
|
|
58
|
-
npx -p degit degit horangelmillan/harness-btp#v0.
|
|
59
|
+
npx -p degit degit horangelmillan/harness-btp#v0.3.0 AI-tmp -- AI-tmp
|
|
59
60
|
powershell -ExecutionPolicy Bypass -File AI-tmp/install.ps1 -Dest .
|
|
60
61
|
Remove-Item -Recurse -Force AI-tmp
|
|
61
62
|
```
|
|
@@ -63,7 +64,7 @@ Remove-Item -Recurse -Force AI-tmp
|
|
|
63
64
|
bash (Linux, macOS o Git Bash):
|
|
64
65
|
|
|
65
66
|
```bash
|
|
66
|
-
npx -p degit degit horangelmillan/harness-btp#v0.
|
|
67
|
+
npx -p degit degit horangelmillan/harness-btp#v0.3.0 AI-tmp -- AI-tmp
|
|
67
68
|
sh AI-tmp/install.sh --dest .
|
|
68
69
|
rm -rf AI-tmp
|
|
69
70
|
```
|
|
@@ -79,7 +80,7 @@ Descarga solo lo necesario, sin historial git:
|
|
|
79
80
|
PowerShell:
|
|
80
81
|
|
|
81
82
|
```powershell
|
|
82
|
-
npx -p degit degit horangelmillan/harness-btp#v0.
|
|
83
|
+
npx -p degit degit horangelmillan/harness-btp#v0.3.0 AI-tmp -- AI-tmp
|
|
83
84
|
powershell -ExecutionPolicy Bypass -File AI-tmp/install.ps1 -Dest .
|
|
84
85
|
Remove-Item -Recurse -Force AI-tmp
|
|
85
86
|
```
|
|
@@ -87,7 +88,7 @@ Remove-Item -Recurse -Force AI-tmp
|
|
|
87
88
|
bash:
|
|
88
89
|
|
|
89
90
|
```bash
|
|
90
|
-
npx -p degit degit horangelmillan/harness-btp#v0.
|
|
91
|
+
npx -p degit degit horangelmillan/harness-btp#v0.3.0 AI-tmp -- AI-tmp
|
|
91
92
|
sh AI-tmp/install.sh --dest .
|
|
92
93
|
rm -rf AI-tmp
|
|
93
94
|
```
|
|
@@ -99,7 +100,7 @@ Clon superficial anclado al tag:
|
|
|
99
100
|
PowerShell:
|
|
100
101
|
|
|
101
102
|
```powershell
|
|
102
|
-
git clone --branch v0.
|
|
103
|
+
git clone --branch v0.3.0 --depth 1 https://github.com/horangelmillan/harness-btp AI-tmp
|
|
103
104
|
powershell -ExecutionPolicy Bypass -File AI-tmp/install.ps1 -Dest .
|
|
104
105
|
Remove-Item -Recurse -Force AI-tmp
|
|
105
106
|
```
|
|
@@ -107,7 +108,7 @@ Remove-Item -Recurse -Force AI-tmp
|
|
|
107
108
|
bash:
|
|
108
109
|
|
|
109
110
|
```bash
|
|
110
|
-
git clone --branch v0.
|
|
111
|
+
git clone --branch v0.3.0 --depth 1 https://github.com/horangelmillan/harness-btp AI-tmp
|
|
111
112
|
sh AI-tmp/install.sh --dest .
|
|
112
113
|
rm -rf AI-tmp
|
|
113
114
|
```
|
|
@@ -117,22 +118,25 @@ rm -rf AI-tmp
|
|
|
117
118
|
Sin descargas manuales (requiere publicar `create-harness-btp` en el registry). Igual en todos los SO:
|
|
118
119
|
|
|
119
120
|
```bash
|
|
120
|
-
pnpm dlx create-harness-btp@0.
|
|
121
|
+
pnpm dlx create-harness-btp@0.3.0 --dest .
|
|
121
122
|
```
|
|
122
123
|
|
|
123
124
|
### Qué hace el instalador
|
|
124
125
|
|
|
125
126
|
- `CREATE: AI/` o `SKIP: AI/ ya existe` (solo lo reemplaza con `-Force` / `--force`, con backup a `AI.bak`).
|
|
126
127
|
- `CREATE: AGENTS.md` o `SKIP: AGENTS.md ya existe` (tu `AGENTS.md` propio se conserva; con `-Force` / `--force` se respalda a `AGENTS.md.bak`).
|
|
128
|
+
- Fusiona el árbol del cliente agéntico (`--client`, por defecto `auto`) desde `AI/clients/<cliente>/` en la raíz (ver [Multi-cliente](#multi-cliente)): sin fuerza solo copia los archivos que falten (`SKIP: <dir>/<ruta> ya existe` por cada uno conservado); con `-Force` / `--force` respalda cada dir a `<dir>.bak` (`BACKUP: <dir>/ -> <dir>.bak`) y copia todo.
|
|
127
129
|
- Fusiona `.gitignore`: añade las líneas que falten, sin duplicar ni borrar las tuyas.
|
|
128
130
|
- **No toca** `package.json` ni `mta.yaml` de tu proyecto, nunca.
|
|
129
131
|
|
|
130
132
|
Salida típica en proyecto nuevo:
|
|
131
133
|
|
|
132
134
|
```text
|
|
133
|
-
CREATE: AI/
|
|
135
|
+
CREATE: AI/ (v0.3.0)
|
|
134
136
|
CREATE: AGENTS.md
|
|
135
|
-
|
|
137
|
+
CLIENT: auto -> opencode
|
|
138
|
+
CREATE: .opencode/ (+17 archivos)
|
|
139
|
+
OK: harness v0.3.0 instalado
|
|
136
140
|
```
|
|
137
141
|
|
|
138
142
|
## Instalación asistida por agente
|
|
@@ -152,7 +156,7 @@ Vale para proyecto nuevo (con URL), existente, Windows/Linux/macOS y cualquier c
|
|
|
152
156
|
PowerShell:
|
|
153
157
|
|
|
154
158
|
```powershell
|
|
155
|
-
npx -p degit degit horangelmillan/harness-btp#v0.
|
|
159
|
+
npx -p degit degit horangelmillan/harness-btp#v0.3.0 AI-tmp -- AI-tmp
|
|
156
160
|
powershell -ExecutionPolicy Bypass -File AI-tmp/install.ps1 -Dest . -Force
|
|
157
161
|
Remove-Item -Recurse -Force AI-tmp
|
|
158
162
|
# tu versión anterior queda en AI.bak por si quieres comparar
|
|
@@ -161,7 +165,7 @@ Remove-Item -Recurse -Force AI-tmp
|
|
|
161
165
|
bash:
|
|
162
166
|
|
|
163
167
|
```bash
|
|
164
|
-
npx -p degit degit horangelmillan/harness-btp#v0.
|
|
168
|
+
npx -p degit degit horangelmillan/harness-btp#v0.3.0 AI-tmp -- AI-tmp
|
|
165
169
|
sh AI-tmp/install.sh --dest . --force
|
|
166
170
|
rm -rf AI-tmp
|
|
167
171
|
# tu versión anterior queda en AI.bak por si quieres comparar
|
|
@@ -192,9 +196,32 @@ El harness funciona con **cualquier** cliente agéntico que lea `AGENTS.md`. Est
|
|
|
192
196
|
- **`AI/.opencode/`** — agentes, comandos y skills de ejemplo con el layout de OpenCode. Si tu cliente usa otro layout, ignóralos o adaptalos: el flujo vive en `AI/AGENTS.md`, `AI/INICIO.md`, `AI/docs/` y `AI/scripts/`, que son Markdown + shell portátil.
|
|
193
197
|
- **`AI/opencode.fragment.jsonc`** — fragmento de ejemplo para fusionar en tu `opencode.jsonc` (p. ej. el bloque MCP `graphify-code`, deshabilitado por defecto). Solo aplica a OpenCode; otros clientes lo ignoran sin efecto.
|
|
194
198
|
- **`install.ps1` / `install.sh`** — elige el de tu shell; ambos aplican la misma lógica idempotente. Los scripts de `AI/scripts/` también vienen en par `.ps1` / `.sh`.
|
|
199
|
+
- **Multi-cliente:** desde v0.3.0 la fuente única es `AI/agents/`, `AI/commands/`, `AI/skills/` y cada cliente recibe su árbol renderizado en `AI/clients/<cliente>/` (ver [Multi-cliente](#multi-cliente)). `AI/.opencode/` se conserva intacto por compatibilidad.
|
|
195
200
|
|
|
196
201
|
Nada del núcleo exige OpenCode, Windows ni ningún modelo concreto.
|
|
197
202
|
|
|
203
|
+
## Multi-cliente
|
|
204
|
+
|
|
205
|
+
El harness se configura para el cliente agéntico de turno desde UNA sola definición canónica:
|
|
206
|
+
|
|
207
|
+
- **Canónico (`AI/`):** `AI/agents/*.md` (11 agentes), `AI/commands/*.md` (`flow`, `verify`), `AI/skills/*/SKILL.md` (4 skills). Es la única fuente que se edita a mano.
|
|
208
|
+
- **Render (`AI/clients/`):** generado con `node scripts/render-clients.js` (sin dependencias); `node scripts/render-clients.js --check` solo verifica. El CI lo exige en verde antes de publicar (ver `.github/workflows/publish.yml`). No edites `AI/clients/` a mano: tus cambios se pierden en el próximo render.
|
|
209
|
+
|
|
210
|
+
| Cliente | `--client` | Rutas generadas en la raíz | Adaptación |
|
|
211
|
+
|---|---|---|---|
|
|
212
|
+
| OpenCode | `opencode` | `.opencode/agents/`, `.opencode/commands/`, `.opencode/skills/` | copia exacta de `AI/.opencode/` |
|
|
213
|
+
| Claude Code | `claude` | `.claude/agents/`, `.claude/commands/`, `.claude/skills/` | agents con `{name,description}` (sin `mode`) |
|
|
214
|
+
| Cursor | `cursor` | `.cursor/commands/`, `.agents/skills/` | commands sin frontmatter (solo cuerpo) |
|
|
215
|
+
| Copilot | `copilot` | `.github/agents/*.agent.md`, `.github/prompts/*.prompt.md`, `.github/skills/` | renombrados a su convención |
|
|
216
|
+
| Aider (y genéricos) | `aider` | nada que generar | usan el `AGENTS.md` raíz |
|
|
217
|
+
|
|
218
|
+
Flag `--client` en `install.ps1` (`-Client`), `install.sh` y `bin/harness-btp.js`:
|
|
219
|
+
|
|
220
|
+
- `auto` (defecto): detecta por huellas (`CLAUDE.md`/`.claude`→claude, `.cursor`→cursor, `.github`→copilot, `opencode.json*`/`.opencode`→opencode); sin huellas usa opencode por compatibilidad histórica. Si hay huellas de varios clientes, fusiona los detectados.
|
|
221
|
+
- `all`: fusiona los cuatro árboles.
|
|
222
|
+
- Lista explícita (`-Client claude,cursor` / `--client claude,cursor`): solo esos.
|
|
223
|
+
- Fusión idempotente con mensajes `CREATE:`/`SKIP:` por archivo y `BACKUP` a `<dir>.bak` con fuerza (mismo patrón que `AI/`).
|
|
224
|
+
|
|
198
225
|
## Estructura del repo
|
|
199
226
|
|
|
200
227
|
```text
|
|
@@ -202,18 +229,24 @@ harness-btp/
|
|
|
202
229
|
├── AI/ # lo que queda instalado en tu proyecto
|
|
203
230
|
│ ├── AGENTS.md # reglas del harness (parametrizado, sin rutas absolutas)
|
|
204
231
|
│ ├── INICIO.md # punto de entrada para el agente
|
|
232
|
+
│ ├── agents/ # CANÓNICO: 11 agentes (única fuente, se edita a mano)
|
|
233
|
+
│ ├── commands/ # CANÓNICO: flow + verify (única fuente)
|
|
234
|
+
│ ├── skills/ # CANÓNICO: 4 skills (única fuente)
|
|
235
|
+
│ ├── clients/ # RENDERIZADO por scripts/render-clients.js (no editar a mano)
|
|
205
236
|
│ ├── opencode.fragment.jsonc# ADAPTER opcional: ejemplo para opencode.jsonc
|
|
206
|
-
│ ├── .opencode/ # ADAPTER opcional:
|
|
237
|
+
│ ├── .opencode/ # ADAPTER opcional: se conserva intacto (compatibilidad)
|
|
207
238
|
│ ├── scripts/ # pares .ps1 / .sh + provision-espacio.template.ps1
|
|
208
239
|
│ ├── docs/ # flujo-etapas, cf-safe, habilitacion-trial
|
|
209
240
|
│ ├── specs/ # plantilla _template.md
|
|
210
241
|
│ └── .gitignore.fragment # líneas a fusionar en tu .gitignore
|
|
242
|
+
├── scripts/
|
|
243
|
+
│ └── render-clients.js # genera AI/clients/ desde el canónico (--check en CI)
|
|
211
244
|
├── templates/
|
|
212
245
|
│ └── AGENTS.pointer.md # plantilla del puntero AGENTS.md raíz
|
|
213
246
|
├── install.ps1 / install.sh # instaladores idempotentes (SKIP / CREATE / BACKUP / OK)
|
|
214
247
|
├── bin/ # ejecutable de create-harness-btp (pnpm dlx)
|
|
215
248
|
├── package.json # name create-harness-btp
|
|
216
|
-
└── VERSION # 0.
|
|
249
|
+
└── VERSION # 0.3.0
|
|
217
250
|
```
|
|
218
251
|
|
|
219
252
|
## Cómo lo descubre el agente
|
|
@@ -230,12 +263,14 @@ Tú no configuras nada: el agente se adapta solo.
|
|
|
230
263
|
| Problema | Causa | Comando |
|
|
231
264
|
|---|---|---|
|
|
232
265
|
| `SKIP: AI/ ya existe` y quería actualizar | reinstalación sin fuerza conserva lo existente | repite con `-Force` (`.ps1`) o `--force` (`.sh`); guarda `AI.bak` |
|
|
266
|
+
| No aparece `orchestrator` / no existe `/flow` | fusión a `.opencode/` raíz ausente (OpenCode solo descubre `.opencode/` en la raíz del proyecto, no `AI/.opencode/`) | reinstala sin fuerza (copia solo faltantes) o copia `AI/.opencode/` a `.opencode/` en la raíz sin pisar archivos propios |
|
|
233
267
|
| Mi `AGENTS.md` propio desapareció | se instaló con fuerza | recupera `AGENTS.md.bak` |
|
|
234
268
|
| Líneas duplicadas en `.gitignore` | edición manual tras la fusión | el instalador fusiona sin duplicar; borra el duplicado a mano |
|
|
235
269
|
| `ExecutionPolicy` bloquea `install.ps1` | política de PowerShell | `powershell -ExecutionPolicy Bypass -File AI-tmp/install.ps1 -Dest .` (o usa `install.sh` en Git Bash) |
|
|
236
270
|
| `ABORT: opción desconocida` en `install.sh` | flag inexistente | `sh install.sh --help` lista `--dest`, `--force` |
|
|
237
|
-
| `degit` falla sin Node | `degit` corre sobre Node 18+ | instala Node o usa `git clone --branch v0.
|
|
271
|
+
| `degit` falla sin Node | `degit` corre sobre Node 18+ | instala Node o usa `git clone --branch v0.3.0` |
|
|
238
272
|
| Tu cliente no lee los agentes de `.opencode/` | layout específico de OpenCode | son un adapter opcional; el flujo está en `AI/AGENTS.md` + `AI/INICIO.md` |
|
|
273
|
+
| Mi cliente no ve los agentes (claude/cursor/copilot) | instalaste sin el `--client` que usa tu proyecto (`auto` no encontró sus huellas) | reinstala sin fuerza con `--client <tu-cliente>` (p. ej. `--client claude`) y verifica la tabla de [Multi-cliente](#multi-cliente): `.claude/`, `.cursor/commands/` + `.agents/skills/`, o `.github/agents\|prompts\|skills` según cliente; si sigue sin verlos, revisa la fusión y no dupliques archivos a mano |
|
|
239
274
|
| No se deja borrar la carpeta del proyecto ("Carpeta en uso") | procesos huérfanos parados dentro (shells/MCPs de una sesión ya cerrada) | resmon → CPU → Identificadores asociados → busca la carpeta y termina solo esos PIDs; nunca fueron del instalador (solo copia archivos y termina) |
|
|
240
275
|
|
|
241
276
|
## Compatibilidad
|
|
@@ -262,8 +297,11 @@ MIT. Haz lo que quieras con el harness; sin garantía.
|
|
|
262
297
|
|
|
263
298
|
## Changelog
|
|
264
299
|
|
|
300
|
+
- **v0.3.0** — multi-cliente: definición canónica única en `AI/agents/`, `AI/commands/`, `AI/skills/`; render a `AI/clients/<cliente>/` con `scripts/render-clients.js` (opencode byte-idéntico a `AI/.opencode/`, que se conserva intacto); instaladores con flag `--client auto|all|<lista>` (detección por huellas, fusión idempotente con `SKIP`/`BACKUP` por dir); `prompts/setup.md` pregunta el cliente si es ambiguo y verifica adopción por cliente; CI exige `render-clients.js --check` antes de la guardia de versiones.
|
|
301
|
+
|
|
302
|
+
- **v0.3.0** — fusión a `.opencode/` raíz: el instalador sincroniza `AI/.opencode/` (agents + commands + skills) en `.opencode/` del proyecto para que OpenCode descubra `orchestrator` y `/flow` (SKIP sin fuerza, `.opencode.bak` con fuerza); `prompts/setup.md` verifica adopción y fusiona el fragmento MCP.
|
|
265
303
|
- **v0.2.4** — estilo Neon: una línea que lee `prompts/setup.md` (versionado, siempre al día) en vez de un bloque que caduca.
|
|
266
304
|
- **v0.2.3** — prompt universal todo-en-uno: clona + instala con la versión que indique el README (nunca caduca), verifica AI/VERSION instalado.
|
|
267
305
|
- **v0.2.2** — anti-huérfanos: bloque de agente con regla de cierre limpio (no dejar servidores corriendo, no borrar carpetas con procesos dentro) + troubleshooting de carpeta bloqueada (resmon → Identificadores asociados).
|
|
268
306
|
- **v0.2.1** — trazabilidad y versión visible: `AI/VERSION` viaja en el paquete, los instaladores imprimen la versión (`OK: harness vX.Y.Z…`, `BACKUP` con vieja→nueva) y el workflow exige que `package.json`, `VERSION` y `AI/VERSION` coincidan. Comandos fijados a `@0.2.1` / `#v0.2.1` / `--branch v0.2.1`.
|
|
269
|
-
- **v0.2.0** — versión inicial: carpeta `AI/` parametrizada, instaladores idempotentes `install.ps1` / `install.sh`, `create-harness-btp` vía `pnpm dlx`, plantilla de puntero, docs de flujo / cf-safe / habilitación trial, plantilla de spec.
|
|
307
|
+
- **v0.2.0** — versión inicial: carpeta `AI/` parametrizada, instaladores idempotentes `install.ps1` / `install.sh`, `create-harness-btp` vía `pnpm dlx`, plantilla de puntero, docs de flujo / cf-safe / habilitación trial, plantilla de spec.
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.3.0
|
package/bin/harness-btp.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// harness-btp init --dest <dir> [--force] [--ref <tag>]
|
|
3
|
-
// Copia AI/, crea AGENTS.md puntero
|
|
2
|
+
// harness-btp init --dest <dir> [--force] [--ref <tag>] [--client auto|all|opencode,claude,...]
|
|
3
|
+
// Copia AI/, crea AGENTS.md puntero, fusiona el árbol del cliente agéntico
|
|
4
|
+
// desde AI/clients/<cliente>/ en la raíz (solo faltantes; con --force hace
|
|
5
|
+
// backup a <dir>.bak) y fusiona .gitignore. Sin secretos.
|
|
4
6
|
// No toca package.json ni mta.yaml del proyecto.
|
|
5
7
|
const fs = require("fs");
|
|
6
8
|
const path = require("path");
|
|
@@ -18,10 +20,11 @@ if (!cmd || cmd.startsWith("-")) {
|
|
|
18
20
|
const dest = arg("--dest", ".");
|
|
19
21
|
const force = process.argv.includes("--force");
|
|
20
22
|
const ref = arg("--ref", null);
|
|
23
|
+
const clientSpec = arg("--client", "auto");
|
|
21
24
|
const src = path.join(__dirname, "..");
|
|
22
25
|
|
|
23
26
|
if (cmd !== "init") {
|
|
24
|
-
console.log("Uso: harness-btp init --dest <dir> [--force] [--ref <tag>]");
|
|
27
|
+
console.log("Uso: harness-btp init --dest <dir> [--force] [--ref <tag>] [--client auto|all|opencode,claude,...]");
|
|
25
28
|
process.exit(1);
|
|
26
29
|
}
|
|
27
30
|
if (ref) console.log("REF: " + ref + " (el paquete incluye su propia versión; ver VERSION)");
|
|
@@ -61,6 +64,87 @@ if (fs.existsSync(agentsDst)) {
|
|
|
61
64
|
console.log("CREATE: AGENTS.md (puntero a AI/AGENTS.md)");
|
|
62
65
|
}
|
|
63
66
|
|
|
67
|
+
const KNOWN = ["opencode", "claude", "cursor", "copilot", "aider"];
|
|
68
|
+
function resolveClients(spec, destDir) {
|
|
69
|
+
const s = (spec + "").trim().toLowerCase();
|
|
70
|
+
if (s === "auto") {
|
|
71
|
+
const d = [];
|
|
72
|
+
if (fs.existsSync(path.join(destDir, "CLAUDE.md")) || fs.existsSync(path.join(destDir, ".claude"))) d.push("claude");
|
|
73
|
+
if (fs.existsSync(path.join(destDir, ".cursor"))) d.push("cursor");
|
|
74
|
+
if (fs.existsSync(path.join(destDir, ".github"))) d.push("copilot");
|
|
75
|
+
if (fs.readdirSync(destDir, { withFileTypes: true }).some((e) => e.isFile() && e.name.startsWith("opencode.json")) || fs.existsSync(path.join(destDir, ".opencode"))) d.push("opencode");
|
|
76
|
+
if (!d.length) d.push("opencode");
|
|
77
|
+
console.log("CLIENT: auto -> " + d.join(","));
|
|
78
|
+
return d;
|
|
79
|
+
}
|
|
80
|
+
if (s === "all") return ["opencode", "claude", "cursor", "copilot"];
|
|
81
|
+
const list = s.split(",").map((x) => x.trim().toLowerCase()).filter(Boolean);
|
|
82
|
+
for (const c of list) {
|
|
83
|
+
if (!KNOWN.includes(c)) {
|
|
84
|
+
console.log("ABORT: cliente desconocido '" + c + "' (usa auto|all|opencode,claude,cursor,copilot,aider)");
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (!list.length) {
|
|
89
|
+
console.log("ABORT: --client vacío (usa auto|all|opencode,claude,cursor,copilot,aider)");
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
return list;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function mergeTree(treeSrc, treeDst, label) {
|
|
96
|
+
if (!fs.existsSync(treeSrc)) {
|
|
97
|
+
console.log("AVISO: no existe " + treeSrc + " (regenera con node scripts/render-clients.js)");
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const bakLabel = label.replace(/\/$/, "") + ".bak";
|
|
101
|
+
if (force) {
|
|
102
|
+
if (fs.existsSync(treeDst)) {
|
|
103
|
+
const bak = treeDst + ".bak";
|
|
104
|
+
fs.rmSync(bak, { recursive: true, force: true });
|
|
105
|
+
fs.renameSync(treeDst, bak);
|
|
106
|
+
console.log("BACKUP: " + label + " -> " + bakLabel);
|
|
107
|
+
}
|
|
108
|
+
fs.cpSync(treeSrc, treeDst, { recursive: true });
|
|
109
|
+
console.log("CREATE: " + label + " (+" + listFilesRec(treeDst, treeDst).length + " archivos)");
|
|
110
|
+
} else {
|
|
111
|
+
let count = 0;
|
|
112
|
+
for (const rel of listFilesRec(treeSrc, treeSrc)) {
|
|
113
|
+
const tgt = path.join(treeDst, rel);
|
|
114
|
+
if (fs.existsSync(tgt)) {
|
|
115
|
+
console.log("SKIP: " + label + rel.split(path.sep).join("/") + " ya existe");
|
|
116
|
+
} else {
|
|
117
|
+
fs.mkdirSync(path.dirname(tgt), { recursive: true });
|
|
118
|
+
fs.copyFileSync(path.join(treeSrc, rel), tgt);
|
|
119
|
+
count++;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
console.log("CREATE: " + label + " (+" + count + " archivos)");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const clientsSrc = path.join(src, "AI", "clients");
|
|
127
|
+
for (const c of resolveClients(clientSpec, dest)) {
|
|
128
|
+
if (c === "opencode") mergeTree(path.join(clientsSrc, "opencode"), path.join(dest, ".opencode"), ".opencode/");
|
|
129
|
+
else if (c === "claude") mergeTree(path.join(clientsSrc, "claude"), path.join(dest, ".claude"), ".claude/");
|
|
130
|
+
else if (c === "cursor") {
|
|
131
|
+
mergeTree(path.join(clientsSrc, "cursor", "commands"), path.join(dest, ".cursor", "commands"), ".cursor/commands/");
|
|
132
|
+
mergeTree(path.join(clientsSrc, "cursor", "skills"), path.join(dest, ".agents", "skills"), ".agents/skills/");
|
|
133
|
+
} else if (c === "copilot") {
|
|
134
|
+
mergeTree(path.join(clientsSrc, "copilot", "agents"), path.join(dest, ".github", "agents"), ".github/agents/");
|
|
135
|
+
mergeTree(path.join(clientsSrc, "copilot", "skills"), path.join(dest, ".github", "skills"), ".github/skills/");
|
|
136
|
+
mergeTree(path.join(clientsSrc, "copilot", "prompts"), path.join(dest, ".github", "prompts"), ".github/prompts/");
|
|
137
|
+
} else if (c === "aider") console.log("SKIP: aider usa AGENTS.md raiz (nada que fusionar)");
|
|
138
|
+
}
|
|
139
|
+
function listFilesRec(dir, base) {
|
|
140
|
+
let out = [];
|
|
141
|
+
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
142
|
+
const p = path.join(dir, e.name);
|
|
143
|
+
if (e.isDirectory()) out = out.concat(listFilesRec(p, base));
|
|
144
|
+
else out.push(path.relative(base, p));
|
|
145
|
+
}
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
64
148
|
const frag = fs.readFileSync(path.join(src, "AI", ".gitignore.fragment"), "utf8")
|
|
65
149
|
.split(/\r?\n/).map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
|
|
66
150
|
let cur = [];
|