claudecode-linter 2.1.148 → 2.1.150

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.
@@ -0,0 +1,36 @@
1
+ import { lstatSync, realpathSync } from "node:fs";
2
+ import { sep } from "node:path";
3
+ /**
4
+ * Decide whether writing to `filePath` (a fix/format target) is safe.
5
+ *
6
+ * The linter may write fixes back to artifact paths supplied by a plugin.
7
+ * A malicious plugin can ship an artifact path that is actually a symlink
8
+ * pointing outside the target tree (`~/.bashrc`, an SSH key, a CI secret);
9
+ * a bare `writeFileSync` would then clobber the symlink's target.
10
+ *
11
+ * Returns a human-readable reason to REFUSE the write, or `null` if the
12
+ * write is safe. The check fails closed: if anything throws (path missing,
13
+ * permission error, etc.) a refusal reason is returned.
14
+ *
15
+ * Refuses when:
16
+ * - `filePath` itself is a symbolic link, or
17
+ * - the real path of `filePath` is not `rootDir` itself and not located
18
+ * under `rootDir + path.sep`.
19
+ */
20
+ export function writeBlockedReason(filePath, rootDir) {
21
+ try {
22
+ if (lstatSync(filePath).isSymbolicLink()) {
23
+ return "path is a symlink";
24
+ }
25
+ const realRoot = realpathSync(rootDir);
26
+ const realPath = realpathSync(filePath);
27
+ if (realPath !== realRoot && !realPath.startsWith(realRoot + sep)) {
28
+ return "path resolves outside the target directory";
29
+ }
30
+ return null;
31
+ }
32
+ catch {
33
+ return "path could not be safely resolved";
34
+ }
35
+ }
36
+ //# sourceMappingURL=safe-write.js.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Strip C0 control characters and DEL from a string before it is written to
3
+ * a terminal, while preserving tab and newline.
4
+ *
5
+ * Diagnostic messages, file paths and `--fix-dry-run` diffs embed untrusted
6
+ * strings (rule content, field values, file content, plugin-controlled file
7
+ * and directory names). Without sanitization an attacker-supplied artifact
8
+ * could smuggle ANSI/control sequences into the user's terminal.
9
+ *
10
+ * Strips U+0000-U+0008, U+000B-U+001F and U+007F (DEL) - every C0 control
11
+ * char and DEL except U+0009 (tab) and U+000A (newline), which are kept.
12
+ * The stripped set includes U+000D (CR) and U+001B (ESC) by design.
13
+ */
14
+ export function sanitizeForTerminal(s) {
15
+ // eslint-disable-next-line no-control-regex
16
+ return s.replace(/[\u0000-\u0008\u000B-\u001F\u007F]/g, "");
17
+ }
18
+ //# sourceMappingURL=terminal.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudecode-linter",
3
- "version": "2.1.148",
3
+ "version": "2.1.150",
4
4
  "description": "Standalone linter for Claude Code plugins and configuration files",
5
5
  "type": "module",
6
6
  "bin": {
@@ -30,6 +30,8 @@
30
30
  "contracts/skill-frontmatter.schema.json",
31
31
  "contracts/agent-frontmatter.schema.json",
32
32
  "contracts/command-frontmatter.schema.json",
33
+ "contracts/mcp.schema.json",
34
+ "contracts/hooks.schema.json",
33
35
  ".claudecode-lint.defaults.yaml",
34
36
  "README.md"
35
37
  ],