diff options
| author | Adam Malczewski <[email protected]> | 2026-03-24 13:18:50 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-03-24 13:18:50 +0900 |
| commit | bb543c3f7840f2a3fa1b7a1fb32245fa87a30f7b (patch) | |
| tree | d2a9db2741dfd9822c5f76dca278562220e9b064 /src/main.ts | |
| parent | e5583b836d4fe2f7f9806ed85a190254a6ea3990 (diff) | |
| download | ai-pulse-obsidian-plugin-bb543c3f7840f2a3fa1b7a1fb32245fa87a30f7b.tar.gz ai-pulse-obsidian-plugin-bb543c3f7840f2a3fa1b7a1fb32245fa87a30f7b.zip | |
initial prototype
Diffstat (limited to 'src/main.ts')
| -rw-r--r-- | src/main.ts | 144 |
1 files changed, 69 insertions, 75 deletions
diff --git a/src/main.ts b/src/main.ts index 6fe0c83..d523bf8 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,99 +1,93 @@ -import {App, Editor, MarkdownView, Modal, Notice, Plugin} from 'obsidian'; -import {DEFAULT_SETTINGS, MyPluginSettings, SampleSettingTab} from "./settings"; +import { Plugin, WorkspaceLeaf } from "obsidian"; +import { AIOrganizerSettings, DEFAULT_SETTINGS } from "./settings"; +import { ChatView, VIEW_TYPE_CHAT } from "./chat-view"; +import { testConnection, listModels } from "./ollama-client"; -// Remember to rename these classes and interfaces! +export default class AIOrganizer extends Plugin { + settings: AIOrganizerSettings = DEFAULT_SETTINGS; -export default class MyPlugin extends Plugin { - settings: MyPluginSettings; + // Runtime connection state (not persisted) + connectionStatus: "disconnected" | "connecting" | "connected" | "error" = "disconnected"; + connectionMessage = ""; + availableModels: string[] = []; - async onload() { + async onload(): Promise<void> { await this.loadSettings(); - // This creates an icon in the left ribbon. - this.addRibbonIcon('dice', 'Sample', (evt: MouseEvent) => { - // Called when the user clicks the icon. - new Notice('This is a notice!'); - }); + this.registerView(VIEW_TYPE_CHAT, (leaf) => new ChatView(leaf, this)); - // This adds a status bar item to the bottom of the app. Does not work on mobile apps. - const statusBarItemEl = this.addStatusBarItem(); - statusBarItemEl.setText('Status bar text'); + this.addRibbonIcon("message-square", "Open AI Chat", () => { + void this.activateView(); + }); - // This adds a simple command that can be triggered anywhere this.addCommand({ - id: 'open-modal-simple', - name: 'Open modal (simple)', + id: "open-chat", + name: "Open AI Chat", callback: () => { - new SampleModal(this.app).open(); - } - }); - // This adds an editor command that can perform some operation on the current editor instance - this.addCommand({ - id: 'replace-selected', - name: 'Replace selected content', - editorCallback: (editor: Editor, view: MarkdownView) => { - editor.replaceSelection('Sample editor command'); - } + void this.activateView(); + }, }); - // This adds a complex command that can check whether the current state of the app allows execution of the command - this.addCommand({ - id: 'open-modal-complex', - name: 'Open modal (complex)', - checkCallback: (checking: boolean) => { - // Conditions to check - const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView); - if (markdownView) { - // If checking is true, we're simply "checking" if the command can be run. - // If checking is false, then we want to actually perform the operation. - if (!checking) { - new SampleModal(this.app).open(); - } - - // This command will only show up in Command Palette when the check function returns true - return true; - } - return false; - } - }); - - // This adds a settings tab so the user can configure various aspects of the plugin - this.addSettingTab(new SampleSettingTab(this.app, this)); + } - // If the plugin hooks up any global DOM events (on parts of the app that doesn't belong to this plugin) - // Using this function will automatically remove the event listener when this plugin is disabled. - this.registerDomEvent(document, 'click', (evt: MouseEvent) => { - new Notice("Click"); - }); + onunload(): void { + this.app.workspace.detachLeavesOfType(VIEW_TYPE_CHAT); + } - // When registering intervals, this function will automatically clear the interval when the plugin is disabled. - this.registerInterval(window.setInterval(() => console.log('setInterval'), 5 * 60 * 1000)); + async activateView(): Promise<void> { + const existing = this.app.workspace.getLeavesOfType(VIEW_TYPE_CHAT); + if (existing.length > 0) { + const first = existing[0]; + if (first !== undefined) { + this.app.workspace.revealLeaf(first); + } + return; + } - } + const leaf: WorkspaceLeaf | null = this.app.workspace.getRightLeaf(false); + if (leaf === null) { + return; + } - onunload() { + await leaf.setViewState({ type: VIEW_TYPE_CHAT, active: true }); + this.app.workspace.revealLeaf(leaf); } - async loadSettings() { - this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData() as Partial<MyPluginSettings>); + async loadSettings(): Promise<void> { + this.settings = Object.assign( + {}, + DEFAULT_SETTINGS, + await this.loadData() as Partial<AIOrganizerSettings> | null, + ); } - async saveSettings() { + async saveSettings(): Promise<void> { await this.saveData(this.settings); } -} - -class SampleModal extends Modal { - constructor(app: App) { - super(app); - } - onOpen() { - let {contentEl} = this; - contentEl.setText('Woah!'); - } + async connect(): Promise<void> { + this.connectionStatus = "connecting"; + this.connectionMessage = "Connecting..."; + this.availableModels = []; + + try { + const version = await testConnection(this.settings.ollamaUrl); + this.connectionMessage = `Connected — Ollama v${version}`; + + try { + this.availableModels = await listModels(this.settings.ollamaUrl); + } catch (modelErr: unknown) { + const modelMsg = + modelErr instanceof Error + ? modelErr.message + : "Failed to list models."; + this.connectionMessage = `Connected — Ollama v${version} (${modelMsg})`; + } - onClose() { - const {contentEl} = this; - contentEl.empty(); + this.connectionStatus = "connected"; + } catch (err: unknown) { + const errMsg = err instanceof Error ? err.message : "Connection failed."; + this.connectionMessage = errMsg; + this.connectionStatus = "error"; + } } } |
