From 55d809f313ad0671c1f9657861a28b9476f288cd Mon Sep 17 00:00:00 2001 From: Tyce Herrman Date: Thu, 19 Mar 2026 17:34:54 -0400 Subject: [PATCH 01/19] fix: warn when atomize blocks missing from highlight template When users enable atomic highlights but don't add atomize blocks to their highlight template, the plugin silently creates an empty Highlight/ folder. This adds warnings in both settings UI and at sync time, updates the default highlight template to include atomize blocks for new users, and hardens the atomizer against non-string basename values. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/constants/index.ts | 4 +++- src/main.ts | 8 ++++++++ src/services/atomizer.ts | 5 +++-- src/ui/settings-tab.ts | 23 +++++++++++++++++++++++ src/utils/template-utils.ts | 9 +++++++++ 5 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 src/utils/template-utils.ts diff --git a/src/constants/index.ts b/src/constants/index.ts index f069213..3f6efe6 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -63,7 +63,8 @@ Summary: {{ summary }} # Highlights `, - highlightTemplate: `{{ text }}{%- if category == 'books' %} ([{{ location }}]({{ location_url }})){%- endif %}{%- if color %} %% Color: {{ color }} %%{%- endif %} ^{{id}}{%- if note %} + highlightTemplate: `{% atomize id=id, basename=id, embed=true %} +{{ text }}{%- if category == 'books' %} ([{{ location }}]({{ location_url }})){%- endif %}{%- if color %} %% Color: {{ color }} %%{%- endif %} ^{{id}}{%- if note %} Note: {{ note }} {%- endif %}{%- if tags %} @@ -75,6 +76,7 @@ Tags: {{ tags }} {%- endif %} --- +{% endatomize %} `, useSlugify: false, slugifySeparator: '-', diff --git a/src/main.ts b/src/main.ts index 213aa3c..95303d8 100644 --- a/src/main.ts +++ b/src/main.ts @@ -19,6 +19,7 @@ import Notify from 'ui/notify'; import ReadwiseMirrorSettingTab from 'ui/settings-tab'; import { normalizeFilename } from 'utils/filename-utils'; import { createdDate, lastHighlightedDate, updatedDate } from 'utils/highlight-date-utils'; +import { hasAtomizeBlocks } from 'utils/template-utils'; import { isInReadwiseLibrary, isTrackedReadwiseNote } from 'utils/tracking-utils'; export default class ReadwiseMirror extends Plugin { @@ -634,6 +635,13 @@ export default class ReadwiseMirror extends Plugin { if (Object.keys(library.books).length > 0) { if (this.settings.atomicHighlights) { library.categories.add('Highlight'); + + if (!hasAtomizeBlocks(this.settings.highlightTemplate)) { + this.notify.notice( + 'Readwise: Atomic highlights enabled but your highlight template has no atomize blocks. No atomic notes will be created.', + 10000 + ); + } } await this.writeLibraryToMarkdown(library); diff --git a/src/services/atomizer.ts b/src/services/atomizer.ts index 02d01bb..0fa78be 100644 --- a/src/services/atomizer.ts +++ b/src/services/atomizer.ts @@ -146,7 +146,7 @@ export class AtomizeExtension implements nunjucks.Extension { switch (this.pass) { case 'FIRST': { - return new nunjucks.runtime.SafeString(`%%! atomize id=${_id}, basename="${basename.replace(/^\n+|\n+$/g, '').trim()}", embed=${embed} !%% + return new nunjucks.runtime.SafeString(`%%! atomize id=${_id}, basename="${String(basename ?? _id).replace(/^\n+|\n+$/g, '').trim()}", embed=${embed} !%% %%! frontmatter !%% ${frontmatter} %%! endfrontmatter !%% @@ -160,7 +160,8 @@ ${content} } // Sanitize filename - const _basename = filenamify(basename.replace(/^\n+|\n+$/g, '').trim() ?? _id.toString(), { + const rawBasename = (basename ?? _id.toString()); + const _basename = filenamify(String(rawBasename).replace(/^\n+|\n+$/g, '').trim() || _id.toString(), { replacement: '-', maxLength: 252, }) diff --git a/src/ui/settings-tab.ts b/src/ui/settings-tab.ts index 9228158..c9aaf28 100644 --- a/src/ui/settings-tab.ts +++ b/src/ui/settings-tab.ts @@ -15,6 +15,7 @@ import type { TemplateValidationResult } from 'types'; import { WarningDialog } from 'ui/dialog'; import type Notify from 'ui/notify'; import { sanitizeFrontmatterTemplate, validateFrontmatterTemplate } from 'utils/frontmatter-utils'; +import { hasAtomizeBlocks } from 'utils/template-utils'; interface SettingsTab { id: string; @@ -626,6 +627,26 @@ export default class ReadwiseMirrorSettingTab extends PluginSettingTab { attr: { style: 'color: var(--text-error);' }, }); } + + if (this.plugin.settings.atomicHighlights && !hasAtomizeBlocks(this.plugin.settings.highlightTemplate)) { + fragment.createEl('br'); + fragment.createEl('br'); + const warningSpan = fragment.createSpan({ + attr: { style: 'color: var(--text-warning);' }, + }); + warningSpan.appendText( + 'Your highlight template does not contain atomize blocks. Atomic highlights will not be created until you add ' + ); + warningSpan.createEl('code', { text: '{% atomize %}...{% endatomize %}' }); + warningSpan.appendText(' blocks. See the '); + warningSpan + .createEl('a', { + text: 'Wiki', + href: 'https://github.com/jsonMartin/readwise-mirror/wiki/Guide:-Atomic-highlights', + }) + .setAttr('target', '_blank'); + warningSpan.appendText(' for details.'); + } }) ) .addToggle((toggle) => { @@ -657,6 +678,7 @@ export default class ReadwiseMirrorSettingTab extends PluginSettingTab { if (confirmed) { this.plugin.settings.atomicHighlights = true; await this.plugin.saveSettings(); + this.display(); } else { toggle.setValue(false); } @@ -665,6 +687,7 @@ export default class ReadwiseMirrorSettingTab extends PluginSettingTab { } else { this.plugin.settings.atomicHighlights = false; await this.plugin.saveSettings(); + this.display(); } }); } diff --git a/src/utils/template-utils.ts b/src/utils/template-utils.ts new file mode 100644 index 0000000..78cde01 --- /dev/null +++ b/src/utils/template-utils.ts @@ -0,0 +1,9 @@ +/** + * Checks whether a highlight template contains atomize blocks. + * Detects both syntaxes: + * - Standard Nunjucks: {% atomize or {%- atomize (FIRST pass in ReadwiseEnvironment) + * - Custom atomizer: %%! atomize (SECOND pass delimiters) + */ +export function hasAtomizeBlocks(template: string): boolean { + return /{%-?\s*atomize/.test(template) || /%%!\s*atomize/.test(template); +} From 88665bbe23bbdc6b3dac7198844581d784ef472e Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 16 Jun 2026 18:01:51 +0000 Subject: [PATCH 02/19] =?UTF-8?q?chore:=20=F0=9F=94=96=20set=20`package.js?= =?UTF-8?q?on`,=20`manifest.json`=20and=20`package-lock.json`=20to=202.4.1?= =?UTF-8?q?-beta.1=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [2.4.1-beta.1](https://github.com/jsonMartin/readwise-mirror/compare/2.4.0...2.4.1-beta.1) (2026-06-16) ### Bug Fixes * 🐛 always register settings tab even if initialization fails ([87ca7a6](https://github.com/jsonMartin/readwise-mirror/commit/87ca7a671710a2014f8bf36812efd989ed0856c1)) --- manifest.json | 2 +- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index 1c3d640..05349fb 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "readwise-mirror", "name": "Readwise Mirror", - "version": "2.4.0", + "version": "2.4.1-beta.1", "minAppVersion": "1.6.6", "description": "Mirror your Readwise library directly to your vault.", "author": "jsonmartin, johannrichard", diff --git a/package-lock.json b/package-lock.json index 4e13054..7665b73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "readwise-mirror", - "version": "2.4.0", + "version": "2.4.1-beta.1", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/package.json b/package.json index 648cdc1..90ade0f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "readwise-mirror", - "version": "2.4.0", + "version": "2.4.1-beta.1", "description": "This is a plugin for Obsidian (https://obsidian.md)", "main": "main.js", "scripts": { From 8cb402ac1b6daf3a0bf7d52d26e7f3a0fa1cbd06 Mon Sep 17 00:00:00 2001 From: Johann Richard <189003+johannrichard@users.noreply.github.com> Date: Tue, 16 Jun 2026 20:28:49 +0200 Subject: [PATCH 03/19] fix: update manifest.json Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- manifest.json | 1 - 1 file changed, 1 deletion(-) diff --git a/manifest.json b/manifest.json index e182e62..05349fb 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,6 @@ "id": "readwise-mirror", "name": "Readwise Mirror", "version": "2.4.1-beta.1", - "version": "2.4.1", "minAppVersion": "1.6.6", "description": "Mirror your Readwise library directly to your vault.", "author": "jsonmartin, johannrichard", From d15d1509f62f4449b375f1ba451b4ff5fa60ec8a Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 16 Jun 2026 18:29:46 +0000 Subject: [PATCH 04/19] =?UTF-8?q?chore:=20=F0=9F=94=96=20set=20`package.js?= =?UTF-8?q?on`,=20`manifest.json`=20and=20`package-lock.json`=20to=202.4.2?= =?UTF-8?q?-beta.1=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [2.4.2-beta.1](https://github.com/jsonMartin/readwise-mirror/compare/2.4.1...2.4.2-beta.1) (2026-06-16) ### Bug Fixes * update manifest.json ([8cb402a](https://github.com/jsonMartin/readwise-mirror/commit/8cb402ac1b6daf3a0bf7d52d26e7f3a0fa1cbd06)) --- manifest.json | 2 +- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index 05349fb..2b41fd5 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "readwise-mirror", "name": "Readwise Mirror", - "version": "2.4.1-beta.1", + "version": "2.4.2-beta.1", "minAppVersion": "1.6.6", "description": "Mirror your Readwise library directly to your vault.", "author": "jsonmartin, johannrichard", diff --git a/package-lock.json b/package-lock.json index 7665b73..7021ae1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "readwise-mirror", - "version": "2.4.1-beta.1", + "version": "2.4.2-beta.1", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/package.json b/package.json index 90ade0f..a7b012f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "readwise-mirror", - "version": "2.4.1-beta.1", + "version": "2.4.2-beta.1", "description": "This is a plugin for Obsidian (https://obsidian.md)", "main": "main.js", "scripts": { From 6bc1bcc3baa05f0a5159cbcf2468de421a0f64e6 Mon Sep 17 00:00:00 2001 From: Johann Richard <189003+johannrichard@users.noreply.github.com> Date: Fri, 19 Jun 2026 19:08:35 +0200 Subject: [PATCH 05/19] =?UTF-8?q?fix:=20=F0=9F=9A=91=EF=B8=8F=20fix=20empt?= =?UTF-8?q?y=20frontmatter=20regression?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit frontmatter is "empty" under certain conditions and triggers a yaml parser error. this fixes it. FIXES: #98 --- src/constants.ts | 1 - src/services/frontmatter-manager.ts | 13 ++++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 5085869..596d8f0 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -96,7 +96,6 @@ Tags: {{ tags }} }; export const FRONTMATTER_TO_ESCAPE = ['title', 'sanitized_title', 'author', 'authorStr']; -export const EMPTY_FRONTMATTER: string = '---\n---\n'; // Core Template export const NUNJUCKS_CORE_TEMPLATE = `{%- block header -%} diff --git a/src/services/frontmatter-manager.ts b/src/services/frontmatter-manager.ts index e27427b..f06c065 100644 --- a/src/services/frontmatter-manager.ts +++ b/src/services/frontmatter-manager.ts @@ -1,7 +1,7 @@ import { type FileManager, parseYaml, type TFile } from 'obsidian'; import { Frontmatter, type FrontmatterData, FrontmatterError } from 'services/frontmatter'; import { renderFrontmatterTemplate } from 'services/template-rendering'; -import { EMPTY_FRONTMATTER, READWISE_URI_FIELD } from 'src/constants'; +import { READWISE_URI_FIELD } from 'src/constants'; import type { AtomicFile, BaseFile, ReadwiseDocument } from 'types/document'; import type { PluginContext } from 'types/plugin-context'; import type { ReadwiseEnvironment } from './readwise-environment'; @@ -100,18 +100,21 @@ export class FrontmatterManager { * @returns The frontmatter record */ public getBaseFrontmatter(metadata: ReadwiseDocument): Frontmatter { - // Render a template if frontmatter is managed or file tracking is set - if (!this.settings.frontMatter && !this.settings.trackFiles) { + // Frontmatter parsing is only needed when frontmatter output is enabled. + // Tracking fields are injected later in getFrontmatter. + if (!this.settings.frontMatter) { return new Frontmatter(); } try { // Get frontmatter template string - // Add Sync properties - const frontmatterTemplate = this.settings.frontMatter ? this.settings.frontMatterTemplate : EMPTY_FRONTMATTER; + const frontmatterTemplate = this.settings.frontMatterTemplate; this.logger.debug(`Processing merged frontmatter template\n${frontmatterTemplate}`); // Render and parse the template into YAML const renderedTemplate = renderFrontmatterTemplate(frontmatterTemplate, this.env, metadata); + if (!renderedTemplate.trim()) { + return new Frontmatter(); + } const yaml: unknown = parseYaml(renderedTemplate); if (typeof yaml !== 'object' || yaml === null) { From 60ddf920efc46e1567a2dbe8c260d38f683f07f4 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 19 Jun 2026 17:09:24 +0000 Subject: [PATCH 06/19] =?UTF-8?q?chore:=20=F0=9F=94=96=20set=20`package.js?= =?UTF-8?q?on`,=20`manifest.json`=20and=20`package-lock.json`=20to=202.4.2?= =?UTF-8?q?-beta.2=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [2.4.2-beta.2](https://github.com/jsonMartin/readwise-mirror/compare/2.4.2-beta.1...2.4.2-beta.2) (2026-06-19) ### Bug Fixes * 🚑️ fix empty frontmatter regression ([6bc1bcc](https://github.com/jsonMartin/readwise-mirror/commit/6bc1bcc3baa05f0a5159cbcf2468de421a0f64e6)), closes [#98](https://github.com/jsonMartin/readwise-mirror/issues/98) --- manifest.json | 2 +- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index 2b41fd5..93c9c85 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "readwise-mirror", "name": "Readwise Mirror", - "version": "2.4.2-beta.1", + "version": "2.4.2-beta.2", "minAppVersion": "1.6.6", "description": "Mirror your Readwise library directly to your vault.", "author": "jsonmartin, johannrichard", diff --git a/package-lock.json b/package-lock.json index 7021ae1..7085b21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "readwise-mirror", - "version": "2.4.2-beta.1", + "version": "2.4.2-beta.2", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/package.json b/package.json index a7b012f..c4931ef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "readwise-mirror", - "version": "2.4.2-beta.1", + "version": "2.4.2-beta.2", "description": "This is a plugin for Obsidian (https://obsidian.md)", "main": "main.js", "scripts": { From cd7487830d13044994ce41f7e349cf542f429db6 Mon Sep 17 00:00:00 2001 From: Johann Richard <189003+johannrichard@users.noreply.github.com> Date: Sun, 21 Jun 2026 21:18:31 +0200 Subject: [PATCH 07/19] =?UTF-8?q?fix:=20=F0=9F=9A=91=EF=B8=8F=20fix=20sett?= =?UTF-8?q?ings=20not=20being=20written=20to=20disc=20anymore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix regression with respect to saving settings in the latest beta. FIXES: #101 --- src/main.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main.ts b/src/main.ts index eb0f3c1..29ce228 100644 --- a/src/main.ts +++ b/src/main.ts @@ -78,7 +78,10 @@ export default class ReadwiseMirror extends Plugin { // exposed methods notice: (message: string, duration?: number) => this.notify.notice(message, duration), setStatusBarText: (message: string) => this.notify.setStatusBarText(message), - saveAndApplySettings: () => this.saveAndApplySettings(), + saveAndApplySettings: () => { + this.settings = ctx.settings; + return this.saveAndApplySettings(); + }, }; return ctx; } From 298ef3284d55e06549bc6832a436d6cc941e0345 Mon Sep 17 00:00:00 2001 From: Johann Richard <189003+johannrichard@users.noreply.github.com> Date: Sun, 21 Jun 2026 21:19:21 +0200 Subject: [PATCH 08/19] =?UTF-8?q?fix:=20=F0=9F=90=9B=20fix=20base=20folder?= =?UTF-8?q?=20name=20reset?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the user clears the folder name, update the settings with the proper "baseFolderName" default --- src/ui/settings-tab.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/settings-tab.ts b/src/ui/settings-tab.ts index 1547410..6469806 100644 --- a/src/ui/settings-tab.ts +++ b/src/ui/settings-tab.ts @@ -556,7 +556,7 @@ export default class ReadwiseMirrorSettingTab extends PluginSettingTab { .setPlaceholder('Readwise') .setValue(this.ctx.settings.baseFolderName) .onChange(async (value) => { - if (!value) return; + if (!value) value = DEFAULT_SETTINGS.baseFolderName; this.ctx.settings.baseFolderName = value; await this.ctx.saveAndApplySettings(); }) From d7c930e2aaffdc1a9b7c73c29555315768ff01ac Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 21 Jun 2026 19:20:09 +0000 Subject: [PATCH 09/19] =?UTF-8?q?chore:=20=F0=9F=94=96=20set=20`package.js?= =?UTF-8?q?on`,=20`manifest.json`=20and=20`package-lock.json`=20to=202.4.2?= =?UTF-8?q?-beta.3=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [2.4.2-beta.3](https://github.com/jsonMartin/readwise-mirror/compare/2.4.2-beta.2...2.4.2-beta.3) (2026-06-21) ### Bug Fixes * 🐛 fix base folder name reset ([298ef32](https://github.com/jsonMartin/readwise-mirror/commit/298ef3284d55e06549bc6832a436d6cc941e0345)) * 🚑️ fix settings not being written to disc anymore ([cd74878](https://github.com/jsonMartin/readwise-mirror/commit/cd7487830d13044994ce41f7e349cf542f429db6)), closes [#101](https://github.com/jsonMartin/readwise-mirror/issues/101) --- manifest.json | 2 +- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index 93c9c85..ec35923 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "readwise-mirror", "name": "Readwise Mirror", - "version": "2.4.2-beta.2", + "version": "2.4.2-beta.3", "minAppVersion": "1.6.6", "description": "Mirror your Readwise library directly to your vault.", "author": "jsonmartin, johannrichard", diff --git a/package-lock.json b/package-lock.json index 7085b21..9796a36 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "readwise-mirror", - "version": "2.4.2-beta.2", + "version": "2.4.2-beta.3", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/package.json b/package.json index c4931ef..3d63a0a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "readwise-mirror", - "version": "2.4.2-beta.2", + "version": "2.4.2-beta.3", "description": "This is a plugin for Obsidian (https://obsidian.md)", "main": "main.js", "scripts": { From 4d2ad0323924e58594369361fb5e9fbbd4636ed7 Mon Sep 17 00:00:00 2001 From: Johann Richard <189003+johannrichard@users.noreply.github.com> Date: Sun, 21 Jun 2026 21:33:52 +0200 Subject: [PATCH 10/19] =?UTF-8?q?fix:=20=F0=9F=A9=B9=20improve=20load=20se?= =?UTF-8?q?quence=20to=20avoid=20stale=20context?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.ts b/src/main.ts index 29ce228..802ed8d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -106,8 +106,8 @@ export default class ReadwiseMirror extends Plugin { private async initializeUI() { try { - this.addSettingTab(new ReadwiseMirrorSettingTab(this, this.ctx, this.env)); await this.loadAndApplySettings(); + this.addSettingTab(new ReadwiseMirrorSettingTab(this, this.ctx, this.env)); this.logger.debug('Readwise Mirror plugin loaded.'); // Instantiate controller and attach to context From 75a55954f6a778908d58e47ec6a5b683a38de7db Mon Sep 17 00:00:00 2001 From: Johann Richard <189003+johannrichard@users.noreply.github.com> Date: Sun, 21 Jun 2026 21:34:52 +0200 Subject: [PATCH 11/19] =?UTF-8?q?fix:=20=F0=9F=A9=B9=20update=20synced=20d?= =?UTF-8?q?ate=20on=20`reset-last-updated`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensure last synced date is properly displayed when `reset-last-updated` is called --- src/utils/plugin-commands.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/utils/plugin-commands.ts b/src/utils/plugin-commands.ts index fc3a222..7aa0bf7 100644 --- a/src/utils/plugin-commands.ts +++ b/src/utils/plugin-commands.ts @@ -2,6 +2,7 @@ import type { Command } from 'obsidian'; import spacetime from 'spacetime'; import { Controller } from '../services/controller'; import type { PluginContext } from '../types/plugin-context'; +import { humanReadableFormat } from './format-utils'; function toErrorMessage(err: unknown): string { if (err instanceof Error) return err.message; @@ -114,6 +115,7 @@ export function getPluginCommands(ctr: Controller, ctx: PluginContext): Command[ void ctx .saveAndApplySettings() .catch((err: unknown) => ctx.notice(`Failed to save settings: ${toErrorMessage(err)}`)); + ctx.setStatusBarText(`Readwise: Synced ${humanReadableFormat(ctx.settings.lastUpdated)}`); } return true; } From db80f9bf576053452ad541308b29f243e2f9e986 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 21 Jun 2026 19:35:54 +0000 Subject: [PATCH 12/19] =?UTF-8?q?chore:=20=F0=9F=94=96=20set=20`package.js?= =?UTF-8?q?on`,=20`manifest.json`=20and=20`package-lock.json`=20to=202.4.2?= =?UTF-8?q?-beta.4=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [2.4.2-beta.4](https://github.com/jsonMartin/readwise-mirror/compare/2.4.2-beta.3...2.4.2-beta.4) (2026-06-21) ### Bug Fixes * 🩹 improve load sequence to avoid stale context ([4d2ad03](https://github.com/jsonMartin/readwise-mirror/commit/4d2ad0323924e58594369361fb5e9fbbd4636ed7)) * 🩹 update synced date on `reset-last-updated` ([75a5595](https://github.com/jsonMartin/readwise-mirror/commit/75a55954f6a778908d58e47ec6a5b683a38de7db)) --- manifest.json | 2 +- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index ec35923..b9866ed 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "readwise-mirror", "name": "Readwise Mirror", - "version": "2.4.2-beta.3", + "version": "2.4.2-beta.4", "minAppVersion": "1.6.6", "description": "Mirror your Readwise library directly to your vault.", "author": "jsonmartin, johannrichard", diff --git a/package-lock.json b/package-lock.json index 9796a36..a9d0049 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "readwise-mirror", - "version": "2.4.2-beta.3", + "version": "2.4.2-beta.4", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/package.json b/package.json index 3d63a0a..f63fa96 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "readwise-mirror", - "version": "2.4.2-beta.3", + "version": "2.4.2-beta.4", "description": "This is a plugin for Obsidian (https://obsidian.md)", "main": "main.js", "scripts": { From cdff1623691ee1041c456d3a24f36f865ef561d0 Mon Sep 17 00:00:00 2001 From: Johann Richard <189003+johannrichard@users.noreply.github.com> Date: Sat, 27 Jun 2026 18:41:01 +0200 Subject: [PATCH 13/19] =?UTF-8?q?ci:=20=F0=9F=91=B7=20simplify=20manifest?= =?UTF-8?q?=20sync=20after=20semantic-release?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace branch-specific semantic-release extends logic with a simpler post-release workflow step. --- .github/workflows/release.yml | 27 +++++++++++++++++++++++++-- .releaserc.yaml | 13 ------------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 36dabec..946d22f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,5 +1,5 @@ name: Release plugin version -on: +on: workflow_dispatch: push: branches: [master, main, beta] @@ -31,10 +31,33 @@ jobs: run: | npm audit --audit-level=high --production npm audit signatures - continue-on-error: true # Don't fail the build, but report issues + continue-on-error: true # Don't fail the build, but report issues - name: Build plugin run: npm run build - name: Release update env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: npx semantic-release + - name: Configure Git + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + run: | + git config --global user.name "${{ github.actor }}" + git config --global user.email "${{ github.actor }}@users.noreply.github.com" + - name: Commit manifest.json (main only) + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + run: | + if git diff --quiet -- manifest.json; then + echo "manifest.json unchanged; skipping commit" + exit 0 + fi + + git add manifest.json + git commit -m "chore: 🔖 sync manifest version [skip ci]" + git push + - name: Generate artifact attestation (main release) + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + uses: actions/attest@v4 + with: + subject-path: | + build/main.js + build/styles.css diff --git a/.releaserc.yaml b/.releaserc.yaml index e91d1cc..65afa06 100644 --- a/.releaserc.yaml +++ b/.releaserc.yaml @@ -17,17 +17,4 @@ plugins: - path: main.js - path: manifest.json - path: src/ui/styles/styles.css - # Uncomment the following block if semantic release *should* commit the - # updated `manifest.json`, `versions.json` and `package.json` files with the new version number. - - - "@semantic-release/git" - - assets: - - manifest.json - - package.json - - package-lock.json - message: >- - chore: 🔖 set `package.json`, `manifest.json` and - `package-lock.json` to ${nextRelease.version} [skip ci] - - - ${nextRelease.notes} tagFormat: "${version}" From b47086aa04a2fe9717720fab0ac40e39365e5cec Mon Sep 17 00:00:00 2001 From: Johann Richard <189003+johannrichard@users.noreply.github.com> Date: Sun, 28 Jun 2026 17:12:35 +0200 Subject: [PATCH 14/19] fix: fix attestation path in .github/workflows/release.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 946d22f..552deb2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -59,5 +59,6 @@ jobs: uses: actions/attest@v4 with: subject-path: | - build/main.js - build/styles.css + main.js + manifest.json + src/ui/styles/styles.css From 995277a3daa8ab5b3070f54b88074ff5046c3807 Mon Sep 17 00:00:00 2001 From: Johann Richard <189003+johannrichard@users.noreply.github.com> Date: Sun, 28 Jun 2026 17:13:43 +0200 Subject: [PATCH 15/19] fix: bug: fix .github/workflows/release.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 552deb2..c55a459 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,12 +39,12 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: npx semantic-release - name: Configure Git - if: github.event_name == 'push' && github.ref == 'refs/heads/main' + if: github.event_name == 'push' && github.ref == 'refs/heads/master' run: | git config --global user.name "${{ github.actor }}" - git config --global user.email "${{ github.actor }}@users.noreply.github.com" + git config --global user.email "${{ github.actor }}`@users.noreply.github.com`" - name: Commit manifest.json (main only) - if: github.event_name == 'push' && github.ref == 'refs/heads/main' + if: github.event_name == 'push' && github.ref == 'refs/heads/master' run: | if git diff --quiet -- manifest.json; then echo "manifest.json unchanged; skipping commit" @@ -55,7 +55,7 @@ jobs: git commit -m "chore: 🔖 sync manifest version [skip ci]" git push - name: Generate artifact attestation (main release) - if: github.event_name == 'push' && github.ref == 'refs/heads/main' + if: github.event_name == 'push' && github.ref == 'refs/heads/master' uses: actions/attest@v4 with: subject-path: | From ca5f45d031846a8dbaf4239a6d52e1f47b5b124f Mon Sep 17 00:00:00 2001 From: Johann Richard <189003+johannrichard@users.noreply.github.com> Date: Sun, 28 Jun 2026 17:15:52 +0200 Subject: [PATCH 16/19] fix: :adhesive-bandage: normalise whitespace-only folder names before persisting [no-ci] Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- src/ui/settings-tab.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/settings-tab.ts b/src/ui/settings-tab.ts index 2d37d80..2c1b47a 100644 --- a/src/ui/settings-tab.ts +++ b/src/ui/settings-tab.ts @@ -557,8 +557,8 @@ export default class ReadwiseMirrorSettingTab extends PluginSettingTab { .setPlaceholder('Readwise') .setValue(this.ctx.settings.baseFolderName) .onChange(async (value) => { - if (!value) value = DEFAULT_SETTINGS.baseFolderName; - this.ctx.settings.baseFolderName = value; + const normalized = value.trim(); + this.ctx.settings.baseFolderName = normalized || DEFAULT_SETTINGS.baseFolderName; await this.ctx.saveAndApplySettings(); }) ); From 0d4c2df4de2f8123691be74870cb693231c9d1c2 Mon Sep 17 00:00:00 2001 From: Johann Richard <189003+johannrichard@users.noreply.github.com> Date: Sun, 28 Jun 2026 17:21:25 +0200 Subject: [PATCH 17/19] =?UTF-8?q?build:=20=F0=9F=A9=B9=20fix=20settings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 10c6e04..796b5a7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,26 +1,3 @@ { - "chat.tools.terminal.autoApprove": { - "/^obsidian vault=\"Obsidian Sandbox\" plugin:reload id=readwise-mirror$/": { - "approve": true, - "matchCommandLine": true - }, - "/^obsidian vault=\"Obsidian Sandbox\" plugin id=readwise-mirror$/": { - "approve": true, - "matchCommandLine": true - }, - "/^obsidian vault=\"Obsidian Sandbox\" commands filter=readwise$/": { - "approve": true, - "matchCommandLine": true - }, - "/^obsidian vault=\"Obsidian Sandbox\" command id=readwise-mirror:reset-last-updated$/": { - "approve": true, - "matchCommandLine": true - }, - "/^obsidian vault=\"Obsidian Sandbox\" command id=readwise-mirror:update$/": { - "approve": true, - "matchCommandLine": true - } - }, "jest.configPath": "jest.config.js" } - From 0fb6a15163f8e77a33a6fbc9cfb57dd6cfd065c4 Mon Sep 17 00:00:00 2001 From: Johann Richard <189003+johannrichard@users.noreply.github.com> Date: Sat, 11 Jul 2026 18:59:56 +0200 Subject: [PATCH 18/19] =?UTF-8?q?fix:=20=F0=9F=9A=91=EF=B8=8F=20fix=20regr?= =?UTF-8?q?ession=20with=20pagination=20(string=20=E2=86=92=20number)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/services/readwise-api.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/services/readwise-api.ts b/src/services/readwise-api.ts index 526c9ae..8be0499 100644 --- a/src/services/readwise-api.ts +++ b/src/services/readwise-api.ts @@ -121,7 +121,7 @@ export default class ReadwiseApi { ): Promise { const url = `${API_ENDPOINT}/${contentType}?`; let data: Record | undefined; - let nextPageCursor: string | undefined; + let nextPageCursor: number | undefined; let rateLimitRetries = 0; const results: Export[] = []; @@ -138,8 +138,8 @@ export default class ReadwiseApi { if (bookId && bookId.length > 0) { queryParams.append('ids', bookId.join(',')); } - if (nextPageCursor) { - queryParams.append('pageCursor', nextPageCursor); + if (nextPageCursor !== undefined) { + queryParams.append('pageCursor', nextPageCursor.toString()); } if (contentType === 'export' && includeDeleted) { queryParams.append('includeDeleted', 'true'); @@ -196,8 +196,8 @@ export default class ReadwiseApi { this.ctx.logger.warn('No results found in the response data.'); } const rawNextPageCursor = pageData.nextPageCursor; - nextPageCursor = typeof rawNextPageCursor === 'string' ? rawNextPageCursor : ''; - if (!nextPageCursor) { + nextPageCursor = typeof rawNextPageCursor === 'number' ? rawNextPageCursor : undefined; + if (nextPageCursor === undefined) { break; } this.ctx.logger.debug(`There are more records left, proceeding to next page: ${nextPageCursor}`); From b4bea3f88ab9b2017e16b24bc644b23ecfb29de6 Mon Sep 17 00:00:00 2001 From: Johann Richard <189003+johannrichard@users.noreply.github.com> Date: Sat, 11 Jul 2026 19:43:37 +0200 Subject: [PATCH 19/19] =?UTF-8?q?fix:=20=F0=9F=90=9B=20use=20unfiltered=20?= =?UTF-8?q?tags=20for=20created=20and=20updated,=20and=20filtered=20highli?= =?UTF-8?q?ghts=20for=20last=20updated=20date?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit make sure we always have a date for created / updated, even if there are no highlights (anymore). --- src/services/readwise-document-mapper.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/readwise-document-mapper.ts b/src/services/readwise-document-mapper.ts index 1c9123a..cf48b27 100644 --- a/src/services/readwise-document-mapper.ts +++ b/src/services/readwise-document-mapper.ts @@ -64,8 +64,8 @@ export function buildReadwiseDocument( ? `[[${author}]]` : ''; - const created = createdDate(filteredHighlights); - const updated = updatedDate(filteredHighlights); + const created = createdDate(highlights); + const updated = updatedDate(highlights); const lastHighlightAt = lastHighlightedDate(filteredHighlights); return {