diff --git a/eslint.config.mjs b/eslint.config.mjs index a418132..5d3145b 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,17 +1,17 @@ -import tsparser from "@typescript-eslint/parser"; -import { defineConfig } from "eslint/config"; import obsidianmd from "eslint-plugin-obsidianmd"; -export default defineConfig([ +export default [ ...obsidianmd.configs.recommended, { files: ["**/*.ts"], languageOptions: { - parser: tsparser, - parserOptions: { project: "./tsconfig.json" }, + parserOptions: { + project: "./tsconfig.json", + tsconfigRootDir: import.meta.dirname, + }, }, }, { ignores: ["main.js", "node_modules/**", "dist/**"], }, -]); +]; diff --git a/manifest.json b/manifest.json index 7fab92f..6d1f76f 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "vault-bridge-sftp", "name": "Vault Bridge SFTP", - "version": "0.9.7", + "version": "0.9.8", "minAppVersion": "1.5.0", "description": "Bridge your vault across devices through your own SSH/SFTP server. Bidirectional sync with conflict resolution, multi-device safety, and full self-hosting.", "author": "Andrew Kopylev", diff --git a/package-lock.json b/package-lock.json index 2c9a6cd..8fa8cf4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "obsidian-vault-bridge-sftp", - "version": "0.9.6", + "version": "0.9.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "obsidian-vault-bridge-sftp", - "version": "0.9.6", + "version": "0.9.7", "license": "MIT", "dependencies": { "ssh2-sftp-client": "^10.0.3" diff --git a/package.json b/package.json index da3597d..e069301 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obsidian-vault-bridge-sftp", - "version": "0.9.7", + "version": "0.9.8", "description": "Vault Bridge SFTP — bidirectional Obsidian vault sync over SSH/SFTP", "main": "main.js", "scripts": { diff --git a/src/main.ts b/src/main.ts index 8e7b77e..364903a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -173,7 +173,7 @@ export default class SftpSyncPlugin extends Plugin { if (this.index) { try { await this.index.flush(); - } catch (_flushErr) { /* ignore — best-effort on shutdown */ } + } catch { /* ignore — best-effort on shutdown */ } } // Clean up any pending debounced calls. for (const fn of this.pendingRefresh.values()) fn.cancel?.(); @@ -562,7 +562,7 @@ export default class SftpSyncPlugin extends Plugin { new Notice("Forcing push from local…", 3000); try { await this._runForcePush(); - } catch (_err) { + } catch { // Already reported by _runForcePush; nothing more to do. } return; diff --git a/src/settings.ts b/src/settings.ts index 0f9ee8a..356556c 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -86,7 +86,7 @@ export class SftpSyncSettingTab extends PluginSettingTab { .setDesc("SFTP server hostname or IP address.") .addText((t) => t - .setPlaceholder("example.com") + .setPlaceholder("Example.com") .setValue(this.plugin.settings.host) .onChange((v) => { this.plugin.settings.host = v.trim(); @@ -121,8 +121,7 @@ export class SftpSyncSettingTab extends PluginSettingTab { new Setting(containerEl) .setName("Authentication") - // eslint-disable-next-line obsidianmd/ui/sentence-case - .setDesc("Password or SSH private key. The server's SSH host key is pinned on first connect (TOFU); subsequent mismatches refuse to connect. Use the \"forget remembered host fingerprint\" command after a deliberate server reinstall.") + .setDesc("Password or SSH private key. The server's SSH host key is pinned on first connect; subsequent mismatches refuse to connect. Run the \"forget remembered host fingerprint\" command after a deliberate server reinstall.") .addDropdown((d) => d .addOption("password", "Password") @@ -138,7 +137,7 @@ export class SftpSyncSettingTab extends PluginSettingTab { if (this.plugin.settings.authMethod === "password") { new Setting(containerEl) .setName("Password") - .setDesc("Encrypted at rest (AES-256-GCM) with a per-device key in state/secret.key. The state directory never syncs, so a leaked data.json on the SFTP server cannot be decrypted without local access. SSH keys are still preferred on shared machines.") + .setDesc("Encrypted at rest (AES-256-GCM) with a per-device key in the plugin state directory. State never syncs, so a leaked data.json on the SFTP server cannot be decrypted without local access. SSH keys are still preferred on shared machines.") .addText((t) => { t.inputEl.type = "password"; t.setValue(this.plugin.settings.password).onChange((v) => { @@ -149,12 +148,9 @@ export class SftpSyncSettingTab extends PluginSettingTab { } else { new Setting(containerEl) .setName("Private key path") - // eslint-disable-next-line obsidianmd/ui/sentence-case - .setDesc("Absolute filesystem path, e.g. /home/user/.ssh/id_ed25519.") + .setDesc("Absolute filesystem path to your SSH private key.") .addText((t) => t - // eslint-disable-next-line obsidianmd/ui/sentence-case - .setPlaceholder("/home/user/.ssh/id_ed25519") .setValue(this.plugin.settings.privateKeyPath) .onChange((v) => { this.plugin.settings.privateKeyPath = v.trim(); @@ -176,12 +172,9 @@ export class SftpSyncSettingTab extends PluginSettingTab { new Setting(containerEl) .setName("Remote root") - // eslint-disable-next-line obsidianmd/ui/sentence-case - .setDesc("Absolute path on the server, e.g. /home/user/obsidian-vault. Created if it doesn't exist.") + .setDesc("Absolute path on the server. Created if it doesn't exist.") .addText((t) => t - // eslint-disable-next-line obsidianmd/ui/sentence-case - .setPlaceholder("/home/user/obsidian-vault") .setValue(this.plugin.settings.remoteRoot) .onChange((v) => { this.plugin.settings.remoteRoot = v.trim(); @@ -326,8 +319,7 @@ export class SftpSyncSettingTab extends PluginSettingTab { .setDesc("Used in conflict-copy filenames so you can tell which device the conflicting edit came from. Lives in state/device.json — each machine has its own.") .addText((t) => t - // eslint-disable-next-line obsidianmd/ui/sentence-case - .setPlaceholder("home-desktop") + .setPlaceholder("Home laptop") .setValue(this.plugin.deviceStore.label) .onChange((v) => { void this.plugin.deviceStore.setLabel(v); diff --git a/src/sftp/transfer.ts b/src/sftp/transfer.ts index f5a2d00..e44715f 100644 --- a/src/sftp/transfer.ts +++ b/src/sftp/transfer.ts @@ -123,7 +123,7 @@ export async function writeBufferToVault( // Best-effort cleanup of the staging file; never let cleanup errors mask the rename failure. try { await adapter.remove(tmp); - } catch (_cleanupErr) { /* ignore */ } + } catch { /* ignore */ } throw err; } } diff --git a/src/sync/pull-engine.ts b/src/sync/pull-engine.ts index ed6b978..6f06ce6 100644 --- a/src/sync/pull-engine.ts +++ b/src/sync/pull-engine.ts @@ -202,7 +202,7 @@ export class PullEngine { // Best-effort cleanup of the staging file; never let cleanup errors mask the rename failure. try { await adapter.remove(tmp); - } catch (_cleanupErr) { /* ignore */ } + } catch { /* ignore */ } throw err; } } diff --git a/src/ui/bulk-delete-modal.ts b/src/ui/bulk-delete-modal.ts index c6a4362..ac1f36d 100644 --- a/src/ui/bulk-delete-modal.ts +++ b/src/ui/bulk-delete-modal.ts @@ -47,7 +47,7 @@ export class BulkDeleteConfirmModal extends Modal { const note = contentEl.createEl("p", { cls: "vbsftp-modal-note" }); note.appendText( - "Choosing \"Skip deletes\" will perform pushes/pulls/conflict-copies but leave deletions for review later — the next sync will re-detect them.", + "Skipping deletes will still perform pushes/pulls/conflict-copies, but leave deletions for review later — the next sync will re-detect them.", ); const buttons = contentEl.createDiv({ cls: "vbsftp-modal-buttons" }); diff --git a/src/ui/server-reset-modal.ts b/src/ui/server-reset-modal.ts index 7f1a217..f1e5598 100644 --- a/src/ui/server-reset-modal.ts +++ b/src/ui/server-reset-modal.ts @@ -37,7 +37,7 @@ export class ServerResetModal extends Modal { "If we proceed with a normal sync, the engine will see your local files as \"deleted on remote\" and try to delete them locally.", ); warn.createEl("br"); - warn.appendText("This is almost certainly NOT what you want — pick one of the safe options below."); + warn.appendText("This is almost certainly the wrong outcome — pick one of the safe options below."); const ul = contentEl.createEl("ul", { cls: "vbsftp-modal-list" }); diff --git a/versions.json b/versions.json index f33ff0c..6b0d9f7 100644 --- a/versions.json +++ b/versions.json @@ -1,4 +1,5 @@ { "0.9.6": "1.5.0", - "0.9.7": "1.5.0" + "0.9.7": "1.5.0", + "0.9.8": "1.5.0" }