task_transfer
Initiates SFTP file transfers with automatic background processing for long-running tasks, handling uploads and downloads between local and remote systems.
Instructions
Lance un transfert SFTP. Si la tâche prend moins de 30s, le résultat est direct. Sinon, elle passe en arrière-plan.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| alias | Yes | Alias du serveur cible. | |
| direction | Yes | ||
| local | Yes | Chemin absolu local. | |
| remote | Yes | Chemin absolu distant. | |
| rappel | No | Définit un rappel en secondes. |
Implementation Reference
- sftp.js:80-169 (handler)Core implementation of the task_transfer tool logic: establishes SFTP connection, handles upload/download operations including directories, glob patterns, and multi-file transfers, manages errors and job status updates.async function executeTransfer(jobId) { const job = queue.getJob(jobId); if (!job) return queue.log('error', `Tâche introuvable: ${jobId}`); let sftp = null; try { const serverConfig = await serverManager.getServer(job.alias); queue.updateJobStatus(jobId, 'running'); sftp = new SftpClient(); // Configuration de la connexion const config = { host: serverConfig.host, port: 22, username: serverConfig.user, readyTimeout: 20000, retries: 3, retry_factor: 2, retry_minTimeout: 2000 }; if (serverConfig.keyPath) { config.privateKey = await fs.readFile(serverConfig.keyPath); } else if (serverConfig.password) { config.password = serverConfig.password; } else { throw new Error(`Aucune méthode d'authentification pour '${job.alias}'.`); } await sftp.connect(config); // Déterminer si on traite plusieurs fichiers const files = job.files || [{ local: job.local, remote: job.remote }]; const isMultiple = Array.isArray(job.files) && job.files.length > 1; let successCount = 0; let failedFiles = []; let totalFiles = 0; // Traiter chaque fichier for (let i = 0; i < files.length; i++) { const file = files[i]; const progress = isMultiple ? ` (${i + 1}/${files.length})` : ''; try { if (job.direction === 'upload') { const localFiles = await expandFileList(file.local); totalFiles += localFiles.length; for (const localFile of localFiles) { queue.log('info', `Transfert${progress}: ${localFile}`); await handleUpload(sftp, localFile, file.remote); successCount++; } } else if (job.direction === 'download') { const downloadedCount = await handleDownload(sftp, file.remote, file.local); totalFiles += downloadedCount; successCount += downloadedCount; } } catch (err) { queue.log('error', `Échec transfert ${file.local || file.remote}: ${err.message}`); failedFiles.push({ file: file.local || file.remote, error: err.message }); } } await sftp.end(); // Génération du rapport let status = successCount === totalFiles ? 'completed' : 'partial'; let output = `Transfert ${job.direction}: ${successCount}/${totalFiles} fichiers réussis`; if (failedFiles.length > 0) { output += `\nÉchecs: ${failedFiles.map(f => f.file).join(', ')}`; if (successCount === 0) status = 'failed'; } queue.updateJobStatus(jobId, status, { output, failedFiles }); } catch (err) { queue.updateJobStatus(jobId, 'failed', { error: err.message }); } finally { if (sftp) { try { await sftp.end(); } catch (e) { // Ignorer les erreurs de fermeture } } } }
- server.js:398-424 (registration)Registers the 'task_transfer' tool with Zod input schema, title, description, and a handler that queues the job, logs it, triggers sftp.executeTransfer, and handles synchronous/async response.server.registerTool( "task_transfer", { title: "Transférer un fichier ou dossier (SFTP)", description: `Lance un transfert SFTP. Si la tâche prend moins de ${config.syncTimeout / 1000}s, le résultat est direct. Sinon, elle passe en arrière-plan.`, inputSchema: z.object({ alias: z.string().describe("Alias du serveur cible."), direction: z.enum(['upload', 'download']), local: z.string().describe("Chemin absolu local."), remote: z.string().describe("Chemin absolu distant."), rappel: z.number().optional().describe("Définit un rappel en secondes.") }) }, async (params) => { const job = queue.addJob({ type: 'sftp', ...params, status: 'pending' }); history.logTask(job); sftp.executeTransfer(job.id); const finalJob = await waitForJobCompletion(job.id, config.syncTimeout); if (finalJob) { return { content: [{ type: "text", text: `Résultat direct (tâche ${finalJob.id}): ${JSON.stringify(finalJob, null, 2)}` }] }; } else { return { content: [{ type: "text", text: `Tâche de transfert ${job.id} initiée en arrière-plan.` }] }; } } );
- server.js:400-410 (schema)Zod input schema defining parameters for task_transfer: server alias, transfer direction, local and remote paths, optional reminder.{ title: "Transférer un fichier ou dossier (SFTP)", description: `Lance un transfert SFTP. Si la tâche prend moins de ${config.syncTimeout / 1000}s, le résultat est direct. Sinon, elle passe en arrière-plan.`, inputSchema: z.object({ alias: z.string().describe("Alias du serveur cible."), direction: z.enum(['upload', 'download']), local: z.string().describe("Chemin absolu local."), remote: z.string().describe("Chemin absolu distant."), rappel: z.number().optional().describe("Définit un rappel en secondes.") }) },
- sftp.js:172-191 (helper)Helper function for handling upload operations, including directory uploads and ensuring remote parent directories exist.async function handleUpload(sftp, localPath, remotePath) { try { const stats = await fs.stat(localPath); if (stats.isDirectory()) { // Upload d'un dossier entier await sftp.uploadDir(localPath, remotePath); } else { // Upload d'un fichier - créer le dossier parent si nécessaire await ensureRemoteDir(sftp, remotePath); await sftp.put(localPath, remotePath); } } catch (err) { // Si le fichier local n'existe pas if (err.code === 'ENOENT') { throw new Error(`Fichier local introuvable: ${localPath}`); } throw err; } }