History Plugin (@lapis-notes/history)
Source target: packages/plugins/plugin-history/src/
Manifest target: id plugin-history, version 0.0.1, min app version 1.7.7.
The History plugin is a first-party core plugin for persisting text-file revision history so users can inspect previous versions of a file and restore a selected revision.
Ownership
The plugin owns the user-facing history workflow:
- Capture debounced text-file snapshots from vault create, modify, rename, delete, and restore flows.
- Provide a workspace history sidebar for the active file plus a main-area compare tab for selected revisions.
- Render a revision list, a syntax-highlighted unified comparison editor, and restore actions.
- Expose settings for revision retention, debounce timing, maximum tracked file size, and tracked extensions.
Generated revision storage belongs to AppDatabase; the plugin must not write
history snapshots into user note folders or .obsidian/. The shared persistence
contract is documented in
File System, Metadata, and Search.
Revision Model
The first rollout stores bounded full-text snapshots rather than patch deltas. Each stored revision records:
- stable file identity and current path
- path at the time the revision was captured
- event type:
baseline,create,modify,rename,delete, orrestore - creation time, source file mtime, source file size, and content hash
- UTF-8 text content
The storage layer deduplicates consecutive revisions with the same content hash and prunes old revisions according to the configured per-file retention limit. The default policy is 100 revisions per file, a 2 MiB maximum tracked file size, and a 2 s per-path debounce window.
File Scope
The planned v1 scope is text files only. Markdown, canvas JSON, bases, notebook
documents, and other UTF-8 text formats may be tracked when they are below the
configured size limit. Binary files and files under .obsidian/ are skipped.
The plugin should treat read failures, oversized files, and invalid text content as skipped captures rather than plugin failures.
View, Commands, And Settings
Workspace surface:
- View type:
HistoryViewType = "history". - Compare view type:
HistoryCompareViewType = "history-compare". - Command:
plugin-history:open-file-history, opening the history view for the active file, preferably in the right sidebar. - Ribbon action: icon-only history action using the plugin command.
- Settings tab: retention count, debounce window, maximum tracked file size, and tracked extension list.
The history sidebar shows the active file path and revision count above a
compact VS Code-style timeline. Timeline rows are newest-first, use rail
markers, relative timestamps, event labels such as File Saved or Restored,
and active-row highlighting. Clicking a timeline row opens or reuses a normal
main-area history-compare workspace tab and compares that revision against the
current file by default.
The compare surface uses CodeMirror’s unified merge extension with history-specific
per-chunk Take revision and Keep current controls on changed regions when
comparing against the live file. Changed current-file lines are highlighted in
green, and revision-only text appears in red deleted-chunk blocks above the
editor. Unchanged regions are not collapsed, so the full compare document stays
visible. Select an older revision to see differences against the current
file; the newest revision usually matches the live file and shows no diff.
Take revision applies the selected revision into the editable compare
document; Keep current dismisses the chunk while keeping the current side.
Those chunk actions update the in-memory compare buffer only until Save current
file writes back through the vault API. The diff
editor resolves the tracked file through determineViewTypeForPath() and injects
the same source-mode editor extensions and workspace editor configuration that a
normal file editor receives, so syntax, line numbers, wrap, indent settings, and
source-mode plugin extensions stay consistent. The current-file editor becomes
editable when comparing a revision against the live file and can be saved back
through the normal vault API. Compare with previous is read-only and hides
chunk action controls.
The compare tab keeps the diff body simple: it does not render a revision aside or component-local toolbar. Compare current, compare previous, save current file, restore, and close are exposed as icon-only workspace view-header actions when the tab title bar is enabled.
Restoring a revision writes through app.vault.modify(), records a restore
revision, and avoids creating a duplicate follow-up modify revision for the
same content hash.
The bundled workspace and web hosts register the plugin as a core plugin and include its CSS through the workspace app bundle.
Rename, Delete, And Restore Behavior
History follows file renames by moving the stable file identity to the new path and recording a rename revision. Deleting a file records delete state for the history identity without deleting prior revisions, so a user can still inspect or copy the latest known content from the history view.
Restore is intentionally file-first: it writes selected text back to the current vault file through the normal vault API, so metadata, search, and file watchers observe the same modify flow as ordinary edits.
Validation Expectations
Current validation covers:
- App-database storage contracts across memory, IndexedDB, SQLite worker, and coordinated proxy paths.
- Direct history-plugin runtime coverage for command and view registration, baseline capture, rename or delete behavior, and restore duplicate suppression.
- Workspace Playwright UI-smoke coverage for opening history, selecting a revision, launching the compare tab, verifying the syntax-highlighted unified diff surface, visible green/red diff decorations, Take revision / Keep current chunk controls, saving current-file edits, and restoring a selected revision through the compare view.