Commit Graph
173 Commits
Author SHA1 Message Date
Ant39140 af538a1387 Merge remote-tracking branch 'upstream/main' into fix/lsp-batch-stale-replay 2026-07-31 00:16:34 +08:00
Ant39140 f816286725 fix(coding-agent): preserve BOMs in LSP batch flushes 2026-07-30 17:02:16 +08:00
Ant39140 40e09c9491 fix(coding-agent): flush pending LSP batch on write failure 2026-07-30 16:32:15 +08:00
Ant39140 b9804edc1a Merge remote-tracking branch 'upstream/main' into fix/lsp-batch-stale-replay 2026-07-30 16:05:41 +08:00
Ant39140 d112790fc7 fix(coding-agent): prevent stale LSP batch writes 2026-07-30 15:49:22 +08:00
Kyle McCleary d90e54fb09 fix(coding-agent): harden native security workflow 2026-07-29 20:05:57 -07:00
can1357 6527671c3a fix(lsp): sanitize expanded generic output
(cherry picked from commit 1260d0633a5fb533c492f272ee500fec60c46e22)
2026-07-29 23:09:14 +02:00
roboompandcan1357 dca8f44b73 fix(lsp): handled quick exits before reader teardown
Waited briefly for process exit publication after clean stdout EOF so the process handler preserves the real exit code and stderr, while genuine reader errors still tear down immediately.

Cleared only the matching initialization failure for explicit reloads and added regressions for quick exits, reader errors, ordinary backoff, and immediate reload retries.

Fixes #7041

(cherry picked from commit a76522b759f14421202d4cc437ec611b78be20d1)
2026-07-29 23:09:13 +02:00
roboomp cb55edd60e fix(lsp): honored custom server language ids
Added an optional per-server languageId override and used it for both disk-backed and in-memory didOpen notifications.

Covered config loading and both document-open paths with a fake custom GDScript server.

Fixes #6800
2026-07-27 11:54:29 +00:00
shoucandanghehe cdf373b77d fix(coding-agent): handle asynchronous LSP pipe failures 2026-07-26 23:37:12 +08:00
can1357 b326e79e6e chore: applied formatter and dropped unused catch binding from merged lsp fix 2026-07-23 22:27:08 +02:00
can1357 bbf0402990 fix(coding-agent): surface JSON-RPC error code so -32601 method-not-found is recognized regardless of message text
Codex P2 on #6403: sendRequest rejected with only the server's error
message; a server answering rust-analyzer/reloadWorkspace with code
-32601 but nonstandard text (e.g. "Unknown request") would fail
isMethodNotFoundError and turn lsp reload into a hard error instead of
falling back to the generic reload. Include the code in the rejection
message so the existing -32601 substring check matches. Adds a
regression test with a -32601/"Unknown request" response.
2026-07-23 22:15:23 +02:00
roboomp eeb3fa6ace fix(coding-agent): propagated cancellation from lsp reload instead of false restart
reloadServer caught every error from both fallback mechanisms in bare
catch blocks, so a caller cancel or tool timeout was swallowed and fell
through to `proc.kill(); return "Restarted"` -- reporting a successful
restart while killing the server with no replacement.

- Propagate ToolAbortError/timeout from both the rust-analyzer request
  and the didChangeConfiguration notification fallback.
- Gate the fallback on genuine method-not-found via isMethodNotFoundError
  instead of any error.
- Replace the blind proc.kill with shutdownClientInstance: remove the
  client from the registry by identity and await confirmed process exit,
  surfacing a truthful teardown error when the process outlives the kill.

Fixes #6369
2026-07-23 18:58:15 +00:00
can1357 536d37ac07 Merge PR #5137: perf(coding-agent): avoid cold LSP startup on format-only writes (@wolfiesch) 2026-07-23 11:37:13 +02:00
roboomp 1b6588e520 fix(tools): cap per-tool default timeout with tools.maxTimeout
clampTimeout resolved the per-tool default (bash 300s) whenever the agent
omitted `timeout` and only enforced the tool's own min/max, so the
tools.maxTimeout global ceiling — applied solely in sdk.ts on explicitly
numeric args — was bypassed on the common default-fallback path.

Thread maxTimeout into clampTimeout so the resolved effective timeout,
including the default path, is capped before the per-tool floor/ceiling
apply. Explicit values below the cap still win; maxTimeout <= 0 stays
no-cap. Applied at every call site (bash, eval, browser, debug, lsp,
fetch, and the session-level bash executor), and the bash clamp notice
now names the global ceiling when it is the binding limit.

Fixes #6294
2026-07-22 15:18:27 +00:00
Wolfgang Schoenberger d866532bd1 perf(coding-agent): reduce format-on-write latency 2026-07-21 13:53:52 -07:00
can1357 f560db8cfe Merge PR #5810: fix(lsp): raise timeout ceiling to 300 seconds (@roboomp) 2026-07-18 20:12:46 +02:00
roboomp db91dbe3ea fix(lsp): returned pull diagnostics promptly
Raced document diagnostic pulls against the push polling interval so completed full reports return without waiting for the deadline.

Covered inline edit writethrough delivery for an immediate pull-only response.

Fixes #5825
2026-07-17 10:17:00 +00:00
roboomp 58b1d4440f fix(lsp): supported pull diagnostics
Advertised document diagnostic support and tracked static and dynamic server capabilities.

Pulled full reports within the existing diagnostics wait window while preserving push precedence.

Fixes #5825
2026-07-17 10:10:11 +00:00
roboomp ca874cf134 fix(lsp): raised timeout ceiling to 300 seconds
Allowed explicit LSP request budgets above 60 seconds and exposed the 5–300 second range in the tool schema.

Fixes #5804
2026-07-17 07:43:40 +00:00
roboomp c6e9763068 fix(lsp): returned null for missing configuration
Answered unconfigured workspace/configuration sections with the spec-required null value and covered the Roslyn post-initialization pull path.

Fixes #5745
2026-07-16 19:55:50 +00:00
roboomp a327992c86 fix(lsp): sent initial workspace configuration
Sent workspace/didChangeConfiguration after initialized so servers waiting for client configuration finish startup before semantic requests.

Added a fake-LSP regression covering notification order and settings payload.

Fixes #5276
2026-07-12 13:38:42 +00:00
can1357 b0d98d9e2b fix(coding-agent): decoupled lsp diagnostics from tool execution
- Offloaded slow LSP diagnostics to a deferred channel in the `write` tool to prevent blocking agent execution for the full 3-second poll window.
- Abstracted deferred diagnostic logic into a reusable `DeferredDiagnostics` class to standardize tracking and deduplication across tools.
- Updated `WriteTool` to support `beginDeferredDiagnosticsForPath` callbacks, surfacing diagnostics as an aside instead of stalling the tool result.
- Added a regression test validating that `write` completes immediately while diagnostics arrive asynchronously.
2026-07-11 07:33:19 +02:00
can1357 e8add61016 fix(debug): stopped native fallback for missing delve
- Kept missing language-specific adapters from falling through to native debuggers.
- Resolved nested launch roots before session-local binaries and PATH, including explicit adapters and go.work workspaces.
- Added actionable install/configuration errors and deterministic regression coverage.

Fixes #5037
2026-07-10 14:06:57 +02:00
roboomp 993b21204e fix(lsp): handled go.work workspace diagnostics
Detected go.work before go.mod for workspace diagnostics and expanded go build package patterns from go.work use entries.

Added regression coverage for go.work-only roots and mixed go.work/go.mod workspaces.

Fixes #5038
2026-07-10 07:14:49 +00:00
can1357 8519286ef7 feat(coding-agent): implemented watchdog and abort logic for lsp notifications
- Implemented a 2-second timeout for `workspace/didChangeWatchedFiles` notifications to prevent agent stalls during server congestion.
- Updated `runLspWritethrough` to gracefully reset notification state when the internal watchdog triggers but the primary operation remains active.
- Added explicit abort signal checks in `acp-bridge` to prevent initiation of file writes after tool cancellation.
- Refactored `notifyWorkspaceWatchedFiles` to use `AbortSignal.any` for unified signaling across timeout and caller-provided triggers.
2026-07-05 15:57:24 +02:00
can1357 535e8256b0 fix(lsp): avoid watched-file side effects 2026-07-05 13:10:26 +02:00
can1357 9a319b8a89 Merge PR #4462: fix(lsp): notify servers about harness file writes (@roboomp) 2026-07-05 13:10:26 +02:00
can1357 6f8e060419 Merge remote-tracking branch 'origin/farm/d78d878e/lsp-duplicate-edits' 2026-07-04 05:14:37 +02:00
roboomp 8d60e361eb fix(lsp): bounded watched-file notifications during writes
Watched-file notifications sent from the LSP writethrough now use the same bounded operation signal as sync/save notifications, so a stalled server cannot hang the write after disk commit.

Extended the freshness regression to assert a bounded signal reaches watched-file notification sends.

Refs #4459
2026-07-03 23:27:10 +00:00
roboomp 75fc4d65bb fix(lsp): notified servers about harness file writes
Announced harness-authored create, change, and delete operations to active LSP clients with workspace/didChangeWatchedFiles before edit-time diagnostics are read.

Added regression coverage for non-LSP sibling files in a batched write so diagnostics see the workspace state the harness just produced.

Fixes #4459
2026-07-03 15:48:48 +00:00
roboomp cf908b1727 fix(lsp): deduped identical replacement edits
Collapsed duplicate byte-identical non-empty LSP text edits before overlap validation so rename_file accepts idempotent server output while still rejecting real conflicts.

Fixes #4458
2026-07-03 15:40:21 +00:00
roboomp 136bda2399 fix(lsp): suppressed orphan ts project diagnostics
Filtered TypeScript project-resolution diagnostics for files with no root marker ancestor while preserving syntax diagnostics. Added regression coverage for Bun scratch files outside project roots.\n\nFixes #4401
2026-07-03 05:54:49 +00:00
roboomp 73a12c7ea2 fix(coding-agent): routed SIGTERM/SIGHUP/uncaughtException through session teardown
The postmortem SIGTERM/SIGHUP/uncaughtException handlers only ran the registered
cleanup callback list before process.exit, and the only session-related callback
was session-manager-flush. So a real kernel signal (terminal close, process
manager killing omp, IDE stop) skipped saveDraft, session.dispose (session_shutdown
emit, owned async job disposal, kernel disposal, MCP disconnect, browser tab
release), and violated the SessionShutdownEvent docstring contract that promises
delivery on SIGINT/SIGTERM. The LSP client also owned its own SIGINT/SIGTERM
handlers that called shutdownAll then process.exit(0), which could race postmortem's
async runCleanup and short-circuit the session teardown.

- Extracted a promise-memoized createSessionTeardown helper (modes/session-teardown.ts)
  that snapshots the editor draft, persists it via sessionManager.saveDraft, then
  invokes session.dispose. A saveDraft failure is logged but never aborts disposal.
- Memoized AgentSession.dispose so the keypress path and the signal path share one
  settled promise and cannot double-emit session_shutdown or double-drain the owned
  AsyncJobManager.
- Registered the teardown on postmortem as "session-teardown" in InteractiveMode.init,
  replacing the narrower session-manager-flush callback. InteractiveMode.shutdown
  now delegates the draft+dispose steps to the same helper.
- Replaced the LSP client's SIGINT/SIGTERM handlers with a "lsp-shutdown" postmortem
  callback so LSP cleanup runs alongside every other session teardown instead of
  racing them via process.exit(0). beforeExit is unchanged.
- Added session-teardown.test.ts covering: draft-then-dispose ordering, disposal
  after saveDraft rejects, empty-string clears stale sidecar, promise memoization
  under concurrent invocation, and snapshot-at-first-call semantics.

Fixes #4080
2026-07-01 07:19:30 +00:00
roboomp 769a9e5807 fix(lsp): only teardown clients on in-flight flush aborts
Distinguish aborts that race an active sink.flush() from aborts that happen
before a queued write starts. Only the former leaves the sink flush pending
and requires killing/evicting the LSP client; pre-write aborts should reject
that caller without disrupting unrelated in-flight operations.

Add a regression with one notification blocked in flush and a second queued
notification whose signal aborts before its write starts, asserting the shared
client is not killed and only the first message is written.
2026-07-01 02:21:40 +00:00
roboomp 0a1392de4b fix(lsp): skip init failure cache on caller abort
Caller cancellations and tool timeout signals are transient initialize failures.
Do not put them in the three-minute init failure backoff, so a later normal
LSP call can retry the server/cwd instead of failing fast as recently failed.

Add a regression that aborts a wedged initialize and then retries the same
server/cwd with a short explicit timeout, asserting it does not hit the
negative-cache error.
2026-07-01 02:13:59 +00:00
roboomp e06fe92649 fix(lsp): normalize sink.flush return to Promise for strict typecheck
sink.flush()'s type is number | Promise<number>, so calling .then/.catch
directly failed under tsgo. Wrap in Promise.resolve() and annotate the
rejection handler's err parameter to satisfy strict noImplicitAny.
2026-07-01 02:06:59 +00:00
roboomp 11edbe01c2 style: bun run fix 2026-07-01 02:06:16 +00:00
roboomp 442ee57283 fix(lsp): honor tool signal in cold-start initialize and notification writes
Two client-level paths in the LSP tool bypassed the combined tool-timeout/
caller abort signal built in `LspTool.execute`, so a wedged server hung
past the advertised tool deadline and past user cancellation:

- `getOrCreateClient` took no `AbortSignal` and its `initialize`
  `sendRequest` was invoked with `signal = undefined`. With no signal
  and no explicit `timeoutMs`, `sendRequest` fell back to the hard-coded
  `DEFAULT_REQUEST_TIMEOUT_MS = 30000` internal timer, so a first-use
  `lsp` call against a server that wedged in `initialize` ignored the
  20s tool default (and any user-supplied shorter `timeout`) until the
  30s internal timer fired.
- `writeMessage`/`queueWriteMessage`/`sendNotification` had no timeout
  and no signal, so a `textDocument/didOpen`/`didChange`/`didSave` sent
  to a server that stopped draining stdin awaited `sink.flush()`
  forever. Because writes serialize through `client.writeQueue`, every
  later op on the client stalled behind the stuck flush too.

Thread the caller `AbortSignal` through `getOrCreateClient` (initialize
+ initialized notification) and through `sendNotification` /
`queueWriteMessage` / `writeMessage` so the sink flush is raced against
the signal. On abort, tear the client down: kill the process and evict
it from the active-clients map so the next `getOrCreateClient` call
spawns a fresh server instead of queueing behind the wedged sink.

Update the LSP tool callsites and internal helpers
(`captureDiagnosticVersions`, `captureOpenFileVersions`,
`syncFileContent`, `notifyFileSaved`, `formatContent`,
`getDiagnosticsForFile`, `reloadServer`, and the rename didClose /
didRenameFiles path) to forward their operation signal.

Warmup keeps its short explicit `initTimeoutMs` and passes no caller
signal; `sendRequest`'s existing `timeoutMs ?? (signal ? undefined : DEFAULT)`
policy still uses that fixed timer.

Fixes #3962
2026-07-01 02:06:03 +00:00
roboomp ad6748ebe7 fix(lsp): covered setup.cfg and pyrightconfig venv lookup
Added setup.cfg and pyrightconfig.json to PYTHON_ROOT_MARKERS so pyright, basedpyright, and pylsp project shapes also probe Windows .venv/Scripts before PATH fallback.

Fixes #3916
2026-06-30 20:26:39 +00:00
roboomp ae0ae68e14 fix(lsp): included ruff-only roots for venv lookup
Extended Python local-bin gating to Ruff-only root marker files so Windows virtualenv Scripts launchers are found before PATH fallback.

Fixes #3916
2026-06-30 20:21:10 +00:00
roboomp 15c889941c fix(lsp): detected windows python venv scripts
Added Windows virtualenv Scripts directories to local LSP command resolution so project-local Ruff launchers are discovered before PATH fallback.

Fixes #3916
2026-06-30 20:14:46 +00:00
can1357 5d4203d52b fix(coding-agent): preserved resume scoping after PR merges 2026-06-26 17:17:43 +02:00
can1357 80c6528c93 fix(coding-agent): resolved PR 3562 merge fallout 2026-06-26 17:08:53 +02:00
arg3t 5ea20952bd fix(coding-agent): rediscover LSPs on workspace reload 2026-06-26 02:33:20 -07:00
can1357 93db34b0d5 refactor(coding-agent): consolidated editor state and unify transcript rendering
- Centralized draft state and image management by migrating fields from context to the CustomEditor component.
- Standardized transcript row construction by introducing shared helpers for background jobs, IRC traffic, and file mentions.
- Refactored redundant UI logic and helper functions into reusable utility modules to streamline message submission and component rendering.
- Standardized event handler types by consolidating lifecycle definitions into a shared module while maintaining public API stability.
2026-06-22 06:11:57 +02:00
can1357 fe33b372f9 refactor(coding-agent): consolidated message framing logic
- Extracted incremental byte-stream framing logic into a shared `MessageFramer` class.
- Replaced redundant, per-client implementations in `dap/client.ts` and `lsp/client.ts`.
- Centralized buffer management to avoid O(n^2) allocation patterns during large message bursts.
2026-06-22 05:29:00 +02:00
can1357 725aa2222b fix(coding-agent/lsp): drain config pulls on lazy cold start
The background message reader matched every incoming message against the
pending client-request map by id before checking for a `method`. Server
request ids live in the server's own id space and routinely collide with
the client's in-flight request ids, so a server-originated
`workspace/configuration` pull whose id matched a pending request (e.g. a
basedpyright pull landing while a `documentSymbol` request with the same
id was open) was swallowed as a bogus response: the client request
resolved with `undefined` and the pull was never answered, wedging
servers that gate analysis on configuration.

Route any message carrying a `method` as a server request (or
notification) before id-matching responses, so every config pull is
answered under lazy init -- parity with the warmup/reload path, which
escaped the bug only because it issues no concurrent semantic request
while the cold-start pulls drain. lsp.lazy default is unchanged.

Fixes #3001
2026-06-21 02:16:26 +02:00
can1357 f88cf45eb6 fix(lsp): also no-op workspace/{inlineValue,foldingRange}/refresh
The PR fixed the -32601 hang for the defined server->client refresh
requests but missed two real spec methods of the identical class:
workspace/inlineValue/refresh (LSP 3.17) and workspace/foldingRange/refresh.
A server emitting either still received Method not found and could stall.
Add both to the void-ack chain and extend the regression test.
2026-06-19 17:17:04 +02:00
roboomp ef901ecb0d fix(lsp): replied to defined server requests with spec no-ops
handleServerRequest fell through to a JSON-RPC -32601 Method not found for several defined server -> client requests (window/showMessageRequest, window/showDocument, workspace/{semanticTokens,inlayHint,codeLens,codeAction,diagnostic}/refresh). Servers that block on a real reply -- the same failure class as the client/registerCapability hang fixed in #3029 -- could stall waiting for an acknowledgement that never came.

Reply with the spec no-op result instead: null for showMessageRequest / *Refresh, { success: false } for showDocument. Headless omp cannot honour the UI surface, but it still owes a defined response.

Fixes #3044
2026-06-19 10:11:54 +00:00