> La revisione linguistica di questa traduzione è in corso. In caso di dubbi, consultare l’[originale inglese](https://www.sm.ch-j.eu/docs/i18n/en/remote-editor-latency.md). # Salvataggio dell'editor remoto e monitoraggio della latenza ## Cause della radice L'editor precedente ha caricato il suo file di lavoro nella directory madre del target, che spesso non può essere scritto dall'account SSH sotto `/etc` o `/var`. SFTP rinomina non ha fornito alcun percorso sudo autorizzato, controllo di conflitto di base, verifica dei metadati di sicurezza o semantica di sovrascrittura affidabile. Il gestore errore ha eliminato la copia temporanea, rimuovendo il materiale di recupero anche quando il completamento era incerto. Stato della sessione precedentemente esposto solo lo stato della connessione. Non c'era una misura di risposta ICMP o autenticata SSH che alimentasse l'indicatore terminale. ## Salva protocollo 1. Un helper SSH fisso apre un file regolare con un collegamento singolo usando il descrittore-relativo operazioni e `O_NOFOLLOW` per ogni componente del percorso. Cattura il contenuto, hash SHA-256, device/inode, UID, GID, bit di autorizzazione completi, tempi di modifica/cambio nanosecondi e tutti gli attributi estesi leggibili. Core verifica l'hash e decodifica UTF-8 rigoroso, conservando un BOM. Ogni documento ottiene un `editId` opaco, per il suo plugin, la sessione del terminale e l'identità del server. 2. Un'operazione di preparazione non privilegiata risolve il conto autenticato home attraverso `pwd.getpwuid(os.getuid())`, crea `$HOME/ch-j-sm/` con la modalità `0700` e crea un diario di recupero privato ed esclusivo. Viene rifiutata una casa non sicura, un workspace di collegamento simbolico o uno spazio di lavoro di proprietà di un altro account. 3. Core carica un file di lavoro 128-bit `.tmp` nascosto e casuale tramite SFTP con creazione esclusiva (`wx`), modalità `0600` e un timeout di 60 secondi/upload. Il diario contiene l'obiettivo, la linea di base originale e l'hash di lavoro previsto; non contiene credenziali. 4. **One SSH esegue l'intera finalizzazione**, opzionalmente attraverso il Esecutore sudo esistente. L'aiutante si apre in modo sicuro e hash la copia di lavoro privata e lo sciacquone. Blocca l'inode originale, controlla la sua linea di base, crea un file di destinazione esclusivo accanto all'obiettivo, scrive tutto il contenuto, applica e verifica i metadati, controlla l'originale nuovamente, e ripulisce la sostituzione. 5. Una stessa directory `os.replace` sostituisce atomicamente l'obiettivo. Il genitore la directory viene ripulita e vengono verificati il percorso finale, l'hash, l'inode e i metadati. Il percorso originale rimane disponibile fino alla sostituzione. Il file di lavoro non viene mai spostato attraverso i filesystem e non viene mai rimosso dalla finalizzazione. 6. Dopo Core riceve un successo verificato, una pulizia separata ricontrolla la finale metadati di contenuto e sicurezza prima di rimuovere il file di lavoro e il diario. Un guasto alla pulizia segnala ancora un salvataggio confermato con `recoveryAvailable: true`. Un upload fallito, un sudo fallito, un conflitto, un errore di metadati o una sostituzione non riuscita mantengono il materiale originale e qualsiasi materiale messo in scena. Gli upload incompleti sono identificati come tali e non possono essere recuperati come un documento modificato completo. Comunicazione SSH persa, stato di uscita mancante, timeout e risultati di finalizzazione inaspettati sono segnalati come **unknown**, mai come salvato. Il core blocca un altro salvataggio su un documento incerto; non c'è nessuna prova automatica di sostituzione. ## Metadati, privilegi e limiti di sicurezza L'helper conserva e verifica i bit UID, GID e tutti i permessi POSIX, inclusi i bit eseguibili, setuid, setgid e appiccicosi. Riproduce il byte degli attributi estesi Linux per byte, inclusi gli ACL POSIX, le funzionalità e le etichette SELinux. La proprietà e il contenuto dei file sono impostati prima degli attributi di sicurezza, perché writes/chown può cancellare le funzionalità o bit permessi speciali. Gli attributi di destinazione ereditati che sono assenti sull'originale vengono rimossi. Il tempo di modifica riflette la nuova scrittura e non è copiato dall'originale. Un attributo illeggibile o irraggiungibile interrompe l'operazione; i metadati non vengono rifiutati in silenzio. Le firme IMA/EVM sono esplicitamente rifiutate perché copiare le firme di integrità con contenuto/inode li invalida. Simlink nel percorso di destinazione o home, file hard-linked e file non regolari sono rifiutati. Non viene utilizzato alcun ripiego in luogo o più debole SFTP. I salvataggi scrivibili ordinari vengono eseguiti come account SSH. I salvataggi protetti richiedono `{ sudo: true }` esplicito; una password sudo è opzionale per il sudo senza passwoword. Le password vengono convalidate e passate solo su stdin canale, mai all'interno del comando, diario, file di lavoro, logger o errore remoto. Le sessioni di Root SSH usano l'eseguitore diretto di root esistente. L'autorizzazione non riuscita lascia intatta la copia originale e funzionante. Tutti i salva eseguiti come root (direct root SSH o sudo) rifiutano anche directory/antenati di destinazione posseduti o scrivibili da altri account, o portano un accesso ACL, piuttosto che fidarsi di un nome di percorso privilegiato controllato da un altro account. L'helper fisso viene eseguito con `python3 -I -B`: ignora i percorsi Python dell'utente, la directory di lavoro e i pacchetti del sito utente, e non scrive alcun bytecode. I percorsi e gli argomenti JSON sono citati nella shell Core. I plugin non ricevono mai arbitrarie SSH exec o SFTP maniglie. La sandbox esistente, CSP, i permessi di manifestazione, la verifica host-key e la verifica dell'aggiornamento rimangono in uso. ## Plugin API e integrazione di Monaco **L'interfaccia utente Monaco/File Manager distribuita separatamente è assente da questo checkout. L'integrazione dell'interfaccia utente, il prompt sudo, la gestione di buffer sporchi e le traduzioni non possono essere implementate o testate qui.** La sorgente del plugin in bundle è il plug-in Hash & Checksum. Non è stato inventato alcun sorgente di File Manager sostitutivo. I metodi esistenti rimangono disponibili. I metodi/le opzioni di additivo sono esposti dal precarico sandboxed e dal runtime controllato con autorizzazione: ```js const opened = await chjPlugin.files.readText(sessionId, path); // For a protected read, explicitly pass { sudo: true, sudoPassword }. const result = await chjPlugin.files.saveText(sessionId, path, editor.getValue(), { editId: opened.editId, sudo: true, // Include only after the user authorizes elevation. sudoPassword // Omit for passwordless sudo; never persist this value. }); if (result.ok && result.value.status === "saved") { // Mark this exact submitted editor version as saved. Later edits stay dirty. } else { // Keep the Monaco model dirty. Translate result.error.code/status. // result.error.recoveryId/recoveryPath identify retained working material. } await chjPlugin.files.closeText(opened.editId); const recovery = await chjPlugin.files.listRecovery(sessionId); const copy = await chjPlugin.files.readRecovery(sessionId, recoveryId); // Review copy.status and copy.text; open a fresh document before another save. await chjPlugin.files.cleanupRecovery(sessionId, recoveryId); // Cleanup rejects anything whose target is not currently confirmed. ``` I metodi di recupero accettano un argomento `{ sudo: true, sudoPassword }` finale opzionale durante l'ispezione di un obiettivo richiede elevazione. Conservano lo spazio di lavoro dell'utente autenticato anche quando eseguito tramite sudo. I giornali sopravvivono al riavvio dell'app e alla riconnessione di SSH; il recupero non ripete mai automaticamente la finalizzazione. Rivedere un buffer recuperato contro un obiettivo appena aperto prima di salvarlo esplicitamente. Le guardie `files.read` leggono, ispezionano e gestiscono il rilascio. Le protezioni `files.write` salvano e ripuliscono il recupero. `writeText` rifiuta ancora il fallimento per i plugin esistenti; `saveText` restituisce una busta strutturata `{ ok, value/error }` perché Electron rilascia proprietà personalizzate sugli oggetti di errore rifiutati. Un'eredità a tre argomenti `writeText` può usare il basale di un singolo documento aperto. Diversi documenti live per lo stesso percorso richiedono `editId`; le chiamate legacy ambigue falliscono in modo sicuro invece di scegliere la linea di base di un altro documento. I plugin devono rilasciare le maniglie non utilizzate. L'interfaccia utente esterna deve visualizzare immediatamente il salvataggio, mantenere i buffer sporchi sul fallimento, offrire sudo solo dopo l'autorizzazione/autenticazione guasti, mostrare conflitti senza sovrascrittura, e offrire recupero dopo perdita di connessione o un risultato sconosciuto. Deve tradurre questi stati in ceco, tedesco e inglese. Copia di stato suggerita: | State | Czech | German | English | | --- | --- | --- | --- | | Saving | Ukládání… | Wird gespeichert… | Saving… | | Confirmed | Uloženo | Gespeichert | Saved | | Failure | Uložení selhalo | Speichern fehlgeschlagen | Save failed | | Sudo required | Vyžadováno oprávnění sudo | sudo-Autorisierung erforderlich | Sudo authorization required | | Conflict | Původní soubor byl změněn | Originaldatei wurde geändert | Original file changed | | Disconnected | Spojení bylo přerušeno | Verbindung unterbrochen | Connection lost | | Unknown | Výsledek uložení není znám | Speicherergebnis unbekannt | Save result unknown | | Recovery | Obnova je dostupná | Wiederherstellung verfügbar | Recovery available | ## Definizioni di latenza e ciclo di vita **Ping** è la latenza segnalata da una reale risposta ICMP echo client-side all'IP risolto utilizzato da SSH. Core invoca la piattaforma ping eseguibile asincronamente con un array di argomenti fisso, senza bisogno di avvio di shell o amministratore. Gli argomenti Linux, macOS (inclusi `ping6`) e Windows sono selezionati separatamente. Bloccato ICMP, un eseguibile mancante, un timeout, output non valido o una risposta Windows solo in alto, come `<1ms` producono un valore non disponibile, non un numero inventato. **SSH RTT** è la durata monotona `performance.now()` di una richiesta exec fissa `true` sul client SSH autenticato esistente. Esso include l'impostazione del canale, l'elaborazione del server e la consegna delle risposte; non è pura rete RTT o SSH durata di accesso. Il suggerimento dell'indicatore tradotto spiega questa distinzione. Il monitoraggio inizia non appena il terminale si connette. Le sonde corrono simultaneamente e in modo asincrono, con un timeout di cinque secondi per la richiesta/processo. Il campione successivo è programmato dodici secondi dopo che il campione precedente ha completato, evitando sovrapposizioni. Disconnetti aborti ICMP, cancella i timer, annulla il lavoro in attesa di SSH e cancella i valori. Registrare i controlli di identità impedisce una connessione precedente dalla pubblicazione dopo la riconnettersi. Il fallimento ICMP non cambia mai lo stato della connessione SSH. La latenza viaggia all'interno dell'evento `state` esistente / `ssh:state` IPC payload: ```js latency: { pingMs: 24.1, sshRttMs: 31.25, measuredAt: "…" } ``` I numeri non disponibili sono `null`. L'indicatore morsetto compatto utilizza millisecondi, testo non disponibile localizzato ed etichette Czech/German/English. Si nasconde sulla disconnessione. Non era necessaria alcuna capacità di esecuzione del render o richiesta IPC. ## Convalida e limiti operativi - Esegui da `app/`: `npm ci`, poi `npm test`. - Risultato finale locale: **179 prove; 163 passato, 0 non riuscito, 16 saltato**. Tutti i salti sono i casi di filesystem Linux su questo host macOS. `npm ci`, compilazione della sintassi Python e `git diff --check` completato con successo. - I test coprono Core salva/recupero, protocollo sudo e redazione password, reale shell POSIX citando percorsi, conflitti, upload ostili, pulizia fallita, esiti incerti, documenti concomitanti, autorizzazioni IPC e ciclo di vita di latenza. - I test Linux del filesystem esercitano il punto d'ingresso Python spedito, usando un privato test account-home lookup: proprietà/mode/xattrs, POSIX ACL, symlinks/hardlinks, FIFO, upload e metadata failts, sostituzioni, gare di destinazione, risultati post-sostituzione sconosciuti e recupero. La messa in scena multi-filesystem utilizza `/dev/shm` e un altro filesystem quando disponibile. Questi test saltano su host non-Linux; mancano le strutture ACL/separat-filesystem. - Il processo Linux GitHub Azioni esegue la suite completa e ripete il file system casi come radice. Questo flusso di lavoro non è stato inviato da questo albero di lavoro. - La convalida locale era su macOS. La sintassi sorgente di Python è stata controllata con la diretta Strumenti di riga di comando Python eseguibile. Un vero loopback macOS ICMP smoke check ha restituito `0.071 ms`. Nessun server SSH live remoto, runtime Windows, runtimetri Linux e distribuzione SELinux o interfaccia utente esterna di Monaco è stata testata localmente. - Editing di testo remoto richiede ora Linux e Python 3 con relativo descrittore supporto filesystem/xattr. Un interprete mancante fallisce esplicitamente. Questo Core rifiuta intenzionalmente metadati, collegamenti e configurazioni delle directory non sicuri. - Il blocco è consultivo: i processi di non cooperazione possono ancora correre nella stretta intervallo tra l'ultimo controllo di base e la rinomina atomica. Linux non fornisce alcuna operazione generale di confronto e sostituzione del contenuto atomico. Controlli rilevano le modifiche prima di tale intervallo; le copie di lavoro mantenute supportano il recupero successivamente. - I dati di recupero rimangono sull'account remoto fino ad una pulizia confermata. Incompleto, Le riviste in conflitto e irripetibili non vengono mai ignorate in silenzio. Non c'è scadenza automatica del file di recupero e nessuna opzione di sovrascrittura forzata. - `npm ci` ha riportato i risultati dell'audit di dipendenza 17 (9 moderato, 8 alto). Questo cambiamento non cambia le dipendenze o il modello di fiducia dell'applicazione. L'utente ha richiesto di mantenere le modifiche nell'albero di lavoro esistente, attualmente `feature/hash-checksum-plugin`; non è stato eseguito alcun interruttore di ramo o pulizia indipendente. ## File modificati per questa attività - `src/main/files/remoteFileService.js` - `src/main/files/remoteEditor.py` (nuovo) - `src/main/sessions/sessionManager.js` - `src/main/sessions/latencyMonitor.js` (nuovo) - `src/main/plugins/pluginRuntime.js` - `src/preload/pluginPreload.js` - `src/renderer/app.js` - `src/renderer/index.html` - `src/renderer/styles.css` - `src/renderer/i18n.js` - `test/remoteFileService.test.js` - `test/sessionManager.test.js` - `test/pluginRuntime.test.js` - `test/remoteEditor.test.js` (nuovo) - `test/remoteEditorProtocol.test.js` (nuovo) - `test/remoteEditorLinux.test.js` (nuovo) - `test/fixtures/remoteEditorLinux.py` (nuovo) - `test/latencyMonitor.test.js` (nuovo) - `README.md` - `docs/remote-editor-latency.md` (questo file) - `../.github/workflows/remote-editor-tests.yml` (nuovo)