From acf7e8eafe3d06981004447509a9de504310b9c8 Mon Sep 17 00:00:00 2001 From: lacasoft Date: Tue, 3 Nov 2026 21:50:19 +0100 Subject: [PATCH 1/4] fix: el instalador detecta el Node de Windows desde WSL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Con WSL y Node solo en Windows, npx corre en Windows, CMD cae a C:\Windows y el instalador fallaba con EPERM. Ahora lo detecta antes de escribir nada y explica cómo instalar Node dentro de WSL. --- install.js | 33 ++++++++++++++++++++++++++++----- test/install-detect.test.cjs | 12 ++++++++++++ 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/install.js b/install.js index f2b186c..aecc212 100644 --- a/install.js +++ b/install.js @@ -1137,7 +1137,26 @@ function summarizeProject(stacks) { } // ---------- main ---------- +// ---------- Node de Windows desde WSL ---------- +// Con WSL y Node instalado solo en Windows, npx corre en Windows: CMD no acepta la carpeta de WSL +// (\\wsl.localhost\…) y se cambia a C:\Windows, donde el kit se instalaría o fallaría con EPERM. +function windowsSystemDir(platform = process.platform, cwd = CWD, env = process.env) { + if (platform !== "win32") return false; + const sys = path.win32.resolve(env.SystemRoot || env.windir || "C:\\Windows").toLowerCase(); + const dir = path.win32.resolve(cwd).toLowerCase(); + return dir === sys || dir.startsWith(sys + "\\") || /^\\\\wsl/i.test(env.INIT_CWD || ""); +} + async function main() { + if (windowsSystemDir()) { + console.error(`❌ El instalador está corriendo con el Node de Windows en ${CWD}. + Si usas WSL: instala Node dentro de WSL (por ejemplo con nvm), comprueba que + \`command -v node npx\` muestre rutas de Linux y no /mnt/c/…, y vuelve a correrlo. + Si usas Windows: córrelo desde la carpeta de tu proyecto, no desde una carpeta del sistema.`); + closeInput(); + process.exitCode = 1; + return; + } const VERSION = (readJSON(path.join(KIT, "package.json")) || {}).version || "?"; console.log("\n╔════════════════════════════════════════════╗"); console.log(`║ Dev Starter Kit v${VERSION} — instalador `.slice(0, 45) + "║"); @@ -1359,8 +1378,12 @@ async function main() { closeInput(); } -main().catch((e) => { - console.error(e); - closeInput(); - process.exit(1); -}); +module.exports = { windowsSystemDir }; + +if (require.main === module) { + main().catch((e) => { + console.error(e); + closeInput(); + process.exit(1); + }); +} diff --git a/test/install-detect.test.cjs b/test/install-detect.test.cjs index f9c2de4..ae6b42c 100644 --- a/test/install-detect.test.cjs +++ b/test/install-detect.test.cjs @@ -139,3 +139,15 @@ test("lo que cuelga de un proyecto detectado no cuenta como otro proyecto", () = }); assert.equal(r.stack, "mobile/react-native"); }); + +// ---- Node de Windows desde WSL ---- +test("detecta el Node de Windows corriendo desde WSL o en una carpeta del sistema", () => { + const { windowsSystemDir } = require(path.join(__dirname, "..", "install.js")); + const sys = { SystemRoot: "C:\\Windows" }; + assert.equal(windowsSystemDir("win32", "C:\\Windows", sys), true, "CMD cayó a C:\\Windows"); + assert.equal(windowsSystemDir("win32", "C:\\Windows\\System32", sys), true); + assert.equal(windowsSystemDir("win32", "C:\\Users\\ana\\x", { ...sys, INIT_CWD: "\\\\wsl.localhost\\Ubuntu\\home\\ana\\x" }), true, "npx se lanzó desde WSL"); + assert.equal(windowsSystemDir("win32", "C:\\Users\\ana\\proyecto", sys), false, "Windows normal: sigue"); + assert.equal(windowsSystemDir("win32", "C:\\WindowsApps\\x", sys), false, "no confunde carpetas con nombre parecido"); + assert.equal(windowsSystemDir("linux", "/home/ana/x", {}), false); +}); From 76a2ba5ea281f4081e699b7025fb2f058cb8a014 Mon Sep 17 00:00:00 2001 From: lacasoft Date: Tue, 3 Nov 2026 21:50:19 +0100 Subject: [PATCH 2/4] =?UTF-8?q?fix:=20en=20Pi,=20las=20skills=20piden=20le?= =?UTF-8?q?er=20su=20referencia=20como=20paso=20expl=C3=ADcito?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Una instrucción de leer un archivo auxiliar escrita a media frase se salta en Pi: project-context no leía desde-design.md e improvisaba el mapeo. Ahora project-context y owasp-review piden leer su referencia con la ruta completa, y desde-design.md aclara que en Pi la ruta del diseño se lee sin --add-dir. --- shared/.claude/skills/owasp-review/SKILL.md | 4 ++-- shared/.claude/skills/project-context/SKILL.md | 4 +++- shared/.claude/skills/project-context/desde-design.md | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/shared/.claude/skills/owasp-review/SKILL.md b/shared/.claude/skills/owasp-review/SKILL.md index 37d284e..a2246e5 100644 --- a/shared/.claude/skills/owasp-review/SKILL.md +++ b/shared/.claude/skills/owasp-review/SKILL.md @@ -19,7 +19,7 @@ Las listas completas (las 10 categorías con qué buscar, los 17 capítulos de A Antes de buscar patrones, dibuja el mapa: puntos de entrada (rutas, handlers, webhooks, jobs, CLI, mensajes de cola), fronteras de confianza, datos sensibles que cruzan cada frontera, dependencias nuevas y llamadas salientes (HTTP, shell, LLM, otras herramientas). Sin mapa, el barrido es ruido. ## 3. Barrido por categoría -Recorre A01→A10 sobre la superficie del paso 2 (tabla en `referencia.md`). Para cada sospecha, **traza fuente → sink**: de dónde viene el dato, qué validación o codificación recibe y dónde se usa. Si no puedes trazarlo, es sospecha, no hallazgo. +**Primero lee `.claude/skills/owasp-review/referencia.md`**: su tabla dice qué buscar en cada categoría. Luego recorre A01→A10 sobre la superficie del paso 2. Para cada sospecha, **traza fuente → sink**: de dónde viene el dato, qué validación o codificación recibe y dónde se usa. Si no puedes trazarlo, es sospecha, no hallazgo. Prioridades que más se escapan: - **A01**: autorización por objeto en cada acceso por id (no basta estar autenticado); SSRF también vive aquí desde 2025. @@ -27,7 +27,7 @@ Prioridades que más se escapan: - **A10**: qué pasa cuando algo falla. Un `catch` que deja pasar, un check de autorización que concede si lanza excepción, un error que filtra internals. ## 4. ASVS por tipo de cambio -Según lo que toque el cambio, verifica los capítulos correspondientes al nivel elegido (mapa en `referencia.md`): auth → V6/V7/V9/V10, permisos → V8, archivos → V5, API → V4, frontend → V3, configuración → V13, cripto → V11, logs y errores → V16. +Según lo que toque el cambio, verifica los capítulos correspondientes al nivel elegido (mapa en `.claude/skills/owasp-review/referencia.md`): auth → V6/V7/V9/V10, permisos → V8, archivos → V5, API → V4, frontend → V3, configuración → V13, cripto → V11, logs y errores → V16. ## 5. LLM y agentes (si el proyecto los usa) Si el código llama a un LLM, revisa contra el **OWASP Top 10 for LLM Applications 2026**; si construye agentes, herramientas o servidores MCP, también contra el **Top 10 for Agentic Applications 2026**. Lo mínimo: el texto que el modelo lee es dato no confiable, su salida se valida antes de tocar SQL/shell/HTML/herramientas, y lo irreversible pide confirmación humana. diff --git a/shared/.claude/skills/project-context/SKILL.md b/shared/.claude/skills/project-context/SKILL.md index a0a205e..c046bea 100644 --- a/shared/.claude/skills/project-context/SKILL.md +++ b/shared/.claude/skills/project-context/SKILL.md @@ -17,7 +17,9 @@ Las rutas que nombra esta skill (`CLAUDE.project.md`, `docs/adr/`, `.claude/…` - **Cero secretos**: nombres de variables de entorno sí; valores nunca. ## 0. Si partes de un diseño (design.md) -Si el argumento es una ruta a un `design.md` del **system-design-kit** (front matter con `language` y marcas ``), ese documento es la fuente de **lo que el repo no puede decir**: visión, requisitos, escala, decisiones y fallas. La persona ya lo pensó y lo decidió; tu trabajo es trasladarlo sin reescribirlo ni reinterpretarlo. Lee [desde-design.md](desde-design.md) y sigue su mapeo. Lo derivable del repo (stack real, comandos, estructura) sigue saliendo de los pasos 1-3: el diseño no sustituye al código. +Si el argumento es una ruta a un `design.md` del **system-design-kit** (front matter con `language` y marcas ``), ese documento es la fuente de **lo que el repo no puede decir**: visión, requisitos, escala, decisiones y fallas. La persona ya lo pensó y lo decidió; tu trabajo es trasladarlo sin reescribirlo ni reinterpretarlo. Lo derivable del repo (stack real, comandos, estructura) sigue saliendo de los pasos 1-3: el diseño no sustituye al código. + +**Antes de escribir nada, lee [desde-design.md](desde-design.md)**, que está junto a este archivo (`.claude/skills/project-context/desde-design.md`). Su tabla dice a qué sección de `CLAUDE.project.md` va cada parte del diseño, incluida la ficha de responsabilidades, que se copia tal cual, y los flujos críticos, que se vuelven tests de recuperación. Sin esa tabla, no traslades nada. ## 1. Lee lo que hay `CLAUDE.project.md` actual (si existe, **actualízalo**, no lo reescribas: conserva lo que escribió el equipo), `README`, manifiestos y lockfiles, configuración de lint/format/tests, `Makefile`/scripts, Dockerfile y compose, workflows de CI, `.env.example`, `docs/adr/`, y la estructura de primer y segundo nivel. Si el argumento nombra un área, profundiza ahí. diff --git a/shared/.claude/skills/project-context/desde-design.md b/shared/.claude/skills/project-context/desde-design.md index c07f122..7a9e8bb 100644 --- a/shared/.claude/skills/project-context/desde-design.md +++ b/shared/.claude/skills/project-context/desde-design.md @@ -11,7 +11,8 @@ reescriba requisitos ni decisiones: el diseño se **traslada**, resumido y con l `api-data-model`, `architecture`, `decisions`, `failures`, `ai-review`. - Una sección que solo tiene `_⏳ Pendiente_` / `_⏳ Pending_` está vacía: no hay nada que trasladar. - Si la ruta está fuera del proyecto, Claude Code pedirá permiso para leerla (o arranca con - `claude --add-dir `). + `claude --add-dir `). En Pi Agent no hace falta: la ruta se lee directo + (`/skill:project-context ..//design.md`). ## Mapeo a CLAUDE.project.md From f97605f2b58ebec922934485b5eed2b191deac0e Mon Sep 17 00:00:00 2001 From: lacasoft Date: Tue, 3 Nov 2026 21:50:19 +0100 Subject: [PATCH 3/4] =?UTF-8?q?feat:=20la=20ficha=20de=20responsabilidades?= =?UTF-8?q?=20del=20dise=C3=B1o=20llega=20al=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /project-context copia la ficha a Arquitectura → Responsabilidades y límites, las reglas de límite a Reglas de negocio, los flujos críticos a Testing → Tests de recuperación (lista para tdd) y los contextos y propiedad a Modelo / dominio. La baseline pide respetar esos límites y avisar antes de cruzarlos. --- shared/.claude/CLAUDE.base.md | 1 + shared/.claude/skills/project-context/desde-design.md | 4 ++++ shared/templates/PROJECT.template.md | 4 +++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/shared/.claude/CLAUDE.base.md b/shared/.claude/CLAUDE.base.md index 646f930..67c222a 100644 --- a/shared/.claude/CLAUDE.base.md +++ b/shared/.claude/CLAUDE.base.md @@ -143,6 +143,7 @@ Esto no es solo documentación: el hook `pre-bash` (`helpers/hook-handler.cjs`) - Nada de código muerto ni comentado "por si acaso". - Manejo de errores explícito; nunca tragar excepciones en silencio. - Tests para la nueva funcionalidad y para cada regresión corregida. +- **Respeta los límites** de *Arquitectura → Responsabilidades y límites* en `CLAUDE.project.md`: cada regla de negocio va en su dueño (no en el controlador, el adaptador ni el job), y ningún módulo escribe el estado de otro. Si una tarea exige cruzar un límite, dilo antes de hacerlo. - TypeScript/tipado **strict**; evita `any` (usa `unknown` + narrowing). - **Gate de código nuevo** (*clean as you code*): lo que cambia no introduce issues nuevos de lint, tipos ni seguridad; **cobertura ≥ 80 % de las líneas nuevas o modificadas** donde se mida; duplicación nueva ≤ 3 %. La deuda heredada no bloquea el cambio, pero no se amplía. - En lógica crítica (dinero, permisos, cálculos), la cobertura no basta: **mutation testing** (Stryker, mutmut, PIT) o **property-based testing** demuestran que los tests fallan cuando el código se rompe. diff --git a/shared/.claude/skills/project-context/desde-design.md b/shared/.claude/skills/project-context/desde-design.md index 7a9e8bb..6771779 100644 --- a/shared/.claude/skills/project-context/desde-design.md +++ b/shared/.claude/skills/project-context/desde-design.md @@ -21,9 +21,13 @@ reescriba requisitos ni decisiones: el diseño se **traslada**, resumido y con l | título + `requirements` (funcionales) | **Visión del producto** | 2-4 líneas: qué es, para quién, los casos de uso principales | | `out-of-scope` | **Visión del producto** → línea "Fuera de alcance (v1)" | Lista corta. Es lo que más evita que el agente construya de más | | `api-data-model` (entidades, términos) | **Modelo / dominio** | Glosario de entidades y su clave de acceso | +| `api-data-model` (*Contextos y propiedad*, si existe) | **Modelo / dominio** → "Contextos y propiedad" | La tabla tal cual: contexto, reglas, dueño de los datos, contratos. Si el repo todavía no tiene estructura, en **Estructura del repositorio** sugiere un módulo por contexto, sin imponerlo | | `api-data-model` (endpoints, eventos) | **Arquitectura** → "Contratos" | Solo los de los casos de uso principales, con idempotencia y paginación si el diseño las fija | | `architecture` | **Arquitectura** | Componentes y flujo principal, síncrono y asíncrono; enlaza el diagrama del diseño en vez de copiarlo | +| `architecture` (*Ficha de responsabilidades*, si existe) | **Arquitectura** → "Responsabilidades y límites" | La tabla tal cual: componente, responsable de, no le toca, estado del que es dueño y ejecución. Son los límites que el código respeta: ahí se ve dónde va cada regla | +| `architecture` y `api-data-model` (dueños) | **Reglas de negocio (invariantes)** | Las de límite, en una línea cada una: qué componente decide qué, y que ningún contexto escribe los datos de otro | | `failures` | **Arquitectura** → "Fallas previstas" y **Testing** | Una línea por escenario (escenario → mitigación). En *Testing*, los que merecen test de regresión | +| `failures` (*Flujos críticos*, si existen) | **Testing** → "Tests de recuperación" | Uno por cada paso con efecto **desconocido** o con recuperación (duplicado, timeout, concurrencia, reinicio): qué se simula y qué evidencia de cierre se comprueba. No los escribas ahora: quedan como lista para la skill `tdd` | | `requirements` (no funcionales) + `scale` | **Atributos de calidad** | Los umbrales con número (latencia, disponibilidad, consistencia) y el orden de magnitud de carga | | `requirements` (seguridad, privacidad) | **Seguridad y compliance** | Si el diseño fija el nivel ASVS, úsalo; si no, propónlo y márcalo como pendiente | | `decisions` | **Decisiones de arquitectura** | Un ADR por decisión (abajo) y aquí solo la línea con el enlace | diff --git a/shared/templates/PROJECT.template.md b/shared/templates/PROJECT.template.md index bf1951b..5e9d26b 100644 --- a/shared/templates/PROJECT.template.md +++ b/shared/templates/PROJECT.template.md @@ -32,7 +32,9 @@ --> ## Arquitectura - + ## Reglas de negocio (invariantes)