@saulwade/swl-ses 1.5.0 → 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 (134) hide show
  1. package/CLAUDE.md +19 -2
  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 +225 -1
  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 +105 -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 +150 -4
  37. package/habilidades/testing-python/SKILL.md +340 -340
  38. package/habilidades/verificar-trabajo/SKILL.md +8 -3
  39. package/habilidades/web-fetcher-routing/SKILL.md +75 -75
  40. package/hooks/check-update.js +31 -3
  41. package/hooks/claudemd-bloat-detector.js +161 -161
  42. package/hooks/lib/agent-routing.js +107 -107
  43. package/hooks/lib/auto-consolidator.js +335 -335
  44. package/hooks/lib/error-classifier.js +308 -308
  45. package/hooks/lib/merkle-audit.js +96 -96
  46. package/hooks/lib/provenance-tracker.js +191 -191
  47. package/hooks/lib/rate-limit-tracker.js +253 -253
  48. package/hooks/lib/resource-quota.js +122 -122
  49. package/hooks/lib/retry-jitter.js +165 -165
  50. package/hooks/lib/security-net.js +201 -201
  51. package/hooks/lib/skill-auditor.js +588 -588
  52. package/hooks/lib/sync-status.js +228 -228
  53. package/hooks/lib/taint-tracker.js +107 -107
  54. package/hooks/lib/text-similarity.js +241 -241
  55. package/hooks/lib/toon-compressor.js +245 -245
  56. package/hooks/registro-turnos.js +209 -209
  57. package/hooks/sugerir-regenerar-inventario.js +170 -170
  58. package/hooks/validar-formato-post-subagente.js +140 -140
  59. package/hooks/validar-memoria-hook.js +218 -218
  60. package/instintos/prompt-appendices.yaml +57 -57
  61. package/manifiestos/agent-output-schemas.json +57 -57
  62. package/manifiestos/modulos.json +1324 -1321
  63. package/manifiestos/skills-lock.json +1114 -1114
  64. package/package.json +2 -2
  65. package/plantillas/auditor-veto-template.md +105 -105
  66. package/plantillas/github-workflows/README.md +47 -47
  67. package/plantillas/github-workflows/release-please.yml +44 -44
  68. package/plantillas/github-workflows/swl-ci.yml +107 -107
  69. package/plantillas/github-workflows/swl-security.yml +51 -51
  70. package/plugin.json +353 -351
  71. package/reglas/analisis-previo-tareas-grandes.md +172 -172
  72. package/reglas/arreglar-al-detectar.md +147 -147
  73. package/reglas/fragmentos-compartidos.md +152 -152
  74. package/reglas/harness-claude-code.md +213 -213
  75. package/reglas/registro-componentes-nuevos.md +192 -0
  76. package/reglas/usar-context7.md +226 -226
  77. package/schemas/diary-entry.schema.json +80 -80
  78. package/scripts/actualizar.js +110 -1
  79. package/scripts/audit-tools/audit-history.js +330 -330
  80. package/scripts/audit-tools/bundle-tracker.js +290 -290
  81. package/scripts/audit-tools/canary-monitor.js +352 -352
  82. package/scripts/audit-tools/code-profiler.js +605 -605
  83. package/scripts/audit-tools/dep-doctor.js +320 -320
  84. package/scripts/audit-tools/env-validator.js +206 -206
  85. package/scripts/audit-tools/lib/fs-walk.js +48 -48
  86. package/scripts/audit-tools/lib/output.js +23 -23
  87. package/scripts/audit-tools/migration-checker.js +392 -392
  88. package/scripts/audit-tools/pentest-scanner.js +1436 -1436
  89. package/scripts/benchmark-memoria.js +167 -167
  90. package/scripts/configurar-branch-protection.js +418 -418
  91. package/scripts/derivar-feature-list.js +489 -489
  92. package/scripts/detectar-aprendizajes-duplicados.js +151 -151
  93. package/scripts/doctor.js +58 -4
  94. package/scripts/field-report.js +199 -199
  95. package/scripts/generar-checklists-consolidados.js +273 -273
  96. package/scripts/generar-inventario.js +420 -420
  97. package/scripts/generar-matriz-lenguajes.js +271 -271
  98. package/scripts/lib/artefactos-python.js +43 -43
  99. package/scripts/lib/benchmark-metrics.js +160 -160
  100. package/scripts/lib/budget-enforcer.js +252 -252
  101. package/scripts/lib/configurar-ci.js +380 -380
  102. package/scripts/lib/contadores-inventario.js +217 -217
  103. package/scripts/lib/detectar-stack-detallado.js +307 -307
  104. package/scripts/lib/diary-entry.js +234 -234
  105. package/scripts/lib/eval-metrics-store.js +218 -218
  106. package/scripts/lib/eval-quality.js +171 -171
  107. package/scripts/lib/eval-schemas.js +144 -144
  108. package/scripts/lib/eval-self-correct.js +106 -106
  109. package/scripts/lib/eval-validator.js +185 -185
  110. package/scripts/lib/expandir-targets.js +71 -71
  111. package/scripts/lib/jaccard-similarity.js +98 -98
  112. package/scripts/lib/longmemeval-runner.js +125 -125
  113. package/scripts/lib/mcp_config.py +127 -0
  114. package/scripts/lib/npm-version.js +261 -261
  115. package/scripts/lib/paquetes-conocidos.js +50 -50
  116. package/scripts/lib/prompt-builder.js +264 -264
  117. package/scripts/lib/rrf-fusion.js +175 -175
  118. package/scripts/lib/scoring-instintos.js +277 -277
  119. package/scripts/lib/semantic-search.js +252 -252
  120. package/scripts/lib/toml-merge.js +204 -204
  121. package/scripts/lib/transformadores/codex.js +375 -375
  122. package/scripts/lib/transformadores/cursor.js +359 -359
  123. package/scripts/limpiar-artefactos-python.js +131 -131
  124. package/scripts/mcp-orchestrator.py +8 -18
  125. package/scripts/mcp-pool-manager.py +12 -23
  126. package/scripts/mcp-server/README.md +170 -170
  127. package/scripts/mcp-server/auth.js +105 -105
  128. package/scripts/mcp-server/cache.js +106 -106
  129. package/scripts/mcp-server/telemetry.js +78 -78
  130. package/scripts/migrar-csv-a-array.js +168 -168
  131. package/scripts/migrar-fase-dominio.js +201 -201
  132. package/scripts/publicar.js +511 -511
  133. package/scripts/run-eval.js +141 -141
  134. 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: