memoryweave/plugins/obsidian/main.ts

215 lines
7.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { App, Plugin, PluginSettingTab, Setting, moment } from "obsidian";
import { MemoryView, MEMORY_VIEW_TYPE } from "./src/MemoryView";
import { GraphView, GRAPH_VIEW_TYPE } from "./src/GraphView";
import { SearchModal } from "./src/SearchModal";
import { setRuntimeConfig, getApiBase, getApiKey, getRuntimeNamespace, writeMemory } from "./src/api";
const SETTINGS_FILE = "zhiyi-settings.json";
interface ZhiYiSettings {
apiUrl: string;
apiKey: string;
namespace: string;
}
const DEFAULT_SETTINGS: ZhiYiSettings = {
apiUrl: "http://localhost:7821",
apiKey: "zhiyi-dev-key-2026",
namespace: "hermes-main",
};
export default class ZhiYiPlugin extends Plugin {
private settings: ZhiYiSettings = { ...DEFAULT_SETTINGS };
private ribbonIcon: HTMLElement | null = null;
async onload() {
// 加载持久化设置
await this.loadSettings();
// 注册视图
this.registerView(MEMORY_VIEW_TYPE, (leaf) => new MemoryView(leaf));
this.registerView(GRAPH_VIEW_TYPE, (leaf) => new GraphView(leaf));
// ─── 命令 ─────────────────────────────────────────────────────
this.addCommand({
id: "zhiyi-open-memory-view",
name: "打开织忆记忆面板",
callback: () => this.openMemoryView(),
});
this.addCommand({
id: "zhiyi-open-graph-view",
name: "打开织忆图谱面板",
callback: () => this.openGraphView(),
});
this.addCommand({
id: "zhiyi-search-memories",
name: "搜索织忆记忆",
callback: () => this.openSearchModal(),
});
// 写记忆(选中文本)
this.addCommand({
id: "zhiyi-write-memory",
name: "将选中内容写入织忆",
editorCallback: (editor) => {
const selection = editor.getSelection();
if (selection) {
this.openWriteModal(selection);
}
},
});
// Ribbon 图标
this.ribbonIcon = this.addStatusBarItem();
this.ribbonIcon.setIcon("brain");
this.ribbonIcon.setTooltip("织忆记忆");
this.ribbonIcon.onClick(() => this.openMemoryView());
// 状态栏
this.addStatusBarItem().setText("🧠 织忆 v1.1");
// 设置页
this.addSettingTab(new ZhiYiSettingTab(this.app, this));
}
onunload() {
this.app.workspace.getLeavesOfType(MEMORY_VIEW_TYPE).forEach((leaf) => leaf.detach());
this.app.workspace.getLeavesOfType(GRAPH_VIEW_TYPE).forEach((leaf) => leaf.detach());
}
// ─── 设置读写 ───────────────────────────────────────────────────
async loadSettings() {
try {
const data = await this.loadData(SETTINGS_FILE);
if (data) {
this.settings = { ...DEFAULT_SETTINGS, ...data };
}
} catch {
this.settings = { ...DEFAULT_SETTINGS };
}
// 同步到 api 运行时配置
setRuntimeConfig(this.settings.apiUrl, this.settings.apiKey, this.settings.namespace);
}
async saveSettings() {
await this.saveData(this.settings, SETTINGS_FILE);
setRuntimeConfig(this.settings.apiUrl, this.settings.apiKey, this.settings.namespace);
}
getSettings() { return this.settings; }
// ─── 视图操作 ────────────────────────────────────────────────────
async openMemoryView() {
const leaf = this.app.workspace.getLeaf("right");
await leaf.setViewState({ type: MEMORY_VIEW_TYPE, active: true });
this.app.workspace.revealLeaf(leaf);
}
async openGraphView() {
const leaf = this.app.workspace.getLeaf("right");
await leaf.setViewState({ type: GRAPH_VIEW_TYPE, active: true });
this.app.workspace.revealLeaf(leaf);
}
openSearchModal() {
const modal = new SearchModal(this.app);
modal.onSelect = (id, content) => {
navigator.clipboard.writeText(content).catch(() => {});
(this.app as unknown as { notify: (m: string) => void }).notify(
`已复制: ${content.slice(0, 80)}`
);
};
modal.open();
}
// 写入记忆模态框
private openWriteModal(initialContent = "") {
const { writeMemory } = require("./src/api");
// 使用 Obsidian 的 PromptModal 或简易 confirm
const content = initialContent || window.prompt("输入记忆内容:");
if (!content?.trim()) return;
const category = window.prompt("分类(可选,如 normal/user_pref/project", "normal") || "normal";
writeMemory(content.trim(), category, this.settings.namespace)
.then(() => {
(this.app as unknown as { notify: (m: string) => void }).notify("✅ 记忆已写入织忆");
})
.catch((e: Error) => {
(this.app as unknown as { notify: (m: string) => void }).notify(`❌ 写入失败: ${e.message}`);
});
}
}
// ─── 设置页 ────────────────────────────────────────────────────────────────
class ZhiYiSettingTab extends PluginSettingTab {
constructor(app: App, private plugin: ZhiYiPlugin) {
super(app, plugin);
}
display() {
const { containerEl } = this;
containerEl.empty();
containerEl.createEl("h2", { text: "🧠 织忆设置" });
new Setting(containerEl)
.setName("API 地址")
.setDesc("织忆 Go API 服务地址(默认 http://localhost:7821")
.addText((text) => {
text.setPlaceholder("http://localhost:7821")
.setValue(this.plugin.getSettings().apiUrl)
.onChange(async (val) => {
this.plugin.getSettings().apiUrl = val;
await this.plugin.saveSettings();
});
});
new Setting(containerEl)
.setName("API Key")
.setDesc("织忆认证密钥")
.addText((text) => {
text.setPlaceholder("zhiyi-dev-key-2026")
.setValue(this.plugin.getSettings().apiKey)
.onChange(async (val) => {
this.plugin.getSettings().apiKey = val;
await this.plugin.saveSettings();
});
});
new Setting(containerEl)
.setName("默认 Namespace")
.setDesc("搜索和查询使用的默认命名空间")
.addText((text) => {
text.setValue(this.plugin.getSettings().namespace)
.onChange(async (val) => {
this.plugin.getSettings().namespace = val;
await this.plugin.saveSettings();
});
});
new Setting(containerEl)
.setName("记忆面板")
.addButton((btn) =>
btn.setButtonText("打开 🧠").onClick(() => {
(this.plugin as unknown as { openMemoryView: () => void }).openMemoryView();
})
);
new Setting(containerEl)
.setName("图谱面板")
.addButton((btn) =>
btn.setButtonText("打开 📐").onClick(() => {
(this.plugin as unknown as { openGraphView: () => void }).openGraphView();
})
);
new Setting(containerEl)
.setName("说明")
.setDesc("Ctrl+P → 织忆 可快速搜索记忆。选中文字后右键或命令面板选择「将选中内容写入织忆」可保存笔记。");
}
}