Nettoyage du dépôt : doublons, code mort, secrets, build

Fichiers hors périmètre ou dupliqués :
- suppression des 5 .md dupliqués à la racine (copies md5-identiques de
  docs/api/ et docs/entities/)
- suppression de JANITOR_main.js / JANITOR_entities.json (application
  Electron sans lien avec le serveur MCP)
- suppression de temp/*.json (dumps de workflows versionnés par accident)
  et ajout de temp/ au .gitignore
- suppression de claude_desktop_config_ssh.json : mots de passe en clair et
  variables ORACLE_* d'une architecture abandonnée
- AD_API_TEST_RESULTS.md -> docs/ad-api-validation.md (credentials du
  snippet remplacés par des variables d'environnement)
- suppression d'IMPLEMENTATION_SUMMARY.md, doublon du précédent
- queries api.php -> docs/reference-queries-api.php (renommage seul)

Code mort :
- suppression de src/resources/documentation.js : la resource docs:// n'a
  jamais été branchée dans src/index.js
- suppression de src/config/constants.js : module entièrement inutilisé,
  requis par wms-query-service.js mais dont aucune constante n'était lue.
  Emporte RESOURCE_URIS.WORKFLOWS_CATEGORIES, URI déclarée jamais servie.
- log-service.js : suppression de findRecentErrors, readFullLog et
  getLogStats, exportées mais exposées par aucun outil MCP
- suppression de LOG_FILE_PATTERN (lue depuis .env, jamais appliquée : le
  scan filtre sur .log en dur), y compris dans .env.example
- log-service.js : préfixe [Logs] sur les messages, comme les autres modules

Secrets :
- test-ad-api.ps1 -> scripts/test-ad-api.ps1, credentials passés en
  paramètres ou par WMS_USERNAME / WMS_PASSWORD au lieu d'être en dur

Build et test :
- @yao-pkg/pkg en devDependency, cible node22-win-x64 : npm run build
  échouait faute de pkg, et node20 n'a pas de binaire prébuilt (bascule sur
  une compilation de Node qui échoue sans toolchain MSVC)
- index.js : le .env est lu à côté de l'exécutable quand le serveur est
  packagé. Avec un chemin statique, pkg embarquait le .env dans le snapshot,
  figeant les credentials dans le binaire.
- scripts/test-connection.js : npm test pointait sur un fichier absent.
  Smoke test en lecture seule (OAuth, QueryExecute, QueryScalarExecute,
  API AD), par profil ou sur tous.

Vérifié après nettoyage : 23 outils et 6 resources répondent au handshake
MCP, npm test passe 4/4 contre le WMS.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Arthur Ria
2026-08-24 15:15:08 +02:00
parent b59cbb3546
commit 9b95e15cbc
28 changed files with 2172 additions and 11497 deletions
-193
View File
@@ -1,193 +0,0 @@
const fs = require('fs').promises;
const path = require('path');
/**
* Resources MCP pour la documentation
* Permet à Claude d'accéder à la documentation structurée en fichiers Markdown
*/
// Chemin vers le dossier de documentation
const DOCS_PATH = process.env.DOCS_PATH || path.join(__dirname, '..', '..', 'docs');
/**
* Scanne récursivement un dossier pour trouver tous les fichiers .md
* @param {string} dir - Dossier à scanner
* @param {string} baseDir - Dossier de base pour les chemins relatifs
* @returns {Promise<Array>} - Liste des fichiers .md
*/
async function scanMarkdownFiles(dir, baseDir = dir) {
let files = [];
try {
const entries = await fs.readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
// Récursion dans les sous-dossiers
const subFiles = await scanMarkdownFiles(fullPath, baseDir);
files = files.concat(subFiles);
} else if (entry.isFile() && entry.name.endsWith('.md')) {
// Fichier Markdown trouvé
const relativePath = path.relative(baseDir, fullPath);
files.push({
name: entry.name,
path: fullPath,
relativePath: relativePath.replace(/\\/g, '/'), // Normaliser les slashes
uri: `docs://${relativePath.replace(/\\/g, '/')}`,
});
}
}
} catch (err) {
// Dossier n'existe pas ou erreur de lecture
console.error(`Error scanning directory ${dir}:`, err.message);
}
return files;
}
/**
* Liste les resources disponibles pour la documentation
* @returns {Promise<Array>} - Liste des resources
*/
async function listResources() {
try {
// Scanner les fichiers Markdown
const mdFiles = await scanMarkdownFiles(DOCS_PATH);
const resources = [
{
uri: 'docs://index',
name: 'Documentation Index',
description: 'Sommaire de toute la documentation disponible',
mimeType: 'text/markdown',
},
];
// Ajouter chaque fichier .md comme resource
mdFiles.forEach((file) => {
resources.push({
uri: file.uri,
name: file.name.replace('.md', ''),
description: `Documentation: ${file.relativePath}`,
mimeType: 'text/markdown',
});
});
return resources;
} catch (err) {
console.error('Error listing documentation resources:', err);
return [
{
uri: 'docs://index',
name: 'Documentation Index',
description: 'Sommaire de toute la documentation disponible',
mimeType: 'text/markdown',
},
];
}
}
/**
* Génère un index/sommaire de la documentation
* @returns {Promise<string>} - Markdown avec le sommaire
*/
async function generateIndex() {
try {
const mdFiles = await scanMarkdownFiles(DOCS_PATH);
if (mdFiles.length === 0) {
return `# Documentation\n\n*Aucun fichier de documentation trouvé dans \`${DOCS_PATH}\`*\n\n` +
`Pour ajouter de la documentation :\n` +
`1. Créez un dossier \`docs\` à la racine du projet\n` +
`2. Ajoutez vos fichiers .md (organisation libre avec sous-dossiers)\n` +
`3. Redémarrez le serveur MCP\n`;
}
let markdown = '# Documentation WMS\n\n';
markdown += `**${mdFiles.length} fichiers de documentation disponibles**\n\n`;
markdown += `📁 Emplacement : \`${DOCS_PATH}\`\n\n`;
// Grouper par dossier
const grouped = {};
mdFiles.forEach((file) => {
const dir = path.dirname(file.relativePath);
const folder = dir === '.' ? '📄 Racine' : `📁 ${dir}`;
if (!grouped[folder]) {
grouped[folder] = [];
}
grouped[folder].push(file);
});
// Générer le sommaire
markdown += '## Sommaire\n\n';
Object.keys(grouped).sort().forEach((folder) => {
markdown += `### ${folder}\n\n`;
grouped[folder].forEach((file) => {
markdown += `- **${file.name.replace('.md', '')}** - \`${file.uri}\`\n`;
});
markdown += '\n';
});
markdown += '---\n\n';
markdown += '*Pour lire un fichier, demandez à Claude de lire la resource correspondante (par exemple: "Lis la documentation X")*\n';
return markdown;
} catch (err) {
return `# Erreur\n\nImpossible de générer l'index de documentation: ${err.message}`;
}
}
/**
* Lit un fichier de documentation
* @param {string} relativePath - Chemin relatif du fichier
* @returns {Promise<string>} - Contenu Markdown du fichier
*/
async function readDocFile(relativePath) {
try {
const filePath = path.join(DOCS_PATH, relativePath);
const content = await fs.readFile(filePath, 'utf8');
return content;
} catch (err) {
return `# Erreur\n\nImpossible de lire le fichier \`${relativePath}\`: ${err.message}`;
}
}
/**
* Lit une resource documentation selon son URI
* @param {string} uri - URI de la resource (format: docs://path/to/file.md)
* @returns {Promise<Object>} - Contenu de la resource
*/
async function readResource(uri) {
let content;
if (uri === 'docs://index') {
content = await generateIndex();
} else if (uri.startsWith('docs://')) {
// Extraire le chemin relatif de l'URI
const relativePath = uri.replace('docs://', '');
content = await readDocFile(relativePath);
} else {
throw new Error(`Unknown documentation resource: ${uri}`);
}
return {
contents: [
{
uri,
mimeType: 'text/markdown',
text: content,
},
],
};
}
module.exports = {
listResources,
readResource,
};