@saulwade/swl-ses 2.6.0 → 2.6.1

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 (207) hide show
  1. package/CLAUDE.md +197 -197
  2. package/README.md +600 -600
  3. package/agentes/_intent-spec.md +73 -73
  4. package/agentes/_propose-step.md +90 -90
  5. package/agentes/accesibilidad-wcag-swl.md +690 -690
  6. package/agentes/arquitecto-swl.md +267 -267
  7. package/agentes/auto-evolucion-swl.md +932 -932
  8. package/agentes/backend-csharp-swl.md +420 -420
  9. package/agentes/backend-go-swl.md +390 -390
  10. package/agentes/backend-java-swl.md +281 -281
  11. package/agentes/backend-rust-swl.md +364 -364
  12. package/agentes/backend-workers-swl.md +482 -482
  13. package/agentes/cloud-infra-swl.md +509 -509
  14. package/agentes/consolidador-swl.md +541 -541
  15. package/agentes/depurador-swl.md +352 -352
  16. package/agentes/devops-ci-swl.md +400 -400
  17. package/agentes/disenador-ui-swl.md +569 -569
  18. package/agentes/documentador-swl.md +345 -345
  19. package/agentes/frontend-angular-swl.md +621 -621
  20. package/agentes/frontend-css-swl.md +716 -716
  21. package/agentes/frontend-react-swl.md +692 -692
  22. package/agentes/frontend-swl.md +496 -496
  23. package/agentes/frontend-tailwind-swl.md +826 -826
  24. package/agentes/investigador-swl.md +432 -432
  25. package/agentes/investigador-ux-swl.md +505 -505
  26. package/agentes/migrador-swl.md +442 -442
  27. package/agentes/mobile-android-swl.md +511 -511
  28. package/agentes/mobile-cross-swl.md +541 -541
  29. package/agentes/mobile-ios-swl.md +502 -502
  30. package/agentes/mobile-testing-swl.md +302 -302
  31. package/agentes/nemesis-auditor-swl.md +285 -285
  32. package/agentes/observabilidad-swl.md +438 -438
  33. package/agentes/pagos-swl.md +310 -310
  34. package/agentes/perfilador-usuario-swl.md +321 -321
  35. package/agentes/planificador-swl.md +399 -399
  36. package/agentes/producto-prd-swl.md +589 -589
  37. package/agentes/red-team-swl.md +218 -218
  38. package/agentes/release-manager-swl.md +590 -590
  39. package/agentes/rendimiento-swl.md +713 -713
  40. package/agentes/revisor-angular-swl.md +278 -278
  41. package/agentes/revisor-csharp-swl.md +264 -264
  42. package/agentes/revisor-go-swl.md +259 -259
  43. package/agentes/revisor-java-swl.md +257 -257
  44. package/agentes/revisor-kotlin-swl.md +273 -273
  45. package/agentes/revisor-nextjs-swl.md +281 -281
  46. package/agentes/revisor-php-swl.md +271 -271
  47. package/agentes/revisor-react-swl.md +278 -278
  48. package/agentes/revisor-rust-swl.md +346 -346
  49. package/agentes/revisor-seguridad-swl.md +399 -399
  50. package/agentes/revisor-swift-swl.md +268 -268
  51. package/agentes/revisor-typescript-swl.md +346 -346
  52. package/agentes/tdd-qa-swl.md +393 -393
  53. package/comandos/swl/actualizar.md +174 -174
  54. package/comandos/swl/adoptar-proyecto.md +265 -265
  55. package/comandos/swl/aprender.md +836 -836
  56. package/comandos/swl/aprobar-plan.md +146 -146
  57. package/comandos/swl/auditar-deps.md +134 -134
  58. package/comandos/swl/autoresearch.md +264 -264
  59. package/comandos/swl/ayuda.md +224 -224
  60. package/comandos/swl/brainstorm.md +51 -51
  61. package/comandos/swl/briefing.md +119 -119
  62. package/comandos/swl/checkpoint.md +325 -325
  63. package/comandos/swl/claudemd.md +234 -234
  64. package/comandos/swl/compactar.md +310 -310
  65. package/comandos/swl/configurar-ci.md +235 -235
  66. package/comandos/swl/contexto.md +110 -110
  67. package/comandos/swl/contribuir.md +233 -233
  68. package/comandos/swl/crear-skill.md +292 -292
  69. package/comandos/swl/cron.md +194 -194
  70. package/comandos/swl/discutir-fase.md +169 -169
  71. package/comandos/swl/ejecutar-fase.md +233 -233
  72. package/comandos/swl/evaluar-skill.md +520 -520
  73. package/comandos/swl/evolucion-continua.md +73 -73
  74. package/comandos/swl/evolucionar.md +267 -267
  75. package/comandos/swl/exportar-vault.md +583 -583
  76. package/comandos/swl/fix.md +118 -118
  77. package/comandos/swl/gateway.md +158 -158
  78. package/comandos/swl/inbox.md +116 -116
  79. package/comandos/swl/instalar.md +220 -220
  80. package/comandos/swl/instintos.md +86 -86
  81. package/comandos/swl/mapear-codebase.md +312 -312
  82. package/comandos/swl/mcp-status.md +175 -175
  83. package/comandos/swl/modelo.md +100 -100
  84. package/comandos/swl/nemesis.md +433 -433
  85. package/comandos/swl/notificaciones.md +299 -299
  86. package/comandos/swl/nuevo-proyecto.md +251 -251
  87. package/comandos/swl/planear-fase.md +263 -263
  88. package/comandos/swl/plugins.md +256 -256
  89. package/comandos/swl/predecir.md +169 -169
  90. package/comandos/swl/reflect-skills.md +125 -125
  91. package/comandos/swl/release.md +450 -450
  92. package/comandos/swl/revisar-impacto.md +201 -201
  93. package/comandos/swl/revisar.md +330 -330
  94. package/comandos/swl/seguridad.md +189 -189
  95. package/comandos/swl/sesiones.md +200 -200
  96. package/comandos/swl/skill-search.md +113 -113
  97. package/comandos/swl/status.md +345 -345
  98. package/comandos/swl/verificar.md +817 -817
  99. package/comandos/swl/wiki.md +620 -620
  100. package/gateway/cron/jobs.example.json +12 -12
  101. package/habilidades/auto-evolucion-protocolo/SKILL.md +294 -294
  102. package/habilidades/backend-async-postgres-testing/SKILL.md +2 -1
  103. package/habilidades/changelog-generator/SKILL.md +174 -174
  104. package/habilidades/compactacion-contexto/SKILL.md +2 -1
  105. package/habilidades/contenedores-docker/SKILL.md +4 -2
  106. package/habilidades/doubt-driven-review/SKILL.md +207 -207
  107. package/habilidades/drift-detection/SKILL.md +1 -1
  108. package/habilidades/ejecutar-task-iterativo/SKILL.md +278 -278
  109. package/habilidades/extractor-de-aprendizajes/SKILL.md +8 -2
  110. package/habilidades/git-worktrees-paralelo/SKILL.md +19 -1
  111. package/habilidades/harness-claude-code/SKILL.md +314 -314
  112. package/habilidades/instalar-sistema/SKILL.md +227 -227
  113. package/habilidades/planear-fase/SKILL.md +358 -358
  114. package/habilidades/prevencion-sobreingenieria/recursos/soluciones-nativas.md +166 -166
  115. package/habilidades/prevencion-sobreingenieria/recursos/variables-residuales-post-refactor.md +85 -85
  116. package/habilidades/proceso-ingenieria-requerimientos/SKILL.md +147 -147
  117. package/habilidades/release-semver/SKILL.md +2 -2
  118. package/habilidades/tdd-workflow/SKILL.md +749 -749
  119. package/hooks/agente-lifecycle.js +1 -1
  120. package/hooks/audit-trail.js +1 -1
  121. package/hooks/auto-consolidacion.js +1 -1
  122. package/hooks/captura-acciones-post.js +1 -1
  123. package/hooks/captura-acciones-session.js +1 -1
  124. package/hooks/captura-feedback-usuario.js +1 -1
  125. package/hooks/contexto-iteracion.js +1 -1
  126. package/hooks/contexto-subagente.js +68 -68
  127. package/hooks/degradacion-instintos.js +1 -1
  128. package/hooks/grafo-contexto.js +1 -1
  129. package/hooks/guardrail-modelo.js +1 -1
  130. package/hooks/inbox-aviso.js +1 -1
  131. package/hooks/inyeccion-contexto.js +1 -1
  132. package/hooks/lib/agent-matcher.js +1 -1
  133. package/hooks/lib/agent-routing.js +1 -1
  134. package/hooks/lib/captura-acciones.js +1 -1
  135. package/hooks/lib/etapa-metricas.js +1 -1
  136. package/hooks/lib/evolution-tracker.js +1 -1
  137. package/hooks/lib/gateway-notify.js +193 -193
  138. package/hooks/lib/mcp-health.js +1 -1
  139. package/hooks/lib/notificacion-formato.js +58 -0
  140. package/hooks/lib/nudge-tracker.js +1 -1
  141. package/hooks/lib/otlp-exporter.js +1 -1
  142. package/hooks/lib/propose-step.js +1 -1
  143. package/hooks/lib/raiz-proyecto.js +127 -102
  144. package/hooks/lib/run-log.js +1 -1
  145. package/hooks/lib/singleton-guard.js +20 -13
  146. package/hooks/lib/telegram-cliente.js +11 -3
  147. package/hooks/notificacion-telegram.js +13 -3
  148. package/hooks/preservar-estado-pre-compact.js +1 -1
  149. package/hooks/registro-turnos.js +1 -1
  150. package/hooks/resumen-sesion.js +1 -1
  151. package/hooks/risk-scoring.js +1 -1
  152. package/hooks/session-briefing.js +1 -1
  153. package/hooks/spec-gate.js +1 -1
  154. package/hooks/sugerir-regenerar-inventario.js +1 -1
  155. package/hooks/tdd-gate.js +1 -1
  156. package/hooks/telemetria-agentes.js +1 -1
  157. package/hooks/telemetria-skill-routing.js +1 -1
  158. package/hooks/tracking-costos.js +1 -1
  159. package/hooks/validar-formato-post-subagente.js +1 -1
  160. package/hooks/validar-intent-spec.js +1 -1
  161. package/hooks/validar-planning-paths.js +1 -1
  162. package/llms.txt +29 -29
  163. package/manifiestos/canonical-hashes.json +5588 -5257
  164. package/manifiestos/hooks-config.json +469 -469
  165. package/manifiestos/invariantes-criticos.json +30 -30
  166. package/manifiestos/modulos.json +1429 -1428
  167. package/manifiestos/skills-lock.json +1275 -1275
  168. package/package.json +94 -94
  169. package/plugin.json +369 -369
  170. package/scripts/auditar-clases-conocidas.js +134 -134
  171. package/scripts/bootstrap-instintos.js +85 -14
  172. package/scripts/canario-hooks.js +166 -166
  173. package/scripts/cli/autonomia.js +23 -23
  174. package/scripts/cli/benchmark-memoria.js +37 -37
  175. package/scripts/cli/ciclo-autonomo.js +73 -73
  176. package/scripts/cli/ciclo-fase-b.js +102 -102
  177. package/scripts/cli/guardrail-metrics.js +39 -39
  178. package/scripts/cli/memoria-search.js +69 -69
  179. package/scripts/cli/nudge-accionar.js +39 -39
  180. package/scripts/cli/run-eval.js +38 -38
  181. package/scripts/doctor.js +26 -3
  182. package/scripts/evidencia-valor.js +101 -101
  183. package/scripts/field-report.js +16 -16
  184. package/scripts/instalador.js +13 -0
  185. package/scripts/lib/activar-hooks-proyecto.js +116 -116
  186. package/scripts/lib/ciclo-autonomo/candidatos.js +174 -174
  187. package/scripts/lib/ciclo-autonomo/config.js +165 -165
  188. package/scripts/lib/ciclo-autonomo/drenador-feedback.js +174 -174
  189. package/scripts/lib/ciclo-autonomo/fallback.js +77 -77
  190. package/scripts/lib/ciclo-autonomo/guard-convivencia.js +139 -139
  191. package/scripts/lib/ciclo-autonomo/higiene-nudges.js +112 -112
  192. package/scripts/lib/ciclo-autonomo/index.js +301 -301
  193. package/scripts/lib/ciclo-autonomo/lock.js +124 -124
  194. package/scripts/lib/ciclo-autonomo/presupuesto.js +122 -122
  195. package/scripts/lib/ciclo-autonomo/puente-degradacion.js +240 -240
  196. package/scripts/lib/ciclo-autonomo/runner-fase-b.js +248 -248
  197. package/scripts/lib/ciclo-autonomo/writer-instintos.js +190 -190
  198. package/scripts/lib/ciclo-autonomo/yaml-instintos.js +535 -535
  199. package/scripts/lib/evidencia-valor.js +228 -228
  200. package/scripts/lib/expandir-targets.js +71 -71
  201. package/scripts/lib/limpiar-basura-global.js +161 -0
  202. package/scripts/lib/toml-merge.js +204 -204
  203. package/scripts/mcp-server/auth.js +105 -105
  204. package/scripts/mcp-server/cache.js +106 -106
  205. package/scripts/tui/pantallas/install-wizard.js +403 -403
  206. package/instintos/.backups/perfil-usuario.yaml.2026-07-10-165128.bak +0 -53
  207. package/instintos/.backups/proyecto.yaml.2026-07-10-165128.bak +0 -372
@@ -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)]`.