215 lines
7.2 KiB
TypeScript
215 lines
7.2 KiB
TypeScript
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 → 织忆 可快速搜索记忆。选中文字后右键或命令面板选择「将选中内容写入织忆」可保存笔记。");
|
||
}
|
||
} |