Extract isCmuxCompatEnvironment to shared module and fix
interactive_bash to resolve cmux executables with the __tmux-compat
prefix, matching all other tmux command paths in the codebase.
After SIGTERM/SIGKILL escalation, the stdout stream may not close immediately on all platforms. The unconditional await on outputPromise could then hang indefinitely, defeating the bounded process lifetime guarantee. Race outputPromise against a short follow-up timeout to ensure getOpenCodeVersion always returns within a bounded time.
Refs #3766
Only clear recentAnyIdles when the stored marker matches the synthetic idle timestamp for the same session, preventing accidental clobbering of newer idle markers. Add a regression test to verify other sessions keep their dedup state during this bypass path.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
When the binary resolved as 'opencode' on PATH is the OpenCode Desktop GUI (not the CLI), it does not respond to --version with prompt exit. proc.exited then waits forever, freezing the installer at 'Checking OpenCode installation'.
Fix: race proc.exited against OPENCODE_VERSION_CHECK_TIMEOUT_MS=1500. On timeout, proc.kill() and treat the binary as failed so the next candidate is tried. Success requires both timedExitCode === 0 and proc.exitCode === 0.
Fixes#3766
- Add /exceeded.*quota/i and /usage\s*quota/i to classifyErrorType quota block
- Align /usage.?quota/i -> /usage\s*quota/i in RETRYABLE_ERROR_PATTERNS for consistency
- Strengthen auto-retry-signal test assertion
- Add classifyErrorType assertion to Volcano Engine regression test
Ensures Volcano Engine errors are both retryable AND logged as
errorType: quota_exceeded.
Volcano Engine sends quota exceeded errors with the words in reverse
order: 'You have exceeded the 5-hour usage quota'. The existing
patterns required 'quota' to precede 'exceeded', so they never matched.
- Add /exceeded.*quota/i and /usage.?quota/i to RETRYABLE_ERROR_PATTERNS
- Add exceeded.*quota and usage\s*quota to AUTO_RETRY_PATTERNS
- Add regression tests for both detection paths
Fixes: runtime-fallback not triggering on Volcano Engine quota errors
The deep and artistry category fallback chains had no opencode-go provider
entries, causing them to fall through to the ultimate fallback
(opencode/gpt-5-nano) which is not available to opencode-go users.
Add opencode-go entries:
- deep: deepseek-v4-pro -> kimi-k2.6 -> glm-5.1
- artistry: kimi-k2.6 -> glm-5.1
Fixes#3924
The same output.trim() bug fixed in PR #3909 for doctor exists in the
installer's opencode-binary.ts. Without this fix, `bunx oh-my-opencode
install` would store polluted Electron stdout (e.g., `00:24:25.202 >
app starting { version: '1.14.33', packaged: true }`) as the OpenCode
version in config, breaking downstream version-dependent logic.
- Extract extractSemverFromOutput to src/shared/extract-semver.ts
(precedent: spawn-with-windows-hide is in shared because used by
both doctor and installer)
- src/cli/doctor/checks/system-binary.ts now imports from shared and
re-exports for backward compat
- src/cli/config-manager/opencode-binary.ts uses the shared helper
with `?? output.trim()` fallback to preserve legacy behavior on
non-semver-shaped successful outputs (e.g., custom builds)
- Add 4 installer regression tests covering: clean semver, polluted
Electron stdout (regression for #3765 installer caller), fallback
for non-semver, null when no binary on PATH
Refs #3765