Release 0.9.8 — full ObsidianReviewBot cleanup

This commit is contained in:
Andrew Kopylev 2026-05-03 14:26:55 +03:00
parent 62e1da82ed
commit 05697e03cb
11 changed files with 24 additions and 31 deletions

View file

@ -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/**"],
},
]);
];

View file

@ -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",

4
package-lock.json generated
View file

@ -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"

View file

@ -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": {

View file

@ -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;

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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" });

View file

@ -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" });

View file

@ -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"
}