cli-lsp-client 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +179 -27
- package/cli-lsp-client +0 -0
- package/package.json +17 -3
- package/src/cli.ts +75 -30
package/README.md
CHANGED
|
@@ -13,23 +13,25 @@ CLI tool for getting LSP diagnostics. Uses a background daemon to keep LSP serve
|
|
|
13
13
|
|
|
14
14
|
## Supported Languages
|
|
15
15
|
|
|
16
|
-
| Language
|
|
17
|
-
|
|
18
|
-
| TypeScript/JavaScript | `typescript-language-server`
|
|
19
|
-
| Python
|
|
20
|
-
| JSON
|
|
21
|
-
| CSS
|
|
22
|
-
| YAML
|
|
23
|
-
| Bash/Shell
|
|
24
|
-
|
|
|
25
|
-
|
|
|
26
|
-
|
|
|
27
|
-
|
|
16
|
+
| Language | LSP Server | Auto-installed | Notes |
|
|
17
|
+
| --------------------- | ------------------------------ | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
18
|
+
| TypeScript/JavaScript | `typescript-language-server` | ✓ (via bunx) | `.ts`, `.tsx`, `.js`, `.jsx`, `.mjs`, `.cjs`, `.mts`, `.cts` |
|
|
19
|
+
| Python | `pyright-langserver` | ✓ (via bunx) | `.py`, `.pyi` |
|
|
20
|
+
| JSON | `vscode-json-language-server` | ✓ (via vscode-langservers-extracted) | `.json`, `.jsonc` - includes schema validation |
|
|
21
|
+
| CSS | `vscode-css-language-server` | ✓ (via vscode-langservers-extracted) | `.css`, `.scss`, `.sass`, `.less` |
|
|
22
|
+
| YAML | `yaml-language-server` | ✓ (via bunx) | `.yaml`, `.yml` - includes schema validation |
|
|
23
|
+
| Bash/Shell | `bash-language-server` | ✓ (via bunx) | `.sh`, `.bash`, `.zsh` - **requires shellcheck** (`brew install shellcheck`) |
|
|
24
|
+
| GraphQL | `graphql-language-service-cli` | ✓ (via bunx) | `.graphql`, `.gql` |
|
|
25
|
+
| **R** | **R languageserver** | **✗** | **`.r`, `.R`, `.rmd`, `.Rmd` - see [R Installation](#r-installation-guide) below** |
|
|
26
|
+
| **C#** | **OmniSharp-Roslyn** | **✗** | **`.cs` - see [C# Installation](#c-installation-guide) below** |
|
|
27
|
+
| Go | `gopls` | ✗ | Requires manual install: `go install golang.org/x/tools/gopls@latest` |
|
|
28
|
+
| Java | `jdtls` (Eclipse JDT) | ✗ | `.java` - see [Java Installation](#java-installation-guide) below |
|
|
29
|
+
| Lua | `lua-language-server` | ✗ | `.lua` - requires manual install via package manager (brew, scoop) or from [releases](https://github.com/LuaLS/lua-language-server/releases) |
|
|
28
30
|
|
|
29
31
|
## How It Works
|
|
30
32
|
|
|
31
33
|
- Daemon starts automatically when needed
|
|
32
|
-
- LSP servers spawn based on file type
|
|
34
|
+
- LSP servers spawn based on file type
|
|
33
35
|
- Finds project roots using config files (tsconfig.json, etc.)
|
|
34
36
|
- Servers stay running for subsequent requests
|
|
35
37
|
|
|
@@ -37,7 +39,7 @@ CLI tool for getting LSP diagnostics. Uses a background daemon to keep LSP serve
|
|
|
37
39
|
|
|
38
40
|
### Real-time Diagnostics Hook
|
|
39
41
|
|
|
40
|
-
Get instant diagnostic feedback for TypeScript, Python,
|
|
42
|
+
Get instant diagnostic feedback for TypeScript, Python, JSON, CSS, YAML, Bash, GraphQL, R, C#, Go, Java, and Lua files as you edit in Claude Code.
|
|
41
43
|
|
|
42
44
|
#### Setup
|
|
43
45
|
|
|
@@ -53,7 +55,7 @@ Configure Claude Code to use the built-in hook command:
|
|
|
53
55
|
"hooks": [
|
|
54
56
|
{
|
|
55
57
|
"type": "command",
|
|
56
|
-
"command": "npx -y cli-lsp-client
|
|
58
|
+
"command": "npx -y cli-lsp-client start"
|
|
57
59
|
}
|
|
58
60
|
]
|
|
59
61
|
}
|
|
@@ -75,9 +77,9 @@ Configure Claude Code to use the built-in hook command:
|
|
|
75
77
|
|
|
76
78
|
#### How It Works
|
|
77
79
|
|
|
78
|
-
- **SessionStart**: Automatically
|
|
80
|
+
- **SessionStart**: Automatically starts LSP servers when Claude Code starts for faster initial diagnostics
|
|
79
81
|
- **PostToolUse**: Runs diagnostics after each file edit (Edit, MultiEdit, Write tools)
|
|
80
|
-
- Built-in file filtering for all supported languages (
|
|
82
|
+
- Built-in file filtering for all supported languages (16 file types)
|
|
81
83
|
- Shows errors, warnings, and hints inline
|
|
82
84
|
- Graceful error handling - never breaks your editing experience
|
|
83
85
|
- Uses the same fast daemon as the regular diagnostics command
|
|
@@ -88,7 +90,7 @@ When you save a file with errors, you'll see immediate feedback:
|
|
|
88
90
|
|
|
89
91
|
```
|
|
90
92
|
Edit operation feedback:
|
|
91
|
-
- [npx -y cli-lsp-client claude-code-hook]:
|
|
93
|
+
- [npx -y cli-lsp-client claude-code-hook]:
|
|
92
94
|
ERROR at line 3, column 9:
|
|
93
95
|
Type 'number' is not assignable to type 'string'.
|
|
94
96
|
Source: typescript
|
|
@@ -106,6 +108,8 @@ npx cli-lsp-client diagnostics src/example.ts
|
|
|
106
108
|
# Check any supported file type
|
|
107
109
|
npx cli-lsp-client diagnostics app.py
|
|
108
110
|
npx cli-lsp-client diagnostics main.go
|
|
111
|
+
npx cli-lsp-client diagnostics analysis.R
|
|
112
|
+
npx cli-lsp-client diagnostics Program.cs
|
|
109
113
|
```
|
|
110
114
|
|
|
111
115
|
Exit codes: 0 for no issues, 2 for issues found.
|
|
@@ -126,20 +130,23 @@ npx cli-lsp-client hover src/main.ts myFunction
|
|
|
126
130
|
|
|
127
131
|
# Get hover info for a variable or type
|
|
128
132
|
npx cli-lsp-client hover app.py MyClass
|
|
133
|
+
npx cli-lsp-client hover analysis.R mean
|
|
134
|
+
npx cli-lsp-client hover Program.cs Console
|
|
129
135
|
```
|
|
130
136
|
|
|
131
|
-
|
|
137
|
+
````bash
|
|
132
138
|
$ npx cli-lsp-client hover src/client.ts runCommand
|
|
133
139
|
Location: src/client.ts:370:17
|
|
134
140
|
```typescript
|
|
135
141
|
export function runCommand(command: string, commandArgs: string[]): Promise<void>
|
|
136
|
-
|
|
137
|
-
|
|
142
|
+
````
|
|
143
|
+
|
|
144
|
+
````
|
|
138
145
|
|
|
139
146
|
### Daemon Management
|
|
140
147
|
|
|
141
148
|
```bash
|
|
142
|
-
# Check daemon status and
|
|
149
|
+
# Check daemon status with uptime and running language servers
|
|
143
150
|
npx cli-lsp-client status
|
|
144
151
|
|
|
145
152
|
# List all running daemons across directories
|
|
@@ -156,6 +163,22 @@ npx cli-lsp-client --version
|
|
|
156
163
|
|
|
157
164
|
# Show help
|
|
158
165
|
npx cli-lsp-client help
|
|
166
|
+
````
|
|
167
|
+
|
|
168
|
+
The `status` command shows the current daemon's uptime and running language servers:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
$ npx cli-lsp-client status
|
|
172
|
+
LSP Daemon Status
|
|
173
|
+
================
|
|
174
|
+
PID: 33502
|
|
175
|
+
Uptime: 1m 38s
|
|
176
|
+
|
|
177
|
+
Language Servers:
|
|
178
|
+
- typescript (.) - running 1m 33s
|
|
179
|
+
- pyright (.) - running 1m 10s
|
|
180
|
+
|
|
181
|
+
Total: 2 language servers running
|
|
159
182
|
```
|
|
160
183
|
|
|
161
184
|
The `list` command shows all running daemon instances with their working directories, PIDs, and status:
|
|
@@ -165,7 +188,7 @@ $ npx cli-lsp-client list
|
|
|
165
188
|
|
|
166
189
|
Running Daemons:
|
|
167
190
|
================
|
|
168
|
-
Hash | PID | Status | Working Directory
|
|
191
|
+
Hash | PID | Status | Working Directory
|
|
169
192
|
----------------------------------------------------------
|
|
170
193
|
h0gx9u | 12345 | ● Running | /Users/user/project-a
|
|
171
194
|
94yi9w | 12346 | ● Running | /Users/user/project-b
|
|
@@ -204,11 +227,13 @@ java -Declipse.application=org.eclipse.jdt.ls.core.id1 \
|
|
|
204
227
|
### Alternative Installation Methods
|
|
205
228
|
|
|
206
229
|
**Homebrew (macOS/Linux)**:
|
|
230
|
+
|
|
207
231
|
```bash
|
|
208
232
|
brew install jdtls
|
|
209
233
|
```
|
|
210
234
|
|
|
211
235
|
**Arch Linux**:
|
|
236
|
+
|
|
212
237
|
```bash
|
|
213
238
|
pacman -S jdtls
|
|
214
239
|
```
|
|
@@ -221,14 +246,141 @@ pacman -S jdtls
|
|
|
221
246
|
|
|
222
247
|
For detailed setup instructions, see the [official Eclipse JDT.LS documentation](https://github.com/eclipse-jdtls/eclipse.jdt.ls).
|
|
223
248
|
|
|
249
|
+
## R Installation Guide
|
|
250
|
+
|
|
251
|
+
The R language server requires R runtime and the `languageserver` package:
|
|
252
|
+
|
|
253
|
+
### Installation Steps
|
|
254
|
+
|
|
255
|
+
1. **Install R**: Download and install R from [CRAN](https://cran.r-project.org/) or use a package manager:
|
|
256
|
+
|
|
257
|
+
**macOS (Homebrew)**:
|
|
258
|
+
```bash
|
|
259
|
+
brew install r
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
**Ubuntu/Debian**:
|
|
263
|
+
```bash
|
|
264
|
+
sudo apt-get update
|
|
265
|
+
sudo apt-get install r-base
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
**Windows**: Download installer from [CRAN Windows](https://cran.r-project.org/bin/windows/base/)
|
|
269
|
+
|
|
270
|
+
2. **Install R languageserver package**: Open R and run:
|
|
271
|
+
```r
|
|
272
|
+
install.packages("languageserver")
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Or from command line:
|
|
276
|
+
```bash
|
|
277
|
+
R --slave -e 'install.packages("languageserver", repos="https://cran.rstudio.com/")'
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Verification
|
|
281
|
+
|
|
282
|
+
Test that the language server works:
|
|
283
|
+
```bash
|
|
284
|
+
R --slave -e 'languageserver::run()'
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Project Detection
|
|
288
|
+
|
|
289
|
+
The R LSP automatically detects R projects based on these files:
|
|
290
|
+
- `DESCRIPTION` (R packages)
|
|
291
|
+
- `NAMESPACE` (R packages)
|
|
292
|
+
- `.Rproj` (RStudio projects)
|
|
293
|
+
- `renv.lock` (renv dependency management)
|
|
294
|
+
- Any `.r`, `.R`, `.rmd`, `.Rmd` files
|
|
295
|
+
|
|
296
|
+
For more information, see the [R languageserver documentation](https://github.com/REditorSupport/languageserver).
|
|
297
|
+
|
|
298
|
+
## C# Installation Guide
|
|
299
|
+
|
|
300
|
+
The C# language server requires .NET SDK and OmniSharp-Roslyn:
|
|
301
|
+
|
|
302
|
+
### Installation Steps
|
|
303
|
+
|
|
304
|
+
1. **Install .NET SDK**: Download .NET 6.0+ from [Microsoft .NET](https://dotnet.microsoft.com/download) or use a package manager:
|
|
305
|
+
|
|
306
|
+
**macOS (Homebrew)**:
|
|
307
|
+
```bash
|
|
308
|
+
brew install dotnet
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
**Ubuntu/Debian**:
|
|
312
|
+
```bash
|
|
313
|
+
# Add Microsoft package repository
|
|
314
|
+
wget https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
|
|
315
|
+
sudo dpkg -i packages-microsoft-prod.deb
|
|
316
|
+
sudo apt-get update
|
|
317
|
+
sudo apt-get install -y dotnet-sdk-8.0
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
**Windows**: Download installer from [.NET Downloads](https://dotnet.microsoft.com/download)
|
|
321
|
+
|
|
322
|
+
2. **Install OmniSharp-Roslyn**: Download the latest release from [OmniSharp releases](https://github.com/OmniSharp/omnisharp-roslyn/releases):
|
|
323
|
+
|
|
324
|
+
**Automatic script** (recommended):
|
|
325
|
+
```bash
|
|
326
|
+
# Download and extract OmniSharp to ~/.omnisharp/
|
|
327
|
+
mkdir -p ~/.omnisharp
|
|
328
|
+
curl -L https://github.com/OmniSharp/omnisharp-roslyn/releases/latest/download/omnisharp-osx-arm64-net6.0.tar.gz | tar -xz -C ~/.omnisharp/
|
|
329
|
+
|
|
330
|
+
# Create symlink to make omnisharp available in PATH
|
|
331
|
+
sudo ln -sf ~/.omnisharp/OmniSharp /usr/local/bin/omnisharp
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
**Manual installation**:
|
|
335
|
+
- Download the appropriate release for your platform (Windows: `omnisharp-win-x64-net6.0.zip`, Linux: `omnisharp-linux-x64-net6.0.tar.gz`)
|
|
336
|
+
- Extract to a directory (e.g., `~/.omnisharp/`)
|
|
337
|
+
- Add the executable to your PATH or create a symlink
|
|
338
|
+
|
|
339
|
+
3. **Set environment variables**:
|
|
340
|
+
|
|
341
|
+
**Fish shell**:
|
|
342
|
+
```bash
|
|
343
|
+
set -Ux DOTNET_ROOT ~/.dotnet
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
**Bash/Zsh**:
|
|
347
|
+
```bash
|
|
348
|
+
echo 'export DOTNET_ROOT=~/.dotnet' >> ~/.bashrc # or ~/.zshrc
|
|
349
|
+
source ~/.bashrc # or ~/.zshrc
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
**Note**: `DOTNET_ROOT` must be set in your shell environment for the C# language server to work. The CLI will only load OmniSharp if this environment variable is defined. Restart your terminal after setting the environment variable to ensure it's available.
|
|
353
|
+
|
|
354
|
+
### Verification
|
|
355
|
+
|
|
356
|
+
Test that OmniSharp works:
|
|
357
|
+
```bash
|
|
358
|
+
# Verify DOTNET_ROOT is set
|
|
359
|
+
echo $DOTNET_ROOT
|
|
360
|
+
|
|
361
|
+
# Test OmniSharp command
|
|
362
|
+
omnisharp --help
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Project Detection
|
|
366
|
+
|
|
367
|
+
The C# LSP automatically detects C# projects based on these files:
|
|
368
|
+
- `*.sln` (Solution files)
|
|
369
|
+
- `*.csproj` (Project files)
|
|
370
|
+
- `project.json` (Legacy project files)
|
|
371
|
+
- `global.json` (.NET global configuration)
|
|
372
|
+
- Any `.cs` files
|
|
373
|
+
|
|
374
|
+
For more information, see the [OmniSharp documentation](https://github.com/OmniSharp/omnisharp-roslyn).
|
|
375
|
+
|
|
224
376
|
### Additional Commands
|
|
225
377
|
|
|
226
378
|
```bash
|
|
227
|
-
#
|
|
228
|
-
npx cli-lsp-client
|
|
379
|
+
# Start LSP servers for current directory (faster subsequent requests)
|
|
380
|
+
npx cli-lsp-client start
|
|
229
381
|
|
|
230
|
-
#
|
|
231
|
-
npx cli-lsp-client
|
|
382
|
+
# Start servers for specific directory
|
|
383
|
+
npx cli-lsp-client start /path/to/project
|
|
232
384
|
|
|
233
385
|
# View daemon logs
|
|
234
386
|
npx cli-lsp-client logs
|
package/cli-lsp-client
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cli-lsp-client",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "CLI tool for fast LSP diagnostics with background daemon and multi-project support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/cli.ts",
|
|
@@ -23,14 +23,27 @@
|
|
|
23
23
|
"build": "bun build src/cli.ts --compile --outfile cli-lsp-client",
|
|
24
24
|
"dev": "bun run src/cli.ts",
|
|
25
25
|
"typecheck": "bun --bun tsc --noEmit",
|
|
26
|
+
"lint": "eslint .",
|
|
27
|
+
"lint:fix": "eslint . --fix",
|
|
28
|
+
"format": "prettier --check .",
|
|
29
|
+
"format:fix": "prettier --write .",
|
|
26
30
|
"test": "bun test",
|
|
27
31
|
"test:watch": "bun test tests/ --watch",
|
|
28
32
|
"prepublish": "bun test && bun run build"
|
|
29
33
|
},
|
|
30
34
|
"devDependencies": {
|
|
35
|
+
"@eslint/js": "^9.33.0",
|
|
31
36
|
"@types/bun": "latest",
|
|
32
37
|
"@types/node": "latest",
|
|
33
|
-
"
|
|
38
|
+
"eslint": "^9.33.0",
|
|
39
|
+
"eslint-config-prettier": "10.1.8",
|
|
40
|
+
"eslint-import-resolver-typescript": "^4.4.4",
|
|
41
|
+
"eslint-plugin-import-x": "^4.16.1",
|
|
42
|
+
"eslint-plugin-unused-imports": "^4.1.4",
|
|
43
|
+
"globals": "^16.3.0",
|
|
44
|
+
"prettier": "3.6.2",
|
|
45
|
+
"typescript": "latest",
|
|
46
|
+
"typescript-eslint": "^8.39.1"
|
|
34
47
|
},
|
|
35
48
|
"peerDependencies": {
|
|
36
49
|
"typescript": "^5.0.0"
|
|
@@ -38,6 +51,7 @@
|
|
|
38
51
|
"dependencies": {
|
|
39
52
|
"pyright": "^1.1.403",
|
|
40
53
|
"vscode-jsonrpc": "^8.2.1",
|
|
41
|
-
"vscode-languageserver-types": "^3.17.5"
|
|
54
|
+
"vscode-languageserver-types": "^3.17.5",
|
|
55
|
+
"zod": "^4.0.17"
|
|
42
56
|
}
|
|
43
57
|
}
|
package/src/cli.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
3
|
import path from 'path';
|
|
4
|
+
import { z } from 'zod';
|
|
4
5
|
import { startDaemon } from './daemon.js';
|
|
5
6
|
import { runCommand, sendToExistingDaemon } from './client.js';
|
|
6
7
|
import { formatDiagnosticsPlain } from './lsp/formatter.js';
|
|
@@ -9,64 +10,104 @@ import { HELP_MESSAGE } from './constants.js';
|
|
|
9
10
|
import { ensureDaemonRunning } from './utils.js';
|
|
10
11
|
import packageJson from '../package.json' with { type: 'json' };
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
// Schema for Claude Code PostToolUse hook payload
|
|
14
|
+
const HookDataSchema = z.object({
|
|
15
|
+
session_id: z.string().optional(),
|
|
16
|
+
transcript_path: z.string().optional(),
|
|
17
|
+
cwd: z.string().optional(),
|
|
18
|
+
hook_event_name: z.string().optional(),
|
|
19
|
+
tool_name: z.string().optional(),
|
|
20
|
+
tool_input: z
|
|
21
|
+
.object({
|
|
22
|
+
file_path: z.string().optional(),
|
|
23
|
+
content: z.string().optional(),
|
|
24
|
+
})
|
|
25
|
+
.optional(),
|
|
26
|
+
tool_response: z.any().optional(),
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export async function handleClaudeCodeHook(
|
|
30
|
+
filePath: string
|
|
31
|
+
): Promise<{ hasIssues: boolean; output: string; daemonFailed?: boolean }> {
|
|
13
32
|
// Check if file exists
|
|
14
|
-
if (!await Bun.file(filePath).exists()) {
|
|
33
|
+
if (!(await Bun.file(filePath).exists())) {
|
|
15
34
|
return { hasIssues: false, output: '' };
|
|
16
35
|
}
|
|
17
|
-
|
|
36
|
+
|
|
18
37
|
// Filter supported file types
|
|
19
38
|
const supportedExts = [
|
|
20
|
-
'.ts',
|
|
21
|
-
'.
|
|
39
|
+
'.ts',
|
|
40
|
+
'.tsx',
|
|
41
|
+
'.js',
|
|
42
|
+
'.jsx',
|
|
43
|
+
'.mjs',
|
|
44
|
+
'.cjs',
|
|
45
|
+
'.mts',
|
|
46
|
+
'.cts',
|
|
47
|
+
'.py',
|
|
48
|
+
'.pyi',
|
|
22
49
|
'.go',
|
|
23
|
-
'.json',
|
|
24
|
-
'.
|
|
25
|
-
'.
|
|
26
|
-
'.
|
|
50
|
+
'.json',
|
|
51
|
+
'.jsonc',
|
|
52
|
+
'.css',
|
|
53
|
+
'.scss',
|
|
54
|
+
'.sass',
|
|
55
|
+
'.less',
|
|
56
|
+
'.yaml',
|
|
57
|
+
'.yml',
|
|
58
|
+
'.sh',
|
|
59
|
+
'.bash',
|
|
60
|
+
'.zsh',
|
|
27
61
|
'.java',
|
|
28
62
|
'.lua',
|
|
29
|
-
'.graphql',
|
|
63
|
+
'.graphql',
|
|
64
|
+
'.gql',
|
|
65
|
+
'.r',
|
|
66
|
+
'.R',
|
|
67
|
+
'.rmd',
|
|
68
|
+
'.Rmd',
|
|
69
|
+
'.cs',
|
|
30
70
|
];
|
|
31
71
|
const ext = path.extname(filePath);
|
|
32
72
|
if (!supportedExts.includes(ext)) {
|
|
33
73
|
return { hasIssues: false, output: '' };
|
|
34
74
|
}
|
|
35
|
-
|
|
75
|
+
|
|
36
76
|
// Get diagnostics (suppress errors to stdout)
|
|
37
77
|
try {
|
|
38
78
|
// Ensure daemon is running
|
|
39
79
|
const daemonStarted = await ensureDaemonRunning();
|
|
40
|
-
|
|
80
|
+
|
|
41
81
|
if (!daemonStarted) {
|
|
42
82
|
// Failed to start daemon - return with flag so caller can handle
|
|
43
|
-
return {
|
|
44
|
-
hasIssues: false,
|
|
45
|
-
output:
|
|
46
|
-
|
|
83
|
+
return {
|
|
84
|
+
hasIssues: false,
|
|
85
|
+
output:
|
|
86
|
+
'Failed to start LSP daemon. Please try running "cli-lsp-client stop" and retry.',
|
|
87
|
+
daemonFailed: true,
|
|
47
88
|
};
|
|
48
89
|
}
|
|
49
|
-
|
|
90
|
+
|
|
50
91
|
const result = await sendToExistingDaemon('diagnostics', [filePath]);
|
|
51
|
-
|
|
92
|
+
|
|
52
93
|
// The diagnostics command returns an array of diagnostics
|
|
53
94
|
if (!Array.isArray(result) || result.length === 0) {
|
|
54
95
|
return { hasIssues: false, output: '' };
|
|
55
96
|
}
|
|
56
|
-
|
|
97
|
+
|
|
57
98
|
const diagnostics = result as Diagnostic[];
|
|
58
|
-
|
|
99
|
+
|
|
59
100
|
// Format output for Claude Code hook (plain text, no ANSI codes)
|
|
60
101
|
const formatted = formatDiagnosticsPlain(filePath, diagnostics);
|
|
61
102
|
return { hasIssues: true, output: formatted || '' };
|
|
62
|
-
} catch (
|
|
103
|
+
} catch (_error) {
|
|
63
104
|
// Silently fail - don't break Claude Code experience
|
|
64
105
|
return { hasIssues: false, output: '' };
|
|
65
106
|
}
|
|
66
107
|
}
|
|
67
108
|
|
|
68
109
|
function showHelp(): void {
|
|
69
|
-
|
|
110
|
+
process.stdout.write(HELP_MESSAGE + '\n');
|
|
70
111
|
}
|
|
71
112
|
|
|
72
113
|
async function run(): Promise<void> {
|
|
@@ -88,7 +129,7 @@ async function run(): Promise<void> {
|
|
|
88
129
|
|
|
89
130
|
// Handle version command directly (no daemon needed)
|
|
90
131
|
if (command === 'version' || command === '--version' || command === '-v') {
|
|
91
|
-
|
|
132
|
+
process.stdout.write(packageJson.version + '\n');
|
|
92
133
|
return;
|
|
93
134
|
}
|
|
94
135
|
|
|
@@ -112,10 +153,14 @@ async function run(): Promise<void> {
|
|
|
112
153
|
}
|
|
113
154
|
|
|
114
155
|
// Parse the JSON to get the file path
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
156
|
+
const parseResult = HookDataSchema.safeParse(JSON.parse(stdinData));
|
|
157
|
+
if (!parseResult.success) {
|
|
158
|
+
process.exit(0); // Invalid JSON format, silently exit
|
|
159
|
+
}
|
|
160
|
+
const hookData = parseResult.data;
|
|
161
|
+
// Extract file_path from PostToolUse tool_input
|
|
162
|
+
const filePath = hookData.tool_input?.file_path;
|
|
163
|
+
|
|
119
164
|
if (!filePath) {
|
|
120
165
|
process.exit(0); // No file path, silently exit
|
|
121
166
|
}
|
|
@@ -123,15 +168,15 @@ async function run(): Promise<void> {
|
|
|
123
168
|
const result = await handleClaudeCodeHook(filePath);
|
|
124
169
|
if (result.daemonFailed) {
|
|
125
170
|
// Daemon failed to start - exit with status 1 to show error to user
|
|
126
|
-
|
|
171
|
+
process.stderr.write(result.output + '\n');
|
|
127
172
|
process.exit(1);
|
|
128
173
|
}
|
|
129
174
|
if (result.hasIssues) {
|
|
130
|
-
|
|
175
|
+
process.stderr.write(result.output + '\n');
|
|
131
176
|
process.exit(2);
|
|
132
177
|
}
|
|
133
178
|
process.exit(0);
|
|
134
|
-
} catch (
|
|
179
|
+
} catch (_error) {
|
|
135
180
|
// Silently fail for hook commands to not break Claude Code
|
|
136
181
|
process.exit(0);
|
|
137
182
|
}
|