murashit_codex-panel/src/plugin-runtime.ts

155 lines
5.4 KiB
TypeScript
Raw Normal View History

import type { App } from "obsidian";
import { VIEW_TYPE_CODEX_THREADS, VIEW_TYPE_CODEX_TURN_DIFF } from "./constants";
2026-06-15 08:44:34 +00:00
import { AppServerQueryCache } from "./app-server/query/cache";
import type { AppServerQueryContext } from "./app-server/query/keys";
import type { CodexChatHost, PluginSettingsRef } from "./features/chat/application/ports/chat-host";
import type { ChatTurnDiffViewState } from "./features/chat/domain/turn-diff";
import { persistedChatTurnDiffViewState } from "./features/chat/domain/turn-diff";
import { CodexChatTurnDiffView } from "./features/chat/ui/turn-diff/view";
import { openThreadPicker, type ThreadPickerHost } from "./features/thread-picker/modal";
import type { CodexThreadsHost, CodexThreadsView } from "./features/threads-view/view";
import type { CodexPanelSettingTabHost } from "./settings/tab";
import { WorkspacePanelCoordinator } from "./workspace/panel-coordinator";
import { createThreadSurfaceActions, type ThreadSurfaceActions } from "./workspace/thread-surface-actions";
import { SharedThreadCatalog } from "./workspace/shared-thread-catalog";
export interface CodexPanelRuntimeOptions {
app: App;
settingsRef: PluginSettingsRef;
saveSettings(): Promise<void>;
}
export class CodexPanelRuntime {
2026-06-15 08:44:34 +00:00
private readonly appServerQueries = new AppServerQueryCache();
readonly panels: WorkspacePanelCoordinator;
2026-06-15 06:00:14 +00:00
private readonly threadSurfaces: ThreadSurfaceActions;
readonly threadCatalog: SharedThreadCatalog;
constructor(private readonly options: CodexPanelRuntimeOptions) {
this.panels = new WorkspacePanelCoordinator({
app: options.app,
refreshThreadsViewLiveState: () => {
this.threadCatalog.refreshThreadsViewLiveState();
},
});
this.threadSurfaces = createThreadSurfaceActions({
app: options.app,
panels: this.panels,
});
this.threadCatalog = new SharedThreadCatalog({
2026-06-15 08:44:34 +00:00
cache: this.appServerQueries,
surfaces: this.threadSurfaces,
2026-06-15 08:44:34 +00:00
context: () => this.appServerQueryContext(),
});
}
reset(): void {
this.panels.reset();
2026-06-15 08:44:34 +00:00
this.appServerQueries.clear();
}
recordLastFocusedPanel(leaf: Parameters<WorkspacePanelCoordinator["recordLastFocusedPanel"]>[0]): void {
this.panels.recordLastFocusedPanel(leaf);
}
activatePanel(): Promise<unknown> {
return this.panels.activateView();
}
activateNewPanel(): Promise<unknown> {
return this.panels.activateNewView();
}
async startNewChat(): Promise<void> {
const view = await this.panels.activateView();
await view.surface.startNewThread();
}
openThreadPicker(): void {
void openThreadPicker(this.threadPickerHost());
}
async activateThreadsView(): Promise<CodexThreadsView> {
const leaf = await this.options.app.workspace.ensureSideLeaf(VIEW_TYPE_CODEX_THREADS, "left", {
active: true,
reveal: true,
});
const view = leaf.view as CodexThreadsView;
await view.refresh();
return view;
}
scheduleBootRestoredPanelLoads(): void {
this.panels.scheduleBootRestoredPanelLoads();
}
cancelBootRestoredPanelLoads(): void {
this.panels.cancelBootRestoredPanelLoads();
}
chatHost(): CodexChatHost {
return {
settingsRef: this.options.settingsRef,
workspace: {
openThreadInNewView: (threadId) => this.panels.openThreadInNewView(threadId),
focusThreadInOpenView: (threadId) => this.panels.focusThreadInOpenView(threadId),
openTurnDiff: (state) => this.openTurnDiff(state),
},
2026-06-15 06:00:14 +00:00
threadCatalog: this.threadCatalog,
};
}
threadsHost(): CodexThreadsHost {
return {
settings: this.options.settingsRef.settings,
vaultPath: this.options.settingsRef.vaultPath,
2026-06-15 06:00:14 +00:00
threadCatalog: this.threadCatalog,
openNewPanel: () => this.panels.openNewPanel(),
openThreadInAvailableView: (threadId) => this.panels.openThreadInAvailableView(threadId),
getOpenPanelSnapshots: () => this.panels.getOpenPanelSnapshots(),
};
}
settingTabHost(): CodexPanelSettingTabHost {
return {
settings: this.options.settingsRef.settings,
vaultPath: this.options.settingsRef.vaultPath,
saveSettings: () => this.options.saveSettings(),
refreshOpenViews: () => {
this.threadSurfaces.refreshOpenViews();
},
2026-06-15 06:00:14 +00:00
threadCatalog: this.threadCatalog,
};
}
private threadPickerHost(): ThreadPickerHost {
return {
app: this.options.app,
settings: this.options.settingsRef.settings,
vaultPath: this.options.settingsRef.vaultPath,
2026-06-15 06:00:14 +00:00
threadCatalog: this.threadCatalog,
openThreadInCurrentView: (threadId) => this.panels.openThreadInCurrentView(threadId),
openThreadInAvailableView: (threadId) => this.panels.openThreadInAvailableView(threadId),
};
}
private async openTurnDiff(state: ChatTurnDiffViewState): Promise<void> {
const existing = this.options.app.workspace.getLeavesOfType(VIEW_TYPE_CODEX_TURN_DIFF).at(0);
const leaf = existing ?? this.options.app.workspace.getLeaf("tab");
await leaf.setViewState({ type: VIEW_TYPE_CODEX_TURN_DIFF, active: true, state: { ...persistedChatTurnDiffViewState(state) } });
await leaf.loadIfDeferred();
if (leaf.view instanceof CodexChatTurnDiffView) {
leaf.view.setDiffPayload(state);
}
await this.options.app.workspace.revealLeaf(leaf);
}
2026-06-15 08:44:34 +00:00
private appServerQueryContext(): AppServerQueryContext {
return {
codexPath: this.options.settingsRef.settings.codexPath,
vaultPath: this.options.settingsRef.vaultPath,
};
}
}