claudecode-linter 2.1.148 → 2.1.150-patch.1

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.
Files changed (37) hide show
  1. package/.claudecode-lint.defaults.yaml +21 -2
  2. package/README.md +90 -3
  3. package/contracts/agent-frontmatter.schema.json +142 -2
  4. package/contracts/command-frontmatter.schema.json +128 -2
  5. package/contracts/hooks.schema.json +275 -0
  6. package/contracts/lsp.schema.json +2 -2
  7. package/contracts/mcp.schema.json +326 -0
  8. package/contracts/monitors.schema.json +3 -3
  9. package/contracts/plugin.schema.json +672 -22
  10. package/contracts/schemastore/keybindings.schema.json +179 -0
  11. package/contracts/schemastore/manifest.json +25 -0
  12. package/contracts/schemastore/marketplace.schema.json +2067 -0
  13. package/contracts/schemastore/plugin-manifest.schema.json +1834 -0
  14. package/contracts/schemastore/settings.schema.json +3062 -0
  15. package/contracts/settings.schema.json +333 -4
  16. package/contracts/skill-frontmatter.schema.json +198 -2
  17. package/dist/config.js +13 -8
  18. package/dist/contracts.js +20 -1
  19. package/dist/discovery.js +23 -0
  20. package/dist/formatters/human.js +3 -2
  21. package/dist/index.js +80 -12
  22. package/dist/linters/agent-md.js +44 -7
  23. package/dist/linters/command-md.js +37 -1
  24. package/dist/linters/hooks-json.js +24 -0
  25. package/dist/linters/keybindings-json.js +53 -0
  26. package/dist/linters/marketplace-json.js +55 -0
  27. package/dist/linters/mcp-json.js +24 -0
  28. package/dist/linters/settings-json.js +42 -15
  29. package/dist/linters/skill-md.js +48 -1
  30. package/dist/plugin-schema.js +96 -39
  31. package/dist/utils/asset-path.js +56 -0
  32. package/dist/utils/effort.js +29 -0
  33. package/dist/utils/frontmatter-keys.js +32 -3
  34. package/dist/utils/frontmatter.js +1 -1
  35. package/dist/utils/safe-write.js +36 -0
  36. package/dist/utils/terminal.js +18 -0
  37. package/package.json +6 -2
@@ -1,13 +1,13 @@
1
1
  {
2
- "extractedFromClaudeCodeVersion": "2.1.146",
3
- "extractedAt": "2026-05-21T20:50:34.861Z",
2
+ "extractedFromClaudeCodeVersion": "2.1.150",
3
+ "extractedAt": "2026-05-23T18:30:08.375Z",
4
4
  "schema": {
5
5
  "$schema": "https://json-schema.org/draft/2020-12/schema",
6
6
  "title": "Claude Code settings.json",
7
7
  "type": "object",
8
8
  "properties": {
9
9
  "$schema": {
10
- "const": "pXq",
10
+ "const": "https://json.schemastore.org/claude-code-settings.json",
11
11
  "description": "JSON Schema reference for Claude Code settings"
12
12
  },
13
13
  "apiKeyHelper": {
@@ -78,6 +78,48 @@
78
78
  "type": "boolean",
79
79
  "description": "Whether file picker should respect .gitignore files (default: true). Note: .ignore files are always respected."
80
80
  },
81
+ "breakReminder": {
82
+ "type": "object",
83
+ "properties": {
84
+ "enabled": {
85
+ "type": "boolean",
86
+ "description": "Show a friendly nudge after sustained continuous use (default false). Must be true for the reminder to fire."
87
+ },
88
+ "intervalMinutes": {
89
+ "type": "number",
90
+ "description": "Minutes of continuous use before the reminder fires (default 120). Re-fires every interval until you take a break."
91
+ },
92
+ "breakThresholdMinutes": {
93
+ "type": "number",
94
+ "description": "Minutes of inactivity that count as a break and reset the timer (default 15)"
95
+ },
96
+ "message": {
97
+ "type": "string",
98
+ "description": "Custom reminder text. Leave unset for a rotating set of friendly nudges."
99
+ }
100
+ },
101
+ "description": "@internal Opt-in break reminder. When enabled, shows a dismissible nudge after sustained continuous use. Never blocks — just a friendly heads-up."
102
+ },
103
+ "quietHours": {
104
+ "type": "object",
105
+ "properties": {
106
+ "enabled": {
107
+ "type": "boolean",
108
+ "description": "Show a one-time nudge when you start or keep using the CLI inside your quiet-hours window (default false)."
109
+ },
110
+ "start": {
111
+ "type": "string",
112
+ "pattern": "^([01]?\\d|2[0-3]):[0-5]\\d$",
113
+ "description": "Start of the quiet-hours window, 24-hour local time \"HH:MM\"."
114
+ },
115
+ "end": {
116
+ "type": "string",
117
+ "pattern": "^([01]?\\d|2[0-3]):[0-5]\\d$",
118
+ "description": "End of the quiet-hours window, 24-hour local time \"HH:MM\". May be earlier than start for an overnight range."
119
+ }
120
+ },
121
+ "description": "@internal Opt-in quiet hours. When enabled, shows a single soft nudge per session while inside the configured local-time window. Never blocks."
122
+ },
81
123
  "cleanupPeriodDays": {
82
124
  "type": "number",
83
125
  "description": "Number of days to retain chat transcripts before automatic cleanup (default: 30). Minimum 1. Use a large value for long retention; use --no-session-persistence to disable transcript writes entirely."
@@ -225,6 +267,264 @@
225
267
  "description": "Enterprise denylist of MCP servers that are explicitly blocked. If a server is on the denylist, it will be blocked across all scopes including enterprise. Denylist takes precedence over allowlist - if a server is on both lists, it is denied."
226
268
  },
227
269
  "hooks": {
270
+ "type": "object",
271
+ "additionalProperties": {
272
+ "type": "array",
273
+ "items": {
274
+ "type": "object",
275
+ "properties": {
276
+ "matcher": {
277
+ "type": "string",
278
+ "description": "String pattern to match (e.g. tool names like \"Write\")"
279
+ },
280
+ "hooks": {
281
+ "type": "array",
282
+ "items": {
283
+ "oneOf": [
284
+ {
285
+ "type": "object",
286
+ "properties": {
287
+ "type": {
288
+ "const": "command",
289
+ "description": "Shell command hook type"
290
+ },
291
+ "command": {
292
+ "type": "string",
293
+ "description": "Shell command to execute"
294
+ },
295
+ "args": {
296
+ "type": "array",
297
+ "items": {
298
+ "type": "string"
299
+ },
300
+ "description": "Argument list for exec form. When present, `command` is resolved as \"+\"an executable and spawned directly with these arguments \\u2014 no shell. \"+\"Path placeholders like ${CLAUDE_PLUGIN_ROOT} are substituted per-element as plain strings, so paths with quotes, $, or backticks never reach a shell parser. When absent, `command` runs through a shell (bash on POSIX, PowerShell on Windows without Git Bash)."
301
+ },
302
+ "if": {
303
+ "type": "string",
304
+ "description": "Permission rule syntax to filter when this hook runs (e.g., \"Bash(git *)\"). Only runs if the tool call matches the pattern. Avoids spawning hooks for non-matching commands."
305
+ },
306
+ "shell": {
307
+ "enum": [
308
+ "bash",
309
+ "powershell"
310
+ ],
311
+ "description": "Shell interpreter. 'bash' uses your $SHELL (bash/zsh/sh); 'powershell' uses pwsh. Defaults to bash (powershell on Windows without Git Bash)."
312
+ },
313
+ "timeout": {
314
+ "type": "number",
315
+ "description": "Timeout in seconds for this specific command"
316
+ },
317
+ "statusMessage": {
318
+ "type": "string",
319
+ "description": "Custom status message to display in spinner while hook runs"
320
+ },
321
+ "once": {
322
+ "type": "boolean",
323
+ "description": "If true, hook runs once and is removed after execution"
324
+ },
325
+ "async": {
326
+ "type": "boolean",
327
+ "description": "If true, hook runs in background without blocking"
328
+ },
329
+ "asyncRewake": {
330
+ "type": "boolean",
331
+ "description": "If true, hook runs in background and wakes the model on exit code 2 (blocking error). Implies async."
332
+ },
333
+ "rewakeMessage": {
334
+ "type": "string",
335
+ "minLength": 1,
336
+ "description": "@internal Custom prefix for the system-reminder shown to the model when an asyncRewake hook exits with code 2. The hook output is appended after this prefix."
337
+ },
338
+ "rewakeSummary": {
339
+ "type": "string",
340
+ "minLength": 1,
341
+ "description": "@internal One-line summary shown to the user in the terminal when an asyncRewake hook exits with code 2. Defaults to \"Stop hook feedback\"."
342
+ }
343
+ },
344
+ "required": [
345
+ "type",
346
+ "command"
347
+ ]
348
+ },
349
+ {
350
+ "type": "object",
351
+ "properties": {
352
+ "type": {
353
+ "const": "prompt",
354
+ "description": "LLM prompt hook type"
355
+ },
356
+ "prompt": {
357
+ "type": "string",
358
+ "description": "Prompt to evaluate with LLM. Use $ARGUMENTS placeholder for hook input JSON."
359
+ },
360
+ "if": {
361
+ "type": "string",
362
+ "description": "Permission rule syntax to filter when this hook runs (e.g., \"Bash(git *)\"). Only runs if the tool call matches the pattern. Avoids spawning hooks for non-matching commands."
363
+ },
364
+ "timeout": {
365
+ "type": "number",
366
+ "description": "Timeout in seconds for this specific prompt evaluation"
367
+ },
368
+ "model": {
369
+ "type": "string",
370
+ "description": "Model to use for this prompt hook (e.g., \"claude-sonnet-4-6\"). If not specified, uses the default small fast model."
371
+ },
372
+ "continueOnBlock": {
373
+ "type": "boolean",
374
+ "description": "`Sets the continue value for the decision:\"block\" produced when ok is false. Default false (turn ends). Whether continue:true lets the turn proceed depends on the event's decision:\"block\" semantics. On PostToolUse, the reason is fed back to Claude and the turn continues.`"
375
+ },
376
+ "statusMessage": {
377
+ "type": "string",
378
+ "description": "Custom status message to display in spinner while hook runs"
379
+ },
380
+ "once": {
381
+ "type": "boolean",
382
+ "description": "If true, hook runs once and is removed after execution"
383
+ }
384
+ },
385
+ "required": [
386
+ "type",
387
+ "prompt"
388
+ ]
389
+ },
390
+ {
391
+ "type": "object",
392
+ "properties": {
393
+ "type": {
394
+ "const": "agent",
395
+ "description": "Agentic verifier hook type"
396
+ },
397
+ "prompt": {
398
+ "type": "string",
399
+ "description": "Prompt describing what to verify (e.g. \"Verify that unit tests ran and passed.\"). Use $ARGUMENTS placeholder for hook input JSON."
400
+ },
401
+ "if": {
402
+ "type": "string",
403
+ "description": "Permission rule syntax to filter when this hook runs (e.g., \"Bash(git *)\"). Only runs if the tool call matches the pattern. Avoids spawning hooks for non-matching commands."
404
+ },
405
+ "timeout": {
406
+ "type": "number",
407
+ "description": "Timeout in seconds for agent execution (default 60)"
408
+ },
409
+ "model": {
410
+ "type": "string",
411
+ "description": "Model to use for this agent hook (e.g., \"claude-sonnet-4-6\"). If not specified, uses Haiku."
412
+ },
413
+ "statusMessage": {
414
+ "type": "string",
415
+ "description": "Custom status message to display in spinner while hook runs"
416
+ },
417
+ "once": {
418
+ "type": "boolean",
419
+ "description": "If true, hook runs once and is removed after execution"
420
+ }
421
+ },
422
+ "required": [
423
+ "type",
424
+ "prompt"
425
+ ]
426
+ },
427
+ {
428
+ "type": "object",
429
+ "properties": {
430
+ "type": {
431
+ "const": "http",
432
+ "description": "HTTP hook type"
433
+ },
434
+ "url": {
435
+ "type": "string",
436
+ "format": "uri",
437
+ "description": "URL to POST the hook input JSON to"
438
+ },
439
+ "if": {
440
+ "type": "string",
441
+ "description": "Permission rule syntax to filter when this hook runs (e.g., \"Bash(git *)\"). Only runs if the tool call matches the pattern. Avoids spawning hooks for non-matching commands."
442
+ },
443
+ "timeout": {
444
+ "type": "number",
445
+ "description": "Timeout in seconds for this specific request"
446
+ },
447
+ "headers": {
448
+ "type": "object",
449
+ "additionalProperties": {
450
+ "type": "string"
451
+ },
452
+ "description": "Additional headers to include in the request. Values may reference environment variables using $VAR_NAME or ${VAR_NAME} syntax (e.g., \"Authorization\": \"Bearer $MY_TOKEN\"). Only variables listed in allowedEnvVars will be interpolated."
453
+ },
454
+ "allowedEnvVars": {
455
+ "type": "array",
456
+ "items": {
457
+ "type": "string"
458
+ },
459
+ "description": "Explicit list of environment variable names that may be interpolated in header values. Only variables listed here will be resolved; all other $VAR references are left as empty strings. Required for env var interpolation to work."
460
+ },
461
+ "statusMessage": {
462
+ "type": "string",
463
+ "description": "Custom status message to display in spinner while hook runs"
464
+ },
465
+ "once": {
466
+ "type": "boolean",
467
+ "description": "If true, hook runs once and is removed after execution"
468
+ }
469
+ },
470
+ "required": [
471
+ "type",
472
+ "url"
473
+ ]
474
+ },
475
+ {
476
+ "type": "object",
477
+ "properties": {
478
+ "type": {
479
+ "const": "mcp_tool",
480
+ "description": "MCP tool hook type"
481
+ },
482
+ "server": {
483
+ "type": "string",
484
+ "description": "Name of an already-configured MCP server to invoke"
485
+ },
486
+ "tool": {
487
+ "type": "string",
488
+ "description": "Name of the tool on that server to call"
489
+ },
490
+ "input": {
491
+ "type": "object",
492
+ "additionalProperties": {},
493
+ "description": "Arguments passed to the MCP tool. String values support ${path} interpolation from the hook input JSON (e.g. \"${tool_input.file_path}\")."
494
+ },
495
+ "if": {
496
+ "type": "string",
497
+ "description": "Permission rule syntax to filter when this hook runs (e.g., \"Bash(git *)\"). Only runs if the tool call matches the pattern. Avoids spawning hooks for non-matching commands."
498
+ },
499
+ "timeout": {
500
+ "type": "number",
501
+ "description": "Timeout in seconds for this specific tool call"
502
+ },
503
+ "statusMessage": {
504
+ "type": "string",
505
+ "description": "Custom status message to display in spinner while hook runs"
506
+ },
507
+ "once": {
508
+ "type": "boolean",
509
+ "description": "If true, hook runs once and is removed after execution"
510
+ }
511
+ },
512
+ "required": [
513
+ "type",
514
+ "server",
515
+ "tool"
516
+ ]
517
+ }
518
+ ]
519
+ },
520
+ "description": "List of hooks to execute when the matcher matches"
521
+ }
522
+ },
523
+ "required": [
524
+ "hooks"
525
+ ]
526
+ }
527
+ },
228
528
  "description": "Custom commands to run before/after tool executions"
229
529
  },
230
530
  "worktree": {
@@ -310,6 +610,10 @@
310
610
  "type": "boolean",
311
611
  "description": "When true (and set in managed settings), allowedMcpServers is only read from managed settings. deniedMcpServers still merges from all sources, so users can deny servers for themselves. Users can still add their own MCP servers, but only the admin-defined allowlist applies."
312
612
  },
613
+ "allowAllClaudeAiMcps": {
614
+ "type": "boolean",
615
+ "description": "When true (and set in managed settings), claude.ai cloud MCP connectors load alongside managed-mcp.json instead of being suppressed by its exclusive-control lockdown. Default off preserves the lockdown. Read from managed settings only."
616
+ },
313
617
  "strictPluginOnlyCustomization": {
314
618
  "anyOf": [
315
619
  {
@@ -317,7 +621,14 @@
317
621
  },
318
622
  {
319
623
  "type": "array",
320
- "items": {}
624
+ "items": {
625
+ "enum": [
626
+ "skills",
627
+ "agents",
628
+ "hooks",
629
+ "mcp"
630
+ ]
631
+ }
321
632
  }
322
633
  ],
323
634
  "description": "'When set in managed settings, blocks non-plugin customization sources for the listed surfaces. Array form locks specific surfaces (e.g. [\"skills\", \"hooks\"]); `true` locks all four; `false` is an explicit no-op. Blocked: ~/.claude/{surface}/, .claude/{surface}/ (project), settings.json hooks, .mcp.json. NOT blocked: managed (policySettings) sources, plugin-provided customizations. '+\"Composes with strictKnownMarketplaces for end-to-end admin control \\u2014 plugins gated by \"+\"marketplace allowlist, everything else blocked here.\""
@@ -2138,6 +2449,10 @@
2138
2449
  "description": "Color theme for the UI"
2139
2450
  },
2140
2451
  "editorMode": {
2452
+ "enum": [
2453
+ "normal",
2454
+ "vim"
2455
+ ],
2141
2456
  "description": "Key binding mode for the prompt input"
2142
2457
  },
2143
2458
  "verbose": {
@@ -2145,6 +2460,15 @@
2145
2460
  "description": "Show full tool output instead of truncated summaries"
2146
2461
  },
2147
2462
  "preferredNotifChannel": {
2463
+ "enum": [
2464
+ "auto",
2465
+ "iterm2",
2466
+ "iterm2_with_bell",
2467
+ "terminal_bell",
2468
+ "kitty",
2469
+ "ghostty",
2470
+ "notifications_disabled"
2471
+ ],
2148
2472
  "description": "Preferred OS notification channel"
2149
2473
  },
2150
2474
  "autoCompactEnabled": {
@@ -2176,6 +2500,11 @@
2176
2500
  "description": "Enable the todo / task tracking panel"
2177
2501
  },
2178
2502
  "teammateMode": {
2503
+ "enum": [
2504
+ "auto",
2505
+ "tmux",
2506
+ "in-process"
2507
+ ],
2179
2508
  "description": "How spawned teammates execute (tmux, in-process, auto)"
2180
2509
  },
2181
2510
  "remoteControlAtStartup": {
@@ -1,18 +1,60 @@
1
1
  {
2
- "extractedFromClaudeCodeVersion": "2.1.146",
3
- "extractedAt": "2026-05-21T21:04:24.797Z",
2
+ "extractedFromClaudeCodeVersion": "2.1.150",
3
+ "extractedAt": "2026-05-23T18:30:08.380Z",
4
4
  "schema": {
5
5
  "$schema": "https://json-schema.org/draft/2020-12/schema",
6
6
  "title": "Claude Code SKILL.md frontmatter",
7
7
  "type": "object",
8
8
  "properties": {
9
9
  "name": {
10
+ "anyOf": [
11
+ {
12
+ "type": "string"
13
+ },
14
+ {
15
+ "type": "number"
16
+ },
17
+ {
18
+ "type": "boolean"
19
+ },
20
+ {
21
+ "type": "null"
22
+ }
23
+ ],
10
24
  "description": "Display name. Defaults to the filename without extension."
11
25
  },
12
26
  "description": {
27
+ "anyOf": [
28
+ {
29
+ "type": "string"
30
+ },
31
+ {
32
+ "type": "number"
33
+ },
34
+ {
35
+ "type": "boolean"
36
+ },
37
+ {
38
+ "type": "null"
39
+ }
40
+ ],
13
41
  "description": "One-line summary shown in listings and the Skill tool."
14
42
  },
15
43
  "model": {
44
+ "anyOf": [
45
+ {
46
+ "type": "string"
47
+ },
48
+ {
49
+ "type": "number"
50
+ },
51
+ {
52
+ "type": "boolean"
53
+ },
54
+ {
55
+ "type": "null"
56
+ }
57
+ ],
16
58
  "description": "Model override (`haiku`, `sonnet`, `opus`, or a full ID). Use `inherit` to match the parent conversation."
17
59
  },
18
60
  "allowed-tools": {
@@ -43,6 +85,20 @@
43
85
  "description": "Tools available to the model while this file is active. Comma-separated string or YAML list."
44
86
  },
45
87
  "argument-hint": {
88
+ "anyOf": [
89
+ {
90
+ "type": "string"
91
+ },
92
+ {
93
+ "type": "number"
94
+ },
95
+ {
96
+ "type": "boolean"
97
+ },
98
+ {
99
+ "type": "null"
100
+ }
101
+ ],
46
102
  "description": "Placeholder text shown after the slash command name."
47
103
  },
48
104
  "arguments": {
@@ -73,21 +129,105 @@
73
129
  "description": "@internal — typed variant of argument-hint; argument-hint is the documented form"
74
130
  },
75
131
  "disable-model-invocation": {
132
+ "anyOf": [
133
+ {
134
+ "type": "string"
135
+ },
136
+ {
137
+ "type": "number"
138
+ },
139
+ {
140
+ "type": "boolean"
141
+ },
142
+ {
143
+ "type": "null"
144
+ }
145
+ ],
76
146
  "description": "If true, the model cannot invoke this via the Skill tool; only users can type the slash command."
77
147
  },
78
148
  "user-invocable": {
149
+ "anyOf": [
150
+ {
151
+ "type": "string"
152
+ },
153
+ {
154
+ "type": "number"
155
+ },
156
+ {
157
+ "type": "boolean"
158
+ },
159
+ {
160
+ "type": "null"
161
+ }
162
+ ],
79
163
  "description": "If false, hides the slash command from users; only the model can invoke it via the Skill tool."
80
164
  },
81
165
  "effort": {
166
+ "anyOf": [
167
+ {
168
+ "type": "string"
169
+ },
170
+ {
171
+ "type": "number"
172
+ },
173
+ {
174
+ "type": "boolean"
175
+ },
176
+ {
177
+ "type": "null"
178
+ }
179
+ ],
82
180
  "description": "Thinking effort for the model: `low`, `medium`, `high`, `max`, or an integer."
83
181
  },
84
182
  "shell": {
183
+ "anyOf": [
184
+ {
185
+ "type": "string"
186
+ },
187
+ {
188
+ "type": "number"
189
+ },
190
+ {
191
+ "type": "boolean"
192
+ },
193
+ {
194
+ "type": "null"
195
+ }
196
+ ],
85
197
  "description": "Shell for `!`-command blocks: `bash` or `powershell`. Defaults to bash regardless of platform."
86
198
  },
87
199
  "version": {
200
+ "anyOf": [
201
+ {
202
+ "type": "string"
203
+ },
204
+ {
205
+ "type": "number"
206
+ },
207
+ {
208
+ "type": "boolean"
209
+ },
210
+ {
211
+ "type": "null"
212
+ }
213
+ ],
88
214
  "description": "@internal — bookkeeping, not surfaced to users"
89
215
  },
90
216
  "when_to_use": {
217
+ "anyOf": [
218
+ {
219
+ "type": "string"
220
+ },
221
+ {
222
+ "type": "number"
223
+ },
224
+ {
225
+ "type": "boolean"
226
+ },
227
+ {
228
+ "type": "null"
229
+ }
230
+ ],
91
231
  "description": "Guidance for when the model should reach for this skill. Becomes part of the tool description."
92
232
  },
93
233
  "paths": {
@@ -129,15 +269,71 @@
129
269
  "description": "Where the skill runs: `inline` expands into the current conversation; `fork` spawns a subagent."
130
270
  },
131
271
  "agent": {
272
+ "anyOf": [
273
+ {
274
+ "type": "string"
275
+ },
276
+ {
277
+ "type": "number"
278
+ },
279
+ {
280
+ "type": "boolean"
281
+ },
282
+ {
283
+ "type": "null"
284
+ }
285
+ ],
132
286
  "description": "Agent type to spawn when `context: fork`."
133
287
  },
134
288
  "fallback": {
289
+ "anyOf": [
290
+ {
291
+ "type": "string"
292
+ },
293
+ {
294
+ "type": "number"
295
+ },
296
+ {
297
+ "type": "boolean"
298
+ },
299
+ {
300
+ "type": "null"
301
+ }
302
+ ],
135
303
  "description": "@internal — interim defense-in-depth for thin-pointer skill stubs. If true, this skill yields to a same-suffix plugin or MCP skill (`<plugin>:<name>` / `<server>:<name>`) when one is loaded. Stubs carrying this should be deleted once their canonical plugin/MCP skill ships, not maintained."
136
304
  },
137
305
  "created_by": {
306
+ "anyOf": [
307
+ {
308
+ "type": "string"
309
+ },
310
+ {
311
+ "type": "number"
312
+ },
313
+ {
314
+ "type": "boolean"
315
+ },
316
+ {
317
+ "type": "null"
318
+ }
319
+ ],
138
320
  "description": "@internal — provenance marker (e.g. dream-proposal)"
139
321
  },
140
322
  "improved_by": {
323
+ "anyOf": [
324
+ {
325
+ "type": "string"
326
+ },
327
+ {
328
+ "type": "number"
329
+ },
330
+ {
331
+ "type": "boolean"
332
+ },
333
+ {
334
+ "type": "null"
335
+ }
336
+ ],
141
337
  "description": "@internal — provenance marker (e.g. dream-proposal)"
142
338
  },
143
339
  "mcpServers": {
package/dist/config.js CHANGED
@@ -1,9 +1,8 @@
1
1
  import { readFileSync, existsSync } from "node:fs";
2
- import { dirname, join } from "node:path";
3
- import { fileURLToPath } from "node:url";
2
+ import { join } from "node:path";
4
3
  import { homedir } from "node:os";
5
4
  import { parse as parseYaml } from "yaml";
6
- const __dirname = dirname(fileURLToPath(import.meta.url));
5
+ import { assetCandidates } from "./utils/asset-path.js";
7
6
  const DEFAULT_CONFIG = {
8
7
  rules: {},
9
8
  };
@@ -13,7 +12,7 @@ export function loadConfig(configPath) {
13
12
  return DEFAULT_CONFIG;
14
13
  try {
15
14
  const content = readFileSync(path, "utf-8");
16
- const parsed = parseYaml(content);
15
+ const parsed = parseYaml(content, { maxAliasCount: 100 });
17
16
  if (!parsed || typeof parsed !== "object")
18
17
  return DEFAULT_CONFIG;
19
18
  const config = { rules: {} };
@@ -47,10 +46,16 @@ function findConfigFile() {
47
46
  if (existsSync(homePath))
48
47
  return homePath;
49
48
  }
50
- // 3. Fall back to bundled defaults
51
- const bundled = join(__dirname, "..", ".claudecode-lint.defaults.yaml");
52
- if (existsSync(bundled))
53
- return bundled;
49
+ // 3. Fall back to bundled defaults. Resolved relative to import.meta.url
50
+ // first (Node / npm package), then relative to process.execPath as a
51
+ // fallback for the `bun build --compile` single-executable variant.
52
+ for (const bundled of assetCandidates(import.meta.url, [
53
+ "..",
54
+ ".claudecode-lint.defaults.yaml",
55
+ ])) {
56
+ if (existsSync(bundled))
57
+ return bundled;
58
+ }
54
59
  return undefined;
55
60
  }
56
61
  export function mergeCliRules(config, enable, disable) {