import * as p from "@clack/prompts" import color from "picocolors" import type { InstallArgs } from "./types" import { addAuthPlugins, addPluginToOpenCodeConfig, addProviderConfig, detectCurrentConfig, getOpenCodeVersion, isOpenCodeInstalled, writeOmoConfig, } from "./config-manager" import { detectedToInitialValues, formatConfigSummary, SYMBOLS } from "./install-validators" import { promptInstallConfig } from "./tui-install-prompts" export async function runTuiInstaller(args: InstallArgs, version: string): Promise { if (!process.stdin.isTTY || !process.stdout.isTTY) { console.error("Error: Interactive installer requires a TTY. Use --non-interactive or set environment variables directly.") return 1 } const detected = detectCurrentConfig() const isUpdate = detected.isInstalled p.intro(color.bgMagenta(color.white(isUpdate ? " oMoMoMoMo... Update " : " oMoMoMoMo... "))) if (isUpdate) { const initial = detectedToInitialValues(detected) p.log.info(`Existing configuration detected: Claude=${initial.claude}, Gemini=${initial.gemini}`) } const spinner = p.spinner() spinner.start("Checking OpenCode installation") const installed = await isOpenCodeInstalled() const openCodeVersion = await getOpenCodeVersion() if (!installed) { spinner.stop(`OpenCode binary not found ${color.yellow("[!]")}`) p.log.warn("OpenCode binary not found. Plugin will be configured, but you'll need to install OpenCode to use it.") p.note("Visit https://opencode.ai/docs for installation instructions", "Installation Guide") } else { spinner.stop(`OpenCode ${openCodeVersion ?? "installed"} ${color.green("[OK]")}`) } const config = await promptInstallConfig(detected) if (!config) return 1 spinner.start("Adding oh-my-opencode to OpenCode config") const pluginResult = await addPluginToOpenCodeConfig(version) if (!pluginResult.success) { spinner.stop(`Failed to add plugin: ${pluginResult.error}`) p.outro(color.red("Installation failed.")) return 1 } spinner.stop(`Plugin added to ${color.cyan(pluginResult.configPath)}`) if (config.hasGemini) { spinner.start("Adding auth plugins (fetching latest versions)") const authResult = await addAuthPlugins(config) if (!authResult.success) { spinner.stop(`Failed to add auth plugins: ${authResult.error}`) p.outro(color.red("Installation failed.")) return 1 } spinner.stop(`Auth plugins added to ${color.cyan(authResult.configPath)}`) spinner.start("Adding provider configurations") const providerResult = addProviderConfig(config) if (!providerResult.success) { spinner.stop(`Failed to add provider config: ${providerResult.error}`) p.outro(color.red("Installation failed.")) return 1 } spinner.stop(`Provider config added to ${color.cyan(providerResult.configPath)}`) } spinner.start("Writing oh-my-opencode configuration") const omoResult = writeOmoConfig(config) if (!omoResult.success) { spinner.stop(`Failed to write config: ${omoResult.error}`) p.outro(color.red("Installation failed.")) return 1 } spinner.stop(`Config written to ${color.cyan(omoResult.configPath)}`) if (!config.hasClaude) { console.log() console.log(color.bgRed(color.white(color.bold(" CRITICAL WARNING ")))) console.log() console.log(color.red(color.bold(" Sisyphus agent is STRONGLY optimized for Claude Opus 4.5."))) console.log(color.red(" Without Claude, you may experience significantly degraded performance:")) console.log(color.dim(" • Reduced orchestration quality")) console.log(color.dim(" • Weaker tool selection and delegation")) console.log(color.dim(" • Less reliable task completion")) console.log() console.log(color.yellow(" Consider subscribing to Claude Pro/Max for the best experience.")) console.log() } if (!config.hasClaude && !config.hasOpenAI && !config.hasGemini && !config.hasCopilot && !config.hasOpencodeZen) { p.log.warn("No model providers configured. Using opencode/glm-4.7-free as fallback.") } p.note(formatConfigSummary(config), isUpdate ? "Updated Configuration" : "Installation Complete") p.log.success(color.bold(isUpdate ? "Configuration updated!" : "Installation complete!")) p.log.message(`Run ${color.cyan("opencode")} to start!`) p.note( `Include ${color.cyan("ultrawork")} (or ${color.cyan("ulw")}) in your prompt.\n` + `All features work like magic—parallel agents, background tasks,\n` + `deep exploration, and relentless execution until completion.`, "The Magic Word", ) p.log.message(`${color.yellow("★")} If you found this helpful, consider starring the repo!`) p.log.message( ` ${color.dim("gh api --silent --method PUT /user/starred/code-yeongyu/oh-my-opencode >/dev/null 2>&1 || true")}`, ) p.outro(color.green("oMoMoMoMo... Enjoy!")) if ((config.hasClaude || config.hasGemini || config.hasCopilot) && !args.skipAuth) { const providers: string[] = [] if (config.hasClaude) providers.push(`Anthropic ${color.gray("→ Claude Pro/Max")}`) if (config.hasGemini) providers.push(`Google ${color.gray("→ OAuth with Antigravity")}`) if (config.hasCopilot) providers.push(`GitHub ${color.gray("→ Copilot")}`) console.log() console.log(color.bold("Authenticate Your Providers")) console.log() console.log(` Run ${color.cyan("opencode auth login")} and select:`) for (const provider of providers) { console.log(` ${SYMBOLS.bullet} ${provider}`) } console.log() } return 0 }