Skip to content

feat: add LSP and ast-grep workspace tools - #202

Merged
terisuke merged 4 commits into
devfrom
feat/workspace-lsp-astgrep
May 5, 2026
Merged

terisuke merged 4 commits into
devfrom
feat/workspace-lsp-astgrep

Conversation

@terisuke

@terisuke terisuke commented May 4, 2026 •

Copy link
Copy Markdown

Issue for this PR

Closes #199

Type of change

  • New feature

What does this PR do?

Adds 6 workspace tools — lsp_diagnostics, lsp_goto_definition, lsp_find_references, lsp_rename, ast_grep_search, ast_grep_replace — using vscode-jsonrpc and @ast-grep/cli.

LSP clients are long-lived and cached per workspace+language. Server registry covers TypeScript, Python, Go, Rust. AST-grep wrapper resolves the sg binary through the @ast-grep/cli package's bin field so it works under Bun workspaces.

Files in packages/plugin/src/tools/workspace/. Follow-up #198 tracks ToolContext.directory plumbing for correct workspace cwd.

How did you verify your code works?

  • bun typecheck: 13/13 packages pass
  • bun test packages/plugin/test/workspace/: 33 pass / 3 skip (integration gated)
  • Regression tests cover Bun-spawn handshake, LSP ENOENT install hint, non-ASCII byte slicing, ast-grep ERROR-stderr, paths cwd fix, binary resolution

Screenshots / recordings

N/A.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@github-actions

github-actions Bot commented May 4, 2026

Copy link
Copy Markdown

This pull request has been automatically closed.

@github-actions github-actions Bot closed this May 4, 2026
@terisuke terisuke reopened this May 4, 2026
terisuke and others added 4 commits May 5, 2026 09:58
Clean-room implementation of six new plugin tools for IDE-precision
workspace operations.

LSP tools (vscode-jsonrpc/node):
- lsp_diagnostics: pull diagnostics for a file from the language server
- lsp_goto_definition: resolve definition site(s) for a symbol position
- lsp_find_references: list every reference to a symbol
- lsp_rename: workspace-wide rename with optional dryRun + atomic write

AST-grep tools (@ast-grep/cli):
- ast_grep_search: structural pattern search with $VAR/$$$ metavariables
- ast_grep_replace: pattern-based rewrite with optional dryRun

Includes:
- LSP server registry (TS/JS, Python, Go, Rust) with friendly install
  hints when a server binary is missing
- Long-lived LSP client cache keyed by workspace root + language
- 10s RPC timeout with poison-on-timeout semantics
- Atomic temp+rename writes for both lsp_rename and ast_grep_replace
- Mock-based unit tests (24 passing) plus INTEGRATION_TESTS=1 gated
  end-to-end smoke tests

All tools registered via workspaceTools() helper, exported from
@opencode-ai/plugin and @opencode-ai/plugin/tools/workspace.

Clean-room: implemented from the Language Server Protocol 3.17 spec
and ast-grep CLI documentation; no source from oh-my-openagent
(SUL-1.0) was read or copied.

Refs #197 (sibling PR-A: hashline edit tool from the same plan).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
…F-8 + HIGH leaks)

- CRITICAL: replace Bun.spawn with node:child_process for LSP client
  (vscode-jsonrpc/node requires Node streams; Bun.spawn returns Web
  ReadableStream which lacks the .on(...) API the JSON-RPC reader uses)
- HIGH: applyByteEdits now uses Buffer for byte-offset slicing (was
  corrupting non-ASCII files because ast-grep emits UTF-8 byte offsets
  but JS strings are UTF-16 code units)
- HIGH: binaryWorks drains stdout/stderr to prevent OS pipe deadlock
  (a chatty `sg` lookalike on PATH would fill the 64 KiB pipe buffer)
- HIGH: ast-grep CLI failures now surface as AstGrepCliError with stderr
  instead of silently returning empty results (broken patterns,
  missing paths, IO errors)
- MEDIUM: replace bare require() with createRequire (ESM-safe sync load)
- MEDIUM: dryRun defaults to true for both lsp_rename and ast_grep_replace
  (destructive operations are now opt-in)
- MEDIUM: setTimeout cleanup on diagnostics waiter resolution
- MEDIUM: findRoot capped at 16 ascents to avoid unbounded walks
- MEDIUM: extract shared friendlyError helper to lsp/util.ts (DRY across
  diagnostics, definition, references, rename)
- MEDIUM: document multi-file atomicity boundary + recovery story
- Regression tests: spawn-based LSP handshake (Bun-spawn bug),
  initialize payload shape, non-ASCII byte-offset slicing,
  CLI failure propagation, exit-code-1 = no-match preservation

Refs #197 (PR-B reviews from code-reviewer + Codex CLI route A).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
…grep correctness)

- HIGH NH1: defaultConnectionFactory now handles spawn 'error' event (prevents uncaughtException, installHint reaches user)
- HIGH NH2: ast-grep CLI errors with exit 0 + ERROR-tagged stderr now surface as AstGrepCliError
- HIGH NH3: paths[0] no longer misused as spawn cwd (was causing hangs and ENOTDIR)
- HIGH NH4: ensureBinary() resolves @ast-grep/cli package.json bin field reliably across Bun workspaces
- MEDIUM NM1: Bun-spawn regression test now exercises production defaultConnectionFactory
- MEDIUM NM2: integration test surfaces error.error on failure for CI diagnostics
- 4 new regression tests added

Refs PR-B re-review (code-reviewer + Codex CLI route A round 2)
Refs #1
- HIGH: add test/test:ci scripts to packages/plugin/package.json and matching
  task entries in turbo.json so turbo picks up regression tests in CI
  (closes a falsifiability gap where plugin tests were never executed)
- MEDIUM: drop excess 'extensions: []' field from LspServerSpec test stub
- TODO: ToolContext.directory plumbing in defaultSpawnCwd is documented as a
  follow-up issue (#198); architectural change kept out of this PR's scope

Refs PR-B re-review round 3 (code-reviewer N3-H1, N3-M1)
Refs #199
@terisuke
terisuke force-pushed the feat/workspace-lsp-astgrep branch from 33a3d9a to 8f8ea2d Compare May 5, 2026 01:01
@terisuke
terisuke merged commit d35c98f into dev May 5, 2026
2 of 9 checks passed
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.

feat: LSP + ast-grep workspace tools

1 participant