@yawlabs/ctxlint 0.14.0 → 0.15.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.
@@ -93,7 +93,7 @@
93
93
  "severity": "error",
94
94
  "description": "A stdio server entry has no \"command\" field.",
95
95
  "trigger": "Server has type \"stdio\" (or no type with no url) and no \"command\" field.",
96
- "message": "Server \"{name}\": missing \"command\" field",
96
+ "message": "Server \"{name}\" has no \"command\" field",
97
97
  "fixable": false,
98
98
  "clients": [
99
99
  "all"
@@ -106,7 +106,20 @@
106
106
  "severity": "error",
107
107
  "description": "An HTTP or SSE server entry has no \"url\" field.",
108
108
  "trigger": "Server has type \"http\" or \"sse\" and no \"url\" field.",
109
- "message": "Server \"{name}\": missing \"url\" field",
109
+ "message": "Server \"{name}\" has no \"url\" field",
110
+ "fixable": false,
111
+ "clients": [
112
+ "all"
113
+ ],
114
+ "stability": "stable"
115
+ },
116
+ {
117
+ "id": "mcp-schema/no-name-field",
118
+ "category": "mcp-schema",
119
+ "severity": "error",
120
+ "description": "A server entry's key (its name) is empty. Every server entry must be named.",
121
+ "trigger": "A key in the mcpServers/servers object is the empty string.",
122
+ "message": "Server name cannot be empty",
110
123
  "fixable": false,
111
124
  "clients": [
112
125
  "all"
@@ -117,9 +130,9 @@
117
130
  "id": "mcp-schema/unknown-transport",
118
131
  "category": "mcp-schema",
119
132
  "severity": "warning",
120
- "description": "Server type field is not a recognized transport.",
121
- "trigger": "\"type\" field is present but is not \"stdio\", \"http\", or \"sse\".",
122
- "message": "Server \"{name}\": unknown transport type \"{type}\"",
133
+ "description": "Server transport cannot be classified: the \"type\" field is not a recognized transport, or the entry has no \"command\", no \"url\", and no valid \"type\" at all.",
134
+ "trigger": "The parser could not classify the server's transport — a string \"type\" outside stdio/http/sse, a non-string \"type\", or an entry with neither \"command\" nor \"url\". The no-recognizable-transport case emits the message variant: Server \"{name}\" has no recognizable transport — expected \"command\", \"url\", or a valid \"type\".",
135
+ "message": "Server \"{name}\" has unknown transport type \"{type}\"",
123
136
  "fixable": false,
124
137
  "clients": [
125
138
  "all"
@@ -132,7 +145,7 @@
132
145
  "severity": "warning",
133
146
  "description": "Server has both a command (stdio) and a URL (http), making the transport ambiguous.",
134
147
  "trigger": "Server entry has both \"command\" and \"url\" fields.",
135
- "message": "Server \"{name}\": has both \"command\" and \"url\" — transport is ambiguous",
148
+ "message": "Server \"{name}\" has both \"command\" and \"url\" — transport is ambiguous",
136
149
  "fixable": false,
137
150
  "clients": [
138
151
  "all"
@@ -158,7 +171,7 @@
158
171
  "severity": "error",
159
172
  "description": "A git-tracked config file contains a literal Bearer token in the Authorization header.",
160
173
  "trigger": "Authorization header value matches \"Bearer <literal>\" where the token is not an env var reference, and the file is tracked by git.",
161
- "message": "Server \"{name}\": hardcoded Bearer token in a git-tracked file",
174
+ "message": "Server \"{name}\" has a hardcoded Bearer token in a git-tracked file",
162
175
  "fixable": true,
163
176
  "fixDescription": "Replace the literal token with an env var reference derived from the server name.",
164
177
  "clients": [
@@ -170,9 +183,9 @@
170
183
  "id": "mcp-security/hardcoded-api-key",
171
184
  "category": "mcp-security",
172
185
  "severity": "error",
173
- "description": "A git-tracked config file contains a value matching known API key patterns.",
174
- "trigger": "A header or env value matches known API key prefixes (sk-, ghp_, xoxb-, AKIA, etc.) or is a high-entropy string > 20 chars, and the file is tracked by git.",
175
- "message": "Server \"{name}\": possible API key in a git-tracked file",
186
+ "description": "A git-tracked config file contains a value matching known API key patterns, or a high-entropy value whose variable name suggests a secret.",
187
+ "trigger": "A header or env value matches known API key prefixes (sk-, ghp_, xoxb-, AKIA, AGE-SECRET-KEY-1, glpat-, sq0atp-, etc.), or is a high-entropy string > 20 chars AND the env var name contains a secret-suggesting keyword (KEY, TOKEN, SECRET, PASSWORD, AUTH, CREDENTIAL, ...) — the name gate keeps build IDs, commit SHAs, and version strings from false-positiving. File must be tracked by git.",
188
+ "message": "Server \"{name}\" has a hardcoded API key in a git-tracked file",
176
189
  "fixable": true,
177
190
  "fixDescription": "Replace the literal value with an env var reference.",
178
191
  "clients": [
@@ -186,7 +199,7 @@
186
199
  "severity": "error",
187
200
  "description": "A git-tracked config URL contains query parameters that look like secrets.",
188
201
  "trigger": "URL contains query params like ?key=, ?token=, ?api_key= with literal values in a git-tracked file.",
189
- "message": "Server \"{name}\": possible secret in URL query string",
202
+ "message": "Server \"{name}\" has a secret in the URL query string",
190
203
  "fixable": false,
191
204
  "clients": [
192
205
  "all"
@@ -198,8 +211,8 @@
198
211
  "category": "mcp-security",
199
212
  "severity": "warning",
200
213
  "description": "Server URL uses HTTP without TLS for a non-localhost target.",
201
- "trigger": "URL scheme is http:// and host is not localhost or 127.0.0.1.",
202
- "message": "Server \"{name}\": URL uses HTTP without TLS",
214
+ "trigger": "URL scheme is http:// and host is not a loopback address (localhost, [::1], 127.0.0.0/8).",
215
+ "message": "Server \"{name}\" uses HTTP without TLS",
203
216
  "fixable": false,
204
217
  "clients": [
205
218
  "all"
@@ -225,7 +238,7 @@
225
238
  "category": "mcp-commands",
226
239
  "severity": "warning",
227
240
  "description": "A stdio command references a local file path that does not exist.",
228
- "trigger": "Command starts with ./ or ../ and the resolved path does not exist.",
241
+ "trigger": "Command starts with ./ or ../ and the resolved path does not exist. Project-scope configs only — a global config's relative command resolves against that client's own working directory.",
229
242
  "message": "Server \"{name}\": command \"{command}\" not found",
230
243
  "fixable": false,
231
244
  "clients": [
@@ -238,8 +251,8 @@
238
251
  "category": "mcp-commands",
239
252
  "severity": "warning",
240
253
  "description": "A stdio arg looks like a local file path but the file does not exist.",
241
- "trigger": "An arg matches a file path pattern (contains / with extension, or starts with ./) and the file does not exist.",
242
- "message": "Server \"{name}\": arg \"{arg}\" references a missing file",
254
+ "trigger": "An arg matches a file path pattern (contains / with extension, or starts with ./) and the file does not exist. Relative paths are checked in project-scope configs only — a global config's relative paths resolve against that client's own working directory. Absolute paths are cwd-independent and are checked at every scope.",
255
+ "message": "Server \"{name}\": arg \"{arg}\" looks like a file path but doesn't exist",
243
256
  "fixable": false,
244
257
  "clients": [
245
258
  "all"
@@ -252,7 +265,7 @@
252
265
  "severity": "warning",
253
266
  "description": "SSE transport was deprecated in the March 2025 MCP spec update. Use Streamable HTTP instead.",
254
267
  "trigger": "Server has \"type\": \"sse\".",
255
- "message": "Server \"{name}\": SSE transport is deprecated — use \"http\" (Streamable HTTP)",
268
+ "message": "Server \"{name}\" uses deprecated SSE transport — use \"http\" (Streamable HTTP) instead",
256
269
  "fixable": true,
257
270
  "fixDescription": "Replace \"sse\" with \"http\" in the type field.",
258
271
  "clients": [
@@ -281,15 +294,18 @@
281
294
  "id": "mcp-env/unset-variable",
282
295
  "category": "mcp-env",
283
296
  "severity": "info",
284
- "description": "A referenced environment variable is not set in the current shell environment.",
285
- "trigger": "Env var reference found but the variable is not in process.env.",
297
+ "description": "A referenced environment variable is not set in the current shell environment. Deliberately info severity: many env vars are set only in CI, .env files, or shell profiles unavailable during linting.",
298
+ "trigger": "Env var reference found in any collected string value (env, url, command, args, headers) but the variable is not in process.env. Skipped entirely for Continue configs — their ${{ secrets.VAR }} refs resolve from GitHub Actions secrets, not the local environment, so every correct Continue config would false-positive.",
286
299
  "message": "Server \"{name}\": environment variable \"{var}\" is not set",
287
300
  "fixable": false,
288
301
  "clients": [
289
302
  "claude-code",
303
+ "claude-desktop",
304
+ "vscode",
290
305
  "cursor",
291
- "continue",
292
- "windsurf"
306
+ "windsurf",
307
+ "cline",
308
+ "amazonq"
293
309
  ],
294
310
  "stability": "stable"
295
311
  },
@@ -307,12 +323,12 @@
307
323
  "stability": "stable"
308
324
  },
309
325
  {
310
- "id": "mcp-urls/malformed",
326
+ "id": "mcp-urls/malformed-url",
311
327
  "category": "mcp-urls",
312
328
  "severity": "error",
313
329
  "description": "Server URL is not a valid URL.",
314
330
  "trigger": "URL cannot be parsed by standard URL parser and does not contain env var placeholders.",
315
- "message": "Server \"{name}\": invalid URL",
331
+ "message": "Server \"{name}\": invalid URL \"{url}\"",
316
332
  "fixable": false,
317
333
  "clients": [
318
334
  "all"
@@ -323,9 +339,9 @@
323
339
  "id": "mcp-urls/localhost-in-project-config",
324
340
  "category": "mcp-urls",
325
341
  "severity": "warning",
326
- "description": "A project-level config (committed to version control) references localhost, which won't work for other team members.",
327
- "trigger": "URL host is localhost or 127.0.0.1 and the file is a project-level config.",
328
- "message": "Server \"{name}\": localhost URL in project config won't work for teammates",
342
+ "description": "A project-level config (committed to version control) references a loopback address, which won't work for other team members.",
343
+ "trigger": "URL host is a loopback address (localhost, [::1], 127.0.0.0/8 — the same set http-no-tls exempts) and the file is a project-level config.",
344
+ "message": "Server \"{name}\": loopback URL in project config won't work for teammates",
329
345
  "fixable": false,
330
346
  "clients": [
331
347
  "all"
@@ -350,7 +366,7 @@
350
366
  "category": "mcp-consistency",
351
367
  "severity": "warning",
352
368
  "description": "The same server name is configured differently across multiple client config files.",
353
- "trigger": "Server name exists in 2+ config files with different url or command/args values.",
369
+ "trigger": "Server name exists in 2+ same-scope config files (project-project or user-user) with different url or command/args values. Cross-scope pairs are skipped — a user/global config differing from the project one is documented client precedence (project overrides user), not drift.",
354
370
  "message": "Server \"{name}\" is configured differently in {file1} and {file2}",
355
371
  "fixable": false,
356
372
  "clients": [
@@ -376,7 +392,7 @@
376
392
  "category": "mcp-consistency",
377
393
  "severity": "info",
378
394
  "description": "A server in .mcp.json is not present in another client's project config that also exists.",
379
- "trigger": "Server exists in .mcp.json but is absent from .cursor/mcp.json or .vscode/mcp.json (when those files exist).",
395
+ "trigger": "Server exists in .mcp.json but is absent from .cursor/mcp.json, .vscode/mcp.json, or .amazonq/mcp.json (when those files exist).",
380
396
  "message": "Server \"{name}\" is in .mcp.json but missing from {file}",
381
397
  "fixable": false,
382
398
  "clients": [
@@ -388,12 +404,12 @@
388
404
  "id": "mcp-redundancy/disabled-server",
389
405
  "category": "mcp-redundancy",
390
406
  "severity": "info",
391
- "description": "A server entry is explicitly disabled.",
392
- "trigger": "Server has \"disabled\": true.",
393
- "message": "Server \"{name}\" is disabled — consider removing if no longer needed",
407
+ "description": "A server entry is explicitly disabled. The \"disabled\" field is Cline-specific, but the rule fires on any config that carries it.",
408
+ "trigger": "Server has \"disabled\": true (any client's config).",
409
+ "message": "Server \"{name}\" is disabled — consider removing it if no longer needed",
394
410
  "fixable": false,
395
411
  "clients": [
396
- "cline"
412
+ "all"
397
413
  ],
398
414
  "stability": "stable"
399
415
  },
@@ -402,8 +418,8 @@
402
418
  "category": "mcp-redundancy",
403
419
  "severity": "info",
404
420
  "description": "The same server is identically configured at both project and global scope, making the global entry redundant.",
405
- "trigger": "Server with same name and identical config exists at both project and global scope.",
406
- "message": "Server \"{name}\" is identically configured in {projectFile} and {globalFile}",
421
+ "trigger": "Server with same name and identical config (command/args/url/env) exists at both project and global scope.",
422
+ "message": "Server \"{name}\" is identically configured in both {projectFile} and {globalFile}",
407
423
  "fixable": false,
408
424
  "clients": [
409
425
  "claude-code",
package/package.json CHANGED
@@ -1,17 +1,23 @@
1
1
  {
2
2
  "name": "@yawlabs/ctxlint",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "mcpName": "io.github.YawLabs/ctxlint",
5
5
  "description": "Lint your AI agent context files, MCP server configs, and session data against your actual codebase",
6
6
  "bin": {
7
7
  "ctxlint": "dist/index.js"
8
8
  },
9
9
  "type": "module",
10
+ "exports": {
11
+ "./package.json": "./package.json"
12
+ },
10
13
  "scripts": {
11
14
  "build": "node build.mjs",
12
15
  "dev": "node build.mjs",
13
16
  "generate": "node scripts/generate-catalog-prose.mjs",
14
17
  "generate:check": "node scripts/generate-catalog-prose.mjs --check",
18
+ "pretest": "node build.mjs",
19
+ "pretest:run": "node build.mjs",
20
+ "pretest:coverage": "node build.mjs",
15
21
  "test": "vitest",
16
22
  "test:run": "vitest run",
17
23
  "test:coverage": "vitest run --coverage --coverage.reporter=text-summary --coverage.reporter=html --coverage.exclude='**/__tests__/**' --coverage.exclude='**/fixtures/**' --coverage.exclude='dist/**' --coverage.exclude='build.mjs' --coverage.exclude='coverage-report.mjs'",
@@ -110,9 +116,13 @@
110
116
  "esbuild"
111
117
  ],
112
118
  "overrides": {
113
- "hono": "^4.12.14",
119
+ "hono": "^4.12.21",
114
120
  "@hono/node-server": "^1.19.13",
115
- "vite": "^8.0.8"
121
+ "vite": "^8.0.8",
122
+ "fast-uri": "^3.1.2",
123
+ "postcss": "^8.5.10",
124
+ "qs": "^6.15.2",
125
+ "ip-address": "^10.1.1"
116
126
  }
117
127
  }
118
128
  }
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://raw.githubusercontent.com/YawLabs/ctxlint/main/schemas/ctxlint-catalog.schema.json",
4
4
  "title": "ctxlint rule catalog",
5
- "description": "Governing schema for the machine-readable rule catalogs that back the ctxlint specifications (context-, mcp-config-, agent-session-lint-rules.json). Defines the shared metadata block + the rule/category shape every catalog must satisfy. Per-catalog extras (formats, clients, agents, dataSources, target) are permitted via additionalProperties.",
5
+ "description": "Governing schema for the machine-readable rule catalogs that back the ctxlint specifications (context-, mcp-config-, agent-session-, agent-skill-lint-rules.json). Defines the shared metadata block + the rule/category shape every catalog must satisfy. Per-catalog extras (formats, clients, agents, dataSources) are permitted via additionalProperties.",
6
6
  "type": "object",
7
7
  "required": ["$schema", "specVersion", "specDate", "repository", "categories", "rules"],
8
8
  "additionalProperties": true,