claudecode-linter 2.1.138-patch.1 → 2.1.138-patch.2
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/.claudecode-lint.defaults.yaml +18 -0
- package/README.md +20 -2
- package/contracts/lsp.schema.json +82 -0
- package/contracts/monitors.schema.json +48 -0
- package/contracts/plugin.schema.json +1319 -0
- package/dist/discovery.js +17 -0
- package/dist/index.js +8 -0
- package/dist/linters/lsp-json.js +94 -0
- package/dist/linters/monitors-json.js +85 -0
- package/dist/linters/plugin-json.js +34 -5
- package/dist/plugin-schema.js +222 -0
- package/package.json +8 -2
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
rules:
|
|
10
10
|
# ── plugin.json ──────────────────────────────────────────
|
|
11
11
|
plugin-json/valid-json: error
|
|
12
|
+
plugin-json/schema-valid: error
|
|
12
13
|
plugin-json/name-required: error
|
|
13
14
|
plugin-json/name-kebab-case: error
|
|
14
15
|
plugin-json/name-length: error
|
|
@@ -111,6 +112,23 @@ rules:
|
|
|
111
112
|
claude-md/no-todo-markers: info
|
|
112
113
|
claude-md/no-trailing-whitespace: info
|
|
113
114
|
|
|
115
|
+
# ── .lsp.json ────────────────────────────────────────────
|
|
116
|
+
# Standalone LSP config files at plugin root. Most common bug:
|
|
117
|
+
# wrapping content under a top-level "lspServers" key, which only
|
|
118
|
+
# belongs inline in plugin.json. Claude Code parses with
|
|
119
|
+
# E.record(E.string(), <per-server>).safeParse — wrapped files
|
|
120
|
+
# validate as a single (invalid) server entry at session start.
|
|
121
|
+
lsp-json/valid-json: error
|
|
122
|
+
lsp-json/no-lsp-servers-wrapper: error
|
|
123
|
+
lsp-json/schema-valid: error
|
|
124
|
+
|
|
125
|
+
# ── monitors/monitors.json ───────────────────────────────
|
|
126
|
+
# Array of monitor entries. Names must be unique within a plugin
|
|
127
|
+
# (Claude Code refines this; not expressible in JSON Schema).
|
|
128
|
+
monitors-json/valid-json: error
|
|
129
|
+
monitors-json/schema-valid: error
|
|
130
|
+
monitors-json/unique-names: error
|
|
131
|
+
|
|
114
132
|
# ── Misplaced files ──────────────────────────────────────
|
|
115
133
|
# Reserved artifact basenames (plugin.json, hooks.json,
|
|
116
134
|
# marketplace.json, SKILL.md) found at non-canonical paths inside
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
Standalone linter for [Claude Code](https://docs.anthropic.com/en/docs/claude-code) plugins and configuration files.
|
|
9
9
|
|
|
10
|
-
Validates `plugin.json`, `SKILL.md`, agent/command markdown, `hooks.json`, `mcp.json`, `settings.json`,
|
|
10
|
+
Validates `plugin.json`, `SKILL.md`, agent/command markdown, `hooks.json`, `mcp.json`, `settings.json`, `CLAUDE.md`, `.lsp.json`, and `monitors/monitors.json` files. plugin.json/lsp.json/monitors.json are checked against JSON Schemas auto-extracted from Claude Code's runtime Zod validators — failures the linter reports are the same failures Claude Code would raise at session start.
|
|
11
11
|
|
|
12
12
|

|
|
13
13
|
|
|
@@ -111,7 +111,7 @@ No issues found.
|
|
|
111
111
|
|
|
112
112
|
| Type | Files | Rules |
|
|
113
113
|
|------|-------|-------|
|
|
114
|
-
| plugin-json | `.claude-plugin/plugin.json` |
|
|
114
|
+
| plugin-json | `.claude-plugin/plugin.json` | 13 |
|
|
115
115
|
| skill-md | `skills/*/SKILL.md` | 11 |
|
|
116
116
|
| agent-md | `agents/*.md` | 13 |
|
|
117
117
|
| command-md | `commands/*.md` | 5 |
|
|
@@ -119,6 +119,24 @@ No issues found.
|
|
|
119
119
|
| settings-json | `.claude-plugin/settings.json` | 14 |
|
|
120
120
|
| mcp-json | `.claude-plugin/mcp.json` | 16 |
|
|
121
121
|
| claude-md | `CLAUDE.md` | 10 |
|
|
122
|
+
| lsp-json | `.lsp.json` | 3 |
|
|
123
|
+
| monitors-json | `monitors/monitors.json` | 3 |
|
|
124
|
+
|
|
125
|
+
## Schema-derived rules
|
|
126
|
+
|
|
127
|
+
`plugin-json/schema-valid`, `lsp-json/schema-valid`, and `monitors-json/schema-valid` validate against JSON Schemas that are *auto-extracted from Claude Code's cli.js bundle* — same Zod schemas that the runtime calls `.safeParse(content)` on. This catches:
|
|
128
|
+
|
|
129
|
+
- **Missing required fields** (e.g., LSP server without `extensionToLanguage`)
|
|
130
|
+
- **Wrong field types** (e.g., `name: 42` instead of a string)
|
|
131
|
+
- **Invalid enum values** (e.g., `transport: "websocket"` when only `stdio`/`socket` are accepted)
|
|
132
|
+
- **Nested-shape violations** in discriminated unions (e.g., `mcpServers.x.type: "telegraph"` when only `stdio`/`sse`/`http`/... are accepted)
|
|
133
|
+
- **Unknown fields** in strict objects (e.g., `filetypes`/`rootPatterns` inside an LSP server config — common confusion with editor-LSP shapes from other ecosystems)
|
|
134
|
+
|
|
135
|
+
The schemas live at `contracts/{plugin,lsp,monitors}.schema.json` and are regenerated by `npm run extract-contracts` on every Claude Code release.
|
|
136
|
+
|
|
137
|
+
`lsp-json/no-lsp-servers-wrapper` catches a specific authoring mistake: putting your `.lsp.json` content under a top-level `lspServers` key. That wrapper belongs **inline in plugin.json** only — the dedicated file is a flat map of server-name → config.
|
|
138
|
+
|
|
139
|
+
`monitors-json/unique-names` enforces Claude Code's "monitor names must be unique within a plugin" check (a `refine()` predicate that JSON Schema can't express natively).
|
|
122
140
|
|
|
123
141
|
## Configuration
|
|
124
142
|
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extractedFromClaudeCodeVersion": "2.1.138",
|
|
3
|
+
"extractedAt": "2026-05-11T08:02:42.911Z",
|
|
4
|
+
"schema": {
|
|
5
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
6
|
+
"title": "Claude Code .lsp.json",
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"properties": {
|
|
11
|
+
"command": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"minLength": 1,
|
|
14
|
+
"description": "Command to execute the LSP server (e.g., \"typescript-language-server\")"
|
|
15
|
+
},
|
|
16
|
+
"args": {
|
|
17
|
+
"type": "array",
|
|
18
|
+
"items": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"minLength": 1
|
|
21
|
+
},
|
|
22
|
+
"description": "Command-line arguments to pass to the server"
|
|
23
|
+
},
|
|
24
|
+
"extensionToLanguage": {
|
|
25
|
+
"type": "object",
|
|
26
|
+
"additionalProperties": {
|
|
27
|
+
"type": "string",
|
|
28
|
+
"minLength": 1
|
|
29
|
+
},
|
|
30
|
+
"description": "Mapping from file extension to LSP language ID. File extensions and languages are derived from this mapping."
|
|
31
|
+
},
|
|
32
|
+
"transport": {
|
|
33
|
+
"enum": [
|
|
34
|
+
"stdio",
|
|
35
|
+
"socket"
|
|
36
|
+
],
|
|
37
|
+
"default": "stdio",
|
|
38
|
+
"description": "Communication transport mechanism"
|
|
39
|
+
},
|
|
40
|
+
"env": {
|
|
41
|
+
"type": "object",
|
|
42
|
+
"additionalProperties": {
|
|
43
|
+
"type": "string"
|
|
44
|
+
},
|
|
45
|
+
"description": "Environment variables to set when starting the server"
|
|
46
|
+
},
|
|
47
|
+
"initializationOptions": {
|
|
48
|
+
"description": "Initialization options passed to the server during initialization"
|
|
49
|
+
},
|
|
50
|
+
"settings": {
|
|
51
|
+
"description": "Settings passed to the server via workspace/didChangeConfiguration"
|
|
52
|
+
},
|
|
53
|
+
"workspaceFolder": {
|
|
54
|
+
"type": "string",
|
|
55
|
+
"description": "Workspace folder path to use for the server"
|
|
56
|
+
},
|
|
57
|
+
"startupTimeout": {
|
|
58
|
+
"type": "number",
|
|
59
|
+
"description": "Maximum time to wait for server startup (milliseconds)"
|
|
60
|
+
},
|
|
61
|
+
"shutdownTimeout": {
|
|
62
|
+
"type": "number",
|
|
63
|
+
"description": "Maximum time to wait for graceful shutdown (milliseconds)"
|
|
64
|
+
},
|
|
65
|
+
"restartOnCrash": {
|
|
66
|
+
"type": "boolean",
|
|
67
|
+
"description": "Whether to restart the server if it crashes"
|
|
68
|
+
},
|
|
69
|
+
"maxRestarts": {
|
|
70
|
+
"type": "number",
|
|
71
|
+
"description": "Maximum number of restart attempts before giving up"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"required": [
|
|
75
|
+
"command",
|
|
76
|
+
"extensionToLanguage"
|
|
77
|
+
],
|
|
78
|
+
"additionalProperties": false
|
|
79
|
+
},
|
|
80
|
+
"description": "Flat map of server-name → LSP server config. The top-level keys are server names; their values match the per-server schema. This file is loaded by Claude Code when present at the plugin root."
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extractedFromClaudeCodeVersion": "2.1.138",
|
|
3
|
+
"extractedAt": "2026-05-11T08:02:42.913Z",
|
|
4
|
+
"schema": {
|
|
5
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
6
|
+
"title": "Claude Code monitors.json",
|
|
7
|
+
"type": "array",
|
|
8
|
+
"items": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"properties": {
|
|
11
|
+
"name": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"minLength": 1,
|
|
14
|
+
"description": "Identifier for this monitor, unique within the plugin. Used to dedupe so re-arming (plugin reload, repeat skill invoke) does not spawn duplicates."
|
|
15
|
+
},
|
|
16
|
+
"command": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"minLength": 1,
|
|
19
|
+
"description": "Shell command to run as a persistent background monitor. Each stdout line is delivered to the model as a <task_notification> event; the process runs for the session lifetime. ${CLAUDE_PLUGIN_ROOT}, ${CLAUDE_PLUGIN_DATA}, ${user_config.*}, and ${ENV_VAR} are substituted. Runs in the session cwd \\u2014 prefix with `cd \"${CLAUDE_PLUGIN_ROOT}\" && ` if the script needs its own directory."
|
|
20
|
+
},
|
|
21
|
+
"description": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"minLength": 1,
|
|
24
|
+
"description": "Short human-readable description of what is being monitored (shown in task panel and notification summary)."
|
|
25
|
+
},
|
|
26
|
+
"when": {
|
|
27
|
+
"anyOf": [
|
|
28
|
+
{
|
|
29
|
+
"const": "always"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"type": "string"
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"default": "always",
|
|
36
|
+
"description": "Arm trigger. \"always\" arms at session start and on plugin reload. \"on-skill-invoke:<skill>\" arms the first time that skill is dispatched (via Skill tool or slash command)."
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"required": [
|
|
40
|
+
"name",
|
|
41
|
+
"command",
|
|
42
|
+
"description"
|
|
43
|
+
],
|
|
44
|
+
"additionalProperties": false
|
|
45
|
+
},
|
|
46
|
+
"description": "Array of monitor entries. Each monitor's `name` must be unique within the plugin (Claude Code enforces this with a refine() check that is not expressible in JSON Schema; the monitors-json linter does it separately)."
|
|
47
|
+
}
|
|
48
|
+
}
|