@saulwade/swl-ses 1.5.1 → 1.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 (133) hide show
  1. package/CLAUDE.md +225 -209
  2. package/README.md +561 -561
  3. package/agentes/arquitecto-swl.md +33 -1
  4. package/agentes/nemesis-auditor-swl.md +59 -19
  5. package/bin/swl-mcp-server.js +214 -214
  6. package/comandos/swl/.evolved.json +22 -22
  7. package/comandos/swl/contribuir.md +233 -233
  8. package/comandos/swl/nemesis.md +230 -56
  9. package/gateway/lib/event-channel.js +191 -191
  10. package/habilidades/backend-production-resilience/SKILL.md +288 -288
  11. package/habilidades/benchmark-memoria/SKILL.md +186 -186
  12. package/habilidades/diagrama-arquitectura/assets/template.html +276 -276
  13. package/habilidades/doubt-driven-review/SKILL.md +171 -171
  14. package/habilidades/doubt-driven-review/recursos/EXAMPLES.md +130 -130
  15. package/habilidades/ejecutar-task-iterativo/SKILL.md +278 -278
  16. package/habilidades/eval-framework/SKILL.md +212 -212
  17. package/habilidades/feynman-auditor-swl/SKILL.md +123 -123
  18. package/habilidades/feynman-auditor-swl/recursos/preguntas-language-agnostic.md +108 -108
  19. package/habilidades/harness-claude-code/SKILL.md +299 -299
  20. package/habilidades/infra-github-actions/SKILL.md +166 -166
  21. package/habilidades/legacy-code-rescue/SKILL.md +267 -267
  22. package/habilidades/manejo-errores/.evolved.json +8 -8
  23. package/habilidades/meta-skills-estandar/SKILL.md +207 -4
  24. package/habilidades/meta-skills-estandar/recursos/convencion-examples.md +93 -93
  25. package/habilidades/meta-skills-estandar/recursos/skills-as-agents.md +163 -163
  26. package/habilidades/nemesis-evaluacion-json/SKILL.md +266 -0
  27. package/habilidades/nemesis-redistribuir/SKILL.md +341 -0
  28. package/habilidades/node-experto/SKILL.md +94 -4
  29. package/habilidades/patrones-python/SKILL.md +229 -229
  30. package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -469
  31. package/habilidades/planear-fase/SKILL.md +319 -319
  32. package/habilidades/protocolo-revision-swl/SKILL.md +350 -276
  33. package/habilidades/release-semver/.evolved.json +8 -8
  34. package/habilidades/state-inconsistency-auditor-swl/SKILL.md +166 -166
  35. package/habilidades/state-inconsistency-auditor-swl/recursos/coupled-state-patterns.md +147 -147
  36. package/habilidades/tdd-workflow/SKILL.md +121 -4
  37. package/habilidades/testing-python/SKILL.md +340 -340
  38. package/habilidades/web-fetcher-routing/SKILL.md +75 -75
  39. package/hooks/check-update.js +31 -3
  40. package/hooks/claudemd-bloat-detector.js +161 -161
  41. package/hooks/lib/agent-routing.js +107 -107
  42. package/hooks/lib/auto-consolidator.js +335 -335
  43. package/hooks/lib/error-classifier.js +308 -308
  44. package/hooks/lib/merkle-audit.js +96 -96
  45. package/hooks/lib/provenance-tracker.js +191 -191
  46. package/hooks/lib/rate-limit-tracker.js +253 -253
  47. package/hooks/lib/resource-quota.js +122 -122
  48. package/hooks/lib/retry-jitter.js +165 -165
  49. package/hooks/lib/security-net.js +201 -201
  50. package/hooks/lib/skill-auditor.js +588 -588
  51. package/hooks/lib/sync-status.js +228 -228
  52. package/hooks/lib/taint-tracker.js +107 -107
  53. package/hooks/lib/text-similarity.js +241 -241
  54. package/hooks/lib/toon-compressor.js +245 -245
  55. package/hooks/registro-turnos.js +209 -209
  56. package/hooks/sugerir-regenerar-inventario.js +170 -170
  57. package/hooks/validar-formato-post-subagente.js +140 -140
  58. package/hooks/validar-memoria-hook.js +218 -218
  59. package/instintos/prompt-appendices.yaml +57 -57
  60. package/manifiestos/agent-output-schemas.json +57 -57
  61. package/manifiestos/modulos.json +1324 -1321
  62. package/manifiestos/skills-lock.json +1114 -1114
  63. package/package.json +2 -2
  64. package/plantillas/auditor-veto-template.md +105 -105
  65. package/plantillas/github-workflows/README.md +47 -47
  66. package/plantillas/github-workflows/release-please.yml +44 -44
  67. package/plantillas/github-workflows/swl-ci.yml +107 -107
  68. package/plantillas/github-workflows/swl-security.yml +51 -51
  69. package/plugin.json +353 -351
  70. package/reglas/analisis-previo-tareas-grandes.md +172 -172
  71. package/reglas/arreglar-al-detectar.md +147 -147
  72. package/reglas/fragmentos-compartidos.md +152 -152
  73. package/reglas/harness-claude-code.md +213 -213
  74. package/reglas/registro-componentes-nuevos.md +192 -0
  75. package/reglas/usar-context7.md +226 -226
  76. package/schemas/diary-entry.schema.json +80 -80
  77. package/scripts/actualizar.js +110 -1
  78. package/scripts/audit-tools/audit-history.js +330 -330
  79. package/scripts/audit-tools/bundle-tracker.js +290 -290
  80. package/scripts/audit-tools/canary-monitor.js +352 -352
  81. package/scripts/audit-tools/code-profiler.js +605 -605
  82. package/scripts/audit-tools/dep-doctor.js +320 -320
  83. package/scripts/audit-tools/env-validator.js +206 -206
  84. package/scripts/audit-tools/lib/fs-walk.js +48 -48
  85. package/scripts/audit-tools/lib/output.js +23 -23
  86. package/scripts/audit-tools/migration-checker.js +392 -392
  87. package/scripts/audit-tools/pentest-scanner.js +1436 -1436
  88. package/scripts/benchmark-memoria.js +167 -167
  89. package/scripts/configurar-branch-protection.js +418 -418
  90. package/scripts/derivar-feature-list.js +489 -489
  91. package/scripts/detectar-aprendizajes-duplicados.js +151 -151
  92. package/scripts/doctor.js +27 -0
  93. package/scripts/field-report.js +199 -199
  94. package/scripts/generar-checklists-consolidados.js +273 -273
  95. package/scripts/generar-inventario.js +420 -420
  96. package/scripts/generar-matriz-lenguajes.js +271 -271
  97. package/scripts/lib/artefactos-python.js +43 -43
  98. package/scripts/lib/benchmark-metrics.js +160 -160
  99. package/scripts/lib/budget-enforcer.js +252 -252
  100. package/scripts/lib/configurar-ci.js +380 -380
  101. package/scripts/lib/contadores-inventario.js +217 -217
  102. package/scripts/lib/detectar-stack-detallado.js +307 -307
  103. package/scripts/lib/diary-entry.js +234 -234
  104. package/scripts/lib/eval-metrics-store.js +218 -218
  105. package/scripts/lib/eval-quality.js +171 -171
  106. package/scripts/lib/eval-schemas.js +144 -144
  107. package/scripts/lib/eval-self-correct.js +106 -106
  108. package/scripts/lib/eval-validator.js +185 -185
  109. package/scripts/lib/expandir-targets.js +71 -71
  110. package/scripts/lib/jaccard-similarity.js +98 -98
  111. package/scripts/lib/longmemeval-runner.js +125 -125
  112. package/scripts/lib/mcp_config.py +127 -0
  113. package/scripts/lib/npm-version.js +261 -261
  114. package/scripts/lib/paquetes-conocidos.js +50 -50
  115. package/scripts/lib/prompt-builder.js +264 -264
  116. package/scripts/lib/rrf-fusion.js +175 -175
  117. package/scripts/lib/scoring-instintos.js +277 -277
  118. package/scripts/lib/semantic-search.js +252 -252
  119. package/scripts/lib/toml-merge.js +204 -204
  120. package/scripts/lib/transformadores/codex.js +375 -375
  121. package/scripts/lib/transformadores/cursor.js +359 -359
  122. package/scripts/limpiar-artefactos-python.js +131 -131
  123. package/scripts/mcp-orchestrator.py +8 -18
  124. package/scripts/mcp-pool-manager.py +12 -23
  125. package/scripts/mcp-server/README.md +170 -170
  126. package/scripts/mcp-server/auth.js +105 -105
  127. package/scripts/mcp-server/cache.js +106 -106
  128. package/scripts/mcp-server/telemetry.js +78 -78
  129. package/scripts/migrar-csv-a-array.js +168 -168
  130. package/scripts/migrar-fase-dominio.js +201 -201
  131. package/scripts/publicar.js +511 -511
  132. package/scripts/run-eval.js +141 -141
  133. package/scripts/validar-userland-vacio.js +110 -110
@@ -1,131 +1,131 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- /**
5
- * limpiar-artefactos-python.js — limpia caché Python antes de empaquetar.
6
- *
7
- * Se ejecuta como `prepack` antes de `npm pack` y `npm publish` para evitar
8
- * que artefactos locales (.pyc, __pycache__/) contaminen el tarball publicado.
9
- *
10
- * Reglas de seguridad (defensa en profundidad):
11
- * 1. Aborta si cwd no coincide con la raíz del package.json del repo.
12
- * 2. Profundidad máxima de recursión: 3 niveles desde la raíz.
13
- * 3. Allowlist explícita de directorios a EXCLUIR de la búsqueda
14
- * (node_modules, .git, temp, .planning, respositorios-git, _userland).
15
- * 4. Solo elimina directorios cuyo nombre coincide exactamente con el
16
- * conjunto cerrado: __pycache__, .pytest_cache, .mypy_cache, .ruff_cache.
17
- * 5. Solo elimina archivos sueltos con extensiones .pyc, .pyo.
18
- * 6. En CI no-interactivo respeta el flag SWL_PREPACK_DRY=1 (no borra,
19
- * solo lista).
20
- *
21
- * Exit codes:
22
- * 0 — OK (limpieza ejecutada o nada que limpiar)
23
- * 1 — error de invariante (cwd incorrecto, package.json no encontrado)
24
- */
25
-
26
- const fs = require('fs');
27
- const path = require('path');
28
-
29
- const { NOMBRES_VALIDOS } = require('./lib/paquetes-conocidos');
30
- const {
31
- DIRS_ARTEFACTOS_PYTHON: DIRS_A_LIMPIAR,
32
- EXTS_ARTEFACTOS_PYTHON: EXTS_A_LIMPIAR,
33
- } = require('./lib/artefactos-python');
34
-
35
- const PROFUNDIDAD_MAX = 3;
36
- const DIRS_EXCLUIDOS = new Set([
37
- 'node_modules', '.git', 'temp', '.planning', 'respositorios-git',
38
- '_userland', 'tests', '.github',
39
- ]);
40
-
41
- const dryRun = process.env.SWL_PREPACK_DRY === '1';
42
-
43
- function log(msg) { process.stdout.write(`[prepack] ${msg}\n`); }
44
- function err(msg) { process.stderr.write(`[prepack] ERROR: ${msg}\n`); }
45
-
46
- /**
47
- * Verifica que el cwd actual contiene el package.json del repo swl-ses.
48
- * Esto evita que el script borre directorios en la máquina del usuario si
49
- * algún día se invocara desde un cwd incorrecto (ej. dentro de un tarball
50
- * extraído por npm en .npm/_cacache).
51
- */
52
- function verificarRaiz() {
53
- const cwd = process.cwd();
54
- const pkgPath = path.join(cwd, 'package.json');
55
- if (!fs.existsSync(pkgPath)) {
56
- err(`no existe package.json en cwd: ${cwd}`);
57
- process.exit(1);
58
- }
59
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
60
- if (!NOMBRES_VALIDOS.includes(pkg.name)) {
61
- err(`package.json en ${cwd} no corresponde a swl-ses (name: ${pkg.name}). Abortando por seguridad.`);
62
- process.exit(1);
63
- }
64
- return cwd;
65
- }
66
-
67
- /**
68
- * Recorre el árbol desde root con profundidad limitada y elimina los
69
- * artefactos Python detectados. No sigue symlinks.
70
- */
71
- function limpiar(root, profundidad = 0) {
72
- if (profundidad > PROFUNDIDAD_MAX) return { dirs: 0, files: 0 };
73
-
74
- let dirsEliminados = 0;
75
- let filesEliminados = 0;
76
-
77
- let entries;
78
- try {
79
- entries = fs.readdirSync(root, { withFileTypes: true });
80
- } catch (e) {
81
- err(`no se pudo leer ${root}: ${e.message}`);
82
- return { dirs: 0, files: 0 };
83
- }
84
-
85
- for (const entry of entries) {
86
- if (entry.isSymbolicLink()) continue;
87
- const fullPath = path.join(root, entry.name);
88
-
89
- if (entry.isDirectory()) {
90
- if (DIRS_A_LIMPIAR.has(entry.name)) {
91
- if (dryRun) {
92
- log(`[dry-run] borraría dir: ${path.relative(process.cwd(), fullPath)}`);
93
- } else {
94
- fs.rmSync(fullPath, { recursive: true, force: true });
95
- log(`borrado dir: ${path.relative(process.cwd(), fullPath)}`);
96
- }
97
- dirsEliminados++;
98
- } else if (!DIRS_EXCLUIDOS.has(entry.name) && !entry.name.startsWith('.')) {
99
- const sub = limpiar(fullPath, profundidad + 1);
100
- dirsEliminados += sub.dirs;
101
- filesEliminados += sub.files;
102
- }
103
- } else if (entry.isFile()) {
104
- const ext = path.extname(entry.name).toLowerCase();
105
- if (EXTS_A_LIMPIAR.has(ext)) {
106
- if (dryRun) {
107
- log(`[dry-run] borraría archivo: ${path.relative(process.cwd(), fullPath)}`);
108
- } else {
109
- fs.rmSync(fullPath, { force: true });
110
- }
111
- filesEliminados++;
112
- }
113
- }
114
- }
115
-
116
- return { dirs: dirsEliminados, files: filesEliminados };
117
- }
118
-
119
- function main() {
120
- const root = verificarRaiz();
121
- const result = limpiar(root);
122
-
123
- if (result.dirs === 0 && result.files === 0) {
124
- log('sin artefactos Python que limpiar.');
125
- } else {
126
- const accion = dryRun ? 'detectados' : 'eliminados';
127
- log(`${accion}: ${result.dirs} directorios + ${result.files} archivos.`);
128
- }
129
- }
130
-
131
- main();
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * limpiar-artefactos-python.js — limpia caché Python antes de empaquetar.
6
+ *
7
+ * Se ejecuta como `prepack` antes de `npm pack` y `npm publish` para evitar
8
+ * que artefactos locales (.pyc, __pycache__/) contaminen el tarball publicado.
9
+ *
10
+ * Reglas de seguridad (defensa en profundidad):
11
+ * 1. Aborta si cwd no coincide con la raíz del package.json del repo.
12
+ * 2. Profundidad máxima de recursión: 3 niveles desde la raíz.
13
+ * 3. Allowlist explícita de directorios a EXCLUIR de la búsqueda
14
+ * (node_modules, .git, temp, .planning, respositorios-git, _userland).
15
+ * 4. Solo elimina directorios cuyo nombre coincide exactamente con el
16
+ * conjunto cerrado: __pycache__, .pytest_cache, .mypy_cache, .ruff_cache.
17
+ * 5. Solo elimina archivos sueltos con extensiones .pyc, .pyo.
18
+ * 6. En CI no-interactivo respeta el flag SWL_PREPACK_DRY=1 (no borra,
19
+ * solo lista).
20
+ *
21
+ * Exit codes:
22
+ * 0 — OK (limpieza ejecutada o nada que limpiar)
23
+ * 1 — error de invariante (cwd incorrecto, package.json no encontrado)
24
+ */
25
+
26
+ const fs = require('fs');
27
+ const path = require('path');
28
+
29
+ const { NOMBRES_VALIDOS } = require('./lib/paquetes-conocidos');
30
+ const {
31
+ DIRS_ARTEFACTOS_PYTHON: DIRS_A_LIMPIAR,
32
+ EXTS_ARTEFACTOS_PYTHON: EXTS_A_LIMPIAR,
33
+ } = require('./lib/artefactos-python');
34
+
35
+ const PROFUNDIDAD_MAX = 3;
36
+ const DIRS_EXCLUIDOS = new Set([
37
+ 'node_modules', '.git', 'temp', '.planning', 'respositorios-git',
38
+ '_userland', 'tests', '.github',
39
+ ]);
40
+
41
+ const dryRun = process.env.SWL_PREPACK_DRY === '1';
42
+
43
+ function log(msg) { process.stdout.write(`[prepack] ${msg}\n`); }
44
+ function err(msg) { process.stderr.write(`[prepack] ERROR: ${msg}\n`); }
45
+
46
+ /**
47
+ * Verifica que el cwd actual contiene el package.json del repo swl-ses.
48
+ * Esto evita que el script borre directorios en la máquina del usuario si
49
+ * algún día se invocara desde un cwd incorrecto (ej. dentro de un tarball
50
+ * extraído por npm en .npm/_cacache).
51
+ */
52
+ function verificarRaiz() {
53
+ const cwd = process.cwd();
54
+ const pkgPath = path.join(cwd, 'package.json');
55
+ if (!fs.existsSync(pkgPath)) {
56
+ err(`no existe package.json en cwd: ${cwd}`);
57
+ process.exit(1);
58
+ }
59
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
60
+ if (!NOMBRES_VALIDOS.includes(pkg.name)) {
61
+ err(`package.json en ${cwd} no corresponde a swl-ses (name: ${pkg.name}). Abortando por seguridad.`);
62
+ process.exit(1);
63
+ }
64
+ return cwd;
65
+ }
66
+
67
+ /**
68
+ * Recorre el árbol desde root con profundidad limitada y elimina los
69
+ * artefactos Python detectados. No sigue symlinks.
70
+ */
71
+ function limpiar(root, profundidad = 0) {
72
+ if (profundidad > PROFUNDIDAD_MAX) return { dirs: 0, files: 0 };
73
+
74
+ let dirsEliminados = 0;
75
+ let filesEliminados = 0;
76
+
77
+ let entries;
78
+ try {
79
+ entries = fs.readdirSync(root, { withFileTypes: true });
80
+ } catch (e) {
81
+ err(`no se pudo leer ${root}: ${e.message}`);
82
+ return { dirs: 0, files: 0 };
83
+ }
84
+
85
+ for (const entry of entries) {
86
+ if (entry.isSymbolicLink()) continue;
87
+ const fullPath = path.join(root, entry.name);
88
+
89
+ if (entry.isDirectory()) {
90
+ if (DIRS_A_LIMPIAR.has(entry.name)) {
91
+ if (dryRun) {
92
+ log(`[dry-run] borraría dir: ${path.relative(process.cwd(), fullPath)}`);
93
+ } else {
94
+ fs.rmSync(fullPath, { recursive: true, force: true });
95
+ log(`borrado dir: ${path.relative(process.cwd(), fullPath)}`);
96
+ }
97
+ dirsEliminados++;
98
+ } else if (!DIRS_EXCLUIDOS.has(entry.name) && !entry.name.startsWith('.')) {
99
+ const sub = limpiar(fullPath, profundidad + 1);
100
+ dirsEliminados += sub.dirs;
101
+ filesEliminados += sub.files;
102
+ }
103
+ } else if (entry.isFile()) {
104
+ const ext = path.extname(entry.name).toLowerCase();
105
+ if (EXTS_A_LIMPIAR.has(ext)) {
106
+ if (dryRun) {
107
+ log(`[dry-run] borraría archivo: ${path.relative(process.cwd(), fullPath)}`);
108
+ } else {
109
+ fs.rmSync(fullPath, { force: true });
110
+ }
111
+ filesEliminados++;
112
+ }
113
+ }
114
+ }
115
+
116
+ return { dirs: dirsEliminados, files: filesEliminados };
117
+ }
118
+
119
+ function main() {
120
+ const root = verificarRaiz();
121
+ const result = limpiar(root);
122
+
123
+ if (result.dirs === 0 && result.files === 0) {
124
+ log('sin artefactos Python que limpiar.');
125
+ } else {
126
+ const accion = dryRun ? 'detectados' : 'eliminados';
127
+ log(`${accion}: ${result.dirs} directorios + ${result.files} archivos.`);
128
+ }
129
+ }
130
+
131
+ main();
@@ -30,6 +30,10 @@ from datetime import datetime, timezone
30
30
  from pathlib import Path
31
31
  from typing import Any
32
32
 
33
+ # Importar helper compartido sin convertir scripts/ en paquete.
34
+ sys.path.insert(0, str(Path(__file__).resolve().parent / 'lib'))
35
+ from mcp_config import cargar_config_mcp # noqa: E402
36
+
33
37
  # ---------------------------------------------------------------------------
34
38
  # Dependencias — raw mcp SDK
35
39
  # ---------------------------------------------------------------------------
@@ -45,32 +49,18 @@ except ImportError:
45
49
  # Constantes
46
50
  # ---------------------------------------------------------------------------
47
51
 
48
- SETTINGS_CANDIDATES = [
49
- '.claude/settings.local.json',
50
- '.claude/settings.json',
51
- 'mcp-servers.json',
52
- ]
53
-
54
52
  TIMEOUT_S = 12
55
53
  SNAPSHOT_FILE = Path('.planning') / 'mcp-snapshot.json'
56
54
 
57
55
  # ---------------------------------------------------------------------------
58
- # Carga de config (identica a mcp-pool-manager para evitar dependencia circular)
56
+ # Carga de config delega a scripts/lib/mcp_config.py para deep merge
57
+ # unificado con mcp-pool-manager.py. Antes hacia first-wins y rompia el
58
+ # health check cuando settings.local.json contenia overrides parciales.
59
59
  # ---------------------------------------------------------------------------
60
60
 
61
61
 
62
62
  def _cargar_config(cwd: Path, config_path: str | None = None) -> dict:
63
- candidates = [Path(config_path)] if config_path else [cwd / p for p in SETTINGS_CANDIDATES]
64
- for p in candidates:
65
- if p.exists():
66
- try:
67
- data = json.loads(p.read_text(encoding='utf-8'))
68
- servers = data.get('mcpServers', {})
69
- if servers:
70
- return servers
71
- except Exception:
72
- continue
73
- return {}
63
+ return cargar_config_mcp(cwd, config_path)
74
64
 
75
65
 
76
66
  def _build_env(cfg: dict) -> dict | None:
@@ -4,10 +4,11 @@
4
4
  Conecta a servidores MCP configurados en .claude/settings.json y expone
5
5
  sus herramientas para uso por agentes y scripts de swl-ses.
6
6
 
7
- Lee la configuracion de mcpServers en orden de precedencia:
8
- 1. .claude/settings.local.json
9
- 2. .claude/settings.json
10
- 3. mcp-servers.json (config independiente opcional)
7
+ Lee la configuracion fusionando las capas con deep merge (semantica de
8
+ Claude Code): mcp-servers.json -> .claude/settings.json -> .claude/settings.local.json.
9
+ La capa mas profunda sobrescribe por clave; env se mergea por sub-clave.
10
+ Esto permite que settings.local.json contenga overrides parciales (p.ej.
11
+ solo OBSIDIAN_API_KEY) sin perder command/args de la capa compartida.
11
12
 
12
13
  Uso:
13
14
  python scripts/mcp-pool-manager.py list-servers
@@ -30,6 +31,10 @@ import time
30
31
  from pathlib import Path
31
32
  from typing import Any
32
33
 
34
+ # Importar helper compartido sin convertir scripts/ en paquete.
35
+ sys.path.insert(0, str(Path(__file__).resolve().parent / 'lib'))
36
+ from mcp_config import cargar_config_mcp # noqa: E402
37
+
33
38
  # ---------------------------------------------------------------------------
34
39
  # Dependencias — raw mcp SDK (disponible en entornos con Claude Code)
35
40
  # ---------------------------------------------------------------------------
@@ -45,33 +50,17 @@ except ImportError:
45
50
  # Constantes
46
51
  # ---------------------------------------------------------------------------
47
52
 
48
- SETTINGS_CANDIDATES = [
49
- '.claude/settings.local.json',
50
- '.claude/settings.json',
51
- 'mcp-servers.json',
52
- ]
53
-
54
53
  TIMEOUT_CONNECT_S = 10 # segundos maximo para conectar a un servidor
55
54
  TIMEOUT_CALL_S = 30 # segundos maximo para llamar una herramienta
56
55
 
57
56
  # ---------------------------------------------------------------------------
58
- # Carga de configuracion
57
+ # Carga de configuracion — delega a scripts/lib/mcp_config.py
59
58
  # ---------------------------------------------------------------------------
60
59
 
61
60
 
62
61
  def _cargar_config(cwd: Path, config_path: str | None = None) -> dict:
63
- """Carga la seccion mcpServers del primer archivo de config encontrado."""
64
- candidates = [Path(config_path)] if config_path else [cwd / p for p in SETTINGS_CANDIDATES]
65
- for p in candidates:
66
- if p.exists():
67
- try:
68
- data = json.loads(p.read_text(encoding='utf-8'))
69
- servers = data.get('mcpServers', {})
70
- if servers:
71
- return servers
72
- except Exception:
73
- continue
74
- return {}
62
+ """Devuelve los servidores MCP fusionados de todas las capas."""
63
+ return cargar_config_mcp(cwd, config_path)
75
64
 
76
65
 
77
66
  def _get_server(servers: dict, nombre: str) -> dict: