feat: OpenCode integration Phases 1-3 — types, CLI resolver, tmux spawn

Phase 1: Type system
- Add SessionMode = 'claude' | 'shell' | 'opencode' to types.ts (single source of truth)
- Add OpenCodeConfig interface (model, autoAllowTools, continueSession, etc.)
- Add openCodeConfig to SessionState
- Import SessionMode in session.ts, mux-interface.ts (remove duplicates)
- Refactor createSession/respawnPane to options objects (CreateSessionOptions, RespawnPaneOptions)

Phase 2: CLI resolver
- New opencode-cli-resolver.ts mirroring claude-cli-resolver.ts
- Searches ~/.opencode/bin, ~/.local/bin, /usr/local/bin, ~/go/bin, etc.
- Exported via utils/index.ts

Phase 3: Tmux spawn
- Extract buildSpawnCommand() shared helper (eliminates duplication)
- Add buildOpenCodeCommand() for opencode CLI flags
- Add setOpenCodeEnvVars() — API keys via tmux setenv (not visible in ps)
- Add setOpenCodeConfigContent() — JSON config via tmux setenv (prevents shell injection)
- Gate _processExpensiveParsers() for opencode mode (skip Claude-specific parsers)
- OpenCode-specific TUI ready detection (timeout-based, no ❯ prompt scanning)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
arkon
2026-02-26 10:07:43 +01:00
co-authored by Claude Opus 4.6
parent 1adcb7656b
commit 0b60f2691f
6 changed files with 386 additions and 93 deletions
+21 -2
View File
@@ -113,6 +113,23 @@ export interface LifecycleEntry {
*/
export type ClaudeMode = 'dangerously-skip-permissions' | 'normal' | 'allowedTools';
/** Session mode: which CLI backend a session runs */
export type SessionMode = 'claude' | 'shell' | 'opencode';
/** OpenCode session configuration */
export interface OpenCodeConfig {
/** Model identifier (e.g., "anthropic/claude-sonnet-4-5", "openai/gpt-5.2", "ollama/codellama") */
model?: string;
/** Whether to auto-allow all tool executions (sets permission.* = allow) */
autoAllowTools?: boolean;
/** Session ID to continue from */
continueSession?: string;
/** Whether to fork when continuing (branch the conversation) */
forkSession?: boolean;
/** Custom inline config JSON (passed via OPENCODE_CONFIG_CONTENT) */
configContent?: string;
}
/**
* Configuration for creating a new session
*/
@@ -158,8 +175,8 @@ export interface SessionState {
lastActivityAt: number;
/** Session display name */
name?: string;
/** Session mode: 'claude' or 'shell' */
mode?: 'claude' | 'shell';
/** Session mode */
mode?: SessionMode;
/** Auto-clear enabled */
autoClearEnabled?: boolean;
/** Auto-clear token threshold */
@@ -208,6 +225,8 @@ export interface SessionState {
cliAccountType?: string;
/** Latest CLI version available (parsed from version check) */
cliLatestVersion?: string;
/** OpenCode-specific configuration (only for mode === 'opencode') */
openCodeConfig?: OpenCodeConfig;
}
// ========== Global Stats Types ==========