summaryrefslogtreecommitdiffhomepage
path: root/src/main.ts
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-03-24 13:18:50 +0900
committerAdam Malczewski <[email protected]>2026-03-24 13:18:50 +0900
commitbb543c3f7840f2a3fa1b7a1fb32245fa87a30f7b (patch)
treed2a9db2741dfd9822c5f76dca278562220e9b064 /src/main.ts
parente5583b836d4fe2f7f9806ed85a190254a6ea3990 (diff)
downloadai-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.ts144
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";
+ }
}
}