# src/tools/ Codemap

## Responsibility

The `src/tools/` directory provides the core tool implementations for the oh-my-opencode-slim plugin. It exposes three main categories of tools:

1. **Grep** - Fast regex-based content search using ripgrep (with fallback to system grep)
2. **LSP** - Language Server Protocol integration for code intelligence (definition, references, diagnostics, rename)
3. **AST-grep** - AST-aware structural code search and replacement across 25 languages
4. **Background Tasks** - Fire-and-forget agent task management with automatic notification

These tools are consumed by the OpenCode plugin system and exposed to AI agents for code navigation, analysis, and modification tasks.

---

## Design

### Architecture Overview

```
src/tools/
├── index.ts              # Central export point
├── background.ts         # Background task tools
├── grep/                 # Regex search (ripgrep-based)
│   ├── cli.ts           # CLI execution layer
│   ├── tools.ts         # Tool definition
│   ├── types.ts         # TypeScript interfaces
│   ├── utils.ts         # Output formatting
│   ├── constants.ts     # Safety limits & CLI resolution
│   └── downloader.ts    # Binary auto-download
├── lsp/                  # Language Server Protocol
│   ├── client.ts        # LSP client & connection pooling
│   ├── tools.ts         # 4 tool definitions
│   ├── types.ts         # LSP type re-exports
│   ├── utils.ts         # Formatters & workspace edit application
│   ├── config.ts        # Server discovery & language mapping
│   └── constants.ts     # Built-in server configs
└── ast-grep/            # AST-aware search
    ├── cli.ts           # CLI execution layer
    ├── tools.ts         # 2 tool definitions
    ├── types.ts         # TypeScript interfaces
    ├── utils.ts         # Output formatting & hints
    ├── constants.ts     # CLI resolution & environment checks
    └── downloader.ts    # Binary auto-download
```

### Key Patterns

#### 1. Tool Definition Pattern
All tools follow the OpenCode plugin tool schema:
```typescript
export const toolName: ToolDefinition = tool({
  description: string,
  args: { /* Zod schema */ },
  execute: async (args, context) => { /* implementation */ }
});
```

#### 2. CLI Abstraction Layer
Both `grep/` and `ast-grep/` use a similar CLI execution pattern:
- **cli.ts**: Low-level subprocess spawning with timeout handling
- **tools.ts**: High-level tool definitions that call CLI functions
- **constants.ts**: CLI path resolution with fallback chain
- **downloader.ts**: Binary auto-download for missing dependencies

#### 3. Connection Pooling (LSP)
The LSP module implements a singleton `LSPServerManager` with:
- **Connection pooling**: Reuse LSP clients per workspace root
- **Reference counting**: Track active usage
- **Idle cleanup**: Auto-shutdown after 5 minutes of inactivity
- **Initialization tracking**: Prevent concurrent initialization

#### 4. Safety Limits
All tools enforce strict safety limits:
- **Timeout**: 60s (grep), 300s (ast-grep, LSP)
- **Output size**: 10MB (grep), 1MB (ast-grep)
- **Match limits**: 500 matches (grep), 200 diagnostics/references (LSP)
- **Depth limits**: 20 directories (grep)

#### 5. Error Handling
- Graceful degradation (ripgrep → grep fallback)
- Clear error messages with installation hints
- Timeout handling with process cleanup
- Truncation detection and reporting

---

## Flow

### Grep Tool Flow

```
User Request
    ↓
grep tool (tools.ts)
    ↓
runRg() (cli.ts)
    ↓
resolveGrepCli() (constants.ts)
    ├─→ OpenCode bundled rg
    ├─→ System PATH rg
    ├─→ Cached download
    └─→ System grep (fallback)
    ↓
buildArgs() → Safety flags + user options
    ↓
spawn([cli, ...args]) with timeout
    ↓
parseOutput() → GrepMatch[]
    ↓
formatGrepResult() (utils.ts)
    ↓
Group by file → Return formatted output
```

### LSP Tool Flow

```
User Request (e.g., lsp_goto_definition)
    ↓
Tool definition (tools.ts)
    ↓
withLspClient() (utils.ts)
    ├─→ findServerForExtension() (config.ts)
    │   ├─→ Match extension to BUILTIN_SERVERS
    │   └─→ isServerInstalled() → PATH check
    ├─→ findWorkspaceRoot() → .git, package.json, etc.
    └─→ lspManager.getClient() (client.ts)
        ├─→ Check cache (root::serverId)
        ├─→ If cached: increment refCount, return
        └─→ If new:
            ├─→ new LSPClient(root, server)
            ├─→ client.start() → spawn server
            ├─→ client.initialize() → LSP handshake
            └─→ Store in pool with refCount=1
    ↓
client.definition() / references() / diagnostics() / rename()
    ├─→ openFile() → textDocument/didOpen
    └─→ Send LSP request
    ↓
Format result (formatLocation, formatDiagnostic, etc.)
    ↓
lspManager.releaseClient() → decrement refCount
    ↓
Return formatted output
```

**LSP Client Lifecycle:**
```
start()
  ├─→ spawn(command)
  ├─→ Create JSON-RPC connection (vscode-jsonrpc)
  ├─→ Register handlers (diagnostics, configuration)
  └─→ Wait for process to stabilize
    ↓
initialize()
  ├─→ sendRequest('initialize', capabilities)
  └─→ sendNotification('initialized')
    ↓
[Operational phase]
  ├─→ openFile() → textDocument/didOpen
  ├─→ definition() / references() / diagnostics() / rename()
  └─→ Receive notifications (diagnostics)
    ↓
stop()
  ├─→ sendRequest('shutdown')
  ├─→ sendNotification('exit')
  └─→ kill process
```

### AST-grep Tool Flow

```
User Request (ast_grep_search or ast_grep_replace)
    ↓
Tool definition (tools.ts)
    ↓
runSg() (cli.ts)
    ├─→ getAstGrepPath()
    │   ├─→ Check cached path
    │   ├─→ findSgCliPathSync()
    │   │   ├─→ Cached binary
    │   │   ├─→ @ast-grep/cli package
    │   │   ├─→ Platform-specific package
    │   │   └─→ Homebrew (macOS)
    │   └─→ ensureAstGrepBinary() → download if missing
    └─→ Build args: pattern, lang, rewrite, globs, paths
    ↓
spawn([sg, 'run', '-p', pattern, '--lang', lang, ...])
    ↓
Parse JSON output → CliMatch[]
    ↓
Handle truncation (max_output_bytes, max_matches)
    ↓
formatSearchResult() / formatReplaceResult() (utils.ts)
    ├─→ Group by file
    ├─→ Truncate long text
    └─→ Add summary
    ↓
Add empty result hints (getEmptyResultHint)
    ↓
Return formatted output
```

### Background Task Flow

```
User Request (background_task)
    ↓
Tool definition (background.ts)
    ↓
manager.launch()
    ├─→ Create task with unique ID
    ├─→ Store in BackgroundTaskManager
    └─→ Return task_id immediately (~1ms)
    ↓
[Background execution]
    ├─→ Agent runs independently
    ├─→ Completes with result/error
    └─→ Auto-notify parent session
    ↓
User Request (background_output)
    ↓
manager.getResult(task_id)
    ├─→ If timeout > 0: waitForCompletion()
    └─→ Return status/result/error
    ↓
User Request (background_cancel)
    ↓
manager.cancel(task_id) or manager.cancel(all)
    └─→ Cancel running tasks only
```

---

## Integration

### Dependencies

#### External Dependencies
- **@opencode-ai/plugin**: Tool definition schema (`tool`, `ToolDefinition`)
- **vscode-jsonrpc**: LSP JSON-RPC protocol implementation
- **vscode-languageserver-protocol**: LSP type definitions
- **bun**: Subprocess spawning (`spawn`), file operations (`Bun.write`)

#### Internal Dependencies
- **src/background**: `BackgroundTaskManager` for background task tools
- **src/config**: `SUBAGENT_NAMES`, `PluginConfig`, `TmuxConfig`
- **src/utils**: `extractZip` for binary extraction

### Consumers

#### Direct Consumers
- **src/index.ts**: Main plugin entry point imports all tools
- **src/cli/index.ts**: CLI entry point may use tools directly

#### Tool Registry
All tools are exported from `src/tools/index.ts`:
```typescript
export { grep } from './grep';
export { ast_grep_search, ast_grep_replace } from './ast-grep';
export {
  lsp_diagnostics,
  lsp_find_references,
  lsp_goto_definition,
  lsp_rename,
  lspManager,
} from './lsp';
export { createBackgroundTools } from './background';
```

### Configuration

#### LSP Server Configuration
- **BUILTIN_SERVERS** (lsp/constants.ts): Pre-configured servers for 12 languages
- **EXT_TO_LANG** (lsp/constants.ts): Extension to language ID mapping
- **LSP_INSTALL_HINTS** (lsp/constants.ts): Installation instructions per server

#### Grep Configuration
- **Safety limits** (grep/constants.ts): Max depth, filesize, count, columns, timeout
- **RG_SAFETY_FLAGS**: `--no-follow`, `--color=never`, `--no-heading`, `--line-number`, `--with-filename`
- **GREP_SAFETY_FLAGS**: `-n`, `-H`, `--color=never`

#### AST-grep Configuration
- **CLI_LANGUAGES** (ast-grep/types.ts): 25 supported languages
- **LANG_EXTENSIONS** (ast-grep/constants.ts): Language to file extension mapping
- **Safety limits**: Timeout (300s), max output (1MB), max matches (500)

### Binary Management

#### Ripgrep (grep/downloader.ts)
- **Version**: 14.1.1
- **Platforms**: darwin-arm64, darwin-x64, linux-arm64, linux-x64, win32-x64
- **Install location**: `~/.cache/oh-my-opencode-slim/bin/rg` (Linux/macOS), `%LOCALAPPDATA%\oh-my-opencode-slim\bin\rg.exe` (Windows)
- **Fallback**: System grep if ripgrep unavailable

#### AST-grep (ast-grep/downloader.ts)
- **Version**: 0.40.0 (synced with @ast-grep/cli package)
- **Platforms**: darwin-arm64, darwin-x64, linux-arm64, linux-x64, win32-x64, win32-arm64, win32-ia32
- **Install location**: `~/.cache/oh-my-opencode-slim/bin/sg` (Linux/macOS), `%LOCALAPPDATA%\oh-my-opencode-slim\bin\sg.exe` (Windows)
- **Fallback**: Manual installation instructions

### Error Handling Integration

All tools follow a consistent error handling pattern:
1. Try-catch around execution
2. Return formatted error messages
3. Include installation hints for missing binaries
4. Graceful degradation (fallback tools)
5. Timeout handling with process cleanup

### Performance Considerations

- **Connection pooling**: LSP clients reused across tool calls
- **Idle cleanup**: LSP clients shutdown after 5 minutes inactivity
- **Output truncation**: Prevent memory issues with large outputs
- **Timeout enforcement**: All subprocess operations have timeouts
- **Caching**: CLI paths cached to avoid repeated filesystem checks
- **Background tasks**: Fire-and-forget pattern for long-running operations

---

## File-by-File Summary

### Root Level
- **index.ts**: Central export point for all tools
- **background.ts**: Background task management (3 tools: launch, output, cancel)

### grep/
- **index.ts**: Re-exports grep module
- **cli.ts**: `runRg()`, `runRgCount()` - subprocess execution with timeout
- **tools.ts**: `grep` tool definition
- **types.ts**: `GrepMatch`, `GrepResult`, `CountResult`, `GrepOptions`
- **utils.ts**: `formatGrepResult()` - output formatting
- **constants.ts**: Safety limits, `resolveGrepCli()`, `resolveGrepCliWithAutoInstall()`
- **downloader.ts**: `downloadAndInstallRipgrep()`, `getInstalledRipgrepPath()`

### lsp/
- **index.ts**: Re-exports LSP module and types
- **client.ts**: `LSPServerManager` (singleton), `LSPClient` class
- **tools.ts**: 4 tools: `lsp_goto_definition`, `lsp_find_references`, `lsp_diagnostics`, `lsp_rename`
- **types.ts**: LSP type re-exports from vscode-languageserver-protocol
- **utils.ts**: `withLspClient()`, formatters, `applyWorkspaceEdit()`
- **config.ts**: `findServerForExtension()`, `getLanguageId()`, `isServerInstalled()`
- **constants.ts**: `BUILTIN_SERVERS`, `EXT_TO_LANG`, `LSP_INSTALL_HINTS`, safety limits

### ast-grep/
- **index.ts**: Re-exports ast-grep module
- **cli.ts**: `runSg()`, `getAstGrepPath()`, `startBackgroundInit()`
- **tools.ts**: 2 tools: `ast_grep_search`, `ast_grep_replace`
- **types.ts**: `CliLanguage`, `CliMatch`, `SgResult`, `CLI_LANGUAGES`
- **utils.ts**: `formatSearchResult()`, `formatReplaceResult()`, `getEmptyResultHint()`
- **constants.ts**: `findSgCliPathSync()`, `checkEnvironment()`, safety limits
- **downloader.ts**: `downloadAstGrep()`, `ensureAstGrepBinary()`, cache management