summaryrefslogtreecommitdiffhomepage
path: root/src/main.ts
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-03-29 13:25:18 +0900
committerAdam Malczewski <[email protected]>2026-03-29 13:25:18 +0900
commit90346a91a81c317b90f4ca9a64cbaaf0ade7868b (patch)
tree0be851269904a3ef76f16cff9d384914face8927 /src/main.ts
parentbffeac84cb7b3094f7a4b879b6bab6ceaec561ac (diff)
downloadai-pulse-obsidian-plugin-90346a91a81c317b90f4ca9a64cbaaf0ade7868b.tar.gz
ai-pulse-obsidian-plugin-90346a91a81c317b90f4ca9a64cbaaf0ade7868b.zip
add persistent chat history with cross-device sync
Diffstat (limited to 'src/main.ts')
-rw-r--r--src/main.ts66
1 files changed, 66 insertions, 0 deletions
diff --git a/src/main.ts b/src/main.ts
index 12dadaf..96eb207 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -4,6 +4,8 @@ import { DEFAULT_SETTINGS } from "./settings";
import { ChatView, VIEW_TYPE_CHAT } from "./chat-view";
import { testConnection, listModels } from "./ollama-client";
import { getDefaultToolStates } from "./tools";
+import { loadChatHistory } from "./chat-history";
+import type { PersistedMessage } from "./chat-history";
export default class AIPulse extends Plugin {
settings: AIPulseSettings = DEFAULT_SETTINGS;
@@ -13,6 +15,9 @@ export default class AIPulse extends Plugin {
connectionMessage = "";
availableModels: string[] = [];
+ // Snapshot of persisted chat history for sync change detection
+ private lastChatSnapshot = "";
+
async onload(): Promise<void> {
await this.loadSettings();
@@ -29,6 +34,14 @@ export default class AIPulse extends Plugin {
void this.activateView();
},
});
+
+ // Detect chat history changes from Obsidian Sync or other devices.
+ // We check when the app regains visibility (user switches back from another app/device).
+ this.registerDomEvent(document, "visibilitychange", () => {
+ if (document.visibilityState === "visible") {
+ void this.checkChatHistorySync();
+ }
+ });
}
onunload(): void {
@@ -72,6 +85,47 @@ export default class AIPulse extends Plugin {
await this.saveData(this.settings);
}
+ /**
+ * Called by Obsidian when data.json is modified externally (e.g., via Sync).
+ * This is a strong signal that other plugin files may also have been synced.
+ */
+ async onExternalSettingsChange(): Promise<void> {
+ await this.loadSettings();
+ void this.checkChatHistorySync();
+ }
+
+ /**
+ * Check if the persisted chat history has changed (e.g., from another device)
+ * and reload the chat view if needed.
+ */
+ async checkChatHistorySync(): Promise<void> {
+ try {
+ const persisted = await loadChatHistory(this.app, this.manifest.id);
+ const snapshot = buildChatSnapshot(persisted);
+
+ if (snapshot === this.lastChatSnapshot) return;
+ this.lastChatSnapshot = snapshot;
+
+ // Find the active chat view and reload it
+ const leaves = this.app.workspace.getLeavesOfType(VIEW_TYPE_CHAT);
+ for (const leaf of leaves) {
+ const view = leaf.view;
+ if (view instanceof ChatView) {
+ void view.reloadChatHistory();
+ }
+ }
+ } catch {
+ // Silently ignore — sync check is best-effort
+ }
+ }
+
+ /**
+ * Update the snapshot after a local save so we don't trigger a false reload.
+ */
+ updateChatSnapshot(messages: PersistedMessage[]): void {
+ this.lastChatSnapshot = buildChatSnapshot(messages);
+ }
+
async connect(): Promise<void> {
this.connectionStatus = "connecting";
this.connectionMessage = "Connecting...";
@@ -99,3 +153,15 @@ export default class AIPulse extends Plugin {
}
}
}
+
+/**
+ * Build a lightweight snapshot string of chat messages for change detection.
+ * Uses message count + last message content hash to detect changes
+ * without deep comparison.
+ */
+function buildChatSnapshot(messages: PersistedMessage[]): string {
+ if (messages.length === 0) return "empty";
+ const last = messages[messages.length - 1];
+ if (last === undefined) return "empty";
+ return `${messages.length}:${last.role}:${last.content.length}:${last.content.slice(0, 100)}`;
+}