fix(server): bound OpenCode CLI health probes with timeouts - #6577

Closed
Adolanium wants to merge 1 commit into
pingdotgg:mainfrom
Adolanium:fix/opencode-probe-timeouts
Closed

fix(server): bound OpenCode CLI health probes with timeouts#6577
Adolanium wants to merge 1 commit into
pingdotgg:mainfrom
Adolanium:fix/opencode-probe-timeouts

Conversation

@Adolanium

@AdolaniumAdolanium commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

What Changed

The OpenCode provider health probes (opencode --version and the model inventory commands via loadInventoryFromCli) awaited child.exitCode with no timeout, so a hung opencode binary (waiting on stdin, stuck on a lock, wedged build) stalled the provider snapshot indefinitely and leaked the spawned process. Every other provider adapter already bounds its probes — Codex (CodexProvider.ts), Claude, Cursor, and Grok all wrap probe commands in Effect.timeoutOption; OpenCode was the only one without.

This wraps both OpenCode probe call sites in Effect.timeoutOption:

  • 4s for the version probe (matches GrokProvider's version probe budget)
  • 15s for the model inventory probe (matches the Grok/Cursor model-discovery budgets; the CLI path can run two subcommands with one 1s-spaced retry)

On timeout the snapshot now reports a clear error (Failed to execute OpenCode CLI health check: Timed out while ..., or the friendly "couldn't reach the configured server" message for external-server setups) instead of hanging. The spawned child is acquired under Effect.scoped in runOpenCodeCommand, so the timeout interrupts the effect and the scope finalizer kills the process — no zombie.

Adds two focused tests (hung version probe, hung inventory probe) using TestClock.

Why

A hung OpenCode CLI leaves the provider stuck in a pending/probing state forever, which previously also surfaced as a cold-start blocker (#2248 — fixed once before, then reintroduced when the health check moved to CLI probes). Bounding the probes turns a silent permanent hang into a bounded, diagnosable failure.

Verified: vp test run on the OpenCode provider/adapter/text-generation test files (48 tests, all passing), targeted typecheck and lint clean.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (N/A — server-only, no UI changes)
  • I included a video for animation/interaction changes (N/A)

Note

Low Risk
Server-only OpenCode health probing; bounded timeouts replace an indefinite hang and match patterns already used by other CLI providers.

Overview
OpenCode’s CLI health check could hang forever when opencode --version or model inventory probes never finish, leaving the provider snapshot stuck probing. This change caps those probes with Effect.timeoutOption: 4s for version (same as Grok) and 15s for inventory.

When a probe exceeds its budget, checkOpenCodeProviderStatus returns an error snapshot with explicit timeout messages instead of blocking indefinitely. Tests extend the runtime mock with hang flags and use TestClock + forked fibers to assert both timeout paths.

Reviewed by Cursor Bugbot for commit e6fcc78. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Bound OpenCode CLI health probes in checkOpenCodeProviderStatus with 4s and 15s timeouts

  • Wraps the --version probe in Effect.timeoutOption(VERSION_PROBE_TIMEOUT_MS) (4000 ms) and the inventory load in Effect.timeoutOption(INVENTORY_PROBE_TIMEOUT_MS) (15000 ms) in OpenCodeProvider.ts.
  • On timeout, returns a fallback snapshot with a specific error message (Timed out while running opencode --version or Timed out while loading the OpenCode model inventory) instead of waiting indefinitely.
  • Adds tests in OpenCodeProvider.test.ts that fork the health check and advance TestClock by 30s to assert the timeout error messages for both probes.
  • Behavioral Change: version and inventory probes that previously hung forever now fail after their respective timeouts; Exit values now wrap Option to account for timeoutOption results.

Macroscope summarized e6fcc78.

@coderabbitai

coderabbitaiBot commented Aug 14, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dede434f-b6a0-4069-b498-fb507e04916d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Aug 14, 2026
macroscopeapp[bot]
macroscopeappBot previously approved these changes Aug 14, 2026
@macroscopeapp

macroscopeappBot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at e6fcc78

Macroscope's review found this PR approvable — This small server-side fix replaces indefinite OpenCode health-check hangs with bounded, diagnosable failures while leaving successful probe behavior unchanged. Focused tests cover both timeout scenarios, and no sensitive or deployment-related files are affected.

You can add or adjust custom eligibility rules. Learn more.

The OpenCode provider probes (opencode --version and the model inventory
CLI commands) awaited child.exitCode with no timeout, so a hung opencode
binary stalled the provider snapshot forever and leaked the spawned
process. Every other provider (Codex, Claude, Cursor, Grok) already wraps
its probes in Effect.timeoutOption.
Wrap both OpenCode probe call sites in Effect.timeoutOption (4s for the
version probe, 15s for the inventory probe, matching peer budgets) and
surface a clear timeout message in the probe status. The spawned child is
scoped, so the timeout interrupts the effect and kills the process.
This is a reintroduction of the regression fixed in pingdotgg#2248, lost when the
health check moved to CLI probes.
@Adolanium
Adolaniumforce-pushed the fix/opencode-probe-timeouts branch from 0330fe6 to e6fcc78CompareAugust 27, 2026 16:11
@macroscopeapp
macroscopeappBot dismissed their stale reviewAugust 27, 2026 16:12

Dismissing prior approval to re-evaluate e6fcc78

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

Closing this because #8750 now gives the OpenCode version probe a four-second limit and cleans up its process group. #8480 moved model inventory to the managed server and SDK, so the CLI inventory path covered by this PR has no production callers.

@t3dotggt3dotgg closed this Sep 3, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Adolanium@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(server): bound OpenCode CLI health probes with timeouts - #6577

Closed
Adolanium wants to merge 1 commit into
pingdotgg:mainfrom
Adolanium:fix/opencode-probe-timeouts
Closed

fix(server): bound OpenCode CLI health probes with timeouts#6577
Adolanium wants to merge 1 commit into
pingdotgg:mainfrom
Adolanium:fix/opencode-probe-timeouts

Conversation

@Adolanium

@AdolaniumAdolanium commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

What Changed

The OpenCode provider health probes (opencode --version and the model inventory commands via loadInventoryFromCli) awaited child.exitCode with no timeout, so a hung opencode binary (waiting on stdin, stuck on a lock, wedged build) stalled the provider snapshot indefinitely and leaked the spawned process. Every other provider adapter already bounds its probes — Codex (CodexProvider.ts), Claude, Cursor, and Grok all wrap probe commands in Effect.timeoutOption; OpenCode was the only one without.

This wraps both OpenCode probe call sites in Effect.timeoutOption:

  • 4s for the version probe (matches GrokProvider's version probe budget)
  • 15s for the model inventory probe (matches the Grok/Cursor model-discovery budgets; the CLI path can run two subcommands with one 1s-spaced retry)

On timeout the snapshot now reports a clear error (Failed to execute OpenCode CLI health check: Timed out while ..., or the friendly "couldn't reach the configured server" message for external-server setups) instead of hanging. The spawned child is acquired under Effect.scoped in runOpenCodeCommand, so the timeout interrupts the effect and the scope finalizer kills the process — no zombie.

Adds two focused tests (hung version probe, hung inventory probe) using TestClock.

Why

A hung OpenCode CLI leaves the provider stuck in a pending/probing state forever, which previously also surfaced as a cold-start blocker (#2248 — fixed once before, then reintroduced when the health check moved to CLI probes). Bounding the probes turns a silent permanent hang into a bounded, diagnosable failure.

Verified: vp test run on the OpenCode provider/adapter/text-generation test files (48 tests, all passing), targeted typecheck and lint clean.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (N/A — server-only, no UI changes)
  • I included a video for animation/interaction changes (N/A)

Note

Low Risk
Server-only OpenCode health probing; bounded timeouts replace an indefinite hang and match patterns already used by other CLI providers.

Overview
OpenCode’s CLI health check could hang forever when opencode --version or model inventory probes never finish, leaving the provider snapshot stuck probing. This change caps those probes with Effect.timeoutOption: 4s for version (same as Grok) and 15s for inventory.

When a probe exceeds its budget, checkOpenCodeProviderStatus returns an error snapshot with explicit timeout messages instead of blocking indefinitely. Tests extend the runtime mock with hang flags and use TestClock + forked fibers to assert both timeout paths.

Reviewed by Cursor Bugbot for commit e6fcc78. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Bound OpenCode CLI health probes in checkOpenCodeProviderStatus with 4s and 15s timeouts

  • Wraps the --version probe in Effect.timeoutOption(VERSION_PROBE_TIMEOUT_MS) (4000 ms) and the inventory load in Effect.timeoutOption(INVENTORY_PROBE_TIMEOUT_MS) (15000 ms) in OpenCodeProvider.ts.
  • On timeout, returns a fallback snapshot with a specific error message (Timed out while running opencode --version or Timed out while loading the OpenCode model inventory) instead of waiting indefinitely.
  • Adds tests in OpenCodeProvider.test.ts that fork the health check and advance TestClock by 30s to assert the timeout error messages for both probes.
  • Behavioral Change: version and inventory probes that previously hung forever now fail after their respective timeouts; Exit values now wrap Option to account for timeoutOption results.

Macroscope summarized e6fcc78.

@coderabbitai

coderabbitaiBot commented Aug 14, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dede434f-b6a0-4069-b498-fb507e04916d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Aug 14, 2026
macroscopeapp[bot]
macroscopeappBot previously approved these changes Aug 14, 2026
@macroscopeapp

macroscopeappBot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at e6fcc78

Macroscope's review found this PR approvable — This small server-side fix replaces indefinite OpenCode health-check hangs with bounded, diagnosable failures while leaving successful probe behavior unchanged. Focused tests cover both timeout scenarios, and no sensitive or deployment-related files are affected.

You can add or adjust custom eligibility rules. Learn more.

The OpenCode provider probes (opencode --version and the model inventory
CLI commands) awaited child.exitCode with no timeout, so a hung opencode
binary stalled the provider snapshot forever and leaked the spawned
process. Every other provider (Codex, Claude, Cursor, Grok) already wraps
its probes in Effect.timeoutOption.
Wrap both OpenCode probe call sites in Effect.timeoutOption (4s for the
version probe, 15s for the inventory probe, matching peer budgets) and
surface a clear timeout message in the probe status. The spawned child is
scoped, so the timeout interrupts the effect and kills the process.
This is a reintroduction of the regression fixed in pingdotgg#2248, lost when the
health check moved to CLI probes.
@Adolanium
Adolaniumforce-pushed the fix/opencode-probe-timeouts branch from 0330fe6 to e6fcc78CompareAugust 27, 2026 16:11
@macroscopeapp
macroscopeappBot dismissed their stale reviewAugust 27, 2026 16:12

Dismissing prior approval to re-evaluate e6fcc78

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

Closing this because #8750 now gives the OpenCode version probe a four-second limit and cleans up its process group. #8480 moved model inventory to the managed server and SDK, so the CLI inventory path covered by this PR has no production callers.

@t3dotggt3dotgg closed this Sep 3, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Adolanium@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(server): bound OpenCode CLI health probes with timeouts - #6577

Closed
Adolanium wants to merge 1 commit into
pingdotgg:mainfrom
Adolanium:fix/opencode-probe-timeouts
Closed

fix(server): bound OpenCode CLI health probes with timeouts#6577
Adolanium wants to merge 1 commit into
pingdotgg:mainfrom
Adolanium:fix/opencode-probe-timeouts

Conversation

@Adolanium

@AdolaniumAdolanium commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

What Changed

The OpenCode provider health probes (opencode --version and the model inventory commands via loadInventoryFromCli) awaited child.exitCode with no timeout, so a hung opencode binary (waiting on stdin, stuck on a lock, wedged build) stalled the provider snapshot indefinitely and leaked the spawned process. Every other provider adapter already bounds its probes — Codex (CodexProvider.ts), Claude, Cursor, and Grok all wrap probe commands in Effect.timeoutOption; OpenCode was the only one without.

This wraps both OpenCode probe call sites in Effect.timeoutOption:

  • 4s for the version probe (matches GrokProvider's version probe budget)
  • 15s for the model inventory probe (matches the Grok/Cursor model-discovery budgets; the CLI path can run two subcommands with one 1s-spaced retry)

On timeout the snapshot now reports a clear error (Failed to execute OpenCode CLI health check: Timed out while ..., or the friendly "couldn't reach the configured server" message for external-server setups) instead of hanging. The spawned child is acquired under Effect.scoped in runOpenCodeCommand, so the timeout interrupts the effect and the scope finalizer kills the process — no zombie.

Adds two focused tests (hung version probe, hung inventory probe) using TestClock.

Why

A hung OpenCode CLI leaves the provider stuck in a pending/probing state forever, which previously also surfaced as a cold-start blocker (#2248 — fixed once before, then reintroduced when the health check moved to CLI probes). Bounding the probes turns a silent permanent hang into a bounded, diagnosable failure.

Verified: vp test run on the OpenCode provider/adapter/text-generation test files (48 tests, all passing), targeted typecheck and lint clean.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (N/A — server-only, no UI changes)
  • I included a video for animation/interaction changes (N/A)

Note

Low Risk
Server-only OpenCode health probing; bounded timeouts replace an indefinite hang and match patterns already used by other CLI providers.

Overview
OpenCode’s CLI health check could hang forever when opencode --version or model inventory probes never finish, leaving the provider snapshot stuck probing. This change caps those probes with Effect.timeoutOption: 4s for version (same as Grok) and 15s for inventory.

When a probe exceeds its budget, checkOpenCodeProviderStatus returns an error snapshot with explicit timeout messages instead of blocking indefinitely. Tests extend the runtime mock with hang flags and use TestClock + forked fibers to assert both timeout paths.

Reviewed by Cursor Bugbot for commit e6fcc78. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Bound OpenCode CLI health probes in checkOpenCodeProviderStatus with 4s and 15s timeouts

  • Wraps the --version probe in Effect.timeoutOption(VERSION_PROBE_TIMEOUT_MS) (4000 ms) and the inventory load in Effect.timeoutOption(INVENTORY_PROBE_TIMEOUT_MS) (15000 ms) in OpenCodeProvider.ts.
  • On timeout, returns a fallback snapshot with a specific error message (Timed out while running opencode --version or Timed out while loading the OpenCode model inventory) instead of waiting indefinitely.
  • Adds tests in OpenCodeProvider.test.ts that fork the health check and advance TestClock by 30s to assert the timeout error messages for both probes.
  • Behavioral Change: version and inventory probes that previously hung forever now fail after their respective timeouts; Exit values now wrap Option to account for timeoutOption results.

Macroscope summarized e6fcc78.

@coderabbitai

coderabbitaiBot commented Aug 14, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dede434f-b6a0-4069-b498-fb507e04916d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Aug 14, 2026
macroscopeapp[bot]
macroscopeappBot previously approved these changes Aug 14, 2026
@macroscopeapp

macroscopeappBot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at e6fcc78

Macroscope's review found this PR approvable — This small server-side fix replaces indefinite OpenCode health-check hangs with bounded, diagnosable failures while leaving successful probe behavior unchanged. Focused tests cover both timeout scenarios, and no sensitive or deployment-related files are affected.

You can add or adjust custom eligibility rules. Learn more.

The OpenCode provider probes (opencode --version and the model inventory
CLI commands) awaited child.exitCode with no timeout, so a hung opencode
binary stalled the provider snapshot forever and leaked the spawned
process. Every other provider (Codex, Claude, Cursor, Grok) already wraps
its probes in Effect.timeoutOption.
Wrap both OpenCode probe call sites in Effect.timeoutOption (4s for the
version probe, 15s for the inventory probe, matching peer budgets) and
surface a clear timeout message in the probe status. The spawned child is
scoped, so the timeout interrupts the effect and kills the process.
This is a reintroduction of the regression fixed in pingdotgg#2248, lost when the
health check moved to CLI probes.
@Adolanium
Adolaniumforce-pushed the fix/opencode-probe-timeouts branch from 0330fe6 to e6fcc78CompareAugust 27, 2026 16:11
@macroscopeapp
macroscopeappBot dismissed their stale reviewAugust 27, 2026 16:12

Dismissing prior approval to re-evaluate e6fcc78

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

Closing this because #8750 now gives the OpenCode version probe a four-second limit and cleans up its process group. #8480 moved model inventory to the managed server and SDK, so the CLI inventory path covered by this PR has no production callers.

@t3dotggt3dotgg closed this Sep 3, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Adolanium@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(server): bound OpenCode CLI health probes with timeouts - #6577

Closed
Adolanium wants to merge 1 commit into
pingdotgg:mainfrom
Adolanium:fix/opencode-probe-timeouts
Closed

fix(server): bound OpenCode CLI health probes with timeouts#6577
Adolanium wants to merge 1 commit into
pingdotgg:mainfrom
Adolanium:fix/opencode-probe-timeouts

Conversation

@Adolanium

@AdolaniumAdolanium commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

What Changed

The OpenCode provider health probes (opencode --version and the model inventory commands via loadInventoryFromCli) awaited child.exitCode with no timeout, so a hung opencode binary (waiting on stdin, stuck on a lock, wedged build) stalled the provider snapshot indefinitely and leaked the spawned process. Every other provider adapter already bounds its probes — Codex (CodexProvider.ts), Claude, Cursor, and Grok all wrap probe commands in Effect.timeoutOption; OpenCode was the only one without.

This wraps both OpenCode probe call sites in Effect.timeoutOption:

  • 4s for the version probe (matches GrokProvider's version probe budget)
  • 15s for the model inventory probe (matches the Grok/Cursor model-discovery budgets; the CLI path can run two subcommands with one 1s-spaced retry)

On timeout the snapshot now reports a clear error (Failed to execute OpenCode CLI health check: Timed out while ..., or the friendly "couldn't reach the configured server" message for external-server setups) instead of hanging. The spawned child is acquired under Effect.scoped in runOpenCodeCommand, so the timeout interrupts the effect and the scope finalizer kills the process — no zombie.

Adds two focused tests (hung version probe, hung inventory probe) using TestClock.

Why

A hung OpenCode CLI leaves the provider stuck in a pending/probing state forever, which previously also surfaced as a cold-start blocker (#2248 — fixed once before, then reintroduced when the health check moved to CLI probes). Bounding the probes turns a silent permanent hang into a bounded, diagnosable failure.

Verified: vp test run on the OpenCode provider/adapter/text-generation test files (48 tests, all passing), targeted typecheck and lint clean.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (N/A — server-only, no UI changes)
  • I included a video for animation/interaction changes (N/A)

Note

Low Risk
Server-only OpenCode health probing; bounded timeouts replace an indefinite hang and match patterns already used by other CLI providers.

Overview
OpenCode’s CLI health check could hang forever when opencode --version or model inventory probes never finish, leaving the provider snapshot stuck probing. This change caps those probes with Effect.timeoutOption: 4s for version (same as Grok) and 15s for inventory.

When a probe exceeds its budget, checkOpenCodeProviderStatus returns an error snapshot with explicit timeout messages instead of blocking indefinitely. Tests extend the runtime mock with hang flags and use TestClock + forked fibers to assert both timeout paths.

Reviewed by Cursor Bugbot for commit e6fcc78. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Bound OpenCode CLI health probes in checkOpenCodeProviderStatus with 4s and 15s timeouts

  • Wraps the --version probe in Effect.timeoutOption(VERSION_PROBE_TIMEOUT_MS) (4000 ms) and the inventory load in Effect.timeoutOption(INVENTORY_PROBE_TIMEOUT_MS) (15000 ms) in OpenCodeProvider.ts.
  • On timeout, returns a fallback snapshot with a specific error message (Timed out while running opencode --version or Timed out while loading the OpenCode model inventory) instead of waiting indefinitely.
  • Adds tests in OpenCodeProvider.test.ts that fork the health check and advance TestClock by 30s to assert the timeout error messages for both probes.
  • Behavioral Change: version and inventory probes that previously hung forever now fail after their respective timeouts; Exit values now wrap Option to account for timeoutOption results.

Macroscope summarized e6fcc78.

@coderabbitai

coderabbitaiBot commented Aug 14, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dede434f-b6a0-4069-b498-fb507e04916d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Aug 14, 2026
macroscopeapp[bot]
macroscopeappBot previously approved these changes Aug 14, 2026
@macroscopeapp

macroscopeappBot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at e6fcc78

Macroscope's review found this PR approvable — This small server-side fix replaces indefinite OpenCode health-check hangs with bounded, diagnosable failures while leaving successful probe behavior unchanged. Focused tests cover both timeout scenarios, and no sensitive or deployment-related files are affected.

You can add or adjust custom eligibility rules. Learn more.

The OpenCode provider probes (opencode --version and the model inventory
CLI commands) awaited child.exitCode with no timeout, so a hung opencode
binary stalled the provider snapshot forever and leaked the spawned
process. Every other provider (Codex, Claude, Cursor, Grok) already wraps
its probes in Effect.timeoutOption.
Wrap both OpenCode probe call sites in Effect.timeoutOption (4s for the
version probe, 15s for the inventory probe, matching peer budgets) and
surface a clear timeout message in the probe status. The spawned child is
scoped, so the timeout interrupts the effect and kills the process.
This is a reintroduction of the regression fixed in pingdotgg#2248, lost when the
health check moved to CLI probes.
@Adolanium
Adolaniumforce-pushed the fix/opencode-probe-timeouts branch from 0330fe6 to e6fcc78CompareAugust 27, 2026 16:11
@macroscopeapp
macroscopeappBot dismissed their stale reviewAugust 27, 2026 16:12

Dismissing prior approval to re-evaluate e6fcc78

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

Closing this because #8750 now gives the OpenCode version probe a four-second limit and cleans up its process group. #8480 moved model inventory to the managed server and SDK, so the CLI inventory path covered by this PR has no production callers.

@t3dotggt3dotgg closed this Sep 3, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Adolanium@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(server): bound OpenCode CLI health probes with timeouts - #6577

Closed
Adolanium wants to merge 1 commit into
pingdotgg:mainfrom
Adolanium:fix/opencode-probe-timeouts
Closed

fix(server): bound OpenCode CLI health probes with timeouts#6577
Adolanium wants to merge 1 commit into
pingdotgg:mainfrom
Adolanium:fix/opencode-probe-timeouts

Conversation

@Adolanium

@AdolaniumAdolanium commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

What Changed

The OpenCode provider health probes (opencode --version and the model inventory commands via loadInventoryFromCli) awaited child.exitCode with no timeout, so a hung opencode binary (waiting on stdin, stuck on a lock, wedged build) stalled the provider snapshot indefinitely and leaked the spawned process. Every other provider adapter already bounds its probes — Codex (CodexProvider.ts), Claude, Cursor, and Grok all wrap probe commands in Effect.timeoutOption; OpenCode was the only one without.

This wraps both OpenCode probe call sites in Effect.timeoutOption:

  • 4s for the version probe (matches GrokProvider's version probe budget)
  • 15s for the model inventory probe (matches the Grok/Cursor model-discovery budgets; the CLI path can run two subcommands with one 1s-spaced retry)

On timeout the snapshot now reports a clear error (Failed to execute OpenCode CLI health check: Timed out while ..., or the friendly "couldn't reach the configured server" message for external-server setups) instead of hanging. The spawned child is acquired under Effect.scoped in runOpenCodeCommand, so the timeout interrupts the effect and the scope finalizer kills the process — no zombie.

Adds two focused tests (hung version probe, hung inventory probe) using TestClock.

Why

A hung OpenCode CLI leaves the provider stuck in a pending/probing state forever, which previously also surfaced as a cold-start blocker (#2248 — fixed once before, then reintroduced when the health check moved to CLI probes). Bounding the probes turns a silent permanent hang into a bounded, diagnosable failure.

Verified: vp test run on the OpenCode provider/adapter/text-generation test files (48 tests, all passing), targeted typecheck and lint clean.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (N/A — server-only, no UI changes)
  • I included a video for animation/interaction changes (N/A)

Note

Low Risk
Server-only OpenCode health probing; bounded timeouts replace an indefinite hang and match patterns already used by other CLI providers.

Overview
OpenCode’s CLI health check could hang forever when opencode --version or model inventory probes never finish, leaving the provider snapshot stuck probing. This change caps those probes with Effect.timeoutOption: 4s for version (same as Grok) and 15s for inventory.

When a probe exceeds its budget, checkOpenCodeProviderStatus returns an error snapshot with explicit timeout messages instead of blocking indefinitely. Tests extend the runtime mock with hang flags and use TestClock + forked fibers to assert both timeout paths.

Reviewed by Cursor Bugbot for commit e6fcc78. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Bound OpenCode CLI health probes in checkOpenCodeProviderStatus with 4s and 15s timeouts

  • Wraps the --version probe in Effect.timeoutOption(VERSION_PROBE_TIMEOUT_MS) (4000 ms) and the inventory load in Effect.timeoutOption(INVENTORY_PROBE_TIMEOUT_MS) (15000 ms) in OpenCodeProvider.ts.
  • On timeout, returns a fallback snapshot with a specific error message (Timed out while running opencode --version or Timed out while loading the OpenCode model inventory) instead of waiting indefinitely.
  • Adds tests in OpenCodeProvider.test.ts that fork the health check and advance TestClock by 30s to assert the timeout error messages for both probes.
  • Behavioral Change: version and inventory probes that previously hung forever now fail after their respective timeouts; Exit values now wrap Option to account for timeoutOption results.

Macroscope summarized e6fcc78.

@coderabbitai

coderabbitaiBot commented Aug 14, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dede434f-b6a0-4069-b498-fb507e04916d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Aug 14, 2026
macroscopeapp[bot]
macroscopeappBot previously approved these changes Aug 14, 2026
@macroscopeapp

macroscopeappBot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at e6fcc78

Macroscope's review found this PR approvable — This small server-side fix replaces indefinite OpenCode health-check hangs with bounded, diagnosable failures while leaving successful probe behavior unchanged. Focused tests cover both timeout scenarios, and no sensitive or deployment-related files are affected.

You can add or adjust custom eligibility rules. Learn more.

The OpenCode provider probes (opencode --version and the model inventory
CLI commands) awaited child.exitCode with no timeout, so a hung opencode
binary stalled the provider snapshot forever and leaked the spawned
process. Every other provider (Codex, Claude, Cursor, Grok) already wraps
its probes in Effect.timeoutOption.
Wrap both OpenCode probe call sites in Effect.timeoutOption (4s for the
version probe, 15s for the inventory probe, matching peer budgets) and
surface a clear timeout message in the probe status. The spawned child is
scoped, so the timeout interrupts the effect and kills the process.
This is a reintroduction of the regression fixed in pingdotgg#2248, lost when the
health check moved to CLI probes.
@Adolanium
Adolaniumforce-pushed the fix/opencode-probe-timeouts branch from 0330fe6 to e6fcc78CompareAugust 27, 2026 16:11
@macroscopeapp
macroscopeappBot dismissed their stale reviewAugust 27, 2026 16:12

Dismissing prior approval to re-evaluate e6fcc78

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

Closing this because #8750 now gives the OpenCode version probe a four-second limit and cleans up its process group. #8480 moved model inventory to the managed server and SDK, so the CLI inventory path covered by this PR has no production callers.

@t3dotggt3dotgg closed this Sep 3, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Adolanium@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(server): bound OpenCode CLI health probes with timeouts - #6577

Closed
Adolanium wants to merge 1 commit into
pingdotgg:mainfrom
Adolanium:fix/opencode-probe-timeouts
Closed

fix(server): bound OpenCode CLI health probes with timeouts#6577
Adolanium wants to merge 1 commit into
pingdotgg:mainfrom
Adolanium:fix/opencode-probe-timeouts

Conversation

@Adolanium

@AdolaniumAdolanium commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

What Changed

The OpenCode provider health probes (opencode --version and the model inventory commands via loadInventoryFromCli) awaited child.exitCode with no timeout, so a hung opencode binary (waiting on stdin, stuck on a lock, wedged build) stalled the provider snapshot indefinitely and leaked the spawned process. Every other provider adapter already bounds its probes — Codex (CodexProvider.ts), Claude, Cursor, and Grok all wrap probe commands in Effect.timeoutOption; OpenCode was the only one without.

This wraps both OpenCode probe call sites in Effect.timeoutOption:

  • 4s for the version probe (matches GrokProvider's version probe budget)
  • 15s for the model inventory probe (matches the Grok/Cursor model-discovery budgets; the CLI path can run two subcommands with one 1s-spaced retry)

On timeout the snapshot now reports a clear error (Failed to execute OpenCode CLI health check: Timed out while ..., or the friendly "couldn't reach the configured server" message for external-server setups) instead of hanging. The spawned child is acquired under Effect.scoped in runOpenCodeCommand, so the timeout interrupts the effect and the scope finalizer kills the process — no zombie.

Adds two focused tests (hung version probe, hung inventory probe) using TestClock.

Why

A hung OpenCode CLI leaves the provider stuck in a pending/probing state forever, which previously also surfaced as a cold-start blocker (#2248 — fixed once before, then reintroduced when the health check moved to CLI probes). Bounding the probes turns a silent permanent hang into a bounded, diagnosable failure.

Verified: vp test run on the OpenCode provider/adapter/text-generation test files (48 tests, all passing), targeted typecheck and lint clean.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (N/A — server-only, no UI changes)
  • I included a video for animation/interaction changes (N/A)

Note

Low Risk
Server-only OpenCode health probing; bounded timeouts replace an indefinite hang and match patterns already used by other CLI providers.

Overview
OpenCode’s CLI health check could hang forever when opencode --version or model inventory probes never finish, leaving the provider snapshot stuck probing. This change caps those probes with Effect.timeoutOption: 4s for version (same as Grok) and 15s for inventory.

When a probe exceeds its budget, checkOpenCodeProviderStatus returns an error snapshot with explicit timeout messages instead of blocking indefinitely. Tests extend the runtime mock with hang flags and use TestClock + forked fibers to assert both timeout paths.

Reviewed by Cursor Bugbot for commit e6fcc78. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Bound OpenCode CLI health probes in checkOpenCodeProviderStatus with 4s and 15s timeouts

  • Wraps the --version probe in Effect.timeoutOption(VERSION_PROBE_TIMEOUT_MS) (4000 ms) and the inventory load in Effect.timeoutOption(INVENTORY_PROBE_TIMEOUT_MS) (15000 ms) in OpenCodeProvider.ts.
  • On timeout, returns a fallback snapshot with a specific error message (Timed out while running opencode --version or Timed out while loading the OpenCode model inventory) instead of waiting indefinitely.
  • Adds tests in OpenCodeProvider.test.ts that fork the health check and advance TestClock by 30s to assert the timeout error messages for both probes.
  • Behavioral Change: version and inventory probes that previously hung forever now fail after their respective timeouts; Exit values now wrap Option to account for timeoutOption results.

Macroscope summarized e6fcc78.

@coderabbitai

coderabbitaiBot commented Aug 14, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dede434f-b6a0-4069-b498-fb507e04916d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Aug 14, 2026
macroscopeapp[bot]
macroscopeappBot previously approved these changes Aug 14, 2026
@macroscopeapp

macroscopeappBot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at e6fcc78

Macroscope's review found this PR approvable — This small server-side fix replaces indefinite OpenCode health-check hangs with bounded, diagnosable failures while leaving successful probe behavior unchanged. Focused tests cover both timeout scenarios, and no sensitive or deployment-related files are affected.

You can add or adjust custom eligibility rules. Learn more.

The OpenCode provider probes (opencode --version and the model inventory
CLI commands) awaited child.exitCode with no timeout, so a hung opencode
binary stalled the provider snapshot forever and leaked the spawned
process. Every other provider (Codex, Claude, Cursor, Grok) already wraps
its probes in Effect.timeoutOption.
Wrap both OpenCode probe call sites in Effect.timeoutOption (4s for the
version probe, 15s for the inventory probe, matching peer budgets) and
surface a clear timeout message in the probe status. The spawned child is
scoped, so the timeout interrupts the effect and kills the process.
This is a reintroduction of the regression fixed in pingdotgg#2248, lost when the
health check moved to CLI probes.
@Adolanium
Adolaniumforce-pushed the fix/opencode-probe-timeouts branch from 0330fe6 to e6fcc78CompareAugust 27, 2026 16:11
@macroscopeapp
macroscopeappBot dismissed their stale reviewAugust 27, 2026 16:12

Dismissing prior approval to re-evaluate e6fcc78

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

Closing this because #8750 now gives the OpenCode version probe a four-second limit and cleans up its process group. #8480 moved model inventory to the managed server and SDK, so the CLI inventory path covered by this PR has no production callers.

@t3dotggt3dotgg closed this Sep 3, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Adolanium@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(server): bound OpenCode CLI health probes with timeouts - #6577

Closed
Adolanium wants to merge 1 commit into
pingdotgg:mainfrom
Adolanium:fix/opencode-probe-timeouts
Closed

fix(server): bound OpenCode CLI health probes with timeouts#6577
Adolanium wants to merge 1 commit into
pingdotgg:mainfrom
Adolanium:fix/opencode-probe-timeouts

Conversation

@Adolanium

@AdolaniumAdolanium commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

What Changed

The OpenCode provider health probes (opencode --version and the model inventory commands via loadInventoryFromCli) awaited child.exitCode with no timeout, so a hung opencode binary (waiting on stdin, stuck on a lock, wedged build) stalled the provider snapshot indefinitely and leaked the spawned process. Every other provider adapter already bounds its probes — Codex (CodexProvider.ts), Claude, Cursor, and Grok all wrap probe commands in Effect.timeoutOption; OpenCode was the only one without.

This wraps both OpenCode probe call sites in Effect.timeoutOption:

  • 4s for the version probe (matches GrokProvider's version probe budget)
  • 15s for the model inventory probe (matches the Grok/Cursor model-discovery budgets; the CLI path can run two subcommands with one 1s-spaced retry)

On timeout the snapshot now reports a clear error (Failed to execute OpenCode CLI health check: Timed out while ..., or the friendly "couldn't reach the configured server" message for external-server setups) instead of hanging. The spawned child is acquired under Effect.scoped in runOpenCodeCommand, so the timeout interrupts the effect and the scope finalizer kills the process — no zombie.

Adds two focused tests (hung version probe, hung inventory probe) using TestClock.

Why

A hung OpenCode CLI leaves the provider stuck in a pending/probing state forever, which previously also surfaced as a cold-start blocker (#2248 — fixed once before, then reintroduced when the health check moved to CLI probes). Bounding the probes turns a silent permanent hang into a bounded, diagnosable failure.

Verified: vp test run on the OpenCode provider/adapter/text-generation test files (48 tests, all passing), targeted typecheck and lint clean.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (N/A — server-only, no UI changes)
  • I included a video for animation/interaction changes (N/A)

Note

Low Risk
Server-only OpenCode health probing; bounded timeouts replace an indefinite hang and match patterns already used by other CLI providers.

Overview
OpenCode’s CLI health check could hang forever when opencode --version or model inventory probes never finish, leaving the provider snapshot stuck probing. This change caps those probes with Effect.timeoutOption: 4s for version (same as Grok) and 15s for inventory.

When a probe exceeds its budget, checkOpenCodeProviderStatus returns an error snapshot with explicit timeout messages instead of blocking indefinitely. Tests extend the runtime mock with hang flags and use TestClock + forked fibers to assert both timeout paths.

Reviewed by Cursor Bugbot for commit e6fcc78. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Bound OpenCode CLI health probes in checkOpenCodeProviderStatus with 4s and 15s timeouts

  • Wraps the --version probe in Effect.timeoutOption(VERSION_PROBE_TIMEOUT_MS) (4000 ms) and the inventory load in Effect.timeoutOption(INVENTORY_PROBE_TIMEOUT_MS) (15000 ms) in OpenCodeProvider.ts.
  • On timeout, returns a fallback snapshot with a specific error message (Timed out while running opencode --version or Timed out while loading the OpenCode model inventory) instead of waiting indefinitely.
  • Adds tests in OpenCodeProvider.test.ts that fork the health check and advance TestClock by 30s to assert the timeout error messages for both probes.
  • Behavioral Change: version and inventory probes that previously hung forever now fail after their respective timeouts; Exit values now wrap Option to account for timeoutOption results.

Macroscope summarized e6fcc78.

@coderabbitai

coderabbitaiBot commented Aug 14, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dede434f-b6a0-4069-b498-fb507e04916d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Aug 14, 2026
macroscopeapp[bot]
macroscopeappBot previously approved these changes Aug 14, 2026
@macroscopeapp

macroscopeappBot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at e6fcc78

Macroscope's review found this PR approvable — This small server-side fix replaces indefinite OpenCode health-check hangs with bounded, diagnosable failures while leaving successful probe behavior unchanged. Focused tests cover both timeout scenarios, and no sensitive or deployment-related files are affected.

You can add or adjust custom eligibility rules. Learn more.

The OpenCode provider probes (opencode --version and the model inventory
CLI commands) awaited child.exitCode with no timeout, so a hung opencode
binary stalled the provider snapshot forever and leaked the spawned
process. Every other provider (Codex, Claude, Cursor, Grok) already wraps
its probes in Effect.timeoutOption.
Wrap both OpenCode probe call sites in Effect.timeoutOption (4s for the
version probe, 15s for the inventory probe, matching peer budgets) and
surface a clear timeout message in the probe status. The spawned child is
scoped, so the timeout interrupts the effect and kills the process.
This is a reintroduction of the regression fixed in pingdotgg#2248, lost when the
health check moved to CLI probes.
@Adolanium
Adolaniumforce-pushed the fix/opencode-probe-timeouts branch from 0330fe6 to e6fcc78CompareAugust 27, 2026 16:11
@macroscopeapp
macroscopeappBot dismissed their stale reviewAugust 27, 2026 16:12

Dismissing prior approval to re-evaluate e6fcc78

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

Closing this because #8750 now gives the OpenCode version probe a four-second limit and cleans up its process group. #8480 moved model inventory to the managed server and SDK, so the CLI inventory path covered by this PR has no production callers.

@t3dotggt3dotgg closed this Sep 3, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Adolanium@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(server): bound OpenCode CLI health probes with timeouts - #6577

Closed
Adolanium wants to merge 1 commit into
pingdotgg:mainfrom
Adolanium:fix/opencode-probe-timeouts
Closed

fix(server): bound OpenCode CLI health probes with timeouts#6577
Adolanium wants to merge 1 commit into
pingdotgg:mainfrom
Adolanium:fix/opencode-probe-timeouts

Conversation

@Adolanium

@AdolaniumAdolanium commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

What Changed

The OpenCode provider health probes (opencode --version and the model inventory commands via loadInventoryFromCli) awaited child.exitCode with no timeout, so a hung opencode binary (waiting on stdin, stuck on a lock, wedged build) stalled the provider snapshot indefinitely and leaked the spawned process. Every other provider adapter already bounds its probes — Codex (CodexProvider.ts), Claude, Cursor, and Grok all wrap probe commands in Effect.timeoutOption; OpenCode was the only one without.

This wraps both OpenCode probe call sites in Effect.timeoutOption:

  • 4s for the version probe (matches GrokProvider's version probe budget)
  • 15s for the model inventory probe (matches the Grok/Cursor model-discovery budgets; the CLI path can run two subcommands with one 1s-spaced retry)

On timeout the snapshot now reports a clear error (Failed to execute OpenCode CLI health check: Timed out while ..., or the friendly "couldn't reach the configured server" message for external-server setups) instead of hanging. The spawned child is acquired under Effect.scoped in runOpenCodeCommand, so the timeout interrupts the effect and the scope finalizer kills the process — no zombie.

Adds two focused tests (hung version probe, hung inventory probe) using TestClock.

Why

A hung OpenCode CLI leaves the provider stuck in a pending/probing state forever, which previously also surfaced as a cold-start blocker (#2248 — fixed once before, then reintroduced when the health check moved to CLI probes). Bounding the probes turns a silent permanent hang into a bounded, diagnosable failure.

Verified: vp test run on the OpenCode provider/adapter/text-generation test files (48 tests, all passing), targeted typecheck and lint clean.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (N/A — server-only, no UI changes)
  • I included a video for animation/interaction changes (N/A)

Note

Low Risk
Server-only OpenCode health probing; bounded timeouts replace an indefinite hang and match patterns already used by other CLI providers.

Overview
OpenCode’s CLI health check could hang forever when opencode --version or model inventory probes never finish, leaving the provider snapshot stuck probing. This change caps those probes with Effect.timeoutOption: 4s for version (same as Grok) and 15s for inventory.

When a probe exceeds its budget, checkOpenCodeProviderStatus returns an error snapshot with explicit timeout messages instead of blocking indefinitely. Tests extend the runtime mock with hang flags and use TestClock + forked fibers to assert both timeout paths.

Reviewed by Cursor Bugbot for commit e6fcc78. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Bound OpenCode CLI health probes in checkOpenCodeProviderStatus with 4s and 15s timeouts

  • Wraps the --version probe in Effect.timeoutOption(VERSION_PROBE_TIMEOUT_MS) (4000 ms) and the inventory load in Effect.timeoutOption(INVENTORY_PROBE_TIMEOUT_MS) (15000 ms) in OpenCodeProvider.ts.
  • On timeout, returns a fallback snapshot with a specific error message (Timed out while running opencode --version or Timed out while loading the OpenCode model inventory) instead of waiting indefinitely.
  • Adds tests in OpenCodeProvider.test.ts that fork the health check and advance TestClock by 30s to assert the timeout error messages for both probes.
  • Behavioral Change: version and inventory probes that previously hung forever now fail after their respective timeouts; Exit values now wrap Option to account for timeoutOption results.

Macroscope summarized e6fcc78.

@coderabbitai

coderabbitaiBot commented Aug 14, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dede434f-b6a0-4069-b498-fb507e04916d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Aug 14, 2026
macroscopeapp[bot]
macroscopeappBot previously approved these changes Aug 14, 2026
@macroscopeapp

macroscopeappBot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at e6fcc78

Macroscope's review found this PR approvable — This small server-side fix replaces indefinite OpenCode health-check hangs with bounded, diagnosable failures while leaving successful probe behavior unchanged. Focused tests cover both timeout scenarios, and no sensitive or deployment-related files are affected.

You can add or adjust custom eligibility rules. Learn more.

The OpenCode provider probes (opencode --version and the model inventory
CLI commands) awaited child.exitCode with no timeout, so a hung opencode
binary stalled the provider snapshot forever and leaked the spawned
process. Every other provider (Codex, Claude, Cursor, Grok) already wraps
its probes in Effect.timeoutOption.
Wrap both OpenCode probe call sites in Effect.timeoutOption (4s for the
version probe, 15s for the inventory probe, matching peer budgets) and
surface a clear timeout message in the probe status. The spawned child is
scoped, so the timeout interrupts the effect and kills the process.
This is a reintroduction of the regression fixed in pingdotgg#2248, lost when the
health check moved to CLI probes.
@Adolanium
Adolaniumforce-pushed the fix/opencode-probe-timeouts branch from 0330fe6 to e6fcc78CompareAugust 27, 2026 16:11
@macroscopeapp
macroscopeappBot dismissed their stale reviewAugust 27, 2026 16:12

Dismissing prior approval to re-evaluate e6fcc78

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

Closing this because #8750 now gives the OpenCode version probe a four-second limit and cleans up its process group. #8480 moved model inventory to the managed server and SDK, so the CLI inventory path covered by this PR has no production callers.

@t3dotggt3dotgg closed this Sep 3, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Adolanium@t3dotgg