Fix mobile compatibility: dynamic import for task dispatch

TaskDispatchService uses Node.js modules (child_process, fs, path) that
are unavailable on Obsidian mobile. Switch to dynamic import with
Platform.isMobile guard so the plugin loads cleanly on mobile while
keeping full task dispatch functionality on desktop.

- Use `import type` + dynamic `import()` for TaskDispatchService
- Guard task dispatch commands behind Platform.isMobile check
- Lazy-import detectTmuxPath in settings tab
- Bump version to 0.5.2

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Chris Lettieri 2026-02-25 21:53:33 -05:00
parent 117b33eb95
commit 6e9ed65d40
6 changed files with 94 additions and 58 deletions

View file

@ -1,7 +1,7 @@
{
"id": "openaugi",
"name": "OpenAugi",
"version": "0.5.1",
"version": "0.5.2",
"minAppVersion": "1.8.9",
"description": "Process information faster with augmented intelligence (AI for thinkers). Parse your voice notes into atomic notes, tasks, and summaries. Grab context from dataview queries and linked notes. De-duplicate and merge atomic ideas into a clean, organized vault.",
"author": "Chris Lettieri",

View file

@ -1,6 +1,6 @@
{
"name": "open-augi",
"version": "0.5.1",
"version": "0.5.2",
"description": "",
"main": "main.js",
"scripts": {

View file

@ -1,10 +1,12 @@
import { Plugin, Notice, TFile } from 'obsidian';
import { Plugin, Notice, TFile, Platform } from 'obsidian';
import { OpenAugiSettings, DEFAULT_SETTINGS } from './types/settings';
import { OpenAIService } from './services/openai-service';
import { FileService } from './services/file-service';
import { DistillService } from './services/distill-service';
import { ContextGatheringService } from './services/context-gathering-service';
import { TaskDispatchService } from './services/task-dispatch-service';
// Lazy-imported: TaskDispatchService uses Node.js modules (child_process, fs, path)
// that are unavailable on mobile. We dynamic-import it only on desktop.
import type { TaskDispatchService } from './services/task-dispatch-service';
import { OpenAugiSettingTab } from './ui/settings-tab';
import { LoadingIndicator } from './ui/loading-indicator';
import { SessionListModal } from './ui/session-list-modal';
@ -32,7 +34,7 @@ export default class OpenAugiPlugin extends Plugin {
fileService: FileService;
distillService: DistillService;
contextGatheringService: ContextGatheringService;
taskDispatchService: TaskDispatchService;
taskDispatchService: TaskDispatchService | null;
loadingIndicator: LoadingIndicator;
async onload() {
@ -116,52 +118,66 @@ export default class OpenAugiPlugin extends Plugin {
}
});
// Task dispatch commands
this.addCommand({
id: 'task-dispatch-launch',
name: 'Task dispatch: Launch or attach',
callback: async () => {
const activeFile = this.app.workspace.getActiveFile();
if (activeFile && activeFile.extension === 'md') {
await this.taskDispatchService.launchOrAttach(activeFile);
} else {
new Notice('Please open a task note first');
}
}
});
this.addCommand({
id: 'task-dispatch-kill',
name: 'Task dispatch: Kill session',
callback: async () => {
const activeFile = this.app.workspace.getActiveFile();
if (activeFile && activeFile.extension === 'md') {
await this.taskDispatchService.killSession(activeFile);
} else {
new Notice('Please open a task note first');
}
}
});
this.addCommand({
id: 'task-dispatch-list',
name: 'Task dispatch: List active sessions',
callback: async () => {
const sessions = await this.taskDispatchService.listActiveSessions();
const modal = new SessionListModal(
this.app,
sessions,
async (session: TaskSession) => {
await this.taskDispatchService.openTerminal(session.tmuxSessionName);
},
async (session: TaskSession) => {
await this.taskDispatchService.killSessionById(session.taskId);
new Notice(`Killed session: ${session.taskId}`);
// Task dispatch commands — desktop only
if (!Platform.isMobile) {
this.addCommand({
id: 'task-dispatch-launch',
name: 'Task dispatch: Launch or attach',
callback: async () => {
if (!this.taskDispatchService) {
new Notice('Task dispatch is still loading, try again in a moment');
return;
}
);
modal.open();
}
});
const activeFile = this.app.workspace.getActiveFile();
if (activeFile && activeFile.extension === 'md') {
await this.taskDispatchService.launchOrAttach(activeFile);
} else {
new Notice('Please open a task note first');
}
}
});
this.addCommand({
id: 'task-dispatch-kill',
name: 'Task dispatch: Kill session',
callback: async () => {
if (!this.taskDispatchService) {
new Notice('Task dispatch is still loading, try again in a moment');
return;
}
const activeFile = this.app.workspace.getActiveFile();
if (activeFile && activeFile.extension === 'md') {
await this.taskDispatchService.killSession(activeFile);
} else {
new Notice('Please open a task note first');
}
}
});
this.addCommand({
id: 'task-dispatch-list',
name: 'Task dispatch: List active sessions',
callback: async () => {
if (!this.taskDispatchService) {
new Notice('Task dispatch is still loading, try again in a moment');
return;
}
const sessions = await this.taskDispatchService.listActiveSessions();
const modal = new SessionListModal(
this.app,
sessions,
async (session: TaskSession) => {
await this.taskDispatchService!.openTerminal(session.tmuxSessionName);
},
async (session: TaskSession) => {
await this.taskDispatchService!.killSessionById(session.taskId);
new Notice(`Killed session: ${session.taskId}`);
}
);
modal.open();
}
});
}
// Add settings tab
this.addSettingTab(new OpenAugiSettingTab(this.app, this));
@ -195,11 +211,23 @@ export default class OpenAugiPlugin extends Plugin {
this.distillService,
this.settings
);
this.taskDispatchService = new TaskDispatchService(
this.app,
this.settings,
this.distillService
);
// TaskDispatchService uses Node.js modules (child_process, fs, path)
// unavailable on mobile. Skip entirely on mobile.
this.taskDispatchService = null;
if (!Platform.isMobile) {
import('./services/task-dispatch-service')
.then(({ TaskDispatchService }) => {
this.taskDispatchService = new TaskDispatchService(
this.app,
this.settings,
this.distillService
);
})
.catch(() => {
// Fallback: Node.js modules unavailable in this environment.
});
}
}
/**

View file

@ -2,12 +2,12 @@ import { Plugin } from 'obsidian';
import { OpenAugiSettings } from './settings';
import { OpenAIService } from '../services/openai-service';
import { FileService } from '../services/file-service';
import { TaskDispatchService } from '../services/task-dispatch-service';
import type { TaskDispatchService } from '../services/task-dispatch-service';
export default interface OpenAugiPlugin extends Plugin {
settings: OpenAugiSettings;
openAIService: OpenAIService;
fileService: FileService;
taskDispatchService: TaskDispatchService;
taskDispatchService: TaskDispatchService | null;
saveSettings(): Promise<void>;
}

View file

@ -2,7 +2,8 @@ import { App, PluginSettingTab, Setting, Notice, DropdownComponent } from 'obsid
import type OpenAugiPlugin from '../types/plugin';
import { OpenAIService } from '../services/openai-service';
import { TerminalApp } from '../types/task-dispatch';
import { detectTmuxPath } from '../services/task-dispatch-service';
// Lazy-imported: detectTmuxPath lives in task-dispatch-service which uses
// Node.js modules unavailable on mobile.
export class OpenAugiSettingTab extends PluginSettingTab {
plugin: OpenAugiPlugin;
@ -387,6 +388,7 @@ export class OpenAugiSettingTab extends PluginSettingTab {
.addButton(button => button
.setButtonText('Detect')
.onClick(async () => {
const { detectTmuxPath } = await import('../services/task-dispatch-service');
const found = await detectTmuxPath();
if (found) {
this.plugin.settings.taskDispatch.tmuxPath = found;

View file

@ -72,5 +72,11 @@ export class FileSystemAdapter {
getBasePath(): string { return this.basePath; }
}
export const Platform = {
isMobile: false,
isDesktop: true,
isDesktopApp: true,
};
export class MarkdownView {}
export class WorkspaceLeaf {}