diff --git a/README.md b/README.md index 414bbec5..f2bc2f1c 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,10 @@ You can also open the plugin page directly: `Codex Panel` and set `Codex executable` to an absolute path such as `/opt/homebrew/bin/codex`. @@ -43,6 +44,8 @@ The composer sends with `Enter` by default. Use `Shift+Enter` for a newline, or Codex Panel launches a local Codex app-server process for the current vault. The vault root becomes Codex's working directory, so Codex sees the same project or notes folder that Obsidian has open. +Each open Codex panel owns its own app-server connection, active thread, pending approvals, Plan mode questions, and composer draft. Thread history is shared through Codex for the same vault. + The plugin does not duplicate Codex's configuration UI. To change model defaults, sandboxing, approval policy, MCP servers, hooks, or network behavior, configure Codex itself. The panel can show the effective config for the current vault as a diagnostic view, but it does not save those settings. Obsidian wikilinks in sent messages are lightly bridged to Codex file mentions when the target file exists. The visible message text is preserved, unresolved wikilinks are not expanded, and note bodies are not automatically attached by the panel. @@ -50,6 +53,7 @@ Obsidian wikilinks in sent messages are lightly bridged to Codex file mentions w ## Features - Start, resume, rename, fork, compact, and archive Codex threads from Obsidian. +- Open multiple right-sidebar Codex panels for separate active threads. - Stream user, assistant, reasoning, command, tool, hook, and file-change events. - Respond to command, file, permission, and Plan mode approval requests. - Toggle Plan mode, fast mode, model override, and reasoning effort override for subsequent turns. diff --git a/src/main.ts b/src/main.ts index 4f1e95e4..e1f122b4 100644 --- a/src/main.ts +++ b/src/main.ts @@ -90,6 +90,12 @@ export default class CodexPanelPlugin extends Plugin { callback: () => void this.activateView(), }); + this.addCommand({ + id: "open-new-panel", + name: "Open new panel", + callback: () => void this.activateNewView(), + }); + this.addCommand({ id: "new-chat", name: "New chat", @@ -112,6 +118,23 @@ export default class CodexPanelPlugin extends Plugin { return leaf.view as CodexPanelView; } + async activateNewView(): Promise { + const leaf = this.createRightSidebarTab(); + if (!leaf) throw new Error("Could not create a right sidebar leaf."); + + await leaf.setViewState({ type: VIEW_TYPE_CODEX_PANEL, active: true }); + await this.app.workspace.revealLeaf(leaf); + return leaf.view as CodexPanelView; + } + + private createRightSidebarTab(): WorkspaceLeaf | null { + const { workspace } = this.app; + const existing = workspace.getLeavesOfType(VIEW_TYPE_CODEX_PANEL).find((leaf) => leaf.getRoot() === workspace.rightSplit); + if (!existing) return workspace.getRightLeaf(false); + + return workspace.createLeafInParent(existing.parent, Number.MAX_SAFE_INTEGER); + } + refreshOpenViews(): void { for (const leaf of this.app.workspace.getLeavesOfType(VIEW_TYPE_CODEX_PANEL)) { if (leaf.view instanceof CodexPanelView) {