vault backup: 2026-01-31 08:25:19

This commit is contained in:
windyboy
2026-01-31 08:25:19 +08:00
parent 0450479e72
commit b83116eb26
35 changed files with 52219 additions and 25059 deletions
+49908
View File
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
-11
View File
@@ -1,11 +0,0 @@
{
"id": "mcp-tools",
"name": "MCP Tools",
"version": "0.2.27",
"minAppVersion": "0.15.0",
"description": "Securely connect Claude Desktop to your vault with semantic search, templates, and file management capabilities.",
"author": "Jack Steam",
"authorUrl": "https://github.com/jacksteamdev",
"fundingUrl": "https://github.com/sponsors/jacksteamdev",
"isDesktopOnly": true
}
-7
View File
@@ -1,7 +0,0 @@
{
"dailyMemosHeader": "Memos",
"memosAPIVersion": "v0.24.0",
"memosAPIURL": "https://memos.windy.me",
"memosAPIToken": "eyJhbGciOiJIUzI1NiIsImtpZCI6InYxIiwidHlwIjoiSldUIn0.eyJuYW1lIjoiemhpcWlhbmciLCJpc3MiOiJtZW1vcyIsInN1YiI6IjEiLCJhdWQiOlsidXNlci5hY2Nlc3MtdG9rZW4iXSwiaWF0IjoxNzY3NDA0MzY0fQ.SR4a3nn3myQUiPV3tJGLpKs_XgpFaOM_aK0i2CmNGoY",
"attachmentFolder": "Attachments"
}
File diff suppressed because it is too large Load Diff
-10
View File
@@ -1,10 +0,0 @@
{
"id": "memos-sync",
"name": "Memos Sync",
"version": "0.5.2",
"minAppVersion": "1.5.12",
"description": "Syncing memos from a [Memos](https://github.com/usememos/memos) server to your daily note. Fully compatible with official Daily Notes plugin, Calendar plugin and Periodic Notes plugin.",
"author": "RyoJerryYu",
"authorUrl": "https://github.com/RyoJerryYu",
"isDesktopOnly": true
}
-8
View File
@@ -1,8 +0,0 @@
/*
This CSS file will be included with your plugin, and
available in the app when your plugin is enabled.
If your plugin does not need CSS, delete this file.
*/
+692
View File
@@ -0,0 +1,692 @@
/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/main.ts
var main_exports = {};
__export(main_exports, {
default: () => NoteBuddyPlugin
});
module.exports = __toCommonJS(main_exports);
var import_obsidian4 = require("obsidian");
// src/chat-view.ts
var import_obsidian2 = require("obsidian");
// src/service.ts
var import_obsidian = require("obsidian");
// src/models.ts
var defaultSettings = {
serviceUrl: "http://127.0.0.1:4096"
};
var MODELS_CACHE_TTL = 5 * 60 * 1e3;
// src/service.ts
var OpenCodeClient = class _OpenCodeClient {
constructor(serviceUrl, defaultModelId, onModelUnavailable) {
this.session = null;
this.cachedProviders = null;
this.providersCacheTime = 0;
this.cachedDefaults = null;
this.serviceUrl = serviceUrl;
this.defaultModelId = defaultModelId;
this.onModelUnavailable = onModelUnavailable;
}
static {
this.DEFAULT_REQUEST_TIMEOUT_MS = 1e4;
}
static {
this.MESSAGE_REQUEST_TIMEOUT_MS = 6e4;
}
async request(options, timeoutMs = _OpenCodeClient.DEFAULT_REQUEST_TIMEOUT_MS) {
return await Promise.race([
(0, import_obsidian.requestUrl)(options),
new Promise(
(_, reject) => setTimeout(() => reject(new Error(`Request timeout after ${timeoutMs / 1e3} seconds`)), timeoutMs)
)
]);
}
async healthCheck() {
const url = `${this.serviceUrl}/global/health`;
try {
const response = await this.request({
url,
method: "GET"
});
if (response.status === 200 && response.json.healthy === true) {
return {
status: "connected" /* Connected */,
lastTestTime: Date.now()
};
} else {
return {
status: "disconnected" /* Disconnected */,
lastTestTime: Date.now(),
lastError: `Service unhealthy or unreachable`
};
}
} catch (error) {
const err = error;
return {
status: "disconnected" /* Disconnected */,
lastTestTime: Date.now(),
lastError: err.message || "Unknown error"
};
}
}
async createSession() {
const url = `${this.serviceUrl}/session`;
try {
const response = await this.request({
url,
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({})
});
if (response.status === 200) {
const data = response.json;
return {
sessionID: data.id,
createTime: data.time.created,
title: data.title
};
}
if (response.status === 400) {
const details = this.formatBadRequest(response.json, response.text);
throw new Error(details);
}
throw new Error(`HTTP ${response.status}: ${response.text}`);
} catch (error) {
const err = error;
throw new Error(`Failed to create session: ${err.message}`);
}
}
formatBadRequest(payload, fallbackText) {
if (!payload || typeof payload !== "object") {
return `Bad request: ${fallbackText || "Unknown error"}`;
}
const p = payload;
const errText = typeof p.errors === "string" ? p.errors : p.errors ? JSON.stringify(p.errors) : "";
const dataText = p.data ? JSON.stringify(p.data) : "";
const msg = [errText, dataText].filter(Boolean).join(" ");
return msg ? `Bad request: ${msg}` : `Bad request: ${fallbackText || "Unknown error"}`;
}
formatNotFound(payload, fallbackText) {
if (!payload || typeof payload !== "object") {
return fallbackText || "Not found";
}
const p = payload;
const name = typeof p.name === "string" ? p.name : "";
const data = p.data ? JSON.stringify(p.data) : "";
return [name, data].filter(Boolean).join(" ") || fallbackText || "Not found";
}
async sendMessageInternal(sessionID, message) {
const url = `${this.serviceUrl}/session/${sessionID}/message`;
try {
const response = await this.request(
{
url,
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(message)
},
_OpenCodeClient.MESSAGE_REQUEST_TIMEOUT_MS
);
if (response.status === 200) {
const raw = (response.text ?? "").trim();
if (!raw) {
throw new Error("Server returned empty response");
}
let data;
try {
data = JSON.parse(raw);
} catch {
throw new Error(`Invalid JSON response: ${raw.slice(0, 50)}${raw.length > 50 ? "..." : ""}`);
}
if (!data || typeof data !== "object" || !Array.isArray(data.parts)) {
throw new Error("Invalid response shape (expected {info, parts[]})");
}
return data;
}
if (response.status === 400) {
const payload = response.json;
throw new Error(this.formatBadRequest(payload, response.text));
}
if (response.status === 404) {
const payload = response.json;
throw new Error(`Session not found: ${this.formatNotFound(payload, response.text)}`);
}
throw new Error(`HTTP ${response.status}: ${response.text}`);
} catch (error) {
const err = error;
throw new Error(`Failed to send message: ${err.message}`);
}
}
async sendMessage(input) {
if (!this.session) {
this.session = await this.createSession();
}
const message = {
parts: [{ type: "text", text: input }]
};
if (this.defaultModelId) {
const parts = this.defaultModelId.split("/");
if (parts.length === 2) {
message.model = {
providerID: parts[0],
modelID: parts[1]
};
}
}
let response;
try {
response = await this.sendMessageInternal(this.session.sessionID, message);
} catch (error) {
const err = error;
if (message.model && this.isLikelyModelError(err)) {
console.log("[NoteBuddy] Selected model unavailable, falling back to server default");
if (this.onModelUnavailable) {
this.onModelUnavailable();
}
const fallbackMessage = {
parts: message.parts
};
response = await this.sendMessageInternal(this.session.sessionID, fallbackMessage);
} else {
throw error;
}
}
const assistantText = response.parts.filter((part) => part.type === "text").map((part) => part.type === "text" ? part.text : "").filter(Boolean).join("\n");
return assistantText;
}
async sendMessageToSession(sessionID, message) {
return await this.sendMessageInternal(sessionID, message);
}
isModelsCacheValid() {
if (!this.cachedProviders) {
return false;
}
const now = Date.now();
return now - this.providersCacheTime < MODELS_CACHE_TTL;
}
clearModelsCache() {
this.cachedProviders = null;
this.providersCacheTime = 0;
this.cachedDefaults = null;
}
async getCapabilities(forceRefresh = false) {
const now = Date.now();
if (!forceRefresh && this.cachedProviders && now - this.providersCacheTime < MODELS_CACHE_TTL) {
return this.cachedProviders;
}
const url = `${this.serviceUrl}/config/providers`;
try {
const response = await this.request({
url,
method: "GET"
});
if (response.status === 200) {
let data;
try {
data = response.json;
} catch {
const preview = (response.text || "").trim().slice(0, 50);
if (preview.toLowerCase().startsWith("<!")) {
throw new Error(
"Server returned HTML instead of JSON. Check the Service URL and ensure the server exposes /config/providers."
);
}
throw new Error(`Invalid JSON response: ${preview}...`);
}
const raw = data.providers || [];
this.cachedDefaults = data.default || {};
const providers = raw.map((p) => ({
id: p.id,
name: p.name,
models: Object.entries(p.models || {}).map(([id, m]) => ({ id, name: m?.name ?? id }))
}));
this.cachedProviders = providers;
this.providersCacheTime = now;
return providers;
} else {
throw new Error(`HTTP ${response.status}: ${response.text}`);
}
} catch (error) {
const err = error;
throw new Error(`Failed to get capabilities: ${err.message}`);
}
}
isLikelyModelError(err) {
const msg = (err.message || "").toLowerCase();
return msg.includes("model") && (msg.includes("not found") || msg.includes("invalid") || msg.includes("unknown"));
}
};
// src/chat-view.ts
var VIEW_TYPE_CHAT = "note-buddy-chat-view";
var ChatView = class extends import_obsidian2.ItemView {
constructor(leaf, plugin) {
super(leaf);
this.plugin = plugin;
this.messages = [];
this.client = new OpenCodeClient(
plugin.settings.serviceUrl,
plugin.settings.defaultModelId,
plugin.onModelUnavailable?.bind(plugin)
);
}
getViewType() {
return VIEW_TYPE_CHAT;
}
getDisplayText() {
return "NoteBuddy Chat";
}
async onOpen() {
const container = this.containerEl.children[1];
container.empty();
const chatContainer = container.createDiv({ cls: "nb-chat-container" });
chatContainer.style.cssText = `
display: flex;
flex-direction: column;
height: 100%;
gap: 1rem;
`;
const messagesContainer = chatContainer.createDiv({ cls: "nb-messages-container" });
this.messagesContainer = messagesContainer;
messagesContainer.style.cssText = `
flex: 1;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 0.5rem;
padding: 1rem;
`;
this.renderMessages();
const welcomeMessage = messagesContainer.createDiv({ cls: "nb-message nb-message-system" });
welcomeMessage.createSpan({ text: "Welcome to NoteBuddy! Chat with your notes here." });
welcomeMessage.style.cssText = `
padding: 0.75rem;
background-color: var(--background-secondary);
border-radius: 0.5rem;
font-size: 0.9rem;
color: var(--text-muted);
`;
const inputContainer = chatContainer.createDiv({ cls: "nb-input-container" });
inputContainer.style.cssText = `
display: flex;
gap: 0.5rem;
padding: 1rem;
border-top: 1px solid var(--background-modifier-border);
`;
const textarea = inputContainer.createEl("textarea", {
cls: "nb-chat-input",
attr: { placeholder: "Type your message..." }
});
textarea.style.cssText = `
flex: 1;
min-height: 60px;
max-height: 150px;
padding: 0.5rem;
border: 1px solid var(--background-modifier-border);
border-radius: 0.375rem;
background-color: var(--background-primary);
color: var(--text-normal);
resize: vertical;
font-family: inherit;
`;
const sendButton = inputContainer.createEl("button", {
cls: "nb-send-button",
text: "Send"
});
sendButton.style.cssText = `
padding: 0.5rem 1rem;
background-color: var(--interactive-accent);
color: var(--text-on-accent);
border: none;
border-radius: 0.375rem;
cursor: pointer;
font-weight: 500;
`;
const sendMessage = async () => {
const message = textarea.value.trim();
if (!message) return;
this.messages.push({ kind: "userText", text: message });
this.renderMessages();
textarea.value = "";
try {
if (!this.plugin.sessionState) {
this.plugin.sessionState = await this.client.createSession();
}
const sendData = {
parts: [{ type: "text", text: message }]
};
if (this.plugin.settings.defaultModelId) {
const parts = this.plugin.settings.defaultModelId.split("/");
if (parts.length === 2) {
sendData.model = {
providerID: parts[0],
modelID: parts[1]
};
}
}
let response;
try {
response = await this.client.sendMessageToSession(this.plugin.sessionState.sessionID, sendData);
} catch (sendError) {
const err = sendError;
if (err.message.includes("Session not found")) {
this.plugin.sessionState = await this.client.createSession();
response = await this.client.sendMessageToSession(this.plugin.sessionState.sessionID, sendData);
} else {
throw sendError;
}
}
for (const part of response.parts) {
this.messages.push({ kind: "assistantPart", part });
}
this.renderMessages();
this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight;
} catch (error) {
console.error("[NoteBuddy] Send failed:", error);
new import_obsidian2.Notice(`Failed to send message: ${error.message}`);
}
};
sendButton.onclick = sendMessage;
textarea.addEventListener("keydown", (e) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
sendMessage();
}
});
}
async onClose() {
console.log("[NoteBuddy] Chat view closed");
}
renderMessages() {
this.messagesContainer.empty();
if (this.messages.length === 0) {
const welcomeMessage = this.messagesContainer.createDiv({ cls: "nb-message nb-message-system" });
welcomeMessage.createSpan({ text: "Welcome to NoteBuddy! Chat with your notes here." });
welcomeMessage.style.cssText = `
padding: 0.75rem;
background-color: var(--background-secondary);
border-radius: 0.5rem;
font-size: 0.9rem;
color: var(--text-muted);
`;
return;
}
for (const item of this.messages) {
if (item.kind === "userText") {
const messageEl2 = this.messagesContainer.createDiv({ cls: "nb-message nb-message-user" });
messageEl2.createSpan({ text: item.text });
messageEl2.style.cssText = `
padding: 0.75rem;
background-color: var(--background-modifier-accent);
border-radius: 0.5rem;
font-size: 0.9rem;
align-self: flex-end;
max-width: 70%;
`;
continue;
}
const part = item.part;
const messageEl = this.messagesContainer.createDiv({ cls: "nb-message nb-message-assistant" });
messageEl.style.cssText = `
padding: 0.75rem;
background-color: var(--background-secondary);
border-radius: 0.5rem;
font-size: 0.9rem;
align-self: flex-start;
max-width: 70%;
`;
switch (part.type) {
case "text":
messageEl.createSpan({ text: part.text });
break;
case "reasoning":
messageEl.createSpan({ text: part.text });
break;
case "tool":
messageEl.createEl("strong", { text: `Tool: ${part.tool}` });
messageEl.createEl("pre", { text: JSON.stringify(part.state ?? {}, null, 2) });
break;
case "patch":
messageEl.createEl("strong", { text: `Patch: ${part.hash}` });
messageEl.createEl("pre", { text: (part.files || []).join("\n") });
break;
case "file":
messageEl.createEl("strong", { text: `File: ${part.filename ?? part.url}` });
messageEl.createEl("div", { text: `mime: ${part.mime}` });
messageEl.createEl("div", { text: `url: ${part.url}` });
break;
case "agent":
messageEl.createEl("strong", { text: `Agent: ${part.name}` });
break;
case "step_start":
messageEl.createEl("strong", { text: `Step start${part.title ? `: ${part.title}` : ""}` });
break;
case "step_finish":
messageEl.createEl("strong", { text: `Step finish${part.title ? `: ${part.title}` : ""}` });
break;
case "snapshot":
messageEl.createEl("strong", { text: "Snapshot" });
messageEl.createEl("pre", { text: JSON.stringify(part, null, 2) });
break;
case "retry":
messageEl.createEl("strong", { text: "Retry" });
messageEl.createEl("pre", { text: JSON.stringify(part, null, 2) });
break;
case "compaction":
messageEl.createEl("strong", { text: "Compaction" });
messageEl.createEl("pre", { text: JSON.stringify(part, null, 2) });
break;
case "unknown":
messageEl.createEl("strong", {
text: `Unsupported part type: ${part.originalType}`
});
messageEl.createEl("pre", { text: JSON.stringify(part, null, 2) });
break;
}
}
}
};
// src/settings.ts
var import_obsidian3 = require("obsidian");
var NoteBuddySettingTab = class extends import_obsidian3.PluginSettingTab {
constructor(app, plugin) {
super(app, plugin);
this.providers = [];
this.isLoadingModels = false;
this.plugin = plugin;
}
async display(useCachedProviders) {
const { containerEl } = this;
containerEl.empty();
containerEl.createEl("h2", { text: "NoteBuddy Settings" });
if (!useCachedProviders) {
try {
await this.loadProviders();
} catch {
}
}
new import_obsidian3.Setting(containerEl).setName("Service URL").setDesc("The URL of the OpenCode service (must include protocol, hostname, and port)").addText(
(text) => text.setPlaceholder("http://127.0.0.1:4096").setValue(this.plugin.settings.serviceUrl).onChange(async (value) => {
if (!value.startsWith("http://") && !value.startsWith("https://")) {
new import_obsidian3.Notice("Service URL must start with http:// or https://");
return;
}
try {
const url = new URL(value);
if (!url.hostname || url.hostname === "") {
new import_obsidian3.Notice("Service URL must include a valid hostname");
return;
}
if (!url.port || url.port === "") {
new import_obsidian3.Notice("Service URL must include a port number");
return;
}
} catch (e) {
new import_obsidian3.Notice("Service URL must be a valid URL format");
return;
}
this.plugin.settings.serviceUrl = value;
await this.plugin.saveSettings();
})
);
new import_obsidian3.Setting(containerEl).setName("Test Connection").setDesc("Test the connection to the service").addButton(
(button) => button.setButtonText("Test").setCta().onClick(async () => {
const client = new OpenCodeClient(this.plugin.settings.serviceUrl, this.plugin.settings.defaultModelId);
const result = await client.healthCheck();
if (result.status === "connected") {
new import_obsidian3.Notice("Connection successful!");
} else {
new import_obsidian3.Notice(`Connection failed: ${result.lastError}`);
}
})
);
this.displayModelSelection(containerEl);
this.displayRefreshButton(containerEl);
}
async loadProviders(client, forceRefresh) {
if (this.isLoadingModels) {
return;
}
this.isLoadingModels = true;
try {
const c = client ?? new OpenCodeClient(this.plugin.settings.serviceUrl, this.plugin.settings.defaultModelId);
this.providers = await c.getCapabilities(forceRefresh ?? false);
} catch (error) {
this.providers = [];
console.error("[NoteBuddy] Failed to load providers:", error);
throw error;
} finally {
this.isLoadingModels = false;
}
}
displayModelSelection(containerEl) {
const modelOptions = {};
modelOptions[""] = "Use server default";
for (const provider of this.providers) {
for (const model of provider.models) {
const value = `${provider.id}/${model.id}`;
modelOptions[value] = `${provider.name} - ${model.name}`;
}
}
const currentValue = this.getCurrentModelSelection();
new import_obsidian3.Setting(containerEl).setName("Default Model").setDesc("Select the default AI model to use for conversations").addDropdown(
(dropdown) => dropdown.addOptions(modelOptions).setValue(currentValue).onChange(async (value) => {
if (value) {
this.plugin.settings.defaultModelId = value;
} else {
this.plugin.settings.defaultModelId = void 0;
}
await this.plugin.saveSettings();
})
);
}
getCurrentModelSelection() {
return this.plugin.settings.defaultModelId || "";
}
displayRefreshButton(container) {
new import_obsidian3.Setting(container).setName("Refresh Models").setDesc("Reload the list of available models from the service").addButton(
(button) => button.setButtonText("Refresh").onClick(async () => {
const client = new OpenCodeClient(this.plugin.settings.serviceUrl, this.plugin.settings.defaultModelId);
client.clearModelsCache();
try {
await this.loadProviders(client, true);
new import_obsidian3.Notice("Models refreshed");
await this.display(true);
} catch (error) {
console.error("[NoteBuddy] Failed to load providers:", error);
new import_obsidian3.Notice(`Failed to refresh models: ${error.message}`);
await this.display(true);
}
})
);
}
};
// src/main.ts
var DEFAULT_SETTINGS = defaultSettings;
var NoteBuddyPlugin = class extends import_obsidian4.Plugin {
constructor() {
super(...arguments);
this.ribbonIconEl = null;
}
async onload() {
console.log("Loading NoteBuddy plugin...");
await this.loadSettings();
this.registerView(
VIEW_TYPE_CHAT,
(leaf) => new ChatView(leaf, this)
);
this.addRibbonIcon("bot", "NoteBuddy", () => {
this.activateView();
});
this.addCommand({
id: "open-chat-view",
name: "Open NoteBuddy Chat",
callback: () => {
this.activateView();
}
});
this.app.workspace.onLayoutReady(() => {
this.activateView();
});
this.addSettingTab(new NoteBuddySettingTab(this.app, this));
}
onunload() {
console.log("Unloading NoteBuddy plugin...");
}
async activateView() {
const { workspace } = this.app;
let leaf = null;
const leaves = workspace.getLeavesOfType(VIEW_TYPE_CHAT);
if (leaves.length > 0) {
leaf = leaves[0];
} else {
leaf = workspace.getRightLeaf(false);
}
if (leaf) {
await workspace.setActiveLeaf(leaf);
await leaf.setViewState({ type: VIEW_TYPE_CHAT, active: true });
}
}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}
// Callback for when selected model is unavailable
onModelUnavailable() {
new import_obsidian4.Notice("Selected model is unavailable. Using server default instead.");
}
async saveSettings() {
await this.saveData(this.settings);
}
};
+48
View File
@@ -0,0 +1,48 @@
.note-buddy-chat {
height: 100%;
display: flex;
flex-direction: column;
background-color: var(--background-secondary);
}
.note-buddy-chat h2 {
margin: 10px;
font-size: var(--font-ui-medium);
color: var(--text-normal);
font-weight: var(--font-semibold);
}
.message-container {
background-color: var(--background-primary-alt);
border-radius: var(--radius-md);
margin: 0 10px 10px 10px;
}
.input-bar textarea {
background-color: var(--background-primary);
color: var(--text-normal);
border: 1px solid var(--background-modifier-border);
border-radius: var(--radius-sm);
font-family: var(--font-interface);
font-size: var(--font-ui-sm);
}
.input-bar textarea:focus {
outline: none;
border-color: var(--interactive-accent);
}
.input-bar button {
background-color: var(--interactive-accent);
color: var(--text-on-accent);
border: none;
border-radius: var(--radius-sm);
font-family: var(--font-interface);
font-weight: var(--font-semibold);
font-size: var(--font-ui-sm);
transition: background-color 0.2s;
}
.input-bar button:hover {
background-color: var(--interactive-accent-hover);
}
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -5,7 +5,7 @@
"isDesktopOnly": false,
"js": "main.js",
"fundingUrl": "https://ko-fi.com/vinzent",
"version": "1.46.0",
"version": "1.46.1",
"author": "Vinzent",
"authorUrl": "https://github.com/Vinzent03"
}
+1 -1
View File
@@ -123,7 +123,7 @@
"mdBorderColor": "Black",
"mdCSS": "",
"scriptEngineSettings": {},
"previousRelease": "2.19.2",
"previousRelease": "2.20.0",
"showReleaseNotes": true,
"compareManifestToPluginVersion": true,
"showNewVersionNotification": true,
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,7 +1,7 @@
{
"id": "obsidian-excalidraw-plugin",
"name": "Excalidraw",
"version": "2.19.2",
"version": "2.20.0",
"minAppVersion": "1.5.7",
"description": "Sketch Your Mind. An Obsidian plugin to edit and view Excalidraw drawings. Enter the world of 4D Visual PKM.",
"author": "Zsolt Viczian",
File diff suppressed because one or more lines are too long
+3 -1
View File
@@ -65,7 +65,9 @@
"generalSettings": {},
"headingOpened": {
"核心状态": true,
"自定义状态": true
"自定义状态": true,
"Core Statuses": true,
"Custom Statuses": true
},
"debugSettings": {
"ignoreSortInstructions": false,
+48
View File
@@ -0,0 +1,48 @@
.note-buddy-chat {
height: 100%;
display: flex;
flex-direction: column;
background-color: var(--background-secondary);
}
.note-buddy-chat h2 {
margin: 10px;
font-size: var(--font-ui-medium);
color: var(--text-normal);
font-weight: var(--font-semibold);
}
.message-container {
background-color: var(--background-primary-alt);
border-radius: var(--radius-md);
margin: 0 10px 10px 10px;
}
.input-bar textarea {
background-color: var(--background-primary);
color: var(--text-normal);
border: 1px solid var(--background-modifier-border);
border-radius: var(--radius-sm);
font-family: var(--font-interface);
font-size: var(--font-ui-sm);
}
.input-bar textarea:focus {
outline: none;
border-color: var(--interactive-accent);
}
.input-bar button {
background-color: var(--interactive-accent);
color: var(--text-on-accent);
border: none;
border-radius: var(--radius-sm);
font-family: var(--font-interface);
font-weight: var(--font-semibold);
font-size: var(--font-ui-sm);
transition: background-color 0.2s;
}
.input-bar button:hover {
background-color: var(--interactive-accent-hover);
}
-5
View File
@@ -1,5 +0,0 @@
Copyright (C) 2020-2025 by Dynalist Inc.
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
File diff suppressed because one or more lines are too long
-11
View File
@@ -1,11 +0,0 @@
{
"id": "opencode-obsidian",
"name": "OpenCode Obsidian",
"version": "0.13.1",
"minAppVersion": "1.0.0",
"description": "OpenCode integration for Obsidian - AI-powered chat interface",
"author": "OpenCode Obsidian Team",
"authorUrl": "",
"fundingUrl": "",
"isDesktopOnly": false
}
-475
View File
@@ -1,475 +0,0 @@
/* Search highlight */
.search-highlight {
background-color: var(--text-highlight-bg);
color: var(--text-highlight);
padding: 0 2px;
border-radius: 2px;
}
/* Server Status Styles */
.opencode-server-status {
display: flex;
flex-direction: column;
gap: 8px;
padding: 8px 0;
}
.opencode-server-status-running {
color: var(--color-green);
}
.opencode-server-status-stopped {
color: var(--text-muted);
}
.opencode-server-status-starting {
color: var(--color-blue);
}
.opencode-server-status-error {
color: var(--color-red);
}
.opencode-server-status-error-message {
color: var(--text-muted);
font-size: 12px;
}
.opencode-server-control-buttons {
display: flex;
gap: 8px;
margin-top: 4px;
}
.opencode-server-metrics {
padding: 8px 0;
}
.opencode-server-metrics-text {
font-size: 12px;
color: var(--text-muted);
}
/* Server Start Modal Styles */
.opencode-server-start-buttons {
display: flex;
gap: 8px;
justify-content: flex-end;
margin-top: 16px;
}
/* Core view layout */
.opencode-obsidian-view {
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
}
.opencode-obsidian-header {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 10px;
border-bottom: 1px solid var(--background-modifier-border);
background-color: var(--background-secondary);
}
.opencode-obsidian-status {
font-size: 12px;
color: var(--text-muted);
white-space: nowrap;
}
.opencode-obsidian-status.connected {
color: var(--text-success);
}
.opencode-obsidian-status.reconnecting,
.opencode-obsidian-status.connecting {
color: var(--text-warning);
}
.opencode-obsidian-status.disconnected {
color: var(--text-error);
}
.opencode-obsidian-controls {
margin-left: auto;
display: flex;
gap: 6px;
}
.opencode-obsidian-view-toggle {
align-self: flex-start;
margin: 8px 10px 0;
}
.opencode-obsidian-search-panel {
padding: 6px 10px;
border-bottom: 1px solid var(--background-modifier-border);
}
/* Conversation selector */
.opencode-obsidian-conversation-selector {
padding: 6px 10px;
border-bottom: 1px solid var(--background-modifier-border);
}
.opencode-obsidian-tabs-container {
display: flex;
gap: 6px;
overflow-x: auto;
padding-bottom: 4px;
}
.opencode-obsidian-tab {
display: flex;
align-items: center;
gap: 6px;
padding: 4px 8px;
border-radius: 6px;
background-color: var(--background-secondary);
border: 1px solid var(--background-modifier-border);
cursor: pointer;
white-space: nowrap;
}
.opencode-obsidian-tab.active {
background-color: var(--interactive-accent);
border-color: var(--interactive-accent);
color: var(--text-on-accent);
}
.opencode-obsidian-tab-content {
display: flex;
flex-direction: column;
gap: 2px;
}
.opencode-obsidian-tab-metadata {
font-size: 11px;
color: var(--text-muted);
}
.opencode-obsidian-tab-close {
margin-left: 6px;
opacity: 0.6;
}
.opencode-obsidian-tab:hover .opencode-obsidian-tab-close {
opacity: 1;
}
.opencode-obsidian-tab-new,
.opencode-obsidian-tab-sync {
font-weight: 600;
}
.opencode-obsidian-tab-disabled {
opacity: 0.6;
pointer-events: none;
}
.opencode-obsidian-no-conversations {
color: var(--text-muted);
padding: 8px 0;
}
/* Message list */
.opencode-obsidian-messages {
flex: 1;
overflow: auto;
padding: 10px;
display: flex;
flex-direction: column;
gap: 10px;
}
.opencode-obsidian-message {
padding: 8px 10px;
border-radius: 8px;
border: 1px solid var(--background-modifier-border);
background-color: var(--background-secondary);
}
.opencode-obsidian-message-user {
align-self: flex-end;
background-color: var(--background-modifier-hover);
}
.opencode-obsidian-message-header {
display: flex;
justify-content: space-between;
font-size: 11px;
color: var(--text-muted);
margin-bottom: 4px;
}
.opencode-obsidian-message-content {
font-size: 13px;
line-height: 1.4;
}
.opencode-obsidian-message-images img {
border-radius: 6px;
margin-top: 6px;
}
.opencode-obsidian-message-actions {
display: flex;
gap: 6px;
margin-top: 6px;
}
.opencode-obsidian-message-action {
font-size: 11px;
color: var(--text-muted);
cursor: pointer;
}
.opencode-obsidian-message-action:hover {
color: var(--text-normal);
}
.opencode-obsidian-empty-messages {
color: var(--text-muted);
text-align: center;
padding: 20px 0;
}
.opencode-obsidian-reverted-indicator {
padding: 8px 10px;
border-radius: 6px;
background-color: var(--background-secondary);
border: 1px dashed var(--background-modifier-border);
font-size: 12px;
color: var(--text-muted);
}
.opencode-obsidian-unrevert-button {
margin-left: 8px;
}
/* Input area */
.opencode-obsidian-input {
border-top: 1px solid var(--background-modifier-border);
padding: 8px 10px;
background-color: var(--background-secondary);
}
.opencode-obsidian-input-container {
display: flex;
flex-direction: column;
gap: 6px;
}
.opencode-obsidian-input-toolbar {
display: flex;
align-items: center;
gap: 8px;
}
.opencode-obsidian-agent-select {
max-width: 200px;
}
.opencode-obsidian-input-textarea {
width: 100%;
min-height: 60px;
resize: none;
}
.opencode-obsidian-input-status {
display: flex;
justify-content: space-between;
font-size: 11px;
color: var(--text-muted);
}
.opencode-obsidian-streaming {
color: var(--text-accent);
}
.opencode-obsidian-input-buttons {
display: flex;
justify-content: flex-end;
gap: 6px;
}
/* Command suggestions */
.opencode-obsidian-command-suggestions {
position: relative;
}
.opencode-obsidian-command-suggestions-list {
position: absolute;
left: 0;
right: 0;
bottom: calc(100% + 6px);
max-height: 200px;
overflow: auto;
background-color: var(--background-primary);
border: 1px solid var(--background-modifier-border);
border-radius: 6px;
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
display: none;
z-index: 20;
}
.opencode-obsidian-command-suggestions.is-visible .opencode-obsidian-command-suggestions-list {
display: block;
}
.opencode-obsidian-command-suggestion {
padding: 6px 8px;
cursor: pointer;
}
.opencode-obsidian-command-suggestion.is-selected {
background-color: var(--background-modifier-hover);
}
.opencode-obsidian-command-suggestion-description {
display: block;
font-size: 11px;
color: var(--text-muted);
}
.opencode-obsidian-command-suggestion-empty {
color: var(--text-muted);
}
/* Loading and spinners */
.opencode-obsidian-loading-overlay {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
color: var(--text-muted);
}
.opencode-obsidian-loading-message {
display: flex;
align-items: center;
gap: 8px;
}
.opencode-obsidian-spinner {
width: 14px;
height: 14px;
border: 2px solid var(--background-modifier-border);
border-top-color: var(--interactive-accent);
border-radius: 50%;
animation: opencode-obsidian-spin 0.8s linear infinite;
}
.opencode-obsidian-spinner-large {
width: 18px;
height: 18px;
border-width: 3px;
}
@keyframes opencode-obsidian-spin {
to {
transform: rotate(360deg);
}
}
/* Context menu */
.opencode-obsidian-context-menu {
background-color: var(--background-primary);
border: 1px solid var(--background-modifier-border);
border-radius: 6px;
padding: 4px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
}
.opencode-obsidian-context-menu-item {
padding: 6px 8px;
cursor: pointer;
border-radius: 4px;
}
.opencode-obsidian-context-menu-item:hover {
background-color: var(--background-modifier-hover);
}
.opencode-obsidian-context-menu-item-danger {
color: var(--text-error);
}
/* Todo list */
.opencode-obsidian-todo-container {
padding: 10px;
display: flex;
flex-direction: column;
gap: 10px;
}
.opencode-obsidian-todo-header {
font-size: 14px;
font-weight: 600;
}
.opencode-obsidian-todo-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.opencode-obsidian-todo-item {
padding: 8px 10px;
border: 1px solid var(--background-modifier-border);
border-radius: 8px;
background-color: var(--background-secondary);
}
.opencode-obsidian-todo-title {
font-weight: 600;
}
.opencode-obsidian-todo-meta {
font-size: 11px;
color: var(--text-muted);
}
.opencode-obsidian-todo-actions {
display: flex;
gap: 6px;
margin-top: 6px;
}
.opencode-obsidian-todo-empty {
color: var(--text-muted);
padding: 8px 0;
}
/* Modals */
.opencode-obsidian-drop-zone {
border: 1px dashed var(--background-modifier-border);
padding: 12px;
text-align: center;
border-radius: 8px;
}
.opencode-obsidian-drop-zone-hover {
background-color: var(--background-modifier-hover);
}
.opencode-obsidian-permission-buttons {
display: flex;
justify-content: flex-end;
gap: 8px;
margin-top: 12px;
}
.opencode-obsidian-code-preview {
font-family: var(--font-monospace);
font-size: 12px;
background-color: var(--background-secondary);
border: 1px solid var(--background-modifier-border);
padding: 8px;
border-radius: 6px;
white-space: pre-wrap;
}
+17 -2
View File
@@ -1,10 +1,12 @@
{
"choices": [],
"inputPrompt": "single-line",
"persistInputPromptDrafts": true,
"useSelectionAsCaptureValue": true,
"devMode": false,
"templateFolderPath": "06_Metadata/Templates",
"announceUpdates": "all",
"version": "2.9.4",
"version": "2.10.0",
"globalVariables": {},
"onePageInputEnabled": false,
"disableOnlineFeatures": true,
@@ -12,6 +14,17 @@
"showCaptureNotification": true,
"showInputCancellationNotification": false,
"enableTemplatePropertyTypes": true,
"dateAliases": {
"t": "today",
"tm": "tomorrow",
"yd": "yesterday",
"nw": "next week",
"nm": "next month",
"ny": "next year",
"lw": "last week",
"lm": "last month",
"ly": "last year"
},
"ai": {
"defaultModel": "Ask me",
"defaultSystemPrompt": "As an AI assistant within Obsidian, your primary goal is to help users manage their ideas and knowledge more effectively. Format your responses using Markdown syntax. Please use the [[Obsidian]] link format. You can write aliases for the links by writing [[Obsidian|the alias after the pipe symbol]]. To use mathematical notation, use LaTeX syntax. LaTeX syntax for larger equations should be on separate lines, surrounded with double dollar signs ($$). You can also inline math expressions by wrapping it in $ symbols. For example, use $$w_{ij}^{\text{new}}:=w_{ij}^{\text{current}}+etacdotdelta_jcdot x_{ij}$$ on a separate line, but you can write \"($eta$ = learning rate, $delta_j$ = error term, $x_{ij}$ = input)\" inline.",
@@ -99,6 +112,8 @@
"addDefaultAIProviders": true,
"removeMacroIndirection": true,
"migrateFileOpeningSettings": true,
"setProviderModelDiscoveryMode": true
"setProviderModelDiscoveryMode": true,
"backfillFileOpeningDefaults": true,
"migrateProviderApiKeysToSecretStorage": true
}
}
+78 -73
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -1,8 +1,8 @@
{
"id": "quickadd",
"name": "QuickAdd",
"version": "2.9.4",
"minAppVersion": "1.6.0",
"version": "2.10.0",
"minAppVersion": "1.11.4",
"description": "Quickly add new pages or content to your vault.",
"author": "Christian B. B. Houmann",
"authorUrl": "https://bagerbach.com",
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,7 +1,7 @@
{
"id": "templater-obsidian",
"name": "Templater",
"version": "2.16.4",
"version": "2.18.1",
"description": "Create and use templates",
"minAppVersion": "1.5.0",
"author": "SilentVoid",