feat: first round of mcp standalone server

This commit is contained in:
2026-02-28 21:23:22 +01:00
parent 1fc2003260
commit c358e1b11c
67 changed files with 3426 additions and 901 deletions

View File

@@ -1,13 +1,5 @@
import { dialog } from 'electron';
import { getPostEngine } from '../engine/PostEngine';
import { getProjectEngine } from '../engine/ProjectEngine';
import { getMetaEngine } from '../engine/MetaEngine';
import { getMediaEngine } from '../engine/MediaEngine';
import { getPostMediaEngine } from '../engine/PostMediaEngine';
import { getMenuEngine } from '../engine/MenuEngine';
import { taskManager } from '../engine/TaskManager';
import {
getBlogGenerationEngine,
resolvePublicBaseUrl,
type BlogGenerationResult,
type BlogGenerationSection,
@@ -15,17 +7,18 @@ import {
type SiteValidationReport,
} from '../engine/BlogGenerationEngine';
import { resolvePageTitle } from '../engine/PageRenderer';
import type { EngineBundle } from '../engine/EngineBundle';
type SafeHandle = (channel: string, handler: (...args: any[]) => Promise<any>) => void;
export function registerBlogHandlers(safeHandle: SafeHandle): void {
export function registerBlogHandlers(safeHandle: SafeHandle, bundle: EngineBundle): void {
const resolveBlogGenerationBaseOptions = async (): Promise<BlogGenerationOptions> => {
const projectEngine = getProjectEngine();
const postEngine = getPostEngine();
const metaEngine = getMetaEngine();
const mediaEngine = getMediaEngine();
const postMediaEngine = getPostMediaEngine();
const menuEngine = getMenuEngine();
const projectEngine = bundle.projectEngine;
const postEngine = bundle.postEngine;
const metaEngine = bundle.metaEngine;
const mediaEngine = bundle.mediaEngine;
const postMediaEngine = bundle.postMediaEngine;
const menuEngine = bundle.menuEngine;
const project = await projectEngine.getActiveProject();
if (!project) {
@@ -76,7 +69,7 @@ export function registerBlogHandlers(safeHandle: SafeHandle): void {
};
safeHandle('blog:generateSitemap', async () => {
const blogGenerationEngine = getBlogGenerationEngine();
const blogGenerationEngine = bundle.blogGenerationEngine;
const baseOptions = await resolveBlogGenerationBaseOptions();
const taskTimestamp = Date.now();
@@ -88,7 +81,7 @@ export function registerBlogHandlers(safeHandle: SafeHandle): void {
taskName: string,
taskIdPrefix: string,
): Promise<BlogGenerationResult> => {
return taskManager.runTask({
return bundle.taskManager.runTask({
id: `${taskIdPrefix}-${taskTimestamp}`,
name: taskName,
groupId: taskGroupId,
@@ -137,11 +130,11 @@ export function registerBlogHandlers(safeHandle: SafeHandle): void {
});
safeHandle('blog:validateSite', async () => {
const blogGenerationEngine = getBlogGenerationEngine();
const blogGenerationEngine = bundle.blogGenerationEngine;
const baseOptions = await resolveBlogGenerationBaseOptions();
const taskTimestamp = Date.now();
return taskManager.runTask({
return bundle.taskManager.runTask({
id: `site-validate-${taskTimestamp}`,
name: 'Validate Site',
execute: async (onProgress) => {
@@ -153,11 +146,11 @@ export function registerBlogHandlers(safeHandle: SafeHandle): void {
});
safeHandle('blog:regenerateCalendar', async () => {
const blogGenerationEngine = getBlogGenerationEngine();
const blogGenerationEngine = bundle.blogGenerationEngine;
const baseOptions = await resolveBlogGenerationBaseOptions();
const taskTimestamp = Date.now();
return taskManager.runTask({
return bundle.taskManager.runTask({
id: `site-calendar-regenerate-${taskTimestamp}`,
name: 'Regenerate Calendar',
execute: async (onProgress) => {
@@ -169,11 +162,11 @@ export function registerBlogHandlers(safeHandle: SafeHandle): void {
});
safeHandle('blog:applyValidation', async (_event, report: SiteValidationReport) => {
const blogGenerationEngine = getBlogGenerationEngine();
const blogGenerationEngine = bundle.blogGenerationEngine;
const baseOptions = await resolveBlogGenerationBaseOptions();
const taskTimestamp = Date.now();
return taskManager.runTask({
return bundle.taskManager.runTask({
id: `site-validate-apply-${taskTimestamp}`,
name: 'Apply Site Validation',
execute: async (onProgress) => {

View File

@@ -5,20 +5,21 @@
import { ipcMain, BrowserWindow } from 'electron';
import { ChatEngine } from '../engine/ChatEngine';
import { OpenCodeManager } from '../engine/OpenCodeManager';
import { getPostEngine } from '../engine/PostEngine';
import { getMediaEngine } from '../engine/MediaEngine';
import { getDatabase } from '../database';
import type { EngineBundle } from '../engine/EngineBundle';
let chatEngine: ChatEngine | null = null;
let openCodeManager: OpenCodeManager | null = null;
let openCodeManagerInitPromise: Promise<void> | null = null;
let mainWindowGetter: (() => BrowserWindow | null) | null = null;
let engineBundle: EngineBundle | null = null;
/**
* Initialize chat handlers with the main window reference
*/
export function initializeChatHandlers(getMainWindow: () => BrowserWindow | null): void {
export function initializeChatHandlers(getMainWindow: () => BrowserWindow | null, bundle: EngineBundle): void {
mainWindowGetter = getMainWindow;
engineBundle = bundle;
}
/**
@@ -40,8 +41,9 @@ async function getOpenCodeManager(): Promise<OpenCodeManager> {
if (!openCodeManager) {
openCodeManager = new OpenCodeManager(
getChatEngine(),
getPostEngine(),
getMediaEngine(),
engineBundle!.postEngine,
engineBundle!.mediaEngine,
engineBundle!.postMediaEngine,
() => mainWindowGetter?.() || null
);

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,11 @@
import { getProjectEngine } from '../engine/ProjectEngine';
import { taskManager } from '../engine/TaskManager';
import type { EngineBundle } from '../engine/EngineBundle';
type SafeHandle = (channel: string, handler: (...args: any[]) => Promise<any>) => void;
export function registerMetadataDiffHandlers(safeHandle: SafeHandle): void {
export function registerMetadataDiffHandlers(safeHandle: SafeHandle, bundle: EngineBundle): void {
safeHandle('metadataDiff:getStats', async () => {
const { getMetadataDiffEngine } = await import('../engine/MetadataDiffEngine');
const engine = getMetadataDiffEngine();
const projectEngine = getProjectEngine();
const engine = bundle.metadataDiffEngine;
const projectEngine = bundle.projectEngine;
const activeProject = await projectEngine.getActiveProject();
if (activeProject) {
engine.setProjectContext(activeProject.id);
@@ -16,16 +14,15 @@ export function registerMetadataDiffHandlers(safeHandle: SafeHandle): void {
});
safeHandle('metadataDiff:scan', async () => {
const { getMetadataDiffEngine } = await import('../engine/MetadataDiffEngine');
const engine = getMetadataDiffEngine();
const projectEngine = getProjectEngine();
const engine = bundle.metadataDiffEngine;
const projectEngine = bundle.projectEngine;
const activeProject = await projectEngine.getActiveProject();
if (activeProject) {
engine.setProjectContext(activeProject.id);
}
const taskId = `metadata-diff-scan-${Date.now()}`;
return taskManager.runTask({
return bundle.taskManager.runTask({
id: taskId,
name: 'Scanning for metadata differences',
execute: async (onProgress) => {
@@ -38,9 +35,8 @@ export function registerMetadataDiffHandlers(safeHandle: SafeHandle): void {
});
safeHandle('metadataDiff:syncDbToFile', async (_, postIds: string[], groupLabel: string) => {
const { getMetadataDiffEngine } = await import('../engine/MetadataDiffEngine');
const engine = getMetadataDiffEngine();
const projectEngine = getProjectEngine();
const engine = bundle.metadataDiffEngine;
const projectEngine = bundle.projectEngine;
const activeProject = await projectEngine.getActiveProject();
if (activeProject) {
engine.setProjectContext(activeProject.id);
@@ -49,9 +45,8 @@ export function registerMetadataDiffHandlers(safeHandle: SafeHandle): void {
});
safeHandle('metadataDiff:syncFileToDb', async (_, postIds: string[], field: string, groupLabel: string) => {
const { getMetadataDiffEngine } = await import('../engine/MetadataDiffEngine');
const engine = getMetadataDiffEngine();
const projectEngine = getProjectEngine();
const engine = bundle.metadataDiffEngine;
const projectEngine = bundle.projectEngine;
const activeProject = await projectEngine.getActiveProject();
if (activeProject) {
engine.setProjectContext(activeProject.id);

View File

@@ -1,18 +1,17 @@
import { getProjectEngine } from '../engine/ProjectEngine';
import { getPublishEngine, type PublishCredentials } from '../engine/PublishEngine';
import { taskManager } from '../engine/TaskManager';
import type { PublishCredentials } from '../engine/PublishEngine';
import type { EngineBundle } from '../engine/EngineBundle';
type SafeHandle = (channel: string, handler: (...args: any[]) => Promise<any>) => void;
export function registerPublishHandlers(safeHandle: SafeHandle): void {
export function registerPublishHandlers(safeHandle: SafeHandle, bundle: EngineBundle): void {
safeHandle('publish:uploadSite', async (_event: unknown, credentials: PublishCredentials) => {
const projectEngine = getProjectEngine();
const projectEngine = bundle.projectEngine;
const project = await projectEngine.getActiveProject();
if (!project) {
throw new Error('No active project');
}
const publishEngine = getPublishEngine();
const publishEngine = bundle.publishEngine;
publishEngine.setProjectContext(project.id, project.dataPath!);
const ts = Date.now();
@@ -20,7 +19,7 @@ export function registerPublishHandlers(safeHandle: SafeHandle): void {
const groupName = 'Site Publishing';
// Launch three parallel tasks, one per directory
const htmlTask = taskManager.runTask({
const htmlTask = bundle.taskManager.runTask({
id: `publish-html-${ts}`,
name: 'Upload HTML',
groupId,
@@ -28,7 +27,7 @@ export function registerPublishHandlers(safeHandle: SafeHandle): void {
execute: (onProgress) => publishEngine.uploadHtml(credentials, onProgress),
});
const thumbsTask = taskManager.runTask({
const thumbsTask = bundle.taskManager.runTask({
id: `publish-thumbnails-${ts}`,
name: 'Upload Thumbnails',
groupId,
@@ -36,7 +35,7 @@ export function registerPublishHandlers(safeHandle: SafeHandle): void {
execute: (onProgress) => publishEngine.uploadThumbnails(credentials, onProgress),
});
const mediaTask = taskManager.runTask({
const mediaTask = bundle.taskManager.runTask({
id: `publish-media-${ts}`,
name: 'Upload Media',
groupId,