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
Reconcile the latest dev branch changes with the delegated child-session fallback work. Preserve the upstream background-agent updates while keeping the delegated bootstrap cleanup and compatibility wiring fixes intact, then re-verify the affected regression suites and typecheck.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Keep the new manager-side bootstrap registration as the primary path, but restore a compatibility fallback when the parent call aborts before the child session id resolves. This preserves late delegated session wiring for already-launched background tasks without reverting the new bootstrap architecture.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
- 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
MessageAbortedError/worker shutdown could race with scheduled removeTask, leaving background_output's manager.getTask returning 'Task not found' even though the task had completed cleanly.
Fix: add completedTaskArchive (max 500, FIFO eviction). On removeTask, archive non-running/pending tasks with sessionId. getTask falls back to archive on active-map miss. addTask clears stale archive entries on re-registration.
Fixes#3895
When session.status(idle) is converted to synthetic session.idle and recorded in recentAnyIdles, a real session.idle arriving within 500ms was being dropped by the dedup logic. recentSyntheticIdles was cleared but recentAnyIdles persisted, causing TODO-DIAG to red-alert with 'no todossession.idle event'.
Fix: when real session.idle arrives, also clear recentAnyIdles entry so dedup does not drop it. Test renamed and expected dispatchCalls updated 1 → 2.
Fixes#2667
openSync with read-only mode fails fsync on Windows because FlushFileBuffers requires write-permission FD. This caused atomic writes to fail silently, leaving migrated config unwritten and triggering repeated migration + .bak.<timestamp> generation on every startup.
Same root cause as PR #3644 (#3643). Hyperplan disappear is a secondary symptom of plugin load instability.
Fixes#3877
The Electron-based OpenCode build leaks log lines like
`00:24:25.202 > app starting { version: '1.14.33', packaged: true }`
into stdout, so `getOpenCodeVersion` was returning the entire log
line as the 'version'. `compareVersions` then split that string on
'.' and produced a nonsensical numeric array (e.g., `[0, 0, 14, 0]`),
which it judged as < the minimum 1.4.0. Result: doctor incorrectly
flagged OpenCode 1.14.x as below the minimum required version.
Replace the raw `stdout.trim()` return with a small
`extractSemverFromOutput` helper that runs a semver-shaped regex
across the output. A negative lookbehind `(?<![\d:])` skips the
milliseconds segment of timestamps (e.g., `25.202` in
`00:24:25.202`), so the parser locks onto the real version token.
Adds 12 unit tests covering plain semver, v-prefix, pre-release,
build metadata, the Electron regression, timestamp-only stdout,
and various invalid inputs.
Fixes#3765
Keep ordinary delegated subagents from seeing team tools while preserving communication tools for real team-mode member sessions, including fallback retry sessions.
- Add src/locales/ with en baseline and zh overrides (Partial<Record> fallback)
- Add src/shared/i18n.ts with initI18n/t/setLocale/getLocale (LANG env auto-detect)
- Add I18nConfigSchema with locale field to plugin config
- Internationalize 13 hardcoded strings in task-toast-manager
- Add 18 unit tests for i18n module
- Pin manager tests to en locale for determinism
Three reviewer-flagged corrections, none with UX impact:
- Category Routing block on the landing page still showed pre-v4.0 model
labels (`ultrabrain → GPT 5.4`, `deep → GPT 5.3 Codex`, `quick →
Claude Haiku 4.5`) which contradicted the rest of the page after the
model refresh. Pinned them to the actual primary chains
(`ultrabrain → GPT 5.5 xHigh`, `deep → GPT 5.5 Medium`,
`quick → GPT 5.4 Mini`). Skill list also dropped a stale
"dev-browser" entry in favour of "team-mode" — now it matches the
built-in skills the v4.0 release ships.
- OG/Twitter image metadata in app/layout.tsx claimed the hero was
1536×1024 — actual file is 1024×683. Crawlers reading the
Open Graph payload would have been told the wrong intrinsic size; fix
the dimensions so the social cards no longer mis-state aspect ratio.
- e2e/example.spec.ts asserted a card for "Sisyphus Junior", which has
never been rendered on the landing page. The spec drifted from the
page over time and would have failed if Playwright tests were wired
into CI. Pruned the list to the nine agents actually rendered.