ftp-deploy-mcp 0.0.0-stage → 0.3.1

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 (89) hide show
  1. package/CHANGELOG.fr.md +468 -0
  2. package/CHANGELOG.md +415 -0
  3. package/CONTRIBUTING.fr.md +120 -0
  4. package/CONTRIBUTING.md +111 -0
  5. package/LICENSE +21 -0
  6. package/LICENSE.fr.md +26 -0
  7. package/README.fr.md +518 -0
  8. package/README.md +501 -2
  9. package/SECURITY.fr.md +99 -0
  10. package/SECURITY.md +94 -0
  11. package/docs/AGENT-PERFORMANCE.fr.md +144 -0
  12. package/docs/AGENT-PERFORMANCE.md +133 -0
  13. package/docs/ERROR-CONTRACT.fr.md +141 -0
  14. package/docs/ERROR-CONTRACT.md +137 -0
  15. package/docs/LANGUAGES.fr.md +68 -0
  16. package/docs/LANGUAGES.md +62 -0
  17. package/docs/RELEASE.fr.md +462 -0
  18. package/docs/RELEASE.md +435 -0
  19. package/docs/RESOURCE-BOUNDS.fr.md +144 -0
  20. package/docs/RESOURCE-BOUNDS.md +132 -0
  21. package/docs/SCRIPTED-EVALUATIONS.fr.md +190 -0
  22. package/docs/SCRIPTED-EVALUATIONS.md +181 -0
  23. package/docs/SECURITY-MODEL.fr.md +262 -0
  24. package/docs/SECURITY-MODEL.md +236 -0
  25. package/docs/STATE-STORAGE.fr.md +236 -0
  26. package/docs/STATE-STORAGE.md +231 -0
  27. package/docs/TRANSFERS.fr.md +140 -0
  28. package/docs/TRANSFERS.md +123 -0
  29. package/docs/WORKFLOW-MODEL.fr.md +63 -0
  30. package/docs/WORKFLOW-MODEL.md +62 -0
  31. package/evaluations/README.fr.md +95 -0
  32. package/evaluations/README.md +92 -0
  33. package/evaluations/fixture/README.txt +3 -0
  34. package/evaluations/fixture/catalog/alpha.txt +4 -0
  35. package/evaluations/fixture/catalog/bravo.txt +4 -0
  36. package/evaluations/fixture/catalog/charlie.txt +4 -0
  37. package/evaluations/fixture/catalog/delta.txt +4 -0
  38. package/evaluations/fixture/catalog/echo.txt +4 -0
  39. package/evaluations/fixture/catalog/foxtrot.txt +4 -0
  40. package/evaluations/fixture/reports/checks.txt +4 -0
  41. package/evaluations/fixture/reports/release.txt +3 -0
  42. package/evaluations/read-only.fr.xml +42 -0
  43. package/evaluations/read-only.xml +42 -0
  44. package/ftp-servers.example.json +27 -0
  45. package/install.cmd +29 -0
  46. package/install.sh +18 -0
  47. package/package.json +88 -4
  48. package/server.json +35 -0
  49. package/src/adapters/ftp.js +392 -0
  50. package/src/adapters/sftp.js +647 -0
  51. package/src/admission.js +15 -0
  52. package/src/atomic-write.js +131 -0
  53. package/src/clients.js +212 -0
  54. package/src/config.js +629 -0
  55. package/src/durable/confirmation.js +88 -0
  56. package/src/durable/engine.js +696 -0
  57. package/src/durable/plan.js +238 -0
  58. package/src/durable/schemas.js +206 -0
  59. package/src/durable/state.js +317 -0
  60. package/src/durable/status.js +175 -0
  61. package/src/durable-tools.js +94 -0
  62. package/src/errors.js +88 -0
  63. package/src/filezilla.js +260 -0
  64. package/src/i18n.js +58 -0
  65. package/src/index.js +175 -0
  66. package/src/local-path.js +130 -0
  67. package/src/locales/en.js +152 -0
  68. package/src/locales/errors.en.js +22 -0
  69. package/src/locales/errors.fr.js +22 -0
  70. package/src/locales/fr.js +152 -0
  71. package/src/locales/runtime.en.js +259 -0
  72. package/src/locales/runtime.fr.js +259 -0
  73. package/src/operations.js +276 -0
  74. package/src/redact.js +105 -0
  75. package/src/remote-path.js +101 -0
  76. package/src/scanner.js +103 -0
  77. package/src/setup.js +888 -0
  78. package/src/state/codec.mjs +103 -0
  79. package/src/state/index.mjs +1 -0
  80. package/src/state/io.mjs +173 -0
  81. package/src/state/records.mjs +60 -0
  82. package/src/state/store.mjs +360 -0
  83. package/src/state/writer.mjs +250 -0
  84. package/src/tool-registry.js +464 -0
  85. package/src/tools.js +1226 -0
  86. package/src/transfers.js +425 -0
  87. package/src/workflow/budget.mjs +83 -0
  88. package/src/workflow/events.mjs +199 -0
  89. package/src/workflow/model.mjs +179 -0
@@ -0,0 +1,468 @@
1
+ # Journal des modifications
2
+
3
+ [English](./CHANGELOG.md) | **Français**
4
+
5
+ Toutes les modifications notables de ce projet sont consignées dans ce fichier.
6
+
7
+ Le format s'inspire de [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/),
8
+ et le projet suit le [versionnement sémantique](https://semver.org/lang/fr/spec/v2.0.0.html).
9
+
10
+ ## [0.3.1] - 2026-10-17
11
+
12
+ Cette version corrective se limite à la qualification de release et à
13
+ l'actualisation du verrouillage de la chaîne d'approvisionnement. Elle préserve
14
+ le tag v0.3.0 immuable et sa release de sources GitHub. La publication sur npm
15
+ et le registre MCP officiel reste en attente.
16
+
17
+ ### Corrigé
18
+
19
+ - La qualification de release verrouille désormais la dépendance transitive
20
+ optionnelle `nan` en 2.29.0, avec son URL de registre et son intégrité revues,
21
+ conformément à la version résolue par une installation neuve. Aucun
22
+ comportement d'exécution ni aucune API publique ne change.
23
+
24
+ ### Modifié
25
+
26
+ - Les métadonnées du paquet, du verrouillage, du serveur MCP et de la release
27
+ bilingue ciblent maintenant v0.3.1 de façon cohérente. L'historique complet
28
+ de v0.3.0 est conservé ci-dessous.
29
+
30
+ ## [0.3.0] - 2026-10-17
31
+
32
+ Cette version mineure utilise le canal distinct des releases de sources
33
+ GitHub ; le tag et la release v0.2.0 publiés restent inchangés.
34
+ La publication sur npm et le registre MCP officiel reste en attente. Installez
35
+ depuis les sources ; aucune disponibilité npm, `npx` ou registre n'est annoncée.
36
+
37
+ ### Ajouts
38
+
39
+ - Déploiement durable facultatif avec `stateDir` : `ftp_plan_deploy`,
40
+ `ftp_apply_deploy`, `ftp_deploy_status` et `ftp_rollback_deploy`. Le workflow
41
+ utilise la confirmation MCP officielle `input_required`, des journaux scellés,
42
+ des sauvegardes vérifiées et bornées, une reprise explicite et une
43
+ réconciliation prudente. Sa garantie est `observable_state_reconciled`, pas
44
+ l'atomicité multi-fichiers ni l'exécution exactement une fois.
45
+ - Le format d'état v2 protège la vie privée : hash de racine locale salé par
46
+ domaine et chemins sources relatifs stricts, jamais la racine absolue. Apply
47
+ revalide l'identité locale avant connexion ; rollback reste utilisable après
48
+ dérive de racine. L'état v1 exige une réinitialisation hors ligne.
49
+
50
+ ### Corrections
51
+
52
+ - La préparation interne est à usage unique, plafonnée à 10 secondes sans
53
+ prolonger l'échéance globale et conserve l'admission jusqu'à la fin réelle
54
+ du travail et du nettoyage. Les contextes préparés sont libérés une fois,
55
+ même après une fin tardive suivant une annulation. Une préparation annulée ou
56
+ expirée n'appelle jamais le handler ; son callback peut lui-même agir.
57
+ Aucun outil MCP public n'est ajouté.
58
+ - La qualification de publication compare le manifeste attendu complet, le
59
+ verrouillage source de référence et les octets de toutes les sources livrées. Les
60
+ modificateurs de dépendances et hooks d'installation non autorisés sont
61
+ refusés avant l'installation du consommateur.
62
+ - L'inspection lit et calcule l'empreinte des octets compressés une fois,
63
+ décompresse gzip strictement avec une borne globale de sortie de 32 MiB,
64
+ rejette les octets non nuls après la limite gzip consommée et fournit le
65
+ même TAR décodé à chaque invocation de tar. Le remplissage NUL terminal est
66
+ admis ; les frontières des membres gzip/TAR ne peuvent pas masquer de
67
+ fichiers supplémentaires à la validation.
68
+ - Les workflows npm et MCP séparent une qualification sans OIDC ni secret de
69
+ la publication dans une copie fraîche épinglée à `github.sha`. npm transfère
70
+ l'identifiant exact de l'artefact déposé et les valeurs d'inventaire/intégrité
71
+ d'origine ; le job de publication vérifie ces liens avant de créer sa preuve
72
+ locale. Installation de dépendances, tests, smoke checks et `--runtime`
73
+ s'exécutent uniquement hors des jobs privilégiés de publication.
74
+ - L'analyse des métadonnées accepte les formes JSON tableau/objet de npm pack
75
+ prises en charge de façon cohérente en CI. Les dates du journal doivent
76
+ correspondre à des dates calendaires valides.
77
+
78
+ ### Changements
79
+
80
+ - Le runtime MCP utilise désormais le SDK TypeScript modulaire stable v2.3.1 :
81
+ `@modelcontextprotocol/server` est la dépendance de production épinglée, tandis
82
+ que le client et le paquet core de protocole brut, eux aussi épinglés, restent
83
+ réservés au développement. L'entrée stdio utilise la factory `serveStdio`,
84
+ négocie la révision `2026-07-28` et conserve le chemin des anciens clients,
85
+ y compris la révision `2024-11-05`.
86
+ - Les cinq dépendances directes de production sont épinglées exactement ; le seul
87
+ `package-lock.json` conserve 35 entrées non racine revues (22 de production
88
+ et 13 de développement). Aucun shrinkwrap n'est livré.
89
+ - Le builder produit une archive d'installation source de 90 fichiers avec le
90
+ verrouillage, distincte du paquet npm de 89 fichiers sans verrouillage. Les
91
+ preuves lient explicitement la distribution, les sources et l'intégrité.
92
+ - L'installation source utilise `npm ci --omit=dev --ignore-scripts` ; celle des
93
+ contributeurs utilise `npm ci --ignore-scripts`. Les octets des archives peuvent
94
+ varier entre systèmes. Le graphe réellement installé est comparé à la référence
95
+ originale, dépendances transitives et peers compris, avant publication.
96
+ - npm reste non qualifié après dix dérives observées lors d'une vraie installation.
97
+ Le job MCP qualifie l'archive réellement téléchargée du registre, puis le job
98
+ privilégié exige son intégrité originale avant authentification.
99
+
100
+ - La documentation anglais/français d'installation et de publication distingue
101
+ les releases de sources GitHub de la disponibilité sur npm et le registre
102
+ MCP officiel.
103
+
104
+ Les tests scriptés ne sont pas un benchmark de LLM et cette version mineure ne revendique
105
+ aucune certification pour un usage en entreprise.
106
+
107
+ ## [0.2.0] - 2026-09-09
108
+
109
+ Le tag et la release GitHub sont créés depuis ce commit. La publication sur npm
110
+ et sur le registre MCP reste en attente : `npx -y ftp-deploy-mcp` et
111
+ l’installation depuis un registre ne fonctionnent donc pas encore ; installez
112
+ depuis les sources. Les métadonnées du paquet et du serveur sont alignées sur
113
+ 0.2.0. Toutes les modifications ci-dessous sont relatives à 0.1.0, la seule
114
+ version jamais publiée.
115
+
116
+ ### Ajouts
117
+
118
+ - Ligne de commande bilingue. `--lang en` et `--lang fr` (ainsi que
119
+ `--lang=fr`) choisissent la langue des aides générale et par sous-commande,
120
+ des questions et choix de `setup`, des libellés des tests de connexion, des
121
+ diagnostics `doctor`, des avertissements d’`import-filezilla` et des messages
122
+ de démarrage du serveur. La nouvelle variable d’environnement `FTP_MCP_LANG`
123
+ fixe le même défaut, et l’option prime sur elle, y compris sur une valeur
124
+ d’environnement invalide. L’option est lue avant l’analyse de la
125
+ sous-commande et peut figurer avant ou après celle-ci. Seules les valeurs `en`
126
+ et `fr` sont acceptées ; une option invalide ou incomplète provoque une sortie
127
+ en échec avant que `setup` ou `import-filezilla` n’écrive quoi que ce soit.
128
+ Les variables régionales du système, comme `LANG`, ne sont jamais consultées.
129
+ Voir les [langues](./docs/LANGUAGES.fr.md).
130
+ - Contrats MCP localisés. Les titres des outils, leurs descriptions, les
131
+ descriptions des champs d’entrée, les textes de succès métier et les messages
132
+ d’erreur suivent la langue choisie. Les dix noms d’outils, les noms des champs
133
+ des résultats structurés et les codes d’erreur publics sont stables et ne sont
134
+ pas traduits, et aucun argument d’outil ne choisit de langue.
135
+ - `setup` inscrit `FTP_MCP_LANG` dans les entrées de clients MCP qu’il génère,
136
+ y compris `en`, afin qu’un serveur configuré conserve après redémarrage la
137
+ langue choisie lors de son `setup`. Le bloc Trae prêt à coller porte le même
138
+ réglage.
139
+ - Enveloppe d’erreur structurée sur chaque erreur d’outil. À côté du texte
140
+ `isError`, les résultats portent désormais `structuredContent.error` avec
141
+ `schema_version`, `code`, `message`, `retryable`, un UUID `request_id` propre
142
+ à l’appel, `next_action` et `effects`. Les erreurs d’envoi, de téléchargement
143
+ et de déploiement peuvent ajouter un bloc `partial` strict
144
+ (`completed_files`, `completed_bytes`, `failed_files`, `total_files`
145
+ facultatif et `final`). `request_id` n’est pas un identifiant d’opération
146
+ durable ; il n’existe ni journal, ni retour arrière, ni commande de
147
+ récupération. Cette version renvoie `retryable: false` pour toute erreur et ne
148
+ réessaie jamais une mutation incertaine. Voir le
149
+ [contrat d’erreur](./docs/ERROR-CONTRACT.fr.md).
150
+ - Six clés de configuration par serveur, chacune avec un défaut et un maximum
151
+ imposés. Les arguments des outils ne peuvent pas les remplacer, et les valeurs
152
+ doivent être des entiers positifs représentables exactement :
153
+ `operationTimeoutMs` (défaut 120000 ms, plage acceptée 100–3600000),
154
+ `maxTransferBytes` (défaut 268435456, maximum 1099511627776),
155
+ `maxDeployFiles` (défaut 10000, maximum 100000),
156
+ `maxDeployBytes` (défaut 1073741824, maximum 1099511627776),
157
+ `maxScanEntries` (défaut 100000, maximum 1000000) et
158
+ `maxScanDepth` (défaut 64, maximum 256). Ces valeurs par défaut s’appliquent
159
+ aux serveurs qui ne les définissent pas : un déploiement qui réussissait en
160
+ 0.1.0 peut désormais être refusé par `TRANSFER_LIMIT` ou `SCAN_LIMIT` avant
161
+ même l’ouverture d’une connexion.
162
+ **RUPTURE — `operationTimeoutMs` introduit aussi une échéance que 0.1.0
163
+ n’avait pas :** tout appel d’outil s’interrompt désormais avec `TIMEOUT` après
164
+ 120000 ms par défaut et, contrairement aux autres limites, elle se déclenche
165
+ en cours d’exécution au lieu de refuser d’emblée ; un `ftp_deploy` volumineux
166
+ ou lent qui allait au bout en 0.1.0 peut donc s’arrêter en cours de route,
167
+ avec des fichiers déjà promus et aucun retour arrière. Augmentez
168
+ `operationTimeoutMs` (jusqu’à 3600000) pour les liaisons lentes. Voir les
169
+ [transferts vérifiés](./docs/TRANSFERS.fr.md) et les
170
+ [limites de ressources](./docs/RESOURCE-BOUNDS.fr.md).
171
+ - Contrôle d’admission à l’échelle du processus. Un isolate Node admet au plus
172
+ 64 appels d’outil simultanés ; le 65e renvoie le nouveau `CAPACITY_LIMIT`
173
+ avec `effects:none`, `retryable:false` et `next_action:retry`. C’est un
174
+ plafond de simultanéité, pas un quota de durée de vie : une place est libérée
175
+ quand son worker et son nettoyage se terminent réellement, y compris après une
176
+ annulation ou un dépassement de délai, et il n’existe ni file d’attente ni
177
+ reprise automatique. L’admission suit la validation du schéma et précède la
178
+ préparation.
179
+ - Annulation MCP et échéances par appel. Une notification
180
+ `notifications/cancelled` d’un pair interrompt l’opération et le SDK supprime
181
+ sa réponse : les clients ne doivent donc pas attendre la livraison d’une
182
+ enveloppe `CANCELLED` ; l’échéance interne, distincte, renvoie `TIMEOUT`.
183
+ L’annulation et l’expiration arrêtent les étapes suivantes et ferment le
184
+ transport, mais n’annulent pas les effets déjà acceptés par le serveur. Un
185
+ décorateur du transport public corrige la lacune d’annulation du SDK installé
186
+ pour l’identifiant de corrélation numérique `0` et la chaîne vide `""` ; les
187
+ autres identifiants, dont la chaîne `"0"`, conservent le comportement natif du
188
+ SDK.
189
+ - Mutations sérialisées. Les outils d’écriture prennent un verrou FIFO sur le
190
+ point d’accès distant (protocole, hôte, port, utilisateur) et `ftp_download`
191
+ en prend un sur la destination locale canonique : deux appels ne peuvent donc
192
+ pas entrelacer leurs écritures sur la même cible. Les verrous sont conservés
193
+ jusqu’à la fin effective du worker sous-jacent, et non jusqu’à l’envoi de la
194
+ réponse, et ils ne coordonnent qu’au sein d’un même processus Node.js.
195
+ - Périmètre `localRoot` par serveur pour `ftp_upload`, `ftp_deploy` et
196
+ `ftp_download`. La racine doit être absolue (`~` est étendu) ; les traversées
197
+ et les sorties locales par symlink ou jonction sont refusées.
198
+ - Épinglage de clé d’hôte SFTP via `hostKeySha256`, qui accepte une empreinte
199
+ SHA-256 ou un tableau non vide pour les rotations de clé contrôlées.
200
+ - Dérogation explicite `allowUnknownHostKey` pour les opérateurs qui acceptent
201
+ temporairement une identité de serveur SFTP non vérifiée.
202
+ - Dérogation explicite `allowUnsafeRemoteRoot` pour les opérateurs FTP/FTPS qui
203
+ acceptent le risque de symlink non résolu d’une sous-racine côté client.
204
+ - Schémas de sortie MCP et réponses structurées en cas de succès pour tous les
205
+ outils sauf `ftp_read`, volontairement textuel, ainsi que des annotations pour
206
+ les dix outils.
207
+ - Ensemble documentaire bilingue, chaque page en anglais et en français :
208
+ [modèle de sécurité](./docs/SECURITY-MODEL.fr.md),
209
+ [processus de publication](./docs/RELEASE.fr.md),
210
+ [contrat d’erreur](./docs/ERROR-CONTRACT.fr.md),
211
+ [langues](./docs/LANGUAGES.fr.md),
212
+ [transferts vérifiés](./docs/TRANSFERS.fr.md),
213
+ [limites de ressources](./docs/RESOURCE-BOUNDS.fr.md),
214
+ [stockage d’état](./docs/STATE-STORAGE.fr.md),
215
+ [modèle de workflow](./docs/WORKFLOW-MODEL.fr.md) et
216
+ [conformité MCP scriptée](./docs/SCRIPTED-EVALUATIONS.fr.md). `CONTRIBUTING`,
217
+ `SECURITY`, `LICENSE` et ce journal reçoivent une contrepartie française, aux
218
+ côtés de la paire `README` déjà livrée en 0.1.0 ; les deux langues du `README`
219
+ ont été réécrites pour cette version.
220
+ - Guide HTML interactif bilingue sous `site/`, généré depuis
221
+ `site/project-data.json` et `site/i18n.json` et vérifié en CI par
222
+ `scripts/build-guide.mjs --check`. Il n’existe que dans le dépôt et il est
223
+ exclu du paquet npm.
224
+ - Jeu de données externe reproductible pour l’évaluation d’agents en lecture
225
+ seule et jeu d’évaluation MCP de 10 questions, désormais en anglais
226
+ (`evaluations/read-only.xml`) et en français (`evaluations/read-only.fr.xml`),
227
+ ainsi qu’un exécuteur distinct de conformité scriptée couvrant 43 scénarios,
228
+ exécutés dans les deux langues contre le vrai client du SDK MCP et un
229
+ transport en mémoire (`npm run eval:scripted`). Cet exécuteur est un outillage
230
+ du dépôt, n’est pas un benchmark de LLM et est exclu du paquet npm. Voir la
231
+ [conformité MCP scriptée](./docs/SCRIPTED-EVALUATIONS.fr.md).
232
+ - Bibliothèques internes inertes `src/state/` et `src/workflow/`. Elles sont
233
+ livrées dans le paquet parce qu’il publie `src`, mais elles n’exposent aucun
234
+ outil MCP, ne lisent aucune configuration, ne créent aucun répertoire d’état
235
+ et ne sont pas importées par le serveur en fonctionnement. Elles ne livrent
236
+ dans cette version ni workflow de déploiement, ni retour arrière, ni
237
+ récupération ; le [stockage d’état](./docs/STATE-STORAGE.fr.md) comme le
238
+ [modèle de workflow](./docs/WORKFLOW-MODEL.fr.md) l’indiquent explicitement.
239
+ - Scripts npm destinés aux contributeurs : `test:transports`, `test:contract`,
240
+ `test:bounds`, `test:state`, `test:workflow`, `test:eval-runner` et
241
+ `eval:scripted`. La CI exécute en plus `scripts/check-docs.mjs` pour la
242
+ documentation bilingue et `test/release-gates.js`.
243
+ - Métadonnées de registre MCP `server.json`, qui déclarent les variables
244
+ d’environnement `FTP_MCP_CONFIG` et `FTP_MCP_LANG` ainsi qu’un transport
245
+ stdio.
246
+ - `Dockerfile` et `.dockerignore` dans le dépôt, construisant une image
247
+ `node:24-alpine` dont le point d’entrée est le serveur stdio ; montez un
248
+ fichier de configuration et faites-y pointer `FTP_MCP_CONFIG`. Aucune image
249
+ n’est publiée, et aucun de ces deux fichiers n’est inclus dans le paquet npm.
250
+
251
+ ### Changements
252
+
253
+ - **RUPTURE — Node.js 18, 19, 20 et 21 ne sont plus pris en charge.**
254
+ `engines.node` passe de `>=18` à `>=22`. La CI qualifie Node 22 et 24 sur
255
+ Linux, Windows et macOS.
256
+ - **RUPTURE — un sélecteur de configuration explicite échoue désormais de façon
257
+ fermée.** Lorsque `--config <chemin>` ou `FTP_MCP_CONFIG` est présent, ce
258
+ chemin unique fait autorité : il doit exister, être un fichier ordinaire et se
259
+ charger correctement, et aucun autre candidat n’est essayé. `--config` prime
260
+ sur `FTP_MCP_CONFIG`, et une valeur explicite vide est rejetée. Ce n’est qu’en
261
+ l’absence des deux que la découverte essaie encore `./ftp-servers.json` puis
262
+ `~/.ftp-mcp/servers.json`. En 0.1.0, ces deux sélecteurs n’étaient que les
263
+ premières entrées d’une liste de repli : un chemin explicite absent ou
264
+ illisible retombait silencieusement sur un autre fichier. Le serveur démarre
265
+ toujours ; chaque outil qui a besoin du fichier de configuration échoue
266
+ désormais avec `CONFIG_INVALID` au lieu de travailler sur une configuration
267
+ non voulue, et `ftp_list_servers` renvoie `status: "invalid"` accompagné du
268
+ diagnostic du chargeur.
269
+ - Une entrée de serveur rejetée ne désactive plus tout le fichier de
270
+ configuration. Les entrées sont validées individuellement : les serveurs
271
+ valides restent utilisables, et chaque entrée invalide est signalée par son
272
+ nom et son motif via `ftp_list_servers` (`status`, `valid_count`,
273
+ `invalid_count` et une liste `errors` bornée). Nommer une entrée rejetée
274
+ renvoie le `CONFIG_INVALID` de cette entrée, un nom inconnu renvoie
275
+ `SERVER_UNKNOWN`, et omettre `server` avec plusieurs candidats valides et sans
276
+ `defaultServer` renvoie `SERVER_REQUIRED`. En 0.1.0, la première entrée
277
+ invalide rendait tout le fichier inutilisable et chaque appel d’outil
278
+ échouait. Les problèmes d’enveloppe — objet `servers` absent ou vide,
279
+ `defaultServer` inconnu, `${ENV:VAR}` non défini — rejettent toujours tout le
280
+ fichier, tout comme un fichier dont chaque entrée est invalide.
281
+ - **RUPTURE — `localRoot` est désormais obligatoire** pour `ftp_upload`,
282
+ `ftp_deploy` et `ftp_download`, **et les chemins d’outil relatifs se résolvent
283
+ désormais par rapport à lui, et non par rapport au répertoire de travail du
284
+ processus serveur.** Une entrée de serveur sans `localRoot` absolu refuse ces
285
+ trois outils avec `CONFIG_INVALID`. En 0.1.0, `local_path` et `local_dir` se
286
+ résolvaient par rapport à `process.cwd()` : un appel inchangé comme
287
+ `ftp_deploy {"local_dir":"dist"}` lit désormais `<localRoot>/dist` au lieu de
288
+ `<cwd>/dist` — il peut silencieusement sélectionner un autre dossier, ou
289
+ échouer avec `NOT_FOUND` ou `PATH_REJECTED` lorsque l’ancienne cible se trouve
290
+ hors de la racine. Les chemins absolus conservent leur sens et doivent
291
+ toujours se résoudre à l’intérieur de `localRoot`. `ftp_list_servers` indique
292
+ l’état du `localRoot` de chaque serveur.
293
+ - Les erreurs d’outil ne sont plus seulement textuelles. Chaque résultat
294
+ d’erreur porte désormais l’enveloppe `{error}` structurée décrite plus haut,
295
+ et les neuf outils dotés d’un schéma de sortie publient un `oneOf` JSON Schema
296
+ draft-07 entre leur objet de succès et cette enveloppe. `ftp_read` conserve un
297
+ succès textuel sans schéma de sortie ; ses erreurs utilisent la même enveloppe
298
+ validée en interne. Les réponses textuelles existantes restent disponibles à
299
+ côté des réponses structurées en cas de succès, et `ftp_deploy` fournit
300
+ toujours des échantillons bornés plutôt que des listes exhaustives de
301
+ fichiers.
302
+ - `ftp_upload`, `ftp_deploy` et `ftp_download` vérifient désormais chaque
303
+ fichier avant de le promouvoir. Les envois calculent le SHA256 de la source
304
+ locale, écrivent dans un fichier voisin imprévisible nommé
305
+ `.ftp-mcp-<aléatoire>.tmp`, relisent ce temporaire, comparent le nombre
306
+ d’octets et l’empreinte, puis promeuvent par un unique renommage. En cas
307
+ d’échec, le serveur ne supprime jamais la destination finale pour faire
308
+ réussir la promotion et ne revient jamais à un écrasement direct ; il ne
309
+ supprime que son propre temporaire, et un échec du nettoyage ajoute un
310
+ avertissement borné indiquant qu’un temporaire peut subsister. Les
311
+ téléchargements lisent d’abord une attente SHA256 distante bornée, puis
312
+ promeuvent par lien physique dans le même dossier avec `overwrite:false`
313
+ (valeur par défaut) ou par renommage avec `overwrite:true`. Le motif de nom
314
+ `.ftp-mcp-*.tmp` est réservé et toujours exclu de `ftp_deploy`, même lorsqu’un
315
+ motif `include` explicite le sélectionne. Cela ajoute du trafic réseau et de
316
+ la latence, ne rend pas atomique un déploiement de plusieurs fichiers et ne
317
+ promet pas un remplacement atomique universel : le comportement du renommage
318
+ FTP et SFTP dépend du serveur et de son système de fichiers. En SFTP, le
319
+ serveur enregistre le mode attribué au temporaire, le restreint à 0600 pendant
320
+ l’écriture puis, avant la promotion, restaure les bits de permission de la
321
+ destination existante (masque 0777) ou ce mode de création enregistré pour un
322
+ fichier neuf ; un échec d’un `stat` ou d’un `chmod` requis empêche la
323
+ promotion. FTP/FTPS ne dispose ici d’aucun mécanisme portable de préservation
324
+ des permissions : remplacer un fichier distant existant peut donc
325
+ réinitialiser ses permissions aux valeurs de création du serveur. Localement,
326
+ `ftp_download` copie les bits 0777 d’une destination existante sur son
327
+ temporaire, mais un **nouveau** fichier local est désormais créé avec le mode
328
+ 0600 au lieu du défaut issu de l’umask du processus en 0.1.0, et la promotion
329
+ avec `overwrite:false` par défaut exige la prise en charge des liens physiques
330
+ dans le dossier de destination et échoue de façon fermée sans elle. Voir les
331
+ [transferts vérifiés](./docs/TRANSFERS.fr.md).
332
+ - La sélection d’un déploiement est désormais bornée et asynchrone.
333
+ `maxScanEntries` et `maxScanDepth` plafonnent les entrées visitées et la
334
+ profondeur des dossiers ; dépasser l’une ou l’autre refuse toute la sélection
335
+ avec `SCAN_LIMIT` (`effects:none`, `retryable:false`, `next_action:fix_input`)
336
+ avant toute connexion distante, en simulation comme en déploiement réel. Voir
337
+ les [limites de ressources](./docs/RESOURCE-BOUNDS.fr.md).
338
+ - **La sélection d’un déploiement peut désormais inclure des fichiers qu’elle
339
+ omettait auparavant.** Seuls les noms de dossiers intégrés `node_modules`,
340
+ `.git` et `.ftp-mcp` élaguent le parcours. Les motifs `exclude` personnalisés
341
+ et les motifs `include` n’élaguent plus les dossiers ; ils conservent leurs
342
+ règles de correspondance existantes, fichier par fichier. Cela supprime un
343
+ ancien faux positif de test par sentinelle de dossier où, par exemple,
344
+ `exclude: ["**/__ftp_deploy_probe__"]` masquait aussi `docs/wanted.txt`.
345
+ Examinez une simulation après la mise à niveau si vous dépendez de motifs
346
+ d’exclusion.
347
+ - **RUPTURE — le FTP en clair, et le FTPS avec `insecureTLS: true`, sont
348
+ désormais refusés.** 0.1.0 n’avait aucun garde-fou de transport non sécurisé
349
+ et se connectait aux deux sans objection. 0.2.0 lève `TRANSPORT_POLICY` avant
350
+ toute entrée-sortie réseau, sauf si l’entrée de serveur définit
351
+ `allowInsecure: true` : chaque entrée `"protocol": "ftp"` de 0.1.0 — le
352
+ protocole par défaut, celui qui donne son nom à ce paquet — cesse donc de se
353
+ connecter tant que ce drapeau n’est pas ajouté.
354
+ - **RUPTURE — les connexions SFTP sans `hostKeySha256` sont refusées** avant
355
+ l’authentification, avec `HOST_KEY_REJECTED`, sauf configuration explicite de
356
+ `allowUnknownHostKey: true`. 0.1.0 n’effectuait aucune vérification de clé
357
+ d’hôte et ne possédait pas ce champ : chaque entrée de serveur SFTP existante
358
+ cesse donc de se connecter tant que l’une des deux clés n’est pas ajoutée.
359
+ - **RUPTURE — les connexions FTP/FTPS dont `root` n’est pas `/` sont refusées**
360
+ sauf configuration explicite de `allowUnsafeRemoteRoot: true` ;
361
+ `REMOTE_ROOT_REJECTED` est levé avant toute entrée-sortie réseau. 0.1.0
362
+ acceptait n’importe quel `root` et son propre README recommandait exactement
363
+ ce motif (`"root": "/var/www/site"`) : ces entrées cessent donc de se
364
+ connecter tant que le drapeau n’est pas ajouté. Le périmètre recommandé repose
365
+ désormais sur un compte dédié, chrooté côté serveur, avec `root: "/"`.
366
+ - `ftp_deploy` renvoie une erreur MCP dès qu’un transfert échoue et inclut un
367
+ résumé du déploiement partiel, désormais aussi sous forme de compteurs
368
+ `partial` structurés. Les transferts déjà réussis ne sont pas annulés.
369
+ - `ftp_list` ne renvoie plus toutes les entrées d’un dossier par défaut. Il
370
+ renvoie les 50 premières avec les métadonnées de pagination ; l’appelant peut
371
+ choisir un décalage et une taille de page comprise entre 1 et 200.
372
+ - Les résultats d’outil sont bornés à 25000 octets de `JSON.stringify` UTF-8,
373
+ couvrant le texte comme les données structurées après masquage. Un résultat
374
+ trop volumineux réduit d’abord ses échantillons bornés et reconstruit la
375
+ pagination, puis tronque le plus grand corps de texte avec un marqueur
376
+ `… [output truncated]`, et ne se rabat sur `OUTPUT_LIMIT` que si plus rien ne
377
+ peut être réduit — tout en préservant l’UUID de requête, les effets et les
378
+ compteurs partiels observés. Ce plafond est inférieur à la fenêtre `max_bytes`
379
+ inchangée de `ftp_read` (262144 par défaut, maximum absolu 1048576) : une
380
+ lecture qui renvoyait 256 Kio de contenu en 0.1.0 en renvoie désormais environ
381
+ 25 Kio, marqués comme tronqués, dans un résultat réussi.
382
+ - Les indicateurs booléens de sécurité et les formats d’empreinte SFTP sont
383
+ validés pour chaque serveur.
384
+ - `setup` affiche les acceptations actives de transport non sécurisé ; `doctor`
385
+ affiche les acceptations actives de transport non sécurisé, de clé d’hôte
386
+ inconnue et de racine distante non sûre.
387
+ - La documentation distingue désormais l’installation fonctionnelle depuis les
388
+ sources des futures installations via `npx` et le registre MCP.
389
+ - Le paquet publié livre désormais aussi `docs/`, `evaluations/`, `server.json`,
390
+ `CONTRIBUTING.md`, `CONTRIBUTING.fr.md`, `SECURITY.md`, `SECURITY.fr.md`,
391
+ `CHANGELOG.fr.md` et `LICENSE.fr.md`. Les descriptions du paquet et de
392
+ `server.json` sont désormais bilingues et décrivent le confinement local et la
393
+ promotion vérifiée.
394
+ - Nouvelle dépendance d’exécution `zod-to-json-schema`, utilisée pour publier
395
+ les schémas JSON d’entrée et de sortie des outils.
396
+ - Le serveur FTP de test local utilise désormais la dépendance de développement
397
+ `@electerm/ftp-srv`.
398
+
399
+ ### Retraits
400
+
401
+ - `assets/banner.svg`, `assets/banner.png`, `assets/demo.svg` et
402
+ `assets/diagram.svg`. Les bannières du README sont désormais
403
+ `assets/banner-en.png` et `assets/banner-fr.png`, avec leurs prompts de
404
+ génération et leur provenance consignés sous `assets/provenance/`.
405
+ - La dépendance de développement `ftp-srv`, remplacée comme indiqué ci-dessus.
406
+
407
+ ### Corrections
408
+
409
+ - La saisie manuelle interactive d’un serveur dans `setup` n’écrit plus le
410
+ résultat de l’assistant via une propriété absente.
411
+ - Les variantes de casse des noms de protocole ne permettent plus de contourner
412
+ les contrôles de transport non sécurisé sur les chemins de `setup` et de
413
+ diagnostic.
414
+ - Les erreurs d’outil conservent les avertissements de sécurité applicables,
415
+ notamment lorsqu’une connexion non sécurisée a pu exposer les identifiants
416
+ avant l’échec.
417
+
418
+ ### Sécurité
419
+
420
+ - Les transports non sécurisés sont refusés par défaut ; voir l’entrée
421
+ **RUPTURE** de la section *Changements* pour le nouveau garde-fou
422
+ `allowInsecure` et son impact à la mise à niveau. Des avertissements
423
+ accompagnent la découverte, les diagnostics, les succès et les échecs
424
+ impliquant un transport non sécurisé accepté.
425
+ - SFTP résout la racine distante configurée et utilise les contrôles
426
+ `realpath`/`lstat` pour refuser les composants symboliques et les chemins
427
+ résolus hors de cette racine. Un serveur malveillant peut encore créer une
428
+ course entre le contrôle et l’usage de cet état. Une connexion SFTP épingle
429
+ aussi sa racine canonique initiale ; un changement de racine constaté renvoie
430
+ `TARGET_CHANGED` et refuse de rebaser un temporaire lui appartenant.
431
+ - FTP/FTPS ne présentent plus la normalisation lexicale des chemins comme un
432
+ jail anti-symlink fiable ; l’isolation du compte côté serveur constitue la
433
+ véritable frontière.
434
+ - Les sources locales et les destinations de téléchargement sont confinées sous
435
+ `localRoot`.
436
+ - Un `setup` non interactif échoue de façon fermée : il signale les transports
437
+ non sécurisés mais n’accorde jamais automatiquement de dérogation
438
+ `allowInsecure`.
439
+ - La confidentialité des erreurs est imposée à la frontière des résultats. Les
440
+ objets d’erreur, leurs causes, les piles d’appels, les identifiants et les
441
+ arguments bruts ne sont jamais sérialisés ; les secrets sont masqués dans le
442
+ texte libre ; les identifiants de configuration sont collectés avant
443
+ validation, y compris les valeurs des entrées rejetées et les substitutions
444
+ `${ENV:VAR}` résolues, afin que les diagnostics du chargeur utilisent le même
445
+ masque. Un JSON de configuration mal formé produit un diagnostic de syntaxe
446
+ générique, sans extrait de l’analyseur, et les blocs FileZilla rejetés sont
447
+ identifiés par leur indice numérique, sans reprendre des noms ou des champs de
448
+ protocole non fiables. Des chaînes distantes comme `Page:` et
449
+ `SECURITY WARNING` ne peuvent pas usurper le rendu des avis de confiance.
450
+ - Le fichier de verrouillage versionné résout la dépendance transitive `hono` du
451
+ SDK MCP vers la version corrigée 4.13.5.
452
+
453
+ ## [0.1.0] - 2026-07-20
454
+
455
+ ### Ajouts
456
+
457
+ - Dix outils MCP : `ftp_list_servers`, `ftp_test`, `ftp_list`, `ftp_read`,
458
+ `ftp_upload`, `ftp_deploy`, `ftp_download`, `ftp_mkdir`, `ftp_rename` et
459
+ `ftp_delete`.
460
+ - Configuration de plusieurs serveurs FTP, FTPS et SFTP.
461
+ - Déploiement récursif de dossiers avec exclusions de type gitignore et simulation.
462
+ - Normalisation de la racine distante `root` et mode `readOnly` par serveur.
463
+ - Variables `${ENV:VAR}` pour les secrets de configuration.
464
+ - Import FileZilla, y compris les sites FTPS implicites.
465
+ - Assistant de configuration avec sauvegardes des configurations des clients MCP.
466
+ - Diagnostic `doctor` en lecture seule et scripts d'installation depuis les sources.
467
+ - Documentation en anglais et en français.
468
+ - Tests de bout en bout contre des serveurs FTP et SFTP locaux.