create-harness-btp 0.2.5 → 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 +52 -18
- package/VERSION +1 -1
- package/bin/harness-btp.js +74 -28
- package/install.ps1 +72 -22
- package/install.sh +88 -28
- 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,24 +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`).
|
|
127
|
-
- Fusiona
|
|
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.
|
|
128
129
|
- Fusiona `.gitignore`: añade las líneas que falten, sin duplicar ni borrar las tuyas.
|
|
129
130
|
- **No toca** `package.json` ni `mta.yaml` de tu proyecto, nunca.
|
|
130
131
|
|
|
131
132
|
Salida típica en proyecto nuevo:
|
|
132
133
|
|
|
133
134
|
```text
|
|
134
|
-
CREATE: AI/
|
|
135
|
+
CREATE: AI/ (v0.3.0)
|
|
135
136
|
CREATE: AGENTS.md
|
|
137
|
+
CLIENT: auto -> opencode
|
|
136
138
|
CREATE: .opencode/ (+17 archivos)
|
|
137
|
-
OK: harness v0.
|
|
139
|
+
OK: harness v0.3.0 instalado
|
|
138
140
|
```
|
|
139
141
|
|
|
140
142
|
## Instalación asistida por agente
|
|
@@ -154,7 +156,7 @@ Vale para proyecto nuevo (con URL), existente, Windows/Linux/macOS y cualquier c
|
|
|
154
156
|
PowerShell:
|
|
155
157
|
|
|
156
158
|
```powershell
|
|
157
|
-
npx -p degit degit horangelmillan/harness-btp#v0.
|
|
159
|
+
npx -p degit degit horangelmillan/harness-btp#v0.3.0 AI-tmp -- AI-tmp
|
|
158
160
|
powershell -ExecutionPolicy Bypass -File AI-tmp/install.ps1 -Dest . -Force
|
|
159
161
|
Remove-Item -Recurse -Force AI-tmp
|
|
160
162
|
# tu versión anterior queda en AI.bak por si quieres comparar
|
|
@@ -163,7 +165,7 @@ Remove-Item -Recurse -Force AI-tmp
|
|
|
163
165
|
bash:
|
|
164
166
|
|
|
165
167
|
```bash
|
|
166
|
-
npx -p degit degit horangelmillan/harness-btp#v0.
|
|
168
|
+
npx -p degit degit horangelmillan/harness-btp#v0.3.0 AI-tmp -- AI-tmp
|
|
167
169
|
sh AI-tmp/install.sh --dest . --force
|
|
168
170
|
rm -rf AI-tmp
|
|
169
171
|
# tu versión anterior queda en AI.bak por si quieres comparar
|
|
@@ -194,9 +196,32 @@ El harness funciona con **cualquier** cliente agéntico que lea `AGENTS.md`. Est
|
|
|
194
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.
|
|
195
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.
|
|
196
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.
|
|
197
200
|
|
|
198
201
|
Nada del núcleo exige OpenCode, Windows ni ningún modelo concreto.
|
|
199
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
|
+
|
|
200
225
|
## Estructura del repo
|
|
201
226
|
|
|
202
227
|
```text
|
|
@@ -204,18 +229,24 @@ harness-btp/
|
|
|
204
229
|
├── AI/ # lo que queda instalado en tu proyecto
|
|
205
230
|
│ ├── AGENTS.md # reglas del harness (parametrizado, sin rutas absolutas)
|
|
206
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)
|
|
207
236
|
│ ├── opencode.fragment.jsonc# ADAPTER opcional: ejemplo para opencode.jsonc
|
|
208
|
-
│ ├── .opencode/ # ADAPTER opcional:
|
|
237
|
+
│ ├── .opencode/ # ADAPTER opcional: se conserva intacto (compatibilidad)
|
|
209
238
|
│ ├── scripts/ # pares .ps1 / .sh + provision-espacio.template.ps1
|
|
210
239
|
│ ├── docs/ # flujo-etapas, cf-safe, habilitacion-trial
|
|
211
240
|
│ ├── specs/ # plantilla _template.md
|
|
212
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)
|
|
213
244
|
├── templates/
|
|
214
245
|
│ └── AGENTS.pointer.md # plantilla del puntero AGENTS.md raíz
|
|
215
246
|
├── install.ps1 / install.sh # instaladores idempotentes (SKIP / CREATE / BACKUP / OK)
|
|
216
247
|
├── bin/ # ejecutable de create-harness-btp (pnpm dlx)
|
|
217
248
|
├── package.json # name create-harness-btp
|
|
218
|
-
└── VERSION # 0.
|
|
249
|
+
└── VERSION # 0.3.0
|
|
219
250
|
```
|
|
220
251
|
|
|
221
252
|
## Cómo lo descubre el agente
|
|
@@ -237,8 +268,9 @@ Tú no configuras nada: el agente se adapta solo.
|
|
|
237
268
|
| Líneas duplicadas en `.gitignore` | edición manual tras la fusión | el instalador fusiona sin duplicar; borra el duplicado a mano |
|
|
238
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) |
|
|
239
270
|
| `ABORT: opción desconocida` en `install.sh` | flag inexistente | `sh install.sh --help` lista `--dest`, `--force` |
|
|
240
|
-
| `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` |
|
|
241
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 |
|
|
242
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) |
|
|
243
275
|
|
|
244
276
|
## Compatibilidad
|
|
@@ -265,9 +297,11 @@ MIT. Haz lo que quieras con el harness; sin garantía.
|
|
|
265
297
|
|
|
266
298
|
## Changelog
|
|
267
299
|
|
|
268
|
-
- **v0.
|
|
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.
|
|
269
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.
|
|
270
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.
|
|
271
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).
|
|
272
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`.
|
|
273
|
-
- **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,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// harness-btp init --dest <dir> [--force] [--ref <tag>]
|
|
3
|
-
// Copia AI/, crea AGENTS.md puntero, fusiona
|
|
4
|
-
// raíz (solo faltantes; con --force hace
|
|
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.
|
|
5
6
|
// No toca package.json ni mta.yaml del proyecto.
|
|
6
7
|
const fs = require("fs");
|
|
7
8
|
const path = require("path");
|
|
@@ -19,10 +20,11 @@ if (!cmd || cmd.startsWith("-")) {
|
|
|
19
20
|
const dest = arg("--dest", ".");
|
|
20
21
|
const force = process.argv.includes("--force");
|
|
21
22
|
const ref = arg("--ref", null);
|
|
23
|
+
const clientSpec = arg("--client", "auto");
|
|
22
24
|
const src = path.join(__dirname, "..");
|
|
23
25
|
|
|
24
26
|
if (cmd !== "init") {
|
|
25
|
-
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,...]");
|
|
26
28
|
process.exit(1);
|
|
27
29
|
}
|
|
28
30
|
if (ref) console.log("REF: " + ref + " (el paquete incluye su propia versión; ver VERSION)");
|
|
@@ -62,43 +64,87 @@ if (fs.existsSync(agentsDst)) {
|
|
|
62
64
|
console.log("CREATE: AGENTS.md (puntero a AI/AGENTS.md)");
|
|
63
65
|
}
|
|
64
66
|
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if (
|
|
72
|
-
|
|
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;
|
|
73
79
|
}
|
|
74
|
-
return
|
|
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;
|
|
75
93
|
}
|
|
76
|
-
|
|
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";
|
|
77
101
|
if (force) {
|
|
78
|
-
if (fs.existsSync(
|
|
79
|
-
const
|
|
80
|
-
fs.rmSync(
|
|
81
|
-
fs.renameSync(
|
|
82
|
-
console.log("BACKUP:
|
|
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);
|
|
83
107
|
}
|
|
84
|
-
fs.cpSync(
|
|
85
|
-
console.log("CREATE:
|
|
108
|
+
fs.cpSync(treeSrc, treeDst, { recursive: true });
|
|
109
|
+
console.log("CREATE: " + label + " (+" + listFilesRec(treeDst, treeDst).length + " archivos)");
|
|
86
110
|
} else {
|
|
87
|
-
let
|
|
88
|
-
for (const rel of listFilesRec(
|
|
89
|
-
const tgt = path.join(
|
|
111
|
+
let count = 0;
|
|
112
|
+
for (const rel of listFilesRec(treeSrc, treeSrc)) {
|
|
113
|
+
const tgt = path.join(treeDst, rel);
|
|
90
114
|
if (fs.existsSync(tgt)) {
|
|
91
|
-
console.log("SKIP:
|
|
115
|
+
console.log("SKIP: " + label + rel.split(path.sep).join("/") + " ya existe");
|
|
92
116
|
} else {
|
|
93
117
|
fs.mkdirSync(path.dirname(tgt), { recursive: true });
|
|
94
|
-
fs.copyFileSync(path.join(
|
|
95
|
-
|
|
118
|
+
fs.copyFileSync(path.join(treeSrc, rel), tgt);
|
|
119
|
+
count++;
|
|
96
120
|
}
|
|
97
121
|
}
|
|
98
|
-
console.log("CREATE:
|
|
122
|
+
console.log("CREATE: " + label + " (+" + count + " archivos)");
|
|
99
123
|
}
|
|
100
124
|
}
|
|
101
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
|
+
}
|
|
102
148
|
const frag = fs.readFileSync(path.join(src, "AI", ".gitignore.fragment"), "utf8")
|
|
103
149
|
.split(/\r?\n/).map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
|
|
104
150
|
let cur = [];
|