diff --git a/src/services/task-dispatch-service.ts b/src/services/task-dispatch-service.ts index d1cdf13..aa24a53 100644 --- a/src/services/task-dispatch-service.ts +++ b/src/services/task-dispatch-service.ts @@ -94,7 +94,8 @@ export class TaskDispatchService { const contextContent = await this.assembleContext(file, taskId); const contextFilePath = await this.writeContextFile(taskId, contextContent); - await this.createTmuxSession(tmux, sessionName, agentConfig, contextFilePath); + const workingDir = this.getWorkingDir(file); + await this.createTmuxSession(tmux, sessionName, agentConfig, contextFilePath, workingDir); await this.openTerminal(sessionName); } } catch (error) { @@ -227,6 +228,22 @@ export class TaskDispatchService { return taskId ? String(taskId) : null; } + /** + * Resolve the working directory for a task session. + * Priority: `repo` frontmatter → defaultWorkingDir setting → home dir. + */ + private getWorkingDir(file: TFile): string { + const cache = this.app.metadataCache.getFileCache(file); + const fm = cache?.frontmatter; + const repo = fm?.['repo']; + if (repo && typeof repo === 'string') return repo; + + const defaultDir = this.settings.taskDispatch.defaultWorkingDir; + if (defaultDir) return defaultDir; + + return process.env.HOME ?? '/tmp'; + } + private async assembleContext(file: TFile, taskId: string): Promise { // Read note body and strip frontmatter const rawContent = await this.app.vault.read(file); @@ -297,9 +314,10 @@ export class TaskDispatchService { tmux: string, sessionName: string, agentConfig: AgentConfig, - contextFilePath: string + contextFilePath: string, + workingDir: string ): Promise { - await execAsync(`${tmux} new-session -d -s ${this.shellEscape(sessionName)}`); + await execAsync(`${tmux} new-session -d -s ${this.shellEscape(sessionName)} -c ${this.shellEscape(workingDir)}`); const agentCommand = `${agentConfig.command} ${agentConfig.contextFlag} ${this.shellEscape(contextFilePath)}`; await execAsync( diff --git a/src/types/settings.ts b/src/types/settings.ts index 2b139dc..e097c64 100644 --- a/src/types/settings.ts +++ b/src/types/settings.ts @@ -59,6 +59,7 @@ export const DEFAULT_SETTINGS: OpenAugiSettings = { taskDispatch: { terminalApp: 'iterm2', tmuxPath: '', + defaultWorkingDir: '', agents: [ { id: 'claude-code', diff --git a/src/types/task-dispatch.ts b/src/types/task-dispatch.ts index cb57d57..fb09f78 100644 --- a/src/types/task-dispatch.ts +++ b/src/types/task-dispatch.ts @@ -12,6 +12,7 @@ export type TerminalApp = 'iterm2' | 'terminal-app'; export interface TaskDispatchSettings { terminalApp: TerminalApp; tmuxPath: string; // absolute path to tmux binary; empty = auto-detect + defaultWorkingDir: string; // directory Claude launches in; overridden by `repo` frontmatter agents: AgentConfig[]; defaultAgent: string; contextTempDir: string; diff --git a/src/ui/settings-tab.ts b/src/ui/settings-tab.ts index 0bae61d..cd60dc1 100644 --- a/src/ui/settings-tab.ts +++ b/src/ui/settings-tab.ts @@ -399,6 +399,23 @@ export class OpenAugiSettingTab extends PluginSettingTab { }) ); + new Setting(containerEl) + .setName('Default working directory') + .setDesc('Directory the agent launches in. Override per-task with `repo` in frontmatter.') + .addText(text => { + text + .setPlaceholder('~/projects') + .setValue(this.plugin.settings.taskDispatch.defaultWorkingDir); + text.inputEl.addEventListener('blur', async () => { + const value = text.getValue().trim(); + if (value !== this.plugin.settings.taskDispatch.defaultWorkingDir) { + this.plugin.settings.taskDispatch.defaultWorkingDir = value; + await this.plugin.saveSettings(); + } + }); + return text; + }); + new Setting(containerEl) .setName('Default agent') .setDesc('Agent to use when task note does not specify one')