@saulwade/swl-ses 2.4.3 → 2.5.2

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.
Files changed (200) hide show
  1. package/CLAUDE.md +194 -241
  2. package/README.md +600 -597
  3. package/agentes/_intent-spec.md +73 -73
  4. package/agentes/_propose-step.md +90 -90
  5. package/agentes/abogado-diablo-swl.md +145 -0
  6. package/agentes/accesibilidad-wcag-swl.md +690 -690
  7. package/agentes/arquitecto-swl.md +267 -267
  8. package/agentes/auto-evolucion-swl.md +908 -908
  9. package/agentes/backend-api-swl.md +1 -1
  10. package/agentes/backend-csharp-swl.md +420 -420
  11. package/agentes/backend-go-swl.md +390 -390
  12. package/agentes/backend-java-swl.md +281 -281
  13. package/agentes/backend-node-swl.md +1 -1
  14. package/agentes/backend-python-swl.md +1 -1
  15. package/agentes/backend-rust-swl.md +364 -364
  16. package/agentes/backend-workers-swl.md +482 -482
  17. package/agentes/cloud-infra-swl.md +509 -509
  18. package/agentes/consolidador-swl.md +541 -541
  19. package/agentes/datos-swl.md +1 -1
  20. package/agentes/depurador-swl.md +352 -352
  21. package/agentes/devops-ci-swl.md +400 -400
  22. package/agentes/disenador-ui-swl.md +569 -569
  23. package/agentes/documentador-swl.md +345 -345
  24. package/agentes/frontend-angular-swl.md +621 -621
  25. package/agentes/frontend-css-swl.md +716 -716
  26. package/agentes/frontend-react-swl.md +692 -692
  27. package/agentes/frontend-swl.md +496 -496
  28. package/agentes/frontend-tailwind-swl.md +826 -826
  29. package/agentes/gh-fix-ci-swl.md +6 -1
  30. package/agentes/implementador-swl.md +1 -1
  31. package/agentes/investigador-swl.md +432 -432
  32. package/agentes/investigador-ux-swl.md +505 -505
  33. package/agentes/llm-apps-swl.md +1 -1
  34. package/agentes/migrador-swl.md +442 -442
  35. package/agentes/mobile-android-swl.md +511 -511
  36. package/agentes/mobile-cross-swl.md +541 -541
  37. package/agentes/mobile-ios-swl.md +502 -502
  38. package/agentes/mobile-testing-swl.md +302 -302
  39. package/agentes/nemesis-auditor-swl.md +285 -285
  40. package/agentes/notificador-swl.md +1 -1
  41. package/agentes/observabilidad-swl.md +438 -438
  42. package/agentes/pagos-swl.md +310 -310
  43. package/agentes/perfilador-usuario-swl.md +321 -321
  44. package/agentes/planificador-swl.md +399 -399
  45. package/agentes/producto-prd-swl.md +589 -589
  46. package/agentes/red-team-swl.md +218 -218
  47. package/agentes/release-manager-swl.md +590 -590
  48. package/agentes/rendimiento-swl.md +713 -713
  49. package/agentes/resolutor-build-swl.md +10 -1
  50. package/agentes/revisor-angular-swl.md +278 -278
  51. package/agentes/revisor-codigo-swl.md +1 -1
  52. package/agentes/revisor-csharp-swl.md +264 -264
  53. package/agentes/revisor-go-swl.md +259 -259
  54. package/agentes/revisor-java-swl.md +257 -257
  55. package/agentes/revisor-kotlin-swl.md +273 -273
  56. package/agentes/revisor-nextjs-swl.md +281 -281
  57. package/agentes/revisor-php-swl.md +271 -271
  58. package/agentes/revisor-react-swl.md +278 -278
  59. package/agentes/revisor-rust-swl.md +346 -346
  60. package/agentes/revisor-seguridad-swl.md +399 -399
  61. package/agentes/revisor-swift-swl.md +268 -268
  62. package/agentes/revisor-typescript-swl.md +346 -346
  63. package/agentes/sre-swl.md +1 -1
  64. package/agentes/tdd-qa-swl.md +393 -393
  65. package/bin/lib/bot-comandos.js +1 -1
  66. package/bin/swl-ses.js +6 -0
  67. package/comandos/swl/adoptar-proyecto.md +14 -2
  68. package/comandos/swl/configurar-ci.md +8 -1
  69. package/comandos/swl/deuda-codigo.md +97 -97
  70. package/comandos/swl/discutir-fase.md +22 -118
  71. package/comandos/swl/fix.md +118 -0
  72. package/comandos/swl/nuevo-proyecto.md +54 -3
  73. package/comandos/swl/predecir.md +32 -2
  74. package/comandos/swl/seguridad.md +189 -0
  75. package/comandos/swl/status.md +5 -3
  76. package/habilidades/aprendizaje-continuo/SKILL.md +3 -1
  77. package/habilidades/discutir-fase/SKILL.md +84 -81
  78. package/habilidades/discutir-fase/recursos/plantilla-contexto.md +136 -0
  79. package/habilidades/doc-sync/SKILL.md +3 -1
  80. package/habilidades/doubt-driven-review/SKILL.md +15 -1
  81. package/habilidades/ejecutar-task-iterativo/SKILL.md +278 -278
  82. package/habilidades/estructura-proyecto-claude/SKILL.md +11 -2
  83. package/habilidades/harness-claude-code/SKILL.md +3 -1
  84. package/habilidades/instalar-sistema/SKILL.md +3 -1
  85. package/habilidades/meta-reglas-extendido/SKILL.md +92 -0
  86. package/habilidades/meta-reglas-extendido/recursos/analisis-previo-tareas-grandes.md +186 -0
  87. package/habilidades/meta-reglas-extendido/recursos/analizar-directorios-antes-de-escribir.md +235 -0
  88. package/habilidades/meta-reglas-extendido/recursos/api-diseno.md +413 -0
  89. package/habilidades/meta-reglas-extendido/recursos/arquitectura.md +491 -0
  90. package/habilidades/meta-reglas-extendido/recursos/arreglar-al-detectar.md +264 -0
  91. package/habilidades/meta-reglas-extendido/recursos/debatir-antes-de-aceptar.md +152 -0
  92. package/habilidades/meta-reglas-extendido/recursos/git-workflow.md +259 -0
  93. package/habilidades/meta-reglas-extendido/recursos/gobernanza.md +291 -0
  94. package/habilidades/meta-reglas-extendido/recursos/memoria-consolidada.md +263 -0
  95. package/habilidades/meta-reglas-extendido/recursos/seguridad-agentes.md +443 -0
  96. package/habilidades/meta-reglas-extendido/recursos/sesiones-paralelas.md +190 -0
  97. package/habilidades/meta-reglas-extendido/recursos/sin-duplicacion-reglas-globales.md +179 -0
  98. package/habilidades/meta-reglas-extendido/recursos/skills-estandar.md +394 -0
  99. package/habilidades/meta-reglas-extendido/recursos/usar-code-review-graph.md +156 -0
  100. package/habilidades/meta-reglas-extendido/recursos/usar-context7.md +236 -0
  101. package/habilidades/meta-reglas-extendido/recursos/usar-sistema-swl.md +253 -0
  102. package/habilidades/meta-reglas-extendido/recursos/verificar-citas-normativas.md +527 -0
  103. package/habilidades/meta-skills-estandar/SKILL.md +3 -1
  104. package/habilidades/nuevo-proyecto/SKILL.md +20 -3
  105. package/habilidades/php-experto/SKILL.md +10 -3
  106. package/habilidades/{filament-admin/SKILL.md → php-experto/recursos/filament-admin.md} +23 -39
  107. package/habilidades/prevencion-sobreingenieria/recursos/soluciones-nativas.md +166 -166
  108. package/habilidades/prevencion-sobreingenieria/recursos/variables-residuales-post-refactor.md +85 -85
  109. package/habilidades/proceso-debate-adversarial/recursos/personas.md +5 -4
  110. package/habilidades/proceso-ingenieria-requerimientos/SKILL.md +147 -0
  111. package/hooks/check-update.js +19 -10
  112. package/hooks/contexto-subagente.js +68 -68
  113. package/hooks/degradacion-instintos.js +1 -1
  114. package/hooks/extraccion-aprendizajes.js +2 -2
  115. package/hooks/lib/briefing.js +3 -3
  116. package/hooks/lib/nudge-tracker.js +1 -1
  117. package/hooks/lib/otlp-exporter.js +1 -1
  118. package/hooks/lib/webhook-dedup.js +1 -1
  119. package/hooks/session-briefing.js +1 -1
  120. package/llms.txt +6 -6
  121. package/manifiestos/canonical-hashes.json +1043 -52
  122. package/manifiestos/hooks-config.json +469 -469
  123. package/manifiestos/invariantes-criticos.json +30 -30
  124. package/manifiestos/modulos.json +168 -135
  125. package/manifiestos/perfiles.json +0 -2
  126. package/manifiestos/skills-lock.json +49 -56
  127. package/package.json +7 -5
  128. package/plantillas/github-workflows/README.md +15 -1
  129. package/plantillas/github-workflows/swl-devsecops.yml +70 -0
  130. package/plugin.json +5 -5
  131. package/reglas/analisis-previo-tareas-grandes.md +30 -156
  132. package/reglas/analizar-directorios-antes-de-escribir.md +30 -211
  133. package/reglas/api-diseno.md +28 -398
  134. package/reglas/arquitectura.md +35 -456
  135. package/reglas/arreglar-al-detectar.md +30 -230
  136. package/reglas/debatir-antes-de-aceptar.md +30 -143
  137. package/reglas/docs.md +7 -0
  138. package/reglas/estilo-codigo.md +9 -0
  139. package/reglas/fragmentos-compartidos.md +6 -0
  140. package/reglas/git-workflow.md +44 -240
  141. package/reglas/gobernanza.md +23 -262
  142. package/reglas/memoria-consolidada.md +34 -228
  143. package/reglas/performance.md +8 -0
  144. package/reglas/pruebas.md +12 -0
  145. package/reglas/seguridad-agentes.md +37 -418
  146. package/reglas/seguridad.md +12 -0
  147. package/reglas/sesiones-paralelas.md +29 -162
  148. package/reglas/sin-duplicacion-reglas-globales.md +25 -166
  149. package/reglas/skills-estandar.md +23 -373
  150. package/reglas/usar-code-review-graph.md +31 -140
  151. package/reglas/usar-context7.md +30 -208
  152. package/reglas/usar-sistema-swl.md +47 -242
  153. package/reglas/verificar-citas-normativas.md +47 -537
  154. package/scripts/actualizar.js +253 -253
  155. package/scripts/audit-tools/auditar-relleno-inventario.js +145 -0
  156. package/scripts/auditar-clases-conocidas.js +106 -0
  157. package/scripts/bootstrap-instintos.js +2 -2
  158. package/scripts/canario-hooks.js +166 -0
  159. package/scripts/cli/configurar-ci.js +2 -1
  160. package/scripts/evidencia-valor.js +101 -0
  161. package/scripts/field-report.js +18 -2
  162. package/scripts/generar-comandos.js +143 -0
  163. package/scripts/generar-inventario.js +236 -23
  164. package/scripts/generar-matriz-lenguajes.js +1 -1
  165. package/scripts/instalador.js +15 -1
  166. package/scripts/instalar-git-hook.js +8 -1
  167. package/scripts/lib/configurar-ci.js +10 -3
  168. package/scripts/lib/diary-entry.js +3 -1
  169. package/scripts/lib/drift-detector.js +1 -1
  170. package/scripts/lib/evidencia-valor.js +228 -0
  171. package/scripts/lib/expandir-targets.js +71 -71
  172. package/scripts/lib/frontmatter-md.js +63 -0
  173. package/scripts/lib/parsear-opciones.js +2 -0
  174. package/scripts/lib/prune-componentes.js +180 -0
  175. package/scripts/lib/reglas-globales-conocidas.json +16 -2
  176. package/scripts/lib/scoring-instintos.js +2 -2
  177. package/scripts/lib/toml-merge.js +204 -204
  178. package/scripts/lib/transformadores/claude.js +1 -1
  179. package/scripts/lib/transformadores/codex.js +1 -1
  180. package/scripts/lib/transformadores/copilot.js +1 -1
  181. package/scripts/lib/transformadores/cursor.js +1 -1
  182. package/scripts/lib/transformadores/gemini.js +22 -2
  183. package/scripts/lib/transformadores/opencode.js +1 -1
  184. package/scripts/mcp-server/auth.js +105 -105
  185. package/scripts/mcp-server/cache.js +106 -106
  186. package/scripts/prune.js +102 -0
  187. package/scripts/publicar.js +18 -2
  188. package/scripts/tui/index.js +10 -1
  189. package/scripts/tui/pantallas/inspect.js +175 -175
  190. package/scripts/tui/pantallas/install-wizard.js +21 -8
  191. package/scripts/tui/pantallas/uninstall-wizard.js +210 -210
  192. package/scripts/tui/pantallas/update-wizard.js +234 -234
  193. package/scripts/tui/pantallas/welcome.js +188 -189
  194. package/habilidades/paid-media-tracking/SKILL.md +0 -269
  195. package/habilidades/paid-media-tracking/recursos/auditoria-tracking.md +0 -220
  196. package/habilidades/paid-media-tracking/recursos/google-ads-api.md +0 -215
  197. package/habilidades/tracking-measurement/SKILL.md +0 -239
  198. package/habilidades/tracking-measurement/recursos/consent-mode.md +0 -231
  199. package/habilidades/tracking-measurement/recursos/gtm-datalayer.md +0 -216
  200. package/habilidades/tracking-measurement/recursos/meta-capi.md +0 -262
@@ -1,44 +1,28 @@
1
- ---
2
- name: filament-admin
3
- description: >
4
- Laravel Filament v3: optimización de paneles admin, formularios con Tabs y
5
- Grid, Infolist para vistas de detalle, Tables con filtros avanzados y bulk
6
- actions, Resources con relaciones anidadas. Cargar cuando se construya o
7
- rediseñe un panel Filament, se implementen formularios complejos, tablas con
8
- filtros o Resources con relaciones.
9
- version: "1.0.0"
10
- herramientasPermitidas: [Read, Grep]
11
- evolvable: true # default para skill estandar
12
- exclusiones:
13
- - "No cargar para paneles admin genéricos sin Filament (Nova, Voyager, backpack) — cada panel tiene su propia API; cargar el skill del framework correspondiente."
14
- - "No cargar para formularios frontend en la app pública de Laravel (Livewire sin Filament, Inertia/Vue) — para formularios de usuario final cargar `livewire-avanzado` o el skill del framework JS."
15
- - "No cargar para migración de datos o seeds de base de datos en proyectos Laravel — para migraciones y seeds cargar `postgresql-experto` o el skill del ORM."
16
- - "No cargar para autenticación y autorización en Laravel sin relación con paneles Filament — para auth cargar `auth-patrones` o `laravel-auth`."
17
- ---
18
1
  # Filament Admin v3 — Paneles, Formularios y Tablas
19
2
 
20
- Skill para construir paneles de administración con Laravel Filament v3.
21
- Cubre optimización de UX, formularios multi-tab, infolistas de detalle,
22
- tablas con filtros y acciones masivas.
23
-
24
- ---
25
-
26
- ## Cuándo NO cargar
27
-
28
- - El proyecto usa un panel admin diferente (Nova, Voyager, Backpack): cargar el skill del framework correspondiente.
29
- - Los formularios son de la app pública del usuario final (Livewire sin Filament, Inertia/Vue): cargar `livewire-avanzado` o el skill del framework JS.
30
- - La tarea es migración de datos, seeds o esquema de BD sin relación con el panel: cargar `postgresql-experto`.
31
- - La tarea es autenticación y autorización sin relación con el panel Filament: cargar `auth-patrones`.
32
-
33
- ## Cuándo cargar este skill
34
-
35
- - Al crear o modificar un `Resource` de Filament (formulario, tabla o infolist)
36
- - Al implementar formularios con más de 6 campos
37
- - Al configurar filtros, ordenamiento o bulk actions en tablas
38
- - Al separar modo vista del modo edición en un panel admin
39
- - Al implementar relaciones anidadas (`HasMany`, `BelongsToMany`) en Forms o Tables
40
-
41
- ---
3
+ > Recurso de `php-experto` (absorbió al skill `filament-admin` el 2026-07-08).
4
+ > Cargar php-experto y leer este archivo cuando se construya o rediseñe un
5
+ > panel Laravel Filament v3: formularios con Tabs/Grid, Infolist, Tables con
6
+ > filtros y bulk actions, Resources con relaciones anidadas.
7
+
8
+ ## Índice
9
+ 1. Jerarquía de optimización de UX
10
+ 2. Formulario con Tabs optimizados
11
+ 3. Infolist para modo vista
12
+ 4. Table con filtros y bulk actions
13
+ 5. Relaciones anidadas HasMany con Repeater
14
+ 6. Reglas obligatorias
15
+ 7. Anti-patrones
16
+ 8. Checklist de verificación
17
+ 9. Referencias
18
+ + Gotchas no obvios
19
+
20
+ ## Alcance cuándo NO aplica este recurso
21
+
22
+ - Panel admin distinto de Filament (Nova, Voyager, Backpack): usar el skill del framework correspondiente.
23
+ - Formularios de la app pública (Livewire sin Filament, Inertia/Vue): no es territorio de Filament.
24
+ - Migraciones/seeds sin relación con el panel: `postgresql-experto`.
25
+ - Auth sin relación con el panel: `auth-patrones`.
42
26
 
43
27
  ## 1. Jerarquía de optimización de UX (en orden de impacto)
44
28
 
@@ -1,166 +1,166 @@
1
- # Soluciones nativas de plataforma
2
-
3
- Recurso de `prevencion-sobreingenieria` — peldaño 4 de la escalera de decisión.
4
- La primera pregunta del ingeniero perezoso-eficiente: *¿la plataforma ya hace
5
- esto?* Antes de instalar un paquete o escribir un componente, revisar aquí.
6
- La plataforma viaja gratis con la app, no se rompe en updates, y la escribió
7
- gente cuyo trabajo es exactamente ese problema.
8
-
9
- Adaptado de [ponytail](https://github.com/DietrichGebert/ponytail)
10
- `docs/platform-native.md` (MIT, DietrichGebert).
11
-
12
- ---
13
-
14
- ## Elementos HTML
15
-
16
- | Crees que necesitas | La plataforma ya tiene |
17
- |---|---|
18
- | Lib de date picker | `<input type="date">` |
19
- | Lib de time picker | `<input type="time">` |
20
- | Lib de color picker | `<input type="color">` |
21
- | Lib de range slider | `<input type="range">` |
22
- | Componente de progress bar | `<progress value="70" max="100">` |
23
- | Componente meter/gauge | `<meter value="0.7">` |
24
- | Lib de modal/diálogo | `<dialog>` + `dialog.showModal()` |
25
- | Componente acordeón/FAQ | `<details><summary>Título</summary>…</details>` |
26
- | Lib de tooltips | atributo `title` + CSS `::before`/`::after` |
27
- | Dropdown con búsqueda | `<input list="id"> <datalist id="id">` |
28
- | Textarea auto-crecible | `field-sizing: content` (CSS) |
29
- | Header sticky | `position: sticky; top: 0` (CSS) |
30
-
31
- ## Capacidades CSS (donde se suele usar JS)
32
-
33
- | Crees que necesitas JS para | CSS ya tiene |
34
- |---|---|
35
- | Font size responsivo | `font-size: clamp(1rem, 2.5vw, 2rem)` |
36
- | Espaciado fluido | `padding: clamp(1rem, 5vw, 3rem)` |
37
- | Dark mode | `@media (prefers-color-scheme: dark)` |
38
- | Reduced motion | `@media (prefers-reduced-motion: reduce)` |
39
- | Layout responsivo sin breakpoints | `grid-template-columns: repeat(auto-fill, minmax(250px, 1fr))` |
40
- | Responsive a nivel componente | `@container` queries |
41
- | Design tokens / theming global | Custom properties (`--color-primario: #7c3aed`) |
42
- | Smooth scroll | `scroll-behavior: smooth` |
43
- | Carrusel con scroll-snap | `scroll-snap-type: x mandatory` + `scroll-snap-align: start` |
44
- | Aspect ratio | `aspect-ratio: 16 / 9` |
45
- | Truncar texto con elipsis | `overflow: hidden; text-overflow: ellipsis; white-space: nowrap` |
46
- | Clamp multilínea | `-webkit-line-clamp: 3` |
47
- | Aislamiento de estilos por capas | `@layer base, components, utilities` |
48
- | Selectores anidados | CSS nesting nativo (sin preprocesador) |
49
- | Selector de padre | `:has(input:checked)` |
50
-
51
- ## JavaScript / APIs del navegador
52
-
53
- | Crees que necesitas | La plataforma ya tiene |
54
- |---|---|
55
- | `query-string` / `qs` | `new URLSearchParams(location.search)` |
56
- | `lodash.clonedeep` | `structuredClone(obj)` |
57
- | `lodash.groupby` | `Object.groupBy(arr, fn)` |
58
- | `numeral` / `accounting` | `new Intl.NumberFormat("es-MX", { style: "currency", currency: "MXN" })` |
59
- | `date-fns` format | `new Intl.DateTimeFormat("es-MX", { dateStyle: "long" }).format(fecha)` |
60
- | Tiempo relativo | `new Intl.RelativeTimeFormat("es", { numeric: "auto" }).format(-3, "day")` |
61
- | Plurales i18n | `new Intl.PluralRules("es-MX").select(cantidad)` |
62
- | `clipboard.js` | `navigator.clipboard.writeText(texto)` |
63
- | `uuid` (v4) | `crypto.randomUUID()` |
64
- | Lib de infinite scroll | `new IntersectionObserver(cb).observe(sentinela)` |
65
- | Lib de resize listener | `new ResizeObserver(cb).observe(elemento)` |
66
- | Watcher de mutaciones DOM | `new MutationObserver(cb).observe(el, opciones)` |
67
- | Check de conectividad | `navigator.onLine` + eventos `online`/`offline` |
68
- | Lib de share sheet | `navigator.share({ title, text, url })` |
69
- | `store.js` / `localForage` (caso simple) | `localStorage.setItem(clave, JSON.stringify(valor))` |
70
- | Abortar fetch por timeout | `AbortSignal.timeout(5000)` pasado a `fetch` |
71
- | Event bus custom | `new EventTarget()` / `dispatchEvent(new CustomEvent("x", { detail }))` |
72
-
73
- **Debounce en 3 líneas** (sin dependencia):
74
-
75
- ```js
76
- // simplificado: debounce de una sola instancia; lib si se necesitan N independientes
77
- let t;
78
- const debounce = (fn, ms) => (...args) => { clearTimeout(t); t = setTimeout(() => fn(...args), ms); };
79
- ```
80
-
81
- ## Swift / SwiftUI
82
-
83
- | Crees que necesitas | La plataforma ya tiene |
84
- |---|---|
85
- | Lib de date/time picker | `DatePicker` |
86
- | Lib de color picker | `ColorPicker` |
87
- | Search bar + filtrado | `.searchable(text:)` |
88
- | Lib de pull-to-refresh | `.refreshable { }` |
89
- | Swipe-to-delete / acciones de fila | `.swipeActions { }` |
90
- | Carga async de imágenes + caché | `AsyncImage` |
91
- | Lib de gráficas | Swift Charts (`import Charts`) |
92
- | Render de Markdown | `Text(...)` markdown / `AttributedString(markdown:)` |
93
- | Share sheet | `ShareLink` |
94
- | Spinner de carga | `ProgressView()` |
95
- | Photo picker | `PhotosPicker` |
96
- | JSON (SwiftyJSON) | `Codable` + `JSONDecoder`/`JSONEncoder` |
97
- | HTTP simple (Alamofire) | `URLSession` async/await |
98
- | Crypto (CryptoSwift) | `CryptoKit` |
99
- | Persistencia / ORM | `SwiftData`, o `@AppStorage` para key-values |
100
- | Logging | `Logger` (`os.log`) |
101
-
102
- ## Stdlib de Node.js
103
-
104
- | Crees que necesitas | Node ya tiene |
105
- |---|---|
106
- | `mkdirp` / `make-dir` | `fs.mkdirSync(ruta, { recursive: true })` |
107
- | `rimraf` | `fs.rmSync(ruta, { recursive: true, force: true })` |
108
- | `uuid` (v4) | `crypto.randomUUID()` |
109
- | `object-assign` | `Object.assign()` / spread |
110
- | `array-uniq` | `[...new Set(arr)]` |
111
- | `array-flatten` / `flat` | `arr.flat(profundidad)` |
112
- | `path-exists` | `fs.existsSync(ruta)` |
113
- | `load-json-file` | `JSON.parse(fs.readFileSync(ruta, "utf8"))` |
114
- | `write-json-file` | `fs.writeFileSync(ruta, JSON.stringify(obj, null, 2))` |
115
- | `pkg-dir` | `path.resolve(__dirname, "..")` / `import.meta.dirname` |
116
-
117
- ## Stdlib de Python
118
-
119
- | Crees que necesitas | Python ya tiene |
120
- |---|---|
121
- | `python-dateutil` (parsing básico) | `datetime.fromisoformat()` (3.7+) |
122
- | `pytz` | `zoneinfo.ZoneInfo("America/Mexico_City")` (3.9+) |
123
- | `attrs` (data classes simples) | `@dataclass` |
124
- | `pathlib2` | `pathlib.Path` (3.4+) |
125
- | `simplejson` (uso básico) | `json` (stdlib) |
126
- | `requests` (GET simple) | `urllib.request.urlopen(url)`; `requests` para algo real |
127
- | `click` (comando único) | `argparse` (stdlib) |
128
- | `mergedeep` | `dict \| otro_dict` (3.9+) |
129
- | `more-itertools` (básico) | `itertools`: `chain`, `islice`, `groupby`, `product` |
130
- | `toolz` (básico) | `functools`: `lru_cache`, `partial`, `reduce` |
131
-
132
- ## Base de datos
133
-
134
- | Crees que necesitas código de app para | La BD ya tiene |
135
- |---|---|
136
- | Paginación | `LIMIT 20 OFFSET 40` |
137
- | Totales acumulados | `SUM(...) OVER (ORDER BY fecha)` (window function) |
138
- | Rank por grupo | `RANK() OVER (PARTITION BY categoria ORDER BY score DESC)` |
139
- | Deduplicación | `SELECT DISTINCT` / `ON CONFLICT DO NOTHING` |
140
- | Recorrido de árboles | CTE recursivo (`WITH RECURSIVE`) |
141
- | Full-text search (básico) | `tsvector` / `MATCH AGAINST` / `FTS5` |
142
- | Almacenar + consultar JSON | `jsonb` (Postgres) / `JSON_EXTRACT` (SQLite/MySQL) |
143
- | Generación de UUID | `gen_random_uuid()` (Postgres) / `UUID()` (MySQL) |
144
- | Timestamps de insert/update | `DEFAULT now()` + trigger / `ON UPDATE CURRENT_TIMESTAMP` |
145
- | Unicidad | constraint `UNIQUE`, no checks en la app |
146
- | Integridad referencial | `FOREIGN KEY`, no checks en la app |
147
- | Rangos de valores | `CHECK (precio > 0)`, no validación en la app |
148
-
149
- ---
150
-
151
- ## El patrón
152
-
153
- En todas las capas es el mismo ciclo:
154
-
155
- ```
156
- El equipo de la plataforma pasa años resolviendo el problema.
157
- Alguien lo envuelve en un paquete.
158
- Instalas el wrapper.
159
- El wrapper queda sin mantenimiento.
160
- Terminas debugueando el wrapper.
161
- ```
162
-
163
- Sáltate el wrapper. Cuando la solución nativa es genuinamente insuficiente
164
- (soporte de navegadores viejos, edge cases que no cubre, ergonomía que importa
165
- a escala), la librería se gana su lugar — instálala entonces, no antes
166
- (y verifica su vigencia con Context7, regla `usar-context7.md`).
1
+ # Soluciones nativas de plataforma
2
+
3
+ Recurso de `prevencion-sobreingenieria` — peldaño 4 de la escalera de decisión.
4
+ La primera pregunta del ingeniero perezoso-eficiente: *¿la plataforma ya hace
5
+ esto?* Antes de instalar un paquete o escribir un componente, revisar aquí.
6
+ La plataforma viaja gratis con la app, no se rompe en updates, y la escribió
7
+ gente cuyo trabajo es exactamente ese problema.
8
+
9
+ Adaptado de [ponytail](https://github.com/DietrichGebert/ponytail)
10
+ `docs/platform-native.md` (MIT, DietrichGebert).
11
+
12
+ ---
13
+
14
+ ## Elementos HTML
15
+
16
+ | Crees que necesitas | La plataforma ya tiene |
17
+ |---|---|
18
+ | Lib de date picker | `<input type="date">` |
19
+ | Lib de time picker | `<input type="time">` |
20
+ | Lib de color picker | `<input type="color">` |
21
+ | Lib de range slider | `<input type="range">` |
22
+ | Componente de progress bar | `<progress value="70" max="100">` |
23
+ | Componente meter/gauge | `<meter value="0.7">` |
24
+ | Lib de modal/diálogo | `<dialog>` + `dialog.showModal()` |
25
+ | Componente acordeón/FAQ | `<details><summary>Título</summary>…</details>` |
26
+ | Lib de tooltips | atributo `title` + CSS `::before`/`::after` |
27
+ | Dropdown con búsqueda | `<input list="id"> <datalist id="id">` |
28
+ | Textarea auto-crecible | `field-sizing: content` (CSS) |
29
+ | Header sticky | `position: sticky; top: 0` (CSS) |
30
+
31
+ ## Capacidades CSS (donde se suele usar JS)
32
+
33
+ | Crees que necesitas JS para | CSS ya tiene |
34
+ |---|---|
35
+ | Font size responsivo | `font-size: clamp(1rem, 2.5vw, 2rem)` |
36
+ | Espaciado fluido | `padding: clamp(1rem, 5vw, 3rem)` |
37
+ | Dark mode | `@media (prefers-color-scheme: dark)` |
38
+ | Reduced motion | `@media (prefers-reduced-motion: reduce)` |
39
+ | Layout responsivo sin breakpoints | `grid-template-columns: repeat(auto-fill, minmax(250px, 1fr))` |
40
+ | Responsive a nivel componente | `@container` queries |
41
+ | Design tokens / theming global | Custom properties (`--color-primario: #7c3aed`) |
42
+ | Smooth scroll | `scroll-behavior: smooth` |
43
+ | Carrusel con scroll-snap | `scroll-snap-type: x mandatory` + `scroll-snap-align: start` |
44
+ | Aspect ratio | `aspect-ratio: 16 / 9` |
45
+ | Truncar texto con elipsis | `overflow: hidden; text-overflow: ellipsis; white-space: nowrap` |
46
+ | Clamp multilínea | `-webkit-line-clamp: 3` |
47
+ | Aislamiento de estilos por capas | `@layer base, components, utilities` |
48
+ | Selectores anidados | CSS nesting nativo (sin preprocesador) |
49
+ | Selector de padre | `:has(input:checked)` |
50
+
51
+ ## JavaScript / APIs del navegador
52
+
53
+ | Crees que necesitas | La plataforma ya tiene |
54
+ |---|---|
55
+ | `query-string` / `qs` | `new URLSearchParams(location.search)` |
56
+ | `lodash.clonedeep` | `structuredClone(obj)` |
57
+ | `lodash.groupby` | `Object.groupBy(arr, fn)` |
58
+ | `numeral` / `accounting` | `new Intl.NumberFormat("es-MX", { style: "currency", currency: "MXN" })` |
59
+ | `date-fns` format | `new Intl.DateTimeFormat("es-MX", { dateStyle: "long" }).format(fecha)` |
60
+ | Tiempo relativo | `new Intl.RelativeTimeFormat("es", { numeric: "auto" }).format(-3, "day")` |
61
+ | Plurales i18n | `new Intl.PluralRules("es-MX").select(cantidad)` |
62
+ | `clipboard.js` | `navigator.clipboard.writeText(texto)` |
63
+ | `uuid` (v4) | `crypto.randomUUID()` |
64
+ | Lib de infinite scroll | `new IntersectionObserver(cb).observe(sentinela)` |
65
+ | Lib de resize listener | `new ResizeObserver(cb).observe(elemento)` |
66
+ | Watcher de mutaciones DOM | `new MutationObserver(cb).observe(el, opciones)` |
67
+ | Check de conectividad | `navigator.onLine` + eventos `online`/`offline` |
68
+ | Lib de share sheet | `navigator.share({ title, text, url })` |
69
+ | `store.js` / `localForage` (caso simple) | `localStorage.setItem(clave, JSON.stringify(valor))` |
70
+ | Abortar fetch por timeout | `AbortSignal.timeout(5000)` pasado a `fetch` |
71
+ | Event bus custom | `new EventTarget()` / `dispatchEvent(new CustomEvent("x", { detail }))` |
72
+
73
+ **Debounce en 3 líneas** (sin dependencia):
74
+
75
+ ```js
76
+ // simplificado: debounce de una sola instancia; lib si se necesitan N independientes
77
+ let t;
78
+ const debounce = (fn, ms) => (...args) => { clearTimeout(t); t = setTimeout(() => fn(...args), ms); };
79
+ ```
80
+
81
+ ## Swift / SwiftUI
82
+
83
+ | Crees que necesitas | La plataforma ya tiene |
84
+ |---|---|
85
+ | Lib de date/time picker | `DatePicker` |
86
+ | Lib de color picker | `ColorPicker` |
87
+ | Search bar + filtrado | `.searchable(text:)` |
88
+ | Lib de pull-to-refresh | `.refreshable { }` |
89
+ | Swipe-to-delete / acciones de fila | `.swipeActions { }` |
90
+ | Carga async de imágenes + caché | `AsyncImage` |
91
+ | Lib de gráficas | Swift Charts (`import Charts`) |
92
+ | Render de Markdown | `Text(...)` markdown / `AttributedString(markdown:)` |
93
+ | Share sheet | `ShareLink` |
94
+ | Spinner de carga | `ProgressView()` |
95
+ | Photo picker | `PhotosPicker` |
96
+ | JSON (SwiftyJSON) | `Codable` + `JSONDecoder`/`JSONEncoder` |
97
+ | HTTP simple (Alamofire) | `URLSession` async/await |
98
+ | Crypto (CryptoSwift) | `CryptoKit` |
99
+ | Persistencia / ORM | `SwiftData`, o `@AppStorage` para key-values |
100
+ | Logging | `Logger` (`os.log`) |
101
+
102
+ ## Stdlib de Node.js
103
+
104
+ | Crees que necesitas | Node ya tiene |
105
+ |---|---|
106
+ | `mkdirp` / `make-dir` | `fs.mkdirSync(ruta, { recursive: true })` |
107
+ | `rimraf` | `fs.rmSync(ruta, { recursive: true, force: true })` |
108
+ | `uuid` (v4) | `crypto.randomUUID()` |
109
+ | `object-assign` | `Object.assign()` / spread |
110
+ | `array-uniq` | `[...new Set(arr)]` |
111
+ | `array-flatten` / `flat` | `arr.flat(profundidad)` |
112
+ | `path-exists` | `fs.existsSync(ruta)` |
113
+ | `load-json-file` | `JSON.parse(fs.readFileSync(ruta, "utf8"))` |
114
+ | `write-json-file` | `fs.writeFileSync(ruta, JSON.stringify(obj, null, 2))` |
115
+ | `pkg-dir` | `path.resolve(__dirname, "..")` / `import.meta.dirname` |
116
+
117
+ ## Stdlib de Python
118
+
119
+ | Crees que necesitas | Python ya tiene |
120
+ |---|---|
121
+ | `python-dateutil` (parsing básico) | `datetime.fromisoformat()` (3.7+) |
122
+ | `pytz` | `zoneinfo.ZoneInfo("America/Mexico_City")` (3.9+) |
123
+ | `attrs` (data classes simples) | `@dataclass` |
124
+ | `pathlib2` | `pathlib.Path` (3.4+) |
125
+ | `simplejson` (uso básico) | `json` (stdlib) |
126
+ | `requests` (GET simple) | `urllib.request.urlopen(url)`; `requests` para algo real |
127
+ | `click` (comando único) | `argparse` (stdlib) |
128
+ | `mergedeep` | `dict \| otro_dict` (3.9+) |
129
+ | `more-itertools` (básico) | `itertools`: `chain`, `islice`, `groupby`, `product` |
130
+ | `toolz` (básico) | `functools`: `lru_cache`, `partial`, `reduce` |
131
+
132
+ ## Base de datos
133
+
134
+ | Crees que necesitas código de app para | La BD ya tiene |
135
+ |---|---|
136
+ | Paginación | `LIMIT 20 OFFSET 40` |
137
+ | Totales acumulados | `SUM(...) OVER (ORDER BY fecha)` (window function) |
138
+ | Rank por grupo | `RANK() OVER (PARTITION BY categoria ORDER BY score DESC)` |
139
+ | Deduplicación | `SELECT DISTINCT` / `ON CONFLICT DO NOTHING` |
140
+ | Recorrido de árboles | CTE recursivo (`WITH RECURSIVE`) |
141
+ | Full-text search (básico) | `tsvector` / `MATCH AGAINST` / `FTS5` |
142
+ | Almacenar + consultar JSON | `jsonb` (Postgres) / `JSON_EXTRACT` (SQLite/MySQL) |
143
+ | Generación de UUID | `gen_random_uuid()` (Postgres) / `UUID()` (MySQL) |
144
+ | Timestamps de insert/update | `DEFAULT now()` + trigger / `ON UPDATE CURRENT_TIMESTAMP` |
145
+ | Unicidad | constraint `UNIQUE`, no checks en la app |
146
+ | Integridad referencial | `FOREIGN KEY`, no checks en la app |
147
+ | Rangos de valores | `CHECK (precio > 0)`, no validación en la app |
148
+
149
+ ---
150
+
151
+ ## El patrón
152
+
153
+ En todas las capas es el mismo ciclo:
154
+
155
+ ```
156
+ El equipo de la plataforma pasa años resolviendo el problema.
157
+ Alguien lo envuelve en un paquete.
158
+ Instalas el wrapper.
159
+ El wrapper queda sin mantenimiento.
160
+ Terminas debugueando el wrapper.
161
+ ```
162
+
163
+ Sáltate el wrapper. Cuando la solución nativa es genuinamente insuficiente
164
+ (soporte de navegadores viejos, edge cases que no cubre, ergonomía que importa
165
+ a escala), la librería se gana su lugar — instálala entonces, no antes
166
+ (y verifica su vigencia con Context7, regla `usar-context7.md`).
@@ -1,85 +1,85 @@
1
- # Variables residuales post-refactor son code smell
2
-
3
- Recurso de `prevencion-sobreingenieria`. Extraído del SKILL.md en v1.3.0 para
4
- respetar el límite de 300 líneas; el contenido es normativo sin cambios.
5
-
6
- ## Regla
7
-
8
- Variables asignadas pero no usadas (F841 en ruff/flake8) **post-refactor** son
9
- casi siempre residuos de una versión anterior del código que el refactor no
10
- limpió. Se parecen a "variables temporales del desarrollador" pero delatan un
11
- refactor incompleto — la lógica que las usaba se movió o eliminó, pero las
12
- asignaciones quedaron.
13
-
14
- ## Por qué son peligrosas
15
-
16
- - **Confunden al próximo lector**: asumirá que la variable se usa más abajo.
17
- - **Inflan el diff cognitivo** del refactor real.
18
- - **Ocultan bugs sutiles**: el valor asignado puede tener side effects (llamada
19
- a función costosa o con efecto en estado) que ya no aporta nada al flujo.
20
- - **Invalidan la métrica de cobertura**: líneas "cubiertas" por tests que en
21
- realidad no afectan el resultado.
22
-
23
- ## Patrón operativo
24
-
25
- Después de **cualquier refactor** que modifique el flujo de una función (extraer
26
- método, inlinear función, cambiar el shape de un return), correr:
27
-
28
- ```bash
29
- ruff check --select=F841 ruta/al/modulo.py
30
- # o para todo el proyecto
31
- ruff check --select=F841 .
32
- ```
33
-
34
- Cada F841 detectado post-refactor es candidato 1 de 2:
35
-
36
- 1. **Variable muerta** (caso común post-refactor): eliminarla.
37
- 2. **Variable viva pero mal nombrada** (caso raro): si el valor se usa como
38
- side effect intencional (ej: evaluar una propiedad para cachear), renombrar
39
- con prefijo `_` y comentar el propósito.
40
-
41
- ## Anti-patrón típico
42
-
43
- ```python
44
- # Antes del refactor: había un if que usaba exito_key
45
- def procesar(data):
46
- exito, exito_key = intentar(data)
47
- if exito_key == "via_rapida":
48
- return procesar_rapido(data)
49
- return procesar_normal(data, exito_key)
50
-
51
-
52
- # Después de refactor que eliminó la rama "via_rapida"
53
- def procesar(data):
54
- exito, exito_key = intentar(data) # ← F841: exito_key asignado, no usado
55
- return procesar_normal(data) # ← también exito residual
56
- ```
57
-
58
- ## Patrón canónico
59
-
60
- ```python
61
- # Post-refactor limpio
62
- def procesar(data):
63
- _ = intentar(data) # si el side effect de intentar() importa
64
- return procesar_normal(data)
65
-
66
- # o mejor: si ni siquiera el side effect importa
67
- def procesar(data):
68
- return procesar_normal(data)
69
- ```
70
-
71
- ## Reglas
72
-
73
- - **Gate pre-commit**: agregar `ruff check --select=F841` al pre-commit hook del proyecto. No bloquea en un repo grande donde F841 preexiste, pero sí bloquea en los archivos modificados por el commit actual.
74
- - **Revisión explícita post-refactor grande**: tras extraer 5+ métodos o mover 5+ bloques, correr `ruff --select=F401,F841` sobre los archivos tocados.
75
- - **NO silenciar con `# noqa: F841` sin justificación** — la excepción legítima (side effect intencional con nombre `_`) es tan rara que vale la pena documentarla; silenciar sin comentario es ocultar deuda.
76
- - **Incluir en checklist de PR**: "F841 limpio en archivos tocados" como item explícito.
77
-
78
- ## Aplicabilidad
79
-
80
- Detectable en:
81
-
82
- - Python: `ruff --select=F841`, `flake8 --select=F841`.
83
- - TypeScript/JavaScript: `eslint --rule 'no-unused-vars: error'`.
84
- - Go: el compilador lo hace obligatorio (`declared but not used`).
85
- - Rust: warning `unused_variables`, promovido a error con `#![deny(unused_variables)]`.
1
+ # Variables residuales post-refactor son code smell
2
+
3
+ Recurso de `prevencion-sobreingenieria`. Extraído del SKILL.md en v1.3.0 para
4
+ respetar el límite de 300 líneas; el contenido es normativo sin cambios.
5
+
6
+ ## Regla
7
+
8
+ Variables asignadas pero no usadas (F841 en ruff/flake8) **post-refactor** son
9
+ casi siempre residuos de una versión anterior del código que el refactor no
10
+ limpió. Se parecen a "variables temporales del desarrollador" pero delatan un
11
+ refactor incompleto — la lógica que las usaba se movió o eliminó, pero las
12
+ asignaciones quedaron.
13
+
14
+ ## Por qué son peligrosas
15
+
16
+ - **Confunden al próximo lector**: asumirá que la variable se usa más abajo.
17
+ - **Inflan el diff cognitivo** del refactor real.
18
+ - **Ocultan bugs sutiles**: el valor asignado puede tener side effects (llamada
19
+ a función costosa o con efecto en estado) que ya no aporta nada al flujo.
20
+ - **Invalidan la métrica de cobertura**: líneas "cubiertas" por tests que en
21
+ realidad no afectan el resultado.
22
+
23
+ ## Patrón operativo
24
+
25
+ Después de **cualquier refactor** que modifique el flujo de una función (extraer
26
+ método, inlinear función, cambiar el shape de un return), correr:
27
+
28
+ ```bash
29
+ ruff check --select=F841 ruta/al/modulo.py
30
+ # o para todo el proyecto
31
+ ruff check --select=F841 .
32
+ ```
33
+
34
+ Cada F841 detectado post-refactor es candidato 1 de 2:
35
+
36
+ 1. **Variable muerta** (caso común post-refactor): eliminarla.
37
+ 2. **Variable viva pero mal nombrada** (caso raro): si el valor se usa como
38
+ side effect intencional (ej: evaluar una propiedad para cachear), renombrar
39
+ con prefijo `_` y comentar el propósito.
40
+
41
+ ## Anti-patrón típico
42
+
43
+ ```python
44
+ # Antes del refactor: había un if que usaba exito_key
45
+ def procesar(data):
46
+ exito, exito_key = intentar(data)
47
+ if exito_key == "via_rapida":
48
+ return procesar_rapido(data)
49
+ return procesar_normal(data, exito_key)
50
+
51
+
52
+ # Después de refactor que eliminó la rama "via_rapida"
53
+ def procesar(data):
54
+ exito, exito_key = intentar(data) # ← F841: exito_key asignado, no usado
55
+ return procesar_normal(data) # ← también exito residual
56
+ ```
57
+
58
+ ## Patrón canónico
59
+
60
+ ```python
61
+ # Post-refactor limpio
62
+ def procesar(data):
63
+ _ = intentar(data) # si el side effect de intentar() importa
64
+ return procesar_normal(data)
65
+
66
+ # o mejor: si ni siquiera el side effect importa
67
+ def procesar(data):
68
+ return procesar_normal(data)
69
+ ```
70
+
71
+ ## Reglas
72
+
73
+ - **Gate pre-commit**: agregar `ruff check --select=F841` al pre-commit hook del proyecto. No bloquea en un repo grande donde F841 preexiste, pero sí bloquea en los archivos modificados por el commit actual.
74
+ - **Revisión explícita post-refactor grande**: tras extraer 5+ métodos o mover 5+ bloques, correr `ruff --select=F401,F841` sobre los archivos tocados.
75
+ - **NO silenciar con `# noqa: F841` sin justificación** — la excepción legítima (side effect intencional con nombre `_`) es tan rara que vale la pena documentarla; silenciar sin comentario es ocultar deuda.
76
+ - **Incluir en checklist de PR**: "F841 limpio en archivos tocados" como item explícito.
77
+
78
+ ## Aplicabilidad
79
+
80
+ Detectable en:
81
+
82
+ - Python: `ruff --select=F841`, `flake8 --select=F841`.
83
+ - TypeScript/JavaScript: `eslint --rule 'no-unused-vars: error'`.
84
+ - Go: el compilador lo hace obligatorio (`declared but not used`).
85
+ - Rust: warning `unused_variables`, promovido a error con `#![deny(unused_variables)]`.
@@ -43,10 +43,11 @@ Presupuesto: `max_hallazgos_por_persona = presupuesto_total / num_personas`
43
43
  - **Red flags**: errores tragados, retries faltantes, sin circuit breakers, fallas silenciosas.
44
44
 
45
45
  ### 5. Abogado del Diablo
46
- - **Enfoque**: asunciones, casos límite, complejidad oculta, mantenibilidad.
47
- - **Preguntas guía**: ¿Qué asunciones son falsas? ¿Qué rompe esto? ¿Está sobre-ingenierizado?
48
- - **Evidencia exigida**: contraejemplos concretos, escenarios de caso límite.
49
- - **Red flags**: diseño solo-happy-path, asunciones sin probar, complejidad sin justificación.
46
+ - **Enfoque**: asunciones, casos límite, complejidad oculta, mantenibilidad — y la legitimidad misma de la decisión.
47
+ - **Preguntas guía**: ¿Qué asunciones son falsas? ¿Qué rompe esto? ¿Está sobre-ingenierizado? ¿Qué alternativa más simple se descartó sin articularla? Pre-mortem exprés: si esto fracasa en 6 meses, ¿cuál es la causa más probable y qué señal de HOY la anticipaba?
48
+ - **Evidencia exigida**: contraejemplos concretos, escenarios de caso límite, y al menos 1 alternativa descartada con su tradeoff real (no de paja).
49
+ - **Red flags**: diseño solo-happy-path, asunciones sin probar, complejidad sin justificación, "es la mejor práctica" sin fuente, "no hay otra opción razonable".
50
+ - **Escalamiento**: si la duda es sobre HACER o NO el cambio (no sobre cómo), esta persona es insuficiente — usar `/swl:predecir --abogado-diablo` (agente `abogado-diablo-swl`: pre-mortem completo + doubt-driven review + dictamen que puede ser NO PROCEDER).
50
51
 
51
52
  ---
52
53