@saulwade/swl-ses 2.6.1 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/CLAUDE.md +14 -2
  2. package/README.md +65 -18
  3. package/agentes/_intent-spec.md +73 -73
  4. package/agentes/_propose-step.md +90 -90
  5. package/bin/swl-ses.js +10 -0
  6. package/comandos/swl/brainstorm.md +1 -0
  7. package/comandos/swl/briefing.md +119 -119
  8. package/comandos/swl/contribuir.md +233 -233
  9. package/comandos/swl/deuda-codigo.md +97 -97
  10. package/comandos/swl/mcp-status.md +1 -0
  11. package/gateway/lib/event-channel.js +191 -191
  12. package/habilidades/agent-deep-links/SKILL.md +148 -148
  13. package/habilidades/backend-async-postgres-testing/SKILL.md +216 -216
  14. package/habilidades/backend-error-design/SKILL.md +221 -221
  15. package/habilidades/backend-production-resilience/SKILL.md +288 -288
  16. package/habilidades/calidad-anti-patrones-universales/SKILL.md +105 -1
  17. package/habilidades/calidad-contract-testing/SKILL.md +165 -165
  18. package/habilidades/calidad-mutation-testing/SKILL.md +25 -1
  19. package/habilidades/checklist-seguridad/recursos/stride-cobertura.md +60 -60
  20. package/habilidades/ci-cd-pipelines/SKILL.md +5 -1
  21. package/habilidades/css-moderno/SKILL.md +7 -1
  22. package/habilidades/diagrama-arquitectura/assets/template.html +276 -276
  23. package/habilidades/doubt-driven-review/recursos/EXAMPLES.md +130 -130
  24. package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +57 -57
  25. package/habilidades/extractor-de-aprendizajes/SKILL.md +5 -1
  26. package/habilidades/feynman-auditor-swl/recursos/preguntas-language-agnostic.md +108 -108
  27. package/habilidades/harness-claude-code/SKILL.md +3 -2
  28. package/habilidades/meta-skills-estandar/recursos/convencion-examples.md +93 -93
  29. package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -469
  30. package/habilidades/perfil-usuario/SKILL.md +200 -200
  31. package/habilidades/prevencion-sobreingenieria/recursos/EXAMPLES.md +580 -580
  32. package/habilidades/prevencion-sobreingenieria/recursos/soluciones-nativas.md +166 -166
  33. package/habilidades/prevencion-sobreingenieria/recursos/variables-residuales-post-refactor.md +85 -85
  34. package/habilidades/proceso-ddia-streaming/SKILL.md +231 -231
  35. package/habilidades/proceso-discovery-machote/SKILL.md +157 -157
  36. package/habilidades/proceso-dynamic-workflows/SKILL.md +60 -0
  37. package/habilidades/proceso-dynamic-workflows/recursos/template-adversarial-verify.js +65 -65
  38. package/habilidades/proceso-dynamic-workflows/recursos/template-triage.js +65 -65
  39. package/habilidades/proceso-intent-engineering/SKILL.md +269 -269
  40. package/habilidades/proceso-modular-split/SKILL.md +256 -256
  41. package/habilidades/state-inconsistency-auditor-swl/recursos/coupled-state-patterns.md +147 -147
  42. package/habilidades/swl-claudemd/recursos/contrato-aprender.md +83 -83
  43. package/habilidades/swl-claudemd/recursos/duplicacion-reglas-globales.md +85 -85
  44. package/habilidades/swl-claudemd/recursos/plantillas-init.md +94 -94
  45. package/habilidades/tdd-workflow/recursos/gherkin-bdd.md +111 -111
  46. package/hooks/calidad-pre-commit.js +159 -10
  47. package/hooks/ciclo-evolucion-subagente.js +26 -26
  48. package/hooks/ciclo-evolucion.js +26 -26
  49. package/hooks/contexto-subagente.js +68 -68
  50. package/hooks/lib/auto-consolidator.js +335 -335
  51. package/hooks/lib/ciclo-evolucion.js +47 -47
  52. package/hooks/lib/deep-links.js +185 -185
  53. package/hooks/lib/error-classifier.js +308 -308
  54. package/hooks/lib/notificacion-formato.js +45 -11
  55. package/hooks/lib/provenance-tracker.js +191 -191
  56. package/hooks/lib/raiz-proyecto.js +35 -4
  57. package/hooks/lib/resource-quota.js +122 -122
  58. package/hooks/lib/retry-jitter.js +165 -165
  59. package/hooks/lib/security-net.js +201 -201
  60. package/hooks/lib/skill-auditor.js +588 -588
  61. package/hooks/lib/sync-status.js +228 -228
  62. package/hooks/lib/taint-tracker.js +107 -107
  63. package/hooks/lib/text-similarity.js +241 -241
  64. package/hooks/lib/toon-compressor.js +245 -245
  65. package/hooks/notificacion-telegram.js +5 -11
  66. package/hooks/session-briefing.js +12 -4
  67. package/instintos/autonomia.yaml +27 -27
  68. package/instintos/prompt-appendices.yaml +57 -57
  69. package/llms.txt +1 -1
  70. package/manifiestos/agent-output-schemas.json +57 -57
  71. package/manifiestos/canonical-hashes.json +662 -0
  72. package/manifiestos/harness-ir.json +47536 -0
  73. package/manifiestos/hooks-config.json +469 -469
  74. package/manifiestos/invariantes-criticos.json +30 -30
  75. package/manifiestos/policy-bundle.json +2065 -0
  76. package/manifiestos/policy-corpus-w2.json +3926 -0
  77. package/manifiestos/runtime-adapters-core3.json +208 -0
  78. package/manifiestos/runtime-conformance.json +139 -0
  79. package/manifiestos/skills-lock.json +43 -43
  80. package/package.json +2 -2
  81. package/plantillas/auditor-veto-template.md +105 -105
  82. package/plantillas/github-workflows/release-please.yml +44 -44
  83. package/plantillas/github-workflows/swl-ci.yml +107 -107
  84. package/plantillas/github-workflows/swl-security.yml +51 -51
  85. package/plugin.json +2 -2
  86. package/reglas/accesibilidad.md +10 -10
  87. package/reglas/auditorias-documentales-estructurales.md +7 -7
  88. package/reglas/cloud-infra.md +8 -8
  89. package/reglas/consultar-vault-primero.md +195 -195
  90. package/reglas/git-workflow.md +1 -0
  91. package/reglas/hooks.md +6 -6
  92. package/reglas/intent-engineering.md +218 -218
  93. package/reglas/markitdown.md +8 -8
  94. package/reglas/monitor-ci.md +12 -0
  95. package/reglas/patrones.md +6 -6
  96. package/reglas/testing.md +7 -7
  97. package/reglas/tests-cleanup.md +224 -224
  98. package/schemas/agent-message.schema.json +73 -73
  99. package/schemas/agent-output-implementacion.schema.json +114 -114
  100. package/schemas/agent-output-planificacion.schema.json +150 -150
  101. package/schemas/agent-output-review.schema.json +98 -98
  102. package/schemas/diary-entry.schema.json +112 -112
  103. package/schemas/gate-state.schema.json +76 -0
  104. package/schemas/harness-ir.schema.json +369 -0
  105. package/schemas/hook-profiles.schema.json +54 -54
  106. package/schemas/hooks-config.schema.json +89 -89
  107. package/schemas/legacy-gates.schema.json +45 -0
  108. package/schemas/modulos.schema.json +38 -38
  109. package/schemas/perfiles.schema.json +36 -36
  110. package/schemas/plugin.schema.json +77 -77
  111. package/schemas/policy-bundle.schema.json +140 -0
  112. package/schemas/policy-enforcement.schema.json +117 -0
  113. package/schemas/policy-operation.schema.json +261 -0
  114. package/schemas/runtime-adapter.schema.json +176 -0
  115. package/schemas/runtime-build-attestation.schema.json +100 -0
  116. package/schemas/runtime-conformance.schema.json +239 -0
  117. package/schemas/runtime-diagnostic.schema.json +395 -0
  118. package/schemas/skill-evals.schema.json +119 -119
  119. package/schemas/skill-frontmatter.schema.json +245 -245
  120. package/schemas/w4-certification-request.schema.json +72 -0
  121. package/schemas/w4-certification-verdict.schema.json +224 -0
  122. package/schemas/w4-corpus.schema.json +172 -0
  123. package/schemas/w4-mutation-report.schema.json +116 -0
  124. package/schemas/w4-replay-result.schema.json +164 -0
  125. package/schemas/w4-scoring-report.schema.json +89 -0
  126. package/scripts/audit-tools/audit-history.js +330 -330
  127. package/scripts/audit-tools/bundle-tracker.js +290 -290
  128. package/scripts/audit-tools/canary-monitor.js +352 -352
  129. package/scripts/audit-tools/code-profiler.js +605 -605
  130. package/scripts/audit-tools/dep-doctor.js +320 -320
  131. package/scripts/audit-tools/env-validator.js +206 -206
  132. package/scripts/audit-tools/lib/fs-walk.js +48 -48
  133. package/scripts/audit-tools/lib/output.js +23 -23
  134. package/scripts/audit-tools/migration-checker.js +392 -392
  135. package/scripts/audit-tools/pentest-scanner.js +1436 -1436
  136. package/scripts/bootstrap-instintos.js +3 -0
  137. package/scripts/cli/aprobar-plan.js +73 -73
  138. package/scripts/cli/briefing.js +23 -23
  139. package/scripts/cli/ciclo-evolucion.js +26 -26
  140. package/scripts/cli/derivar-feature-list.js +25 -25
  141. package/scripts/cli/detectar-host.js +27 -27
  142. package/scripts/cli/diary-entry.js +69 -69
  143. package/scripts/cli/execution-state.js +18 -18
  144. package/scripts/cli/gateway-notify.js +41 -41
  145. package/scripts/cli/liberar-fase.js +42 -42
  146. package/scripts/cli/mark-evolved.js +56 -56
  147. package/scripts/cli/metricas-dora.js +26 -26
  148. package/scripts/cli/near-duplicate.js +55 -55
  149. package/scripts/cli/notificaciones.js +123 -123
  150. package/scripts/cli/propose-step.js +29 -29
  151. package/scripts/cli/schedule-parse.js +19 -19
  152. package/scripts/cli/sugerir-modelo.js +20 -20
  153. package/scripts/cli/verificar-plan.js +36 -36
  154. package/scripts/cli/verificar-trazabilidad.js +35 -35
  155. package/scripts/comandos/install-asistido.js +8 -7
  156. package/scripts/configurar-branch-protection.js +418 -418
  157. package/scripts/detectar-aprendizajes-duplicados.js +151 -151
  158. package/scripts/doctor.js +61 -36
  159. package/scripts/generar-checklists-consolidados.js +273 -273
  160. package/scripts/generar-claims-runtime.js +1342 -0
  161. package/scripts/generar-harness-ir.js +257 -0
  162. package/scripts/generar-inventario.js +52 -54
  163. package/scripts/generar-policy-bundle.js +202 -0
  164. package/scripts/instalador.js +26 -7
  165. package/scripts/lib/approval-receipts.js +190 -0
  166. package/scripts/lib/artefactos-python.js +43 -43
  167. package/scripts/lib/benchmark-metrics.js +160 -160
  168. package/scripts/lib/budget-enforcer.js +252 -252
  169. package/scripts/lib/certificacion-loop-state.js +421 -0
  170. package/scripts/lib/ci-reader.js +193 -193
  171. package/scripts/lib/ciclo-autonomo/yaml-instintos.js +56 -0
  172. package/scripts/lib/clasificar-directorio.js +92 -0
  173. package/scripts/lib/contadores-inventario.js +217 -217
  174. package/scripts/lib/detectar-host-swl.js +175 -175
  175. package/scripts/lib/detectar-runtime.js +29 -20
  176. package/scripts/lib/detectar-stack-detallado.js +307 -307
  177. package/scripts/lib/detector-autoduplicacion-intra-archivo.js +234 -234
  178. package/scripts/lib/detector-reglas-duplicadas.js +220 -220
  179. package/scripts/lib/eval-metrics-store.js +218 -218
  180. package/scripts/lib/eval-quality.js +171 -171
  181. package/scripts/lib/eval-schemas.js +144 -144
  182. package/scripts/lib/eval-self-correct.js +106 -106
  183. package/scripts/lib/eval-validator.js +185 -185
  184. package/scripts/lib/evidence-verifier.js +192 -0
  185. package/scripts/lib/evidencia-release.js +322 -322
  186. package/scripts/lib/frontmatter-canonico.js +509 -0
  187. package/scripts/lib/gate-engine.js +871 -0
  188. package/scripts/lib/gate-hooks-requires.js +249 -249
  189. package/scripts/lib/gate-licencias.js +212 -212
  190. package/scripts/lib/git-config-preflight.js +48 -0
  191. package/scripts/lib/git-metricas.js +257 -257
  192. package/scripts/lib/harness-ir.js +778 -0
  193. package/scripts/lib/harness-source-snapshot.js +309 -0
  194. package/scripts/lib/integrity-ledger.js +1147 -0
  195. package/scripts/lib/jaccard-similarity.js +98 -98
  196. package/scripts/lib/legacy-gate-migration.js +324 -0
  197. package/scripts/lib/limpiar-basura-global.js +45 -2
  198. package/scripts/lib/longmemeval-runner.js +125 -125
  199. package/scripts/lib/metricas-dora.js +204 -204
  200. package/scripts/lib/notificaciones-telegram.js +1 -0
  201. package/scripts/lib/npm-version.js +1 -0
  202. package/scripts/lib/paquetes-conocidos.js +50 -50
  203. package/scripts/lib/plan-lock.js +61 -13
  204. package/scripts/lib/policy-broker.js +338 -0
  205. package/scripts/lib/policy-bundle.js +342 -0
  206. package/scripts/lib/policy-context-provider.js +310 -0
  207. package/scripts/lib/policy-contract.js +479 -0
  208. package/scripts/lib/policy-verifier-utils.js +65 -0
  209. package/scripts/lib/pr-analyzer.js +399 -399
  210. package/scripts/lib/principal-verifier.js +178 -0
  211. package/scripts/lib/prompt-builder.js +264 -264
  212. package/scripts/lib/resolver-plan-fase.js +37 -37
  213. package/scripts/lib/rrf-fusion.js +175 -175
  214. package/scripts/lib/runtime-adapter-contract.js +267 -0
  215. package/scripts/lib/runtime-artifact-verifier.js +426 -0
  216. package/scripts/lib/runtime-build-attestation.js +127 -0
  217. package/scripts/lib/runtime-bundle-installer.js +586 -0
  218. package/scripts/lib/runtime-compiler.js +327 -0
  219. package/scripts/lib/runtime-conformance.js +202 -0
  220. package/scripts/lib/runtime-doctor-core3.js +567 -0
  221. package/scripts/lib/runtime-doctor-input.js +59 -0
  222. package/scripts/lib/runtime-operation-adapter.js +267 -0
  223. package/scripts/lib/schema-version.js +164 -164
  224. package/scripts/lib/semantic-search.js +252 -252
  225. package/scripts/lib/signed-envelope.js +545 -0
  226. package/scripts/lib/single-use-store.js +359 -0
  227. package/scripts/lib/skills-externas.js +31 -0
  228. package/scripts/lib/transformadores/codex.js +15 -8
  229. package/scripts/lib/transformadores/gemini.js +79 -5
  230. package/scripts/lib/w4-attestation-adapter.js +158 -0
  231. package/scripts/lib/w4-canario.js +337 -0
  232. package/scripts/lib/w4-claims.js +182 -0
  233. package/scripts/lib/w4-corpus-generador.js +542 -0
  234. package/scripts/lib/w4-gate-c5.js +115 -0
  235. package/scripts/lib/w4-harness-bajo-prueba.js +155 -0
  236. package/scripts/lib/w4-matriz-combos.js +55 -0
  237. package/scripts/lib/w4-motor-mutacion.js +1348 -0
  238. package/scripts/lib/w4-motor-replay.js +735 -0
  239. package/scripts/lib/w4-pin-origen.js +54 -0
  240. package/scripts/lib/w4-publicar-request.js +132 -0
  241. package/scripts/lib/w4-revocacion.js +62 -0
  242. package/scripts/lib/w4-runtimes-core3.js +38 -0
  243. package/scripts/lib/w4-scorer-certificacion.js +692 -0
  244. package/scripts/lib/w4-superficie-candidato.js +49 -0
  245. package/scripts/lib/w4-veredicto.js +452 -0
  246. package/scripts/lib/w4-verificar-veredicto.js +302 -0
  247. package/scripts/limpiar-artefactos-python.js +131 -131
  248. package/scripts/migrar-csv-a-array.js +168 -168
  249. package/scripts/migrar-fase-dominio.js +200 -200
  250. package/scripts/migrar-gates-legacy.js +108 -0
  251. package/scripts/publicar-certification-request.js +115 -0
  252. package/scripts/runtime-doctor.js +107 -0
  253. package/scripts/tui/componentes/selector-multi.js +189 -189
  254. package/scripts/tui/componentes/selector-unico.js +158 -158
  255. package/scripts/tui/ejecutores.js +375 -375
  256. package/scripts/tui/lib/colores.js +129 -129
  257. package/scripts/tui/lib/render.js +264 -264
  258. package/scripts/tui/lib/teclas.js +113 -113
  259. package/scripts/tui/pantallas/install-wizard.js +12 -7
  260. package/scripts/tui/pantallas/menu-principal.js +52 -52
  261. package/scripts/tui/pantallas/progreso.js +274 -274
  262. package/scripts/tui/pantallas/resumen.js +132 -132
  263. package/scripts/validar-userland-vacio.js +110 -110
  264. package/scripts/verificar-aislamiento-swl-eval.js +87 -0
  265. package/scripts/verificar-empaquetado-downstream.js +375 -0
  266. package/scripts/verificar-loop-constructor.js +215 -0
  267. package/scripts/verificar-trazabilidad.js +13 -6
  268. package/scripts/verificar-veredicto-real.js +84 -0
@@ -5,6 +5,7 @@ description: >
5
5
  gestion de conexiones MCP configuradas en swl-ses.
6
6
  version: 1.0.0
7
7
  tipo: comando
8
+ allowed_tools: ["Read", "Bash", "Glob"]
8
9
  ---
9
10
 
10
11
  # /swl:mcp-status — Estado y descubrimiento MCP
@@ -1,191 +1,191 @@
1
- 'use strict';
2
-
3
- /**
4
- * event-channel.js
5
- *
6
- * Pub/sub event channel para CommandRelay y otros componentes del gateway.
7
- *
8
- * Patrón adaptado de `temp/obsidian-agent-client-master/src/acp/acp-handler.ts`
9
- * (Set<listeners> con callback unsubscribe). Diferencias:
10
- * - Zero-deps Node.js (sin RxJS, sin EventEmitter de node — Set nativo).
11
- * - Backward compat: si no hay listeners, comportamiento idéntico al actual.
12
- * - Tipos de evento explícitos para evitar typos.
13
- *
14
- * Casos de uso en SWL:
15
- * - CommandRelay emite eventos al recibir/aceptar/rechazar/procesar comandos.
16
- * - Múltiples adaptadores (Telegram, Discord) pueden suscribirse simultáneamente.
17
- * - El consumidor /swl:inbox puede mostrar progreso sin polling.
18
- *
19
- * Uso:
20
- * const channel = new EventChannel();
21
- * const off = channel.on('cmd:queued', (event) => console.log(event));
22
- * channel.emit({ type: 'cmd:queued', commandId: 'cmd-abc', userId: '123' });
23
- * off(); // unsubscribe
24
- *
25
- * @module gateway/lib/event-channel
26
- */
27
-
28
- // ── tipos de evento ──────────────────────────────────────────────────────────
29
-
30
- /**
31
- * Tipos válidos de evento. Se usan strings para serializar fácilmente
32
- * a JSONL si se requiere persistencia (no obligatorio).
33
- */
34
- const EVENTS = Object.freeze({
35
- // Lifecycle de comandos en CommandRelay
36
- CMD_RECEIVED: 'cmd:received', // mensaje llegó al relay
37
- CMD_REJECTED: 'cmd:rejected', // rechazado por validación (auth/rate/dedup)
38
- CMD_QUEUED: 'cmd:queued', // encolado en .planning/inbox/
39
- CMD_PROCESSED: 'cmd:processed', // marcado como procesado por consumidor
40
-
41
- // Lifecycle de notificaciones
42
- NOTIFICATION_SENT: 'notification:sent',
43
- NOTIFICATION_FAILED: 'notification:failed',
44
- });
45
-
46
- // ── implementación ────────────────────────────────────────────────────────────
47
-
48
- /**
49
- * Canal de eventos pub/sub con escucha por tipo o wildcard.
50
- *
51
- * Mantiene dos estructuras:
52
- * - listenersByType: Map<eventType, Set<callback>>
53
- * - wildcardListeners: Set<callback> (escuchan TODOS los eventos)
54
- *
55
- * Una excepción en un listener NO interrumpe la propagación a los demás —
56
- * patrón de aislamiento del mismo origen (acp-handler.ts:47-50).
57
- */
58
- class EventChannel {
59
- constructor() {
60
- this.listenersByType = new Map();
61
- this.wildcardListeners = new Set();
62
- this.errorHandler = null; // opcional: callback para errores en listeners
63
- }
64
-
65
- /**
66
- * Suscribe un listener a un tipo de evento (o '*' para todos).
67
- *
68
- * @param {string} eventType - tipo de evento o '*'
69
- * @param {function} callback - recibe el objeto event
70
- * @returns {function} función de unsubscribe (idempotente)
71
- */
72
- on(eventType, callback) {
73
- if (typeof callback !== 'function') {
74
- throw new TypeError('callback debe ser función');
75
- }
76
- if (typeof eventType !== 'string' || !eventType) {
77
- throw new TypeError('eventType debe ser string no vacío');
78
- }
79
-
80
- if (eventType === '*') {
81
- this.wildcardListeners.add(callback);
82
- return () => this.wildcardListeners.delete(callback);
83
- }
84
-
85
- if (!this.listenersByType.has(eventType)) {
86
- this.listenersByType.set(eventType, new Set());
87
- }
88
- const set = this.listenersByType.get(eventType);
89
- set.add(callback);
90
- return () => set.delete(callback);
91
- }
92
-
93
- /**
94
- * Suscribe un listener que se invoca UNA sola vez y luego se desuscribe.
95
- */
96
- once(eventType, callback) {
97
- const off = this.on(eventType, (event) => {
98
- off();
99
- callback(event);
100
- });
101
- return off;
102
- }
103
-
104
- /**
105
- * Emite un evento a todos los listeners suscriptos al tipo + wildcards.
106
- * El evento debe tener al menos `type`. Se enriquece con `ts` (ISO).
107
- *
108
- * @param {object} event - objeto con `type` y datos arbitrarios
109
- * @returns {number} cantidad de listeners notificados
110
- */
111
- emit(event) {
112
- if (!event || typeof event !== 'object') {
113
- throw new TypeError('event debe ser objeto');
114
- }
115
- if (typeof event.type !== 'string' || !event.type) {
116
- throw new TypeError('event.type es obligatorio');
117
- }
118
-
119
- const enriched = { ts: new Date().toISOString(), ...event };
120
- let notified = 0;
121
-
122
- // Listeners específicos del tipo
123
- const typedSet = this.listenersByType.get(enriched.type);
124
- if (typedSet) {
125
- for (const cb of typedSet) {
126
- notified++;
127
- this._safeInvoke(cb, enriched);
128
- }
129
- }
130
-
131
- // Listeners wildcard
132
- for (const cb of this.wildcardListeners) {
133
- notified++;
134
- this._safeInvoke(cb, enriched);
135
- }
136
-
137
- return notified;
138
- }
139
-
140
- /**
141
- * Cuenta de listeners para un tipo (o total si no se pasa tipo).
142
- */
143
- listenerCount(eventType) {
144
- if (eventType == null) {
145
- let total = this.wildcardListeners.size;
146
- for (const set of this.listenersByType.values()) total += set.size;
147
- return total;
148
- }
149
- if (eventType === '*') return this.wildcardListeners.size;
150
- const set = this.listenersByType.get(eventType);
151
- return (set ? set.size : 0) + this.wildcardListeners.size;
152
- }
153
-
154
- /**
155
- * Limpia todos los listeners. Útil para tests.
156
- */
157
- clear() {
158
- this.listenersByType.clear();
159
- this.wildcardListeners.clear();
160
- }
161
-
162
- /**
163
- * Asigna un handler para errores en listeners.
164
- * Si no se asigna, los errores se silencian (no rompen la propagación).
165
- */
166
- onError(handler) {
167
- if (typeof handler !== 'function') {
168
- throw new TypeError('handler debe ser función');
169
- }
170
- this.errorHandler = handler;
171
- }
172
-
173
- // ── internos ────────────────────────────────────────────────────────────────
174
-
175
- _safeInvoke(cb, event) {
176
- try {
177
- cb(event);
178
- } catch (err) {
179
- if (this.errorHandler) {
180
- try { this.errorHandler(err, event); } catch (_) { /* silencioso */ }
181
- }
182
- }
183
- }
184
- }
185
-
186
- // ── exports ───────────────────────────────────────────────────────────────────
187
-
188
- module.exports = {
189
- EventChannel,
190
- EVENTS,
191
- };
1
+ 'use strict';
2
+
3
+ /**
4
+ * event-channel.js
5
+ *
6
+ * Pub/sub event channel para CommandRelay y otros componentes del gateway.
7
+ *
8
+ * Patrón adaptado de `temp/obsidian-agent-client-master/src/acp/acp-handler.ts`
9
+ * (Set<listeners> con callback unsubscribe). Diferencias:
10
+ * - Zero-deps Node.js (sin RxJS, sin EventEmitter de node — Set nativo).
11
+ * - Backward compat: si no hay listeners, comportamiento idéntico al actual.
12
+ * - Tipos de evento explícitos para evitar typos.
13
+ *
14
+ * Casos de uso en SWL:
15
+ * - CommandRelay emite eventos al recibir/aceptar/rechazar/procesar comandos.
16
+ * - Múltiples adaptadores (Telegram, Discord) pueden suscribirse simultáneamente.
17
+ * - El consumidor /swl:inbox puede mostrar progreso sin polling.
18
+ *
19
+ * Uso:
20
+ * const channel = new EventChannel();
21
+ * const off = channel.on('cmd:queued', (event) => console.log(event));
22
+ * channel.emit({ type: 'cmd:queued', commandId: 'cmd-abc', userId: '123' });
23
+ * off(); // unsubscribe
24
+ *
25
+ * @module gateway/lib/event-channel
26
+ */
27
+
28
+ // ── tipos de evento ──────────────────────────────────────────────────────────
29
+
30
+ /**
31
+ * Tipos válidos de evento. Se usan strings para serializar fácilmente
32
+ * a JSONL si se requiere persistencia (no obligatorio).
33
+ */
34
+ const EVENTS = Object.freeze({
35
+ // Lifecycle de comandos en CommandRelay
36
+ CMD_RECEIVED: 'cmd:received', // mensaje llegó al relay
37
+ CMD_REJECTED: 'cmd:rejected', // rechazado por validación (auth/rate/dedup)
38
+ CMD_QUEUED: 'cmd:queued', // encolado en .planning/inbox/
39
+ CMD_PROCESSED: 'cmd:processed', // marcado como procesado por consumidor
40
+
41
+ // Lifecycle de notificaciones
42
+ NOTIFICATION_SENT: 'notification:sent',
43
+ NOTIFICATION_FAILED: 'notification:failed',
44
+ });
45
+
46
+ // ── implementación ────────────────────────────────────────────────────────────
47
+
48
+ /**
49
+ * Canal de eventos pub/sub con escucha por tipo o wildcard.
50
+ *
51
+ * Mantiene dos estructuras:
52
+ * - listenersByType: Map<eventType, Set<callback>>
53
+ * - wildcardListeners: Set<callback> (escuchan TODOS los eventos)
54
+ *
55
+ * Una excepción en un listener NO interrumpe la propagación a los demás —
56
+ * patrón de aislamiento del mismo origen (acp-handler.ts:47-50).
57
+ */
58
+ class EventChannel {
59
+ constructor() {
60
+ this.listenersByType = new Map();
61
+ this.wildcardListeners = new Set();
62
+ this.errorHandler = null; // opcional: callback para errores en listeners
63
+ }
64
+
65
+ /**
66
+ * Suscribe un listener a un tipo de evento (o '*' para todos).
67
+ *
68
+ * @param {string} eventType - tipo de evento o '*'
69
+ * @param {function} callback - recibe el objeto event
70
+ * @returns {function} función de unsubscribe (idempotente)
71
+ */
72
+ on(eventType, callback) {
73
+ if (typeof callback !== 'function') {
74
+ throw new TypeError('callback debe ser función');
75
+ }
76
+ if (typeof eventType !== 'string' || !eventType) {
77
+ throw new TypeError('eventType debe ser string no vacío');
78
+ }
79
+
80
+ if (eventType === '*') {
81
+ this.wildcardListeners.add(callback);
82
+ return () => this.wildcardListeners.delete(callback);
83
+ }
84
+
85
+ if (!this.listenersByType.has(eventType)) {
86
+ this.listenersByType.set(eventType, new Set());
87
+ }
88
+ const set = this.listenersByType.get(eventType);
89
+ set.add(callback);
90
+ return () => set.delete(callback);
91
+ }
92
+
93
+ /**
94
+ * Suscribe un listener que se invoca UNA sola vez y luego se desuscribe.
95
+ */
96
+ once(eventType, callback) {
97
+ const off = this.on(eventType, (event) => {
98
+ off();
99
+ callback(event);
100
+ });
101
+ return off;
102
+ }
103
+
104
+ /**
105
+ * Emite un evento a todos los listeners suscriptos al tipo + wildcards.
106
+ * El evento debe tener al menos `type`. Se enriquece con `ts` (ISO).
107
+ *
108
+ * @param {object} event - objeto con `type` y datos arbitrarios
109
+ * @returns {number} cantidad de listeners notificados
110
+ */
111
+ emit(event) {
112
+ if (!event || typeof event !== 'object') {
113
+ throw new TypeError('event debe ser objeto');
114
+ }
115
+ if (typeof event.type !== 'string' || !event.type) {
116
+ throw new TypeError('event.type es obligatorio');
117
+ }
118
+
119
+ const enriched = { ts: new Date().toISOString(), ...event };
120
+ let notified = 0;
121
+
122
+ // Listeners específicos del tipo
123
+ const typedSet = this.listenersByType.get(enriched.type);
124
+ if (typedSet) {
125
+ for (const cb of typedSet) {
126
+ notified++;
127
+ this._safeInvoke(cb, enriched);
128
+ }
129
+ }
130
+
131
+ // Listeners wildcard
132
+ for (const cb of this.wildcardListeners) {
133
+ notified++;
134
+ this._safeInvoke(cb, enriched);
135
+ }
136
+
137
+ return notified;
138
+ }
139
+
140
+ /**
141
+ * Cuenta de listeners para un tipo (o total si no se pasa tipo).
142
+ */
143
+ listenerCount(eventType) {
144
+ if (eventType == null) {
145
+ let total = this.wildcardListeners.size;
146
+ for (const set of this.listenersByType.values()) total += set.size;
147
+ return total;
148
+ }
149
+ if (eventType === '*') return this.wildcardListeners.size;
150
+ const set = this.listenersByType.get(eventType);
151
+ return (set ? set.size : 0) + this.wildcardListeners.size;
152
+ }
153
+
154
+ /**
155
+ * Limpia todos los listeners. Útil para tests.
156
+ */
157
+ clear() {
158
+ this.listenersByType.clear();
159
+ this.wildcardListeners.clear();
160
+ }
161
+
162
+ /**
163
+ * Asigna un handler para errores en listeners.
164
+ * Si no se asigna, los errores se silencian (no rompen la propagación).
165
+ */
166
+ onError(handler) {
167
+ if (typeof handler !== 'function') {
168
+ throw new TypeError('handler debe ser función');
169
+ }
170
+ this.errorHandler = handler;
171
+ }
172
+
173
+ // ── internos ────────────────────────────────────────────────────────────────
174
+
175
+ _safeInvoke(cb, event) {
176
+ try {
177
+ cb(event);
178
+ } catch (err) {
179
+ if (this.errorHandler) {
180
+ try { this.errorHandler(err, event); } catch (_) { /* silencioso */ }
181
+ }
182
+ }
183
+ }
184
+ }
185
+
186
+ // ── exports ───────────────────────────────────────────────────────────────────
187
+
188
+ module.exports = {
189
+ EventChannel,
190
+ EVENTS,
191
+ };