Skip to content

feat: support pull diagnostics in the LSP client (C#, Kotlin, etc)#23771

Merged
Hona merged 32 commits intoanomalyco:devfrom
Hona:fix/lsp-incremental-sync
Apr 22, 2026
Merged

feat: support pull diagnostics in the LSP client (C#, Kotlin, etc)#23771
Hona merged 32 commits intoanomalyco:devfrom
Hona:fix/lsp-incremental-sync

Conversation

@Hona
Copy link
Copy Markdown
Member

@Hona Hona commented Apr 22, 2026

TL;DR

  1. Dev (no errors showing)
    Our client only spoke push diagnostics.
    Roslyn doesn't push for C# - it registers pull providers and waits to be asked.
    So after an edit we waited 3s for a push that never came and surfaced nothing.

  2. Earlier branch (~4s)
    Added pull diagnostics but wrapped in smart "waiting/settling/convergence" policy and a Roslyn-specific compiler-category branch.
    It worked, but the extra policy/sweeps added ~3-4s of latency even on warm files, and some cases hit a 10s pull timeout.

  3. New branch (near instant)
    Generic pull-aware client, no server-specific branches, no settle timers.
    After didOpen/didChange we issue current-document pulls in parallel for every registered identifier and return on the first match.
    Warm C# edit in the UpBlazor repro: about 0.7s and returns the 3 CS0103 errors.

fixes #3116 and ...?

C#, Kotlin etc work great now

many LSPs only do pulled diagnostics, and dev used to do push only

Copilot AI review requested due to automatic review settings April 22, 2026 00:48
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the LSP client to respect servers that advertise incremental text sync, and extends the fake LSP fixture + tests to verify the new didChange behavior.

Changes:

  • Send ranged textDocument/didChange notifications when the server advertises textDocumentSync.change = 2 (incremental sync).
  • Extend the fake LSP server to advertise incremental sync and capture the last didChange payload for assertions.
  • Add a regression test asserting ranged didChange content for incremental-sync servers.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
packages/opencode/src/lsp/client.ts Determine sync kind from server capabilities and send ranged didChange for incremental sync; adds diagnostics polling/request infrastructure used by waitForDiagnostics.
packages/opencode/test/fixture/lsp/fake-lsp-server.js Advertises incremental sync and records/returns the last textDocument/didChange params for tests.
packages/opencode/test/lsp/client.test.ts Adds test validating ranged didChange payload for incremental sync servers using the fake server.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/opencode/src/lsp/client.ts
@Hona Hona changed the title fix: honor incremental LSP didChange sync mode fix: our LSP client did not support incremental-sync servers Apr 22, 2026
@Hona Hona requested a review from Copilot April 22, 2026 01:25
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/opencode/src/lsp/client.ts Outdated
Comment thread packages/opencode/src/lsp/client.ts Outdated
@Hona Hona force-pushed the fix/lsp-incremental-sync branch from bec3085 to 587e2b0 Compare April 22, 2026 05:23
@Hona Hona changed the title fix: our LSP client did not support incremental-sync servers fix: support pull diagnostics in the LSP client Apr 22, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +469 to +474
const next = await Promise.race([
pushWait.then((ready) => (ready ? "push" : "timeout" as const)),
waitForRegistrationChange(remaining).then((changed) => (changed ? "registration" : "timeout" as const)),
])
if (next !== "registration") return
}
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

waitForDocumentDiagnostics only retries pulls when a new diagnostic registration arrives (next !== "registration" returns). If the server supports pull but the first pull times out/returns empty while the server is still computing, and it doesn’t change registrations or push diagnostics, this will exit early (on push timeout) without retrying within the overall 5s window. Consider polling/retrying pull requests (with a small backoff) until the overall timeout elapses.

Copilot uses AI. Check for mistakes.
Comment on lines +491 to +495
const next = await Promise.race([
pushWait.then((ready) => (ready ? "push" : "timeout" as const)),
waitForRegistrationChange(remaining).then((changed) => (changed ? "registration" : "timeout" as const)),
])
if (next !== "registration") return
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

waitForFullDiagnostics has the same early-exit behavior: after one pull sweep it returns unless registrations change. For pull-only servers that take longer than DIAGNOSTICS_REQUEST_TIMEOUT_MS (3s) to compute, this can cause waitForDiagnostics to return before the overall 10s timeout without ever seeing diagnostics. Consider retrying pull requests until the full timeout expires (or until a push arrives).

Suggested change
const next = await Promise.race([
pushWait.then((ready) => (ready ? "push" : "timeout" as const)),
waitForRegistrationChange(remaining).then((changed) => (changed ? "registration" : "timeout" as const)),
])
if (next !== "registration") return
const retryDelay = Math.min(DIAGNOSTICS_DEBOUNCE_MS, remaining)
const next = await Promise.race([
pushWait.then((ready) => (ready ? "push" : "timeout" as const)),
waitForRegistrationChange(remaining).then((changed) => (changed ? "registration" : "timeout" as const)),
new Promise<"retry">((resolve) => setTimeout(() => resolve("retry"), retryDelay)),
])
if (next === "push" || next === "timeout") return

Copilot uses AI. Check for mistakes.
Comment on lines 197 to +203
connection.onRequest("workspace/workspaceFolders", async () => [
{
name: "workspace",
uri: pathToFileURL(input.root).href,
},
])
connection.onRequest("workspace/diagnostic/refresh", async () => null)
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The client advertises workspace.diagnostics.refreshSupport: true but the workspace/diagnostic/refresh handler currently just returns null and doesn't trigger any re-pull. Per the LSP diagnostics spec, receiving this request should cause the client to re-request diagnostics (at least for currently-open documents), otherwise servers that rely on refresh will never update pull diagnostics.

Suggested change
connection.onRequest("workspace/workspaceFolders", async () => [
{
name: "workspace",
uri: pathToFileURL(input.root).href,
},
])
connection.onRequest("workspace/diagnostic/refresh", async () => null)
const applyPulledDiagnostics = (
filePath: string,
report:
| {
kind?: "full" | "unchanged"
items?: VSCodeDiagnostic[]
relatedDocuments?: Record<
string,
{
kind?: "full" | "unchanged"
items?: VSCodeDiagnostic[]
}
>
}
| null
| undefined,
) => {
if (!report) return
const previous = published.get(filePath)
published.set(filePath, {
at: Date.now(),
version: previous?.version,
})
if (report.kind !== "unchanged" && Array.isArray(report.items)) {
updatePushDiagnostics(filePath, report.items)
}
for (const [uri, relatedReport] of Object.entries(report.relatedDocuments ?? {})) {
const relatedPath = getFilePath(uri)
if (!relatedPath) continue
const relatedPrevious = published.get(relatedPath)
published.set(relatedPath, {
at: Date.now(),
version: relatedPrevious?.version,
})
if (relatedReport.kind !== "unchanged" && Array.isArray(relatedReport.items)) {
updatePushDiagnostics(relatedPath, relatedReport.items)
}
}
}
connection.onRequest("workspace/workspaceFolders", async () => [
{
name: "workspace",
uri: pathToFileURL(input.root).href,
},
])
connection.onRequest("workspace/diagnostic/refresh", async () => {
l.info("workspace/diagnostic/refresh")
const trackedFilePaths = new Set([...published.keys(), ...pushDiagnostics.keys()])
await Promise.allSettled(
[...trackedFilePaths].map(async (filePath) => {
try {
const report = await connection.sendRequest<{
kind?: "full" | "unchanged"
items?: VSCodeDiagnostic[]
relatedDocuments?: Record<
string,
{
kind?: "full" | "unchanged"
items?: VSCodeDiagnostic[]
}
>
}>("textDocument/diagnostic", {
textDocument: {
uri: pathToFileURL(filePath).href,
},
})
applyPulledDiagnostics(filePath, report)
} catch (error) {
l.warn("workspace/diagnostic/refresh failed", {
path: filePath,
error,
})
}
}),
)
return null
})

Copilot uses AI. Check for mistakes.
Comment on lines +346 to +350
matched = matched || relatedPath === filePath
}

return { handled: byFile.size > 0, matched, byFile }
}
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

requestWorkspaceDiagnosticReport treats the request as handled only when byFile.size > 0. A successful workspace/diagnostic response with zero items (meaning “no workspace diagnostics”) would be considered unhandled, which can unnecessarily extend waits and can leave stale workspace pull diagnostics around. Consider setting handled based on receiving a valid report (e.g., Array.isArray(report.items)), not on whether any diagnostics were returned.

Copilot uses AI. Check for mistakes.
Comment on lines +218 to 221
// Caller picked a specific bin (e.g. pyright exposes both `pyright` and
// `pyright-langserver`); trust the hint if the package provides it.
if (bin) return files.includes(bin) ? Option.some(bin) : Option.none<string>()
if (files.length === 1) return Option.some(files[0])
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Npm.which(pkg, bin) checks files.includes(bin) for an exact match. On Windows, npm/bun typically creates shims like pyright-langserver.cmd (and/or .ps1) in node_modules/.bin, so this exact-match check can return none even though the requested bin exists. Consider matching against PATHEXT variants (or doing a prefix match + extension handling) so callers can pass the logical bin name and still resolve correctly cross-platform.

Copilot uses AI. Check for mistakes.
version: typeof params.version === "number" ? params.version : undefined,
})
if (input.serverID === "typescript" && !pushDiagnostics.has(filePath)) {
pushDiagnostics.set(filePath, params.diagnostics)
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TypeScript special-case stores the first publishDiagnostics into pushDiagnostics but returns without calling updatePushDiagnostics, so no Event.Diagnostics is published. waitForFreshPush() relies on that bus event to re-check published, which means waitForDiagnostics() can unnecessarily block until timeout even though diagnostics have already arrived. Consider still publishing the event (or remove this special-case and rely on debounce/version checks instead).

Suggested change
pushDiagnostics.set(filePath, params.diagnostics)
updatePushDiagnostics(filePath, params.diagnostics)

Copilot uses AI. Check for mistakes.
Hona added 3 commits April 22, 2026 17:33
Document-mode waits were still missing a matching push that arrived before the
wait subscription, and pull diagnostics could still block on the slowest
identifier even after the current file already had errors.

Capture the wait start before didOpen/didChange, accept matching published
versions that already landed, return document waits once current-file
diagnostics exist, and treat empty workspace pull responses as handled. Add
regression coverage for all three cases.
The client was advertising publish-diagnostics version support and workspace
diagnostic refresh support without implementing either behavior, and
workspace/configuration always returned a single initialization blob instead
of one result per requested item.

Downgrade the unsupported capability claims and return configuration entries
in the shape servers expect so they don't assume features we don't actually
have.
@Hona Hona changed the title fix: support pull diagnostics in the LSP client fix: support pull diagnostics in the LSP client (C#, Kotlin, etc) Apr 22, 2026
@lowlyocean
Copy link
Copy Markdown

lowlyocean commented Apr 22, 2026

After checking out this branch, I'm having trouble getting bun dev debug lsp diagnostics </path/to/file.kt> --print-logs --log-level DEBUG to show anything other than empty result {}. Is there something else needed besides having .config/opencode/opencode.json have a top-level "lsp": true ?

@Hona Hona enabled auto-merge (squash) April 22, 2026 23:09
@Hona Hona disabled auto-merge April 22, 2026 23:09
@Hona Hona enabled auto-merge (squash) April 22, 2026 23:09
@Hona
Copy link
Copy Markdown
Member Author

Hona commented Apr 22, 2026

@lowlyocean i assume you're running bun dev from the opencode repo - and passing an absolute path to the file?
it kinda needs the cwd to be the kotlin dir to spawn and etc

@Hona
Copy link
Copy Markdown
Member Author

Hona commented Apr 22, 2026

e.g. bun dev debug lsp diagnostics "C:\Repos\kotlin-real-smoke-ktor\src\main\kotlin\com\example\LspProbe.kt" --print-logs --log-level DEBUG

will return nothing

i have a pwsh wrapper that does this correctly, e.g.

ocl -- debug lsp diagnostics "src/main/kotlin/com/example/LspProbe.kt" --print-logs --log-level DEBUG does work

e.g. here's what that looks like:

function opencode-local {
  $ArgumentList = @($args)
  $repo = "C:/Repos/sst/opencode/packages/opencode"
  if ($ArgumentList.Count -gt 0 -and $ArgumentList[0] -eq '--') {
    $ArgumentList = @($ArgumentList | Select-Object -Skip 1)
  }
  $entryPath = Join-Path $repo 'src/index.ts'
  $entryUri = [System.Uri]::new($entryPath).AbsoluteUri
  $cwd = $PWD.ProviderPath
  $script = @"
const cwd = $($cwd | ConvertTo-Json -Compress)
process.chdir(cwd)
process.env.PWD = cwd
process.argv = ['bun', $($entryPath | ConvertTo-Json -Compress), ...process.argv.slice(1)]
await import($($entryUri | ConvertTo-Json -Compress))
"@
  & bun --cwd $repo --conditions=browser -e $script -- @ArgumentList
}
Set-Alias ocl opencode-local

@Hona Hona disabled auto-merge April 22, 2026 23:17
@Hona Hona changed the title fix: support pull diagnostics in the LSP client (C#, Kotlin, etc) feat: support pull diagnostics in the LSP client (C#, Kotlin, etc) Apr 22, 2026
@Hona Hona enabled auto-merge (squash) April 22, 2026 23:17
@Hona Hona merged commit 8cade05 into anomalyco:dev Apr 22, 2026
13 of 14 checks passed
@lowlyocean
Copy link
Copy Markdown

lowlyocean commented Apr 23, 2026

Thanks - still no luck, I tried converting to bash,

opencode-local() {
  local repo="~/.local/bin/opencode/packages/opencode"
  local entryPath="$repo/src/index.ts"

  # Handle '--' argument if it's the first one
  if [[ "$1" == '--' ]]; then
    shift
  fi

  # Generate URI and JSON strings using bun (since bun is required anyway)
  # This replaces PowerShell's [System.Uri] and ConvertTo-Json
  local entryUri
  entryUri=$(bun -e "console.log(require('url').pathToFileURL('$entryPath').href)" 2>/dev/null)

  local cwdJson
  cwdJson=$(bun -e "console.log(JSON.stringify('$(pwd)'))" 2>/dev/null)

  local entryPathJson
  entryPathJson=$(bun -e "console.log(JSON.stringify('$entryPath'))" 2>/dev/null)

  local entryUriJson
  entryUriJson=$(bun -e "console.log(JSON.stringify('$entryUri'))" 2>/dev/null)

  # Construct the script
  local script="
const cwd = $cwdJson
process.chdir(cwd)
process.env.PWD = cwd
process.argv = ['bun', $entryPathJson, ...process.argv.slice(1)]
await import($entryUriJson)
"

  # Run bun with the script and arguments
  bun --cwd "$repo" --conditions=browser -e "$script" -- "$@"
}

alias ocl=opencode-local

And cwd when I run the ocl command is the directory where have the symlink defined for "kotlin-lsp"

My opencode.json:

  "lsp": {
    "kotlin-ls": {
      "disabled": true,
    },
    "kotlin-lsp": {
      "command": ["kotlin-lsp", "--stdio"],
      "extensions": [".kt", ".kts"]
    }
  }

@Hona
Copy link
Copy Markdown
Member Author

Hona commented Apr 23, 2026

@lowlyocean can you try with just "lsp": true - we use the official kotlin-lsp already so I'm not sure why we need the override?

@Hona
Copy link
Copy Markdown
Member Author

Hona commented Apr 23, 2026

I threw an agent at your script:
image

sdeonvacation pushed a commit to sdeonvacation/opencode-x that referenced this pull request Apr 23, 2026
vaur94 pushed a commit to vaur94/opencode that referenced this pull request Apr 23, 2026
vaur94 pushed a commit to vaur94/opencode that referenced this pull request Apr 23, 2026
balcsida added a commit to balcsida/opencode that referenced this pull request Apr 28, 2026
* refactor(core): migrate MessageV2 internal Cursor to Effect Schema (anomalyco#23763)

* refactor(core): migrate MessageV2 errors to Schema-backed named errors (anomalyco#23764)

* chore: generate

* chore: bump Bun to 1.3.13 (anomalyco#23791)

* fix(app): improve icon override handling in project edit dialog (anomalyco#23768)

* chore: update nix node_modules hashes

* fix: preserve BOM in text tool round-trips (anomalyco#23797)

* chore: generate

* test: fix cross-spawn stderr race on Windows CI (anomalyco#23808)

* chore: generate

* fix: consolidate project avatar source logic (anomalyco#23819)

* fix(tui): fail fast on invalid session startup (anomalyco#23837)

* chore: generate

* fix(session): improve session compaction (anomalyco#23870)

* chore: generate

* fix(project): use git common dir for bare repo project cache (anomalyco#19054)

* docs: add MiMo V2.5 to Go pages (anomalyco#23876)

* chore: generate

* chore: update nix bun version (anomalyco#23881)

* feat: support pull diagnostics in the LSP client (C#, Kotlin, etc) (anomalyco#23771)

* chore: generate

* log session sdk errors (anomalyco#23652)

* fix(beta): PR resolvers/smoke check should typecheck all pacakges (anomalyco#23913)

* tweak: codex model logic (anomalyco#23925)

* refactor: remove redundant pending check from working memo (anomalyco#23929)

* sync release versions for v1.14.21

* zen: hy3 preview

* fix: add keyed prop to Show components for proper reactivity (anomalyco#23935)

* feat(project): add icon_url_override field to projects (anomalyco#23955)

* chore: generate

* chore: add to TEAM_MEMBERS (anomalyco#23975)

* fix(npm): respect npmrc config (anomalyco#24001)

* fix(tui): render all non-synthetic text parts of a user message (anomalyco#24009)

* refactor(session): migrate session domain to Effect Schema (anomalyco#24005)

* chore: generate

* sync release versions for v1.14.22

* fix(npm): respect npmrc for version lookups (anomalyco#24016)

* chore: generate

* refactor(sync): make session events schema-first (anomalyco#24019)

* chore: generate

* docs(schema): mark sync/index.ts migrated with compat-bridge note (anomalyco#24024)

* sync

* refactor(provider): migrate provider domain to Effect Schema (anomalyco#24027)

* refactor(schema): use Schema.Int and consolidate PositiveInt/NonNegativeInt (anomalyco#24029)

* refactor(bus): migrate BusEvent to Effect Schema (anomalyco#24040)

* chore: generate

* refactor(tool): migrate tool framework + all 18 built-in tools to Effect Schema (anomalyco#23244)

* chore: generate

* feat(tui): support builtin protocol for handling context from editors (anomalyco#24034)

* chore: generate

* docs: update effect schema migration tracker (anomalyco#24054)

* refactor(control-plane): migrate workspace DTO schemas (anomalyco#24056)

* chore: generate

* chore: update copilot readme to symlink to an agents md to prevent dumbass agents from touching these files (anomalyco#24057)

* fix: account for additional openai retry case (anomalyco#24063)

* feat(httpapi): bridge workspace read endpoints (anomalyco#24062)

* feat(truncate): allow configuring tool output truncation limits (anomalyco#23770)

Co-authored-by: rgs_ramp <[email protected]>
Co-authored-by: Aiden Cline <[email protected]>

* chore: generate

* ci: add platform-specific bun install flags (anomalyco#23822)

* fix(desktop): avoid relaunching without installing updates (anomalyco#23806)

* chore: generate

* feat(prompt): add shell mode UI with cancel button, custom icon, and example placeholder (anomalyco#24105)

* sync

* zen: deepseek v4 pro

* fix(app): conditionally show model variant selector (anomalyco#24115)

* test(prompt): align shell placeholder expectation (anomalyco#24147)

* fix: deepseek variants (anomalyco#24157)

* fix: preserve empty reasoning_content for DeepSeek V4 thinking mode (anomalyco#24146)

Co-authored-by: Simon Klee <[email protected]>

* fix: support `max` for deepseek (anomalyco#24163)

* feat(httpapi): bridge file read endpoints (anomalyco#24098)

* sync release versions for v1.14.23

* feat(httpapi): bridge mcp status endpoint (anomalyco#24100)

* chore: generate

* fix: use existingModel as fallback for interleaved field (anomalyco#24172)

* fix: ensure assistant messages always have reasoning on them for deepseek (anomalyco#24180)

* Use OpenTUI theme detection for initial TUI mode, again (anomalyco#23846)

* chore: update nix node_modules hashes

* zen: deepseek v4 pro

* chore: generate

* sync release versions for v1.14.24

* zen: gpt-5.5

* zen: gpt-5.5

* zen: gpt-5.5

* zen: gpt-5.5

* Refactor HttpApi auth middleware wiring (anomalyco#24168)

* refactor(schema): decode effect schemas directly (anomalyco#24169)

* chore: generate

* Clarify HttpApi migration plan (anomalyco#24211)

* ignore: denounce ai spammer

* chore: generate

* fix: ensure gpt-5.5 compacts at correct context size when using openai oauth (anomalyco#24212)

* fix(opencode): clarify git amend condition to require verifying commit landed (anomalyco#19937)

Co-authored-by: Aiden Cline <[email protected]>
Co-authored-by: Luke Parker <[email protected]>
Co-authored-by: Brendan Allan <[email protected]>
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: Shoubhit Dash <[email protected]>

* refactor(ripgrep): migrate result schemas to effect (anomalyco#24213)

* test(httpapi): cover hono bridge middleware (anomalyco#24216)

* chore: generate

* Add Roslyn support for Razor and C# scripts (anomalyco#24228)

* fix: validate beta before pushing (anomalyco#24230)

* chore: generate

* chore: group beta PR logs (anomalyco#24236)

* fix(build): add prettier to devDependencies (anomalyco#23255)

* chore: update nix node_modules hashes

* ci: adjust auto close issue script to use not planned instead of completed (anomalyco#24253)

* Fix shell cwd after login startup (anomalyco#24215)

* tool/lsp: include request details in permission metadata (anomalyco#24139)

* fix permission config order (anomalyco#24222)

* chore: generate

* ci: centralize opentui dependencies in workspace catalog

Use catalog references for @opentui/core, @opentui/solid, and opentui-spinner
across packages to ensure consistent versions and simplify updates.

* core: permission config schema now provides full IntelliSense for all tool permission keys

The permission configuration previously used a generic record type that didn't offer editor completions. Updated the schema to explicitly list all tool permission keys (read, edit, glob, grep, list, bash, task, external_directory, lsp, skill, todowrite, question, webfetch, websearch, codesearch, doom_loop) with proper types, enabling autocomplete when editing permission files.

* sync release versions for v1.14.25

* feat(httpapi): bridge instance read endpoints (anomalyco#24258)

* chore: generate

* refactor: remove lazy cross-spawn runtime (anomalyco#24305)

* refactor: rename shared package to core (anomalyco#24309)

* feat: add startup debug command (anomalyco#24310)

* chore: update nix node_modules hashes

* fix(config): preserve permission order with Effect decode (anomalyco#24308)

* core: consolidate shared infrastructure into core package

Moves effect logging, observability, runtime utilities, flags, installation
version info, and process utilities from opencode to core package. This
enables better code sharing across packages and establishes core as the
single source of truth for foundational utilities.

All internal imports updated to use @opencode-ai/core paths for consistency.

* chore: generate

* chore: update nix node_modules hashes

* ci: adjust review flow (anomalyco#24355)

* core: move Global module to @opencode-ai/core for centralized path management

Move the Global module from packages/opencode/src/global to packages/core/src/global
to provide a unified location for managing XDG directories and application paths.
This eliminates duplicate path definitions across packages and ensures consistent
access to data, config, cache, state, log, and bin directories throughout the codebase.

* feat(httpapi): bridge catalog read endpoints (anomalyco#24353)

* chore: generate

* feat(tui): read Zed editor context from state db (anomalyco#24352)

* feat(httpapi): bridge file search endpoints (anomalyco#24356)

* ci: fix model name

* chore: generate

* core: move cross-spawn-spawner from opencode to core package

Moved the cross-spawn-spawner module from packages/opencode to packages/core
to enable code sharing across the monorepo. This consolidates the process
spawning infrastructure into the core package so other packages can use
cross-platform child process spawning without duplicating the implementation.

Updated all import statements across the codebase to reference the new
location (@opencode-ai/core/effect/cross-spawn-spawner). Removed the
local copy from the opencode package along with its tests.

* core: move cross-spawn-spawner to root and remove unused types

The cross-spawn-spawner module has been moved from src/effect/ to src/
to simplify the core package structure. The src/types.d.ts file which
contained unused type declarations has also been removed. All imports
throughout the codebase have been updated to reflect the new location.

This change reduces the package's internal complexity by flattening the
module hierarchy and removing dead code, making future maintenance easier.

* core: move npm service to core package for shared dependency management

* feat(httpapi): bridge experimental read endpoints (anomalyco#24365)

* chore: generate

* chore: update nix node_modules hashes

* feat(httpapi): bridge worktree read endpoint (anomalyco#24366)

* chore: generate

* feat(tui): show /connect tip when user has no models configured (anomalyco#24014)

* feat(httpapi): bridge instance dispose endpoint (anomalyco#24368)

* chore: generate

* feat(httpapi): bridge worktree mutations (anomalyco#24371)

* chore: generate

* feat(httpapi): bridge config update endpoint (anomalyco#24387)

* feat(httpapi): bridge project git init endpoint (anomalyco#24394)

* chore: generate

* feat(httpapi): bridge project update endpoint (anomalyco#24398)

* feat(httpapi): bridge mcp control endpoints (anomalyco#24403)

* chore: generate

* feat(httpapi): bridge mcp oauth endpoints (anomalyco#24405)

* chore: generate

* feat(httpapi): bridge experimental tool routes (anomalyco#24407)

* chore: generate

* test(provider): avoid plugin dependency install timeout (anomalyco#24416)

* sync

* core: Add User-Agent header to identify client version in HTTP requests

* fix: bump openrouter sdk version to resolve deepseek reasoning issue (bug was in sdk pkg) (anomalyco#24435)

* chore: update nix node_modules hashes

* fix: correct typo in comment (anomalyco#24420)

* feat(httpapi): bridge experimental session list (anomalyco#24478)

* chore: generate

* feat(httpapi): bridge workspace mutations (anomalyco#24483)

* chore: generate

* fix(docs): correct OpenCode Go DeepSeek endpoints (anomalyco#24500)

* ci: update team assignments in github-triage

Update team member assignments in the triage tool:
- Remove thdxr from tui and core teams
- Add simonklee to tui team
- Add kitlangton to core team

* feat(httpapi): bridge sync routes (anomalyco#24484)

* chore: generate

* feat(httpapi): bridge session read routes (anomalyco#24485)

* chore: generate

* feat(httpapi): bridge session lifecycle routes (anomalyco#24486)

* chore: generate

* feat(httpapi): bridge session message mutations (anomalyco#24487)

* chore: generate

* feat(httpapi): bridge remaining session routes (anomalyco#24510)

* chore: generate

* sync

* sync

* chore: generate

* chore: rm empty file

* fix(editor): reject lock files with no workspace match for cwd (anomalyco#24323)

* feat(go): add Go model listing endpoint (anomalyco#24304)

Co-authored-by: Frank <[email protected]>

* upgrade opentui to 0.1.104 (anomalyco#24531)

* chore: update nix node_modules hashes

* sync release versions for v1.14.26

* fix(tui): update toast duration handling to use default value (anomalyco#23395)

Co-authored-by: Aiden Cline <[email protected]>

* tui: remove excessive debug logging from workspace creation flow to reduce terminal output noise

* feat(httpapi): bridge event stream (anomalyco#24518)

* chore: generate

* feat: configurable shell selection + desktop settings UI (anomalyco#20602)

* feat(httpapi): bridge pty routes (anomalyco#24547)

* core: refactor Installation service to use a single consolidated result object

Reorganizes the Installation service implementation by grouping info, method, latest, and upgrade methods into a single result object. This improves code locality and makes the service interface more maintainable. Also adds a clarifying comment explaining why the package manager's resolver is used for version lookups (to ensure registries, mirrors, auth, proxies, and dist-tags match upgrade behavior).

* feat(httpapi): bridge tui routes (anomalyco#24548)

* fix(tui): hide provider checks before onboarding (anomalyco#24551)

* upgrade opentui to 0.1.105 (anomalyco#24555)

* chore: update nix node_modules hashes

* sync release versions for v1.14.27

* go: models endpoint

* Update VOUCHED list

anomalyco#24563 (comment)

* fix: ignore GitHub Actions changelog contributor (anomalyco#24567)

* Refactor npm config handling (anomalyco#24565)

* go: add deepseek icon

* chore: generate

* sync release versions for v1.14.28

* fix: default tool call streaming to false for google vertex (anomalyco#24573)

* sync

* ignore: split up reasoning transforms (anomalyco#24574)

* update Go DeepSeek request estimates for cache pricing changes (anomalyco#24575)

* fix(opencode): agent create generates permissions field with deny ins… (anomalyco#24482)

Co-authored-by: Aiden Cline <[email protected]>
Co-authored-by: Aiden Cline <[email protected]>

* chore: generate

* zen: coupons

* chore: generate

* fix: pass workspace symbol query to experimental LSP tool (anomalyco#24576)

* chore: generate

* update Go DeepSeek flash limits for cache pricing drop (anomalyco#24592)

* docs: fix duplicated word in CLI env var table (anomalyco#24614)

Co-authored-by: Seashore <[email protected]>

* chore: generate

* tweak: make interleaved reasoning_content default to true for openai compat deepseek setups (anomalyco#24630)

* fix(httpapi): mount workspace bridge routes (anomalyco#24626)

* fix(httpapi): accept empty session create body (anomalyco#24640)

* refactor: remove module barrels (anomalyco#24554)

* chore: generate

* fix: ensure toolStreaming is set to off by default when using non anthropic models with anthropic sdk (anomalyco#24642)

* fix(tui): stabilize Zed editor context polling (anomalyco#24656)

* chore: generate

* fix(httpapi): enforce instance route parity (anomalyco#24660)

* feat(core): file context improvements and option to disable (anomalyco#24661)

* fix(tui): preserve Zed context on terminal focus (anomalyco#24662)

* test(httpapi): verify reflected route mounts (anomalyco#24663)

* chore: generate

* fix(tui): consume Enter in dialog useKeyboard handlers (anomalyco#23390)

* fix(session): harden shell cancellation (anomalyco#24553)

* test(httpapi): cover full OpenAPI route inventory (anomalyco#24667)

* chore: generate

* fix(httpapi): preserve optional session fields (anomalyco#24671)

* fix(session): omit undefined optional fields (anomalyco#24676)

* fix(session): remove compaction summary dividers (anomalyco#24677)

* test(httpapi): cover session json parity (anomalyco#24682)

* fix(httpapi): align session boolean query parsing (anomalyco#24693)

* chore: generate

* fix(httpapi): preserve provider oauth authorize parity (anomalyco#24703)

* chore: generate

* chore: bump effect beta (anomalyco#24705)

* chore: update nix node_modules hashes

* fix(tui): keep Zed context polling responsive (anomalyco#24711)

* fix(httpapi): preserve mcp oauth error parity (anomalyco#24706)

* chore: generate

* refactor(app): load sync state through TanStack Query (anomalyco#23792)

* fix: sanitize tools for moonshot (anomalyco#24730)

* chore: generate

* Update VOUCHED list

anomalyco#24732 (comment)

* fix(ui): remove redundant flex overrides in tool components (anomalyco#24749)

* ci: add release-cli workflow

---------

Co-authored-by: Kit Langton <[email protected]>
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: Luke Parker <[email protected]>
Co-authored-by: Brendan Allan <[email protected]>
Co-authored-by: Shoubhit Dash <[email protected]>
Co-authored-by: Steven T. Cramer <[email protected]>
Co-authored-by: Jack <[email protected]>
Co-authored-by: Caleb Norton <[email protected]>
Co-authored-by: Aiden Cline <[email protected]>
Co-authored-by: opencode <[email protected]>
Co-authored-by: Frank <[email protected]>
Co-authored-by: Simon Klee <[email protected]>
Co-authored-by: James Long <[email protected]>
Co-authored-by: rahul <[email protected]>
Co-authored-by: rgs_ramp <[email protected]>
Co-authored-by: 黑墨水鱼 <[email protected]>
Co-authored-by: 07akioni <[email protected]>
Co-authored-by: Sebastian <[email protected]>
Co-authored-by: Kyle Altendorf <[email protected]>
Co-authored-by: Maddison Hellstrom <[email protected]>
Co-authored-by: Dax <[email protected]>
Co-authored-by: Dax Raad <[email protected]>
Co-authored-by: Aiden Cline <[email protected]>
Co-authored-by: Ariane Emory <[email protected]>
Co-authored-by: Jermiah Joseph <[email protected]>
Co-authored-by: OpeOginni <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: 21pounder <[email protected]>
Co-authored-by: Seashore Shi <[email protected]>
Co-authored-by: Seashore <[email protected]>
Co-authored-by: Cas <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Kotlin LSP support

4 participants