diff --git a/src/web/public/app.js b/src/web/public/app.js index 195a4c43..8e846c18 100644 --- a/src/web/public/app.js +++ b/src/web/public/app.js @@ -5440,7 +5440,7 @@ class ClaudemanApp { - ${mode === 'shell' ? '' : ''} + ${mode === 'shell' ? '' : mode === 'opencode' ? '' : ''} ${this.escapeHtml(name)} ${showFolder ? `\u{1F4C1} ${this.escapeHtml(folderName)}` : ''} @@ -9507,6 +9507,48 @@ class ClaudemanApp { } } + async runOpenCode() { + const caseName = document.getElementById('quickStartCase').value || 'testcase'; + + this.terminal.clear(); + this.terminal.writeln(`\x1b[1;32m Starting OpenCode session in ${caseName}...\x1b[0m`); + this.terminal.writeln(''); + + try { + // Check if OpenCode is available + const statusRes = await fetch('/api/opencode/status'); + const status = await statusRes.json(); + if (!status.available) { + this.terminal.writeln('\x1b[1;31m OpenCode CLI not found.\x1b[0m'); + this.terminal.writeln('\x1b[90m Install with: curl -fsSL https://opencode.ai/install | bash\x1b[0m'); + return; + } + + // Quick-start with opencode mode (auto-allow tools by default) + const res = await fetch('/api/quick-start', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + caseName, + mode: 'opencode', + openCodeConfig: { autoAllowTools: true }, + }) + }); + const data = await res.json(); + if (!data.success) throw new Error(data.error || 'Failed to start OpenCode'); + + // Switch to the new session + if (data.sessionId) { + this.activeSessionId = data.sessionId; + await this.selectSession(data.sessionId); + } + + this.terminal.focus(); + } catch (err) { + this.terminal.writeln(`\x1b[1;31m Error: ${err.message}\x1b[0m`); + } + } + // ========== Directory Input ========== toggleDirInput() { @@ -10263,8 +10305,8 @@ class ClaudemanApp { this.editingSessionId = sessionId; - // Reset to Respawn tab - this.switchOptionsTab('respawn'); + // Reset to an appropriate tab — Summary for OpenCode (Respawn/Ralph are Claude-only) + this.switchOptionsTab(session.mode === 'opencode' ? 'summary' : 'respawn'); // Update respawn status display and buttons const respawnStatus = document.getElementById('sessionRespawnStatus'); @@ -10292,6 +10334,11 @@ class ClaudemanApp { respawnSection.style.display = 'none'; } + // Hide Claude-specific options for OpenCode sessions + const isOpenCode = session.mode === 'opencode'; + const claudeOnlyEls = document.querySelectorAll('[data-claude-only]'); + claudeOnlyEls.forEach(el => { el.style.display = isOpenCode ? 'none' : ''; }); + // Reset duration presets to default (unlimited) this.selectDurationPreset(''); diff --git a/src/web/public/index.html b/src/web/public/index.html index f8cffcb6..50e56dca 100644 --- a/src/web/public/index.html +++ b/src/web/public/index.html @@ -238,6 +238,10 @@ Run Claude + +