mirror of
https://github.com/aaronsb/obsidian-mcp-plugin.git
synced 2026-07-22 06:45:14 +00:00
Merge pull request #225 from aaronsb/chore/217-lint-debt
chore: adopt dev-dependency bump + clear lint debt (supersedes #217)
This commit is contained in:
commit
882a10c332
13 changed files with 861 additions and 823 deletions
1564
package-lock.json
generated
1564
package-lock.json
generated
File diff suppressed because it is too large
Load diff
18
package.json
18
package.json
|
|
@ -29,19 +29,19 @@
|
|||
"@eslint/js": "^9.39.2",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/minimatch": "^5.1.2",
|
||||
"@types/node": "^25.3.0",
|
||||
"@typescript-eslint/utils": "^8.56.0",
|
||||
"esbuild": "^0.27.3",
|
||||
"@types/node": "^25.9.2",
|
||||
"@typescript-eslint/utils": "^8.60.1",
|
||||
"esbuild": "^0.28.0",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-plugin-obsidianmd": "^0.3.0",
|
||||
"globals": "^17.3.0",
|
||||
"jest": "^30.2.0",
|
||||
"jiti": "^2.6.1",
|
||||
"obsidian": "^1.12.2",
|
||||
"ts-jest": "^29.1.1",
|
||||
"globals": "^17.6.0",
|
||||
"jest": "^30.4.2",
|
||||
"jiti": "^2.7.0",
|
||||
"obsidian": "^1.13.0",
|
||||
"ts-jest": "^29.4.11",
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.56.0"
|
||||
"typescript-eslint": "^8.60.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.29.0",
|
||||
|
|
|
|||
|
|
@ -87,9 +87,15 @@ function formatDataviewTable(headers: string[], rows: DataviewValue[]): string {
|
|||
} else if (row !== null && typeof row === 'object') {
|
||||
val = row[headers[i]];
|
||||
}
|
||||
const display = val === null || val === undefined
|
||||
? ''
|
||||
: typeof val === 'object' ? JSON.stringify(val) : String(val as string | number | boolean);
|
||||
let display: string;
|
||||
if (val === null || val === undefined) {
|
||||
display = '';
|
||||
} else if (typeof val === 'object') {
|
||||
display = JSON.stringify(val);
|
||||
} else {
|
||||
const primitive = val as string | number | boolean | bigint | symbol;
|
||||
display = String(primitive);
|
||||
}
|
||||
return truncate(display, 30);
|
||||
});
|
||||
lines.push('| ' + cells.join(' | ') + (hasMore ? ' | ...' : '') + ' |');
|
||||
|
|
@ -327,7 +333,8 @@ export function formatBasesRead(response: BasesReadResponse): string {
|
|||
} else if (typeof value === 'object') {
|
||||
displayValue = JSON.stringify(value);
|
||||
} else {
|
||||
displayValue = String(value as string | number | boolean);
|
||||
const primitive = value as string | number | boolean | bigint | symbol;
|
||||
displayValue = String(primitive);
|
||||
}
|
||||
lines.push(property(key, truncate(displayValue, 50), 0));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -226,7 +226,8 @@ export function formatFileRead(response: FileReadResponse): string {
|
|||
displayValue = JSON.stringify(value).substring(0, 50);
|
||||
} else {
|
||||
// Primitives (string, number, boolean, bigint, symbol) are safe to stringify
|
||||
displayValue = String(value as string | number | boolean | bigint | symbol).substring(0, 50);
|
||||
const primitive = value as string | number | boolean | bigint | symbol;
|
||||
displayValue = String(primitive).substring(0, 50);
|
||||
}
|
||||
lines.push(property(key, displayValue, 0));
|
||||
});
|
||||
|
|
|
|||
51
src/main.ts
51
src/main.ts
|
|
@ -582,7 +582,17 @@ class MCPSettingTab extends PluginSettingTab {
|
|||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
// Obsidian's settings entry point. PluginSettingTab.display() is deprecated
|
||||
// since 1.13.0 in favor of the declarative getSettingDefinitions() API, but
|
||||
// display() remains the supported fallback for plugins that still target
|
||||
// older Obsidian versions. Keep it as a thin wrapper; the imperative render
|
||||
// lives in render(), which internal refreshes call directly so they don't
|
||||
// reference the deprecated method. Declarative migration tracked in #224.
|
||||
display(): void {
|
||||
this.render();
|
||||
}
|
||||
|
||||
private render(): void {
|
||||
const {containerEl} = this;
|
||||
|
||||
containerEl.empty();
|
||||
|
|
@ -692,7 +702,7 @@ class MCPSettingTab extends PluginSettingTab {
|
|||
}
|
||||
|
||||
// Update the status display
|
||||
this.display();
|
||||
this.render();
|
||||
}));
|
||||
|
||||
const portSetting = new Setting(containerEl)
|
||||
|
|
@ -805,7 +815,7 @@ class MCPSettingTab extends PluginSettingTab {
|
|||
this.plugin.settings.customBindHost = '';
|
||||
}
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
this.render();
|
||||
await this.restartIfRunning('bind address');
|
||||
}));
|
||||
|
||||
|
|
@ -839,7 +849,7 @@ class MCPSettingTab extends PluginSettingTab {
|
|||
this.plugin.settings.bindMode = normalized.mode;
|
||||
this.plugin.settings.customBindHost = normalized.customHost;
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
this.render();
|
||||
await this.restartIfRunning('bind address');
|
||||
})();
|
||||
}));
|
||||
|
|
@ -876,7 +886,7 @@ class MCPSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
|
||||
// Show/hide HTTPS settings and update HTTP toggle state
|
||||
this.display();
|
||||
this.render();
|
||||
|
||||
// Restart server if running
|
||||
if (this.plugin.mcpServer?.isServerRunning()) {
|
||||
|
|
@ -919,7 +929,7 @@ class MCPSettingTab extends PluginSettingTab {
|
|||
this.plugin.settings.certificateConfig.autoGenerate = value;
|
||||
await this.plugin.saveSettings();
|
||||
// Refresh the display to update the description
|
||||
this.display();
|
||||
this.render();
|
||||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
|
|
@ -932,7 +942,7 @@ class MCPSettingTab extends PluginSettingTab {
|
|||
this.plugin.settings.certificateConfig.certPath = value || undefined;
|
||||
await this.plugin.saveSettings();
|
||||
// Refresh display to update configuration examples
|
||||
this.display();
|
||||
this.render();
|
||||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
|
|
@ -1020,6 +1030,11 @@ class MCPSettingTab extends PluginSettingTab {
|
|||
.addButton(button => button
|
||||
.setButtonText('Regenerate')
|
||||
.setTooltip('Generate a new API key')
|
||||
// setDestructive() (the non-deprecated replacement) requires Obsidian
|
||||
// 1.13.0, but our manifest minAppVersion is 1.6.6, so it's not available
|
||||
// to all supported users. Keep setWarning() until minAppVersion is raised
|
||||
// (tracked with the 1.13.0 API adoption in #224).
|
||||
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
||||
.setWarning()
|
||||
.onClick(() => {
|
||||
new ConfirmationModal(
|
||||
|
|
@ -1029,7 +1044,7 @@ class MCPSettingTab extends PluginSettingTab {
|
|||
this.plugin.settings.apiKey = this.plugin.generateApiKey();
|
||||
await this.plugin.saveSettings();
|
||||
new Notice('API key regenerated. Update your mcp clients with the new key.');
|
||||
this.display();
|
||||
this.render();
|
||||
}
|
||||
).open();
|
||||
}));
|
||||
|
|
@ -1064,7 +1079,7 @@ class MCPSettingTab extends PluginSettingTab {
|
|||
}
|
||||
|
||||
// Refresh display to update examples
|
||||
this.display();
|
||||
this.render();
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
@ -1090,7 +1105,7 @@ class MCPSettingTab extends PluginSettingTab {
|
|||
}
|
||||
|
||||
// Refresh display to update examples
|
||||
this.display();
|
||||
this.render();
|
||||
}));
|
||||
|
||||
// Path Exclusions Setting
|
||||
|
|
@ -1116,7 +1131,7 @@ class MCPSettingTab extends PluginSettingTab {
|
|||
}
|
||||
|
||||
// Refresh display to show/hide file management options
|
||||
this.display();
|
||||
this.render();
|
||||
}));
|
||||
|
||||
// Show context menu toggle if path exclusions are enabled
|
||||
|
|
@ -1290,7 +1305,7 @@ class MCPSettingTab extends PluginSettingTab {
|
|||
// Force reload to ensure fresh state
|
||||
await this.plugin.ignoreManager!.forceReload();
|
||||
new Notice('📄 Default .mcpignore template created');
|
||||
this.display(); // Refresh to update status
|
||||
this.render(); // Refresh to update status
|
||||
} catch (error) {
|
||||
Debug.log('Failed to create .mcpignore template:', error);
|
||||
new Notice('❌ Failed to create template');
|
||||
|
|
@ -1307,7 +1322,7 @@ class MCPSettingTab extends PluginSettingTab {
|
|||
try {
|
||||
await this.plugin.ignoreManager!.forceReload();
|
||||
new Notice('🔄 Exclusion patterns reloaded');
|
||||
this.display(); // Refresh to update status
|
||||
this.render(); // Refresh to update status
|
||||
} catch (error) {
|
||||
Debug.log('Failed to reload patterns:', error);
|
||||
new Notice('❌ Failed to reload patterns');
|
||||
|
|
@ -1412,7 +1427,7 @@ class MCPSettingTab extends PluginSettingTab {
|
|||
visibility[`${operation}.${action}`] = value;
|
||||
}
|
||||
await this.plugin.saveSettings();
|
||||
this.display(); // Re-render for updated states
|
||||
this.render(); // Re-render for updated states
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -1448,7 +1463,7 @@ class MCPSettingTab extends PluginSettingTab {
|
|||
}
|
||||
|
||||
await this.plugin.saveSettings();
|
||||
this.display(); // Re-render for parent state update
|
||||
this.render(); // Re-render for parent state update
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
@ -1763,7 +1778,7 @@ class MCPSettingTab extends PluginSettingTab {
|
|||
refreshConnectionStatus(): void {
|
||||
// Simply refresh the entire settings display to ensure accurate data
|
||||
// This is more reliable than trying to manually update DOM elements
|
||||
this.display();
|
||||
this.render();
|
||||
}
|
||||
|
||||
private updatePortApplyButton(setting: Setting, hasChanges: boolean, pendingPort: number): void {
|
||||
|
|
@ -1784,7 +1799,7 @@ class MCPSettingTab extends PluginSettingTab {
|
|||
const info = this.plugin.getMCPServerInfo();
|
||||
|
||||
// Update connection status grid
|
||||
const connectionEl = document.querySelector('.mcp-status-grid');
|
||||
const connectionEl = activeDocument.querySelector('.mcp-status-grid');
|
||||
if (connectionEl) {
|
||||
const connectionItems = connectionEl.querySelectorAll('div');
|
||||
for (let i = 0; i < connectionItems.length; i++) {
|
||||
|
|
@ -1807,7 +1822,7 @@ class MCPSettingTab extends PluginSettingTab {
|
|||
// Update Claude Code connection section with proper auth handling.
|
||||
// Rebuild via the shared renderer so the live view matches the initial
|
||||
// render exactly (including the JSON-config + warning auth path).
|
||||
const protocolSection = document.querySelector('.protocol-command-example');
|
||||
const protocolSection = activeDocument.querySelector('.protocol-command-example');
|
||||
if (protocolSection instanceof HTMLElement && info) {
|
||||
// Get correct protocol and port based on HTTPS setting
|
||||
const protocol = this.plugin.settings.httpsEnabled ? 'https' : 'http';
|
||||
|
|
@ -1818,7 +1833,7 @@ class MCPSettingTab extends PluginSettingTab {
|
|||
}
|
||||
|
||||
// Update any other dynamic content areas that need live updates
|
||||
const statusElements = document.querySelectorAll('[data-live-update]');
|
||||
const statusElements = activeDocument.querySelectorAll('[data-live-update]');
|
||||
for (let i = 0; i < statusElements.length; i++) {
|
||||
const el = statusElements[i];
|
||||
const updateType = el.getAttribute('data-live-update');
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import express from 'express';
|
||||
import cors from 'cors';
|
||||
import { App, Notice } from 'obsidian';
|
||||
import { createServer as createHttpServer, Server, IncomingMessage, ServerResponse } from 'http';
|
||||
import { createServer as createHttpServer, Server } from 'http';
|
||||
import { Server as HttpsServer } from 'https';
|
||||
import { Server as MCPServer } from '@modelcontextprotocol/sdk/server/index.js';
|
||||
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
||||
|
|
@ -571,9 +571,9 @@ export class MCPHttpServer {
|
|||
|
||||
// Handle the request using the transport
|
||||
await transport.handleRequest(
|
||||
req as unknown as IncomingMessage,
|
||||
res as unknown as ServerResponse,
|
||||
request as unknown
|
||||
req,
|
||||
res,
|
||||
request
|
||||
);
|
||||
|
||||
Debug.log('📤 MCP Response sent via transport');
|
||||
|
|
|
|||
|
|
@ -143,10 +143,10 @@ export class VaultSecurityManager {
|
|||
};
|
||||
|
||||
if (operation.path) {
|
||||
result.path = operation.path as ValidatedPath;
|
||||
result.path = operation.path;
|
||||
}
|
||||
if (operation.targetPath) {
|
||||
result.targetPath = operation.targetPath as ValidatedPath;
|
||||
result.targetPath = operation.targetPath;
|
||||
}
|
||||
|
||||
return result as ValidatedOperation;
|
||||
|
|
|
|||
|
|
@ -436,7 +436,8 @@ export class BasesAPI {
|
|||
if (value == null) return '';
|
||||
if (typeof value === 'object') return JSON.stringify(value);
|
||||
// At this point value is a primitive (string, number, boolean, bigint, symbol)
|
||||
return String(value as string | number | boolean | bigint | symbol);
|
||||
const primitive = value as string | number | boolean | bigint | symbol;
|
||||
return String(primitive);
|
||||
}
|
||||
|
||||
private escapeCSV(value: unknown): string {
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ export class ConnectionPool extends EventEmitter {
|
|||
} else if (typeof response.error === 'string') {
|
||||
reject(new Error(response.error));
|
||||
} else if (response.error && typeof response.error === 'object' && 'message' in response.error) {
|
||||
reject(new Error(String((response.error as { message: unknown }).message)));
|
||||
reject(new Error(String((response.error).message)));
|
||||
} else {
|
||||
reject(new Error(JSON.stringify(response.error)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,8 @@ export function ensureStringContent(content: unknown, context?: string): string
|
|||
}
|
||||
|
||||
// Fallback: convert primitives (number, boolean, bigint, symbol) to string
|
||||
return String(content as string | number | boolean | bigint | symbol);
|
||||
const primitive = content as string | number | boolean | bigint | symbol;
|
||||
return String(primitive);
|
||||
|
||||
} catch (error) {
|
||||
Debug.warn(`Content conversion failed${context ? ` in ${context}` : ''}:`, {
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ export async function readFileWithFragments(
|
|||
|
||||
// Image / binary: passthrough unchanged
|
||||
if (isImageFile(fileResponse)) {
|
||||
return fileResponse as FileReadResult;
|
||||
return fileResponse;
|
||||
}
|
||||
|
||||
// Extract verbatim content + metadata (metadata WITHOUT a copy of the body)
|
||||
|
|
@ -129,7 +129,7 @@ export async function readFileWithFragments(
|
|||
} else if (fileResponse && typeof fileResponse === 'object' && 'content' in fileResponse) {
|
||||
const fc = (fileResponse as { content: unknown }).content;
|
||||
if (typeof fc !== 'string') {
|
||||
return fileResponse as FileReadResult; // image/binary structured
|
||||
return fileResponse; // image/binary structured
|
||||
}
|
||||
fileContent = fc;
|
||||
// Strip the body so it is not embedded twice in the envelope (ADR-203 §3)
|
||||
|
|
@ -140,7 +140,7 @@ export async function readFileWithFragments(
|
|||
frontmatter = fm;
|
||||
tags = tg;
|
||||
} else {
|
||||
return fileResponse as FileReadResult;
|
||||
return fileResponse;
|
||||
}
|
||||
|
||||
const totalChars = fileContent.length;
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ async function resizeImageWithCanvas(
|
|||
// Check if resizing is needed
|
||||
if (originalWidth <= maxDimension && originalHeight <= maxDimension) {
|
||||
// No resizing needed, but convert to JPEG with quality
|
||||
const canvas = document.createElement('canvas');
|
||||
const canvas = activeDocument.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
if (!ctx) {
|
||||
|
|
@ -165,7 +165,7 @@ async function resizeImageWithCanvas(
|
|||
}
|
||||
|
||||
// Create canvas for resizing
|
||||
const canvas = document.createElement('canvas');
|
||||
const canvas = activeDocument.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
if (!ctx) {
|
||||
|
|
|
|||
|
|
@ -187,7 +187,8 @@ export class FileSizeValidator implements Validator {
|
|||
contentStr = JSON.stringify(content);
|
||||
} else {
|
||||
// Primitives (number, boolean, bigint, symbol) are safe to stringify
|
||||
contentStr = String(content as number | boolean | bigint | symbol);
|
||||
const primitive = content as string | number | boolean | bigint | symbol;
|
||||
contentStr = String(primitive);
|
||||
}
|
||||
const sizeInBytes = Buffer.byteLength(contentStr, 'utf8');
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue