claudecode-linter 2.1.150 → 2.1.152
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 +8 -2
- package/contracts/agent-frontmatter.schema.json +2 -2
- package/contracts/command-frontmatter.schema.json +56 -2
- package/contracts/hooks.schema.json +2 -2
- package/contracts/lsp.schema.json +2 -2
- package/contracts/mcp.schema.json +26 -2
- package/contracts/monitors.schema.json +3 -3
- package/contracts/plugin.schema.json +672 -22
- package/contracts/schemastore/keybindings.schema.json +179 -0
- package/contracts/schemastore/manifest.json +25 -0
- package/contracts/schemastore/marketplace.schema.json +2067 -0
- package/contracts/schemastore/plugin-manifest.schema.json +1834 -0
- package/contracts/schemastore/settings.schema.json +3240 -0
- package/contracts/settings.schema.json +61 -4
- package/contracts/skill-frontmatter.schema.json +56 -2
- package/dist/contracts.js +4 -1
- package/dist/discovery.js +23 -0
- package/dist/fixers/mcp-json.js +6 -0
- package/dist/index.js +8 -0
- package/dist/linters/agent-md.js +16 -7
- package/dist/linters/keybindings-json.js +53 -0
- package/dist/linters/marketplace-json.js +55 -0
- package/dist/linters/mcp-json.js +8 -0
- package/dist/linters/plugin-json.js +8 -0
- package/dist/linters/settings-json.js +89 -16
- package/dist/linters/skill-md.js +7 -1
- package/dist/plugin-schema.js +89 -41
- package/package.json +4 -2
package/dist/plugin-schema.js
CHANGED
|
@@ -25,36 +25,87 @@ function getAjv() {
|
|
|
25
25
|
addFormats(ajvShared);
|
|
26
26
|
return ajvShared;
|
|
27
27
|
}
|
|
28
|
-
function
|
|
29
|
-
if (compiledCache.has(fileName))
|
|
30
|
-
return compiledCache.get(fileName) ?? null;
|
|
28
|
+
function tryReadFile(relPath) {
|
|
31
29
|
const candidates = [
|
|
32
|
-
...assetCandidates(import.meta.url, ["..",
|
|
33
|
-
...assetCandidates(import.meta.url, ["..", "..",
|
|
30
|
+
...assetCandidates(import.meta.url, ["..", ...relPath]),
|
|
31
|
+
...assetCandidates(import.meta.url, ["..", "..", ...relPath]),
|
|
34
32
|
];
|
|
35
|
-
let raw = null;
|
|
36
33
|
for (const p of candidates) {
|
|
37
34
|
try {
|
|
38
|
-
|
|
39
|
-
break;
|
|
35
|
+
return readFileSync(p, "utf8");
|
|
40
36
|
}
|
|
41
37
|
catch {
|
|
42
38
|
// try next
|
|
43
39
|
}
|
|
44
40
|
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Compile a schema document, handling both wrapper shapes:
|
|
45
|
+
* - extracted (`{ extractedFromClaudeCodeVersion, schema: {...} }`)
|
|
46
|
+
* - bare JSON Schema (the schemastore.org files, no envelope)
|
|
47
|
+
*/
|
|
48
|
+
function compileSchemaDoc(raw, sourceLabel) {
|
|
49
|
+
const parsed = JSON.parse(raw);
|
|
50
|
+
let schema;
|
|
51
|
+
let version;
|
|
52
|
+
if ("extractedFromClaudeCodeVersion" in parsed &&
|
|
53
|
+
typeof parsed.extractedFromClaudeCodeVersion === "string" &&
|
|
54
|
+
"schema" in parsed &&
|
|
55
|
+
typeof parsed.schema === "object" &&
|
|
56
|
+
parsed.schema !== null) {
|
|
57
|
+
schema = parsed.schema;
|
|
58
|
+
version = parsed.extractedFromClaudeCodeVersion;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
// Bare schemastore document. Strip `$id` (Ajv registers it globally
|
|
62
|
+
// and trips `$id already exists` on a second compile) and any
|
|
63
|
+
// `$schema` meta-pointer Ajv2020 can't resolve (draft-07 etc.).
|
|
64
|
+
const { $id: _id, $schema: _meta, ...rest } = parsed;
|
|
65
|
+
void _id;
|
|
66
|
+
void _meta;
|
|
67
|
+
schema = rest;
|
|
68
|
+
version = sourceLabel;
|
|
69
|
+
}
|
|
70
|
+
const propSrc = schema.properties ?? {};
|
|
71
|
+
return {
|
|
72
|
+
validate: getAjv().compile(schema),
|
|
73
|
+
extractedFromVersion: version,
|
|
74
|
+
knownFields: new Set(Object.keys(propSrc)),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function loadCompiledSchema(fileName) {
|
|
78
|
+
if (compiledCache.has(fileName))
|
|
79
|
+
return compiledCache.get(fileName) ?? null;
|
|
80
|
+
const raw = tryReadFile(["contracts", fileName]);
|
|
45
81
|
if (!raw) {
|
|
46
82
|
compiledCache.set(fileName, null);
|
|
47
83
|
return null;
|
|
48
84
|
}
|
|
49
|
-
const
|
|
50
|
-
const compiled = {
|
|
51
|
-
validate: getAjv().compile(wrapped.schema),
|
|
52
|
-
extractedFromVersion: wrapped.extractedFromClaudeCodeVersion,
|
|
53
|
-
knownFields: new Set(Object.keys(wrapped.schema.properties ?? {})),
|
|
54
|
-
};
|
|
85
|
+
const compiled = compileSchemaDoc(raw, fileName);
|
|
55
86
|
compiledCache.set(fileName, compiled);
|
|
56
87
|
return compiled;
|
|
57
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Load a schemastore.org-curated schema from `contracts/schemastore/`.
|
|
91
|
+
* Schemastore is preferred for top-level artifact validation because it's
|
|
92
|
+
* Anthropic's own published source of truth and stays stable across Claude
|
|
93
|
+
* Code minifier rotations. The Zod-extracted schemas (`loadCompiledSchema`)
|
|
94
|
+
* remain authoritative for sub-shapes schemastore doesn't enumerate.
|
|
95
|
+
*/
|
|
96
|
+
function loadSchemastoreSchema(fileName) {
|
|
97
|
+
const cacheKey = `schemastore/${fileName}`;
|
|
98
|
+
if (compiledCache.has(cacheKey))
|
|
99
|
+
return compiledCache.get(cacheKey) ?? null;
|
|
100
|
+
const raw = tryReadFile(["contracts", "schemastore", fileName]);
|
|
101
|
+
if (!raw) {
|
|
102
|
+
compiledCache.set(cacheKey, null);
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
const compiled = compileSchemaDoc(raw, `schemastore:${fileName}`);
|
|
106
|
+
compiledCache.set(cacheKey, compiled);
|
|
107
|
+
return compiled;
|
|
108
|
+
}
|
|
58
109
|
export function loadLspSchema() {
|
|
59
110
|
return loadCompiledSchema("lsp.schema.json");
|
|
60
111
|
}
|
|
@@ -62,8 +113,24 @@ export function loadMonitorsSchema() {
|
|
|
62
113
|
return loadCompiledSchema("monitors.schema.json");
|
|
63
114
|
}
|
|
64
115
|
export function loadSettingsSchema() {
|
|
116
|
+
// gitea#6: prefer the Zod-extracted schema (runtime truth, e.g.
|
|
117
|
+
// `disableAutoMode` is `boolean` in 2.1.150) over schemastore (which
|
|
118
|
+
// still lists it as a string literal — out of date). Schemastore is
|
|
119
|
+
// only used for artifacts with no Zod source (marketplace, keybindings).
|
|
65
120
|
return loadCompiledSchema("settings.schema.json");
|
|
66
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* Marketplace and keybindings schemas come exclusively from schemastore —
|
|
124
|
+
* there is no Zod source for them in the Claude Code bundle. Returns null
|
|
125
|
+
* if the user's install was shipped without the schemastore bundle (rare;
|
|
126
|
+
* the package.json includes them in `files`).
|
|
127
|
+
*/
|
|
128
|
+
export function loadMarketplaceSchema() {
|
|
129
|
+
return loadSchemastoreSchema("marketplace.schema.json");
|
|
130
|
+
}
|
|
131
|
+
export function loadKeybindingsSchema() {
|
|
132
|
+
return loadSchemastoreSchema("keybindings.schema.json");
|
|
133
|
+
}
|
|
67
134
|
export function loadMcpJsonSchema() {
|
|
68
135
|
return loadCompiledSchema("mcp.schema.json");
|
|
69
136
|
}
|
|
@@ -82,36 +149,17 @@ export function loadCommandFrontmatterSchema() {
|
|
|
82
149
|
export function loadPluginSchema() {
|
|
83
150
|
if (cached)
|
|
84
151
|
return cached;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
"..",
|
|
90
|
-
"contracts",
|
|
91
|
-
"plugin.schema.json",
|
|
92
|
-
]),
|
|
93
|
-
];
|
|
94
|
-
let raw = null;
|
|
95
|
-
for (const p of candidates) {
|
|
96
|
-
try {
|
|
97
|
-
raw = readFileSync(p, "utf8");
|
|
98
|
-
break;
|
|
99
|
-
}
|
|
100
|
-
catch {
|
|
101
|
-
// try next
|
|
102
|
-
}
|
|
103
|
-
}
|
|
152
|
+
// gitea#6: prefer the Zod-extracted plugin.schema.json (runtime truth);
|
|
153
|
+
// schemastore copy stays committed at `contracts/schemastore/` for
|
|
154
|
+
// reference and for the marketplace/keybindings artifacts only.
|
|
155
|
+
const raw = tryReadFile(["contracts", "plugin.schema.json"]);
|
|
104
156
|
if (!raw)
|
|
105
157
|
return null;
|
|
106
|
-
const
|
|
107
|
-
const ajv = new Ajv2020({ allErrors: true, strict: false });
|
|
108
|
-
addFormats(ajv);
|
|
109
|
-
const validate = ajv.compile(wrapped.schema);
|
|
110
|
-
const knownFields = new Set(Object.keys(wrapped.schema.properties ?? {}));
|
|
158
|
+
const compiled = compileSchemaDoc(raw, "plugin.schema.json");
|
|
111
159
|
cached = {
|
|
112
|
-
validate,
|
|
113
|
-
extractedFromVersion:
|
|
114
|
-
knownFields,
|
|
160
|
+
validate: compiled.validate,
|
|
161
|
+
extractedFromVersion: compiled.extractedFromVersion,
|
|
162
|
+
knownFields: compiled.knownFields,
|
|
115
163
|
};
|
|
116
164
|
return cached;
|
|
117
165
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claudecode-linter",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.152",
|
|
4
4
|
"description": "Standalone linter for Claude Code plugins and configuration files",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -17,8 +17,9 @@
|
|
|
17
17
|
"deps:update": "ncu -u",
|
|
18
18
|
"knip": "knip --exclude types",
|
|
19
19
|
"check-deps": "tsx scripts/check-deps.ts",
|
|
20
|
-
"extract-contracts": "tsx scripts/extract-contracts.ts && tsx scripts/extract-plugin-schema.ts",
|
|
20
|
+
"extract-contracts": "tsx scripts/extract-contracts.ts && tsx scripts/extract-plugin-schema.ts && tsx scripts/fetch-schemastore.ts",
|
|
21
21
|
"extract-plugin-schema": "tsx scripts/extract-plugin-schema.ts",
|
|
22
|
+
"fetch-schemastore": "tsx scripts/fetch-schemastore.ts",
|
|
22
23
|
"generate-contracts": "tsx scripts/generate-contracts.ts"
|
|
23
24
|
},
|
|
24
25
|
"files": [
|
|
@@ -32,6 +33,7 @@
|
|
|
32
33
|
"contracts/command-frontmatter.schema.json",
|
|
33
34
|
"contracts/mcp.schema.json",
|
|
34
35
|
"contracts/hooks.schema.json",
|
|
36
|
+
"contracts/schemastore/*.json",
|
|
35
37
|
".claudecode-lint.defaults.yaml",
|
|
36
38
|
"README.md"
|
|
37
39
|
],
|