mustard-claude 3.0.16 → 3.0.18
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/package.json
CHANGED
|
@@ -111,7 +111,7 @@ process.stdin.on('end', () => {
|
|
|
111
111
|
hookSpecificOutput: {
|
|
112
112
|
hookEventName: 'PreToolUse',
|
|
113
113
|
permissionDecision: 'allow',
|
|
114
|
-
updatedInput: { command: rewritten }
|
|
114
|
+
updatedInput: { command: `${rewritten} 2>/dev/null` }
|
|
115
115
|
}
|
|
116
116
|
}));
|
|
117
117
|
process.exit(0);
|
|
@@ -28,6 +28,18 @@ const SECRET_PATTERNS = [
|
|
|
28
28
|
{ name: 'Generic Secret Assignment', re: /(?:secret|password|passwd|api_key|apikey|token|auth_token)\s*[:=]\s*["'][^"']{8,}["']/gi },
|
|
29
29
|
];
|
|
30
30
|
|
|
31
|
+
// File name patterns that commonly trigger false positives on generic patterns
|
|
32
|
+
// (seeds with hashed passwords, error code constants, test fixtures, etc.)
|
|
33
|
+
const FP_FILE_PATTERNS = [
|
|
34
|
+
/[Ss]eeder/, // DatabaseSeeder.cs, UserSeeder.cs
|
|
35
|
+
/[Ss]eed[s]?\./, // Seeds.cs, seed.ts
|
|
36
|
+
/ErrorCode/i, // ApiExceptionErrorCodes.cs, ErrorCodes.ts
|
|
37
|
+
/Exception.*Code/i, // ExceptionCodes, ExceptionErrorCodes
|
|
38
|
+
/\.d\.ts$/, // Type declaration files
|
|
39
|
+
/\.test\./, // Test files
|
|
40
|
+
/\.spec\./, // Spec files
|
|
41
|
+
];
|
|
42
|
+
|
|
31
43
|
// ── Ignore lists ────────────────────────────────────────────────────
|
|
32
44
|
const IGNORE_DIRS = new Set([
|
|
33
45
|
'node_modules', '.git', 'dist', 'bin', 'obj', '.next', 'vendor',
|
|
@@ -73,11 +85,17 @@ function scanFile(filePath, results) {
|
|
|
73
85
|
let content;
|
|
74
86
|
try { content = fs.readFileSync(filePath, 'utf8'); } catch { return; }
|
|
75
87
|
|
|
88
|
+
// Check if file matches false-positive suppression patterns
|
|
89
|
+
const baseName = path.basename(filePath);
|
|
90
|
+
const isFpFile = FP_FILE_PATTERNS.some(re => re.test(baseName));
|
|
91
|
+
|
|
76
92
|
// Secret pattern matching
|
|
77
93
|
for (const { name, re } of SECRET_PATTERNS) {
|
|
78
94
|
re.lastIndex = 0;
|
|
79
95
|
const match = re.exec(content);
|
|
80
96
|
if (match) {
|
|
97
|
+
// Skip generic patterns on known false-positive files
|
|
98
|
+
if (isFpFile && name === 'Generic Secret Assignment') continue;
|
|
81
99
|
// Find line number
|
|
82
100
|
const beforeMatch = content.substring(0, match.index);
|
|
83
101
|
const line = (beforeMatch.match(/\n/g) || []).length + 1;
|
|
@@ -597,8 +597,9 @@ function getGitDirtyFiles(subprojectPath) {
|
|
|
597
597
|
if (!trimmed) continue;
|
|
598
598
|
// Format: "XY filename" or "XY filename -> newname"
|
|
599
599
|
const filePath = trimmed.substring(3).split(" -> ").pop().trim();
|
|
600
|
+
const fileName = path.basename(filePath);
|
|
600
601
|
const ext = path.extname(filePath).toLowerCase();
|
|
601
|
-
if (!sourceExts.has(ext)) continue;
|
|
602
|
+
if (!sourceExts.has(ext) && !MANIFEST_FILES.has(fileName)) continue;
|
|
602
603
|
// Skip ignored directories
|
|
603
604
|
const parts = filePath.split("/");
|
|
604
605
|
if (parts.some((p) => ignoreNames.has(p) || p === "migrations")) continue;
|
|
@@ -627,6 +628,26 @@ const SOURCE_IGNORE_PATTERNS = [
|
|
|
627
628
|
|
|
628
629
|
const SOURCE_EXTENSIONS = new Set([".cs", ".ts", ".tsx", ".js", ".jsx", ".dart"]);
|
|
629
630
|
|
|
631
|
+
/**
|
|
632
|
+
* Manifest files that affect project behavior without changing source code.
|
|
633
|
+
* Changes to these files (dependency upgrades, SDK bumps) should invalidate
|
|
634
|
+
* the source hash even when no source file changed.
|
|
635
|
+
*/
|
|
636
|
+
const MANIFEST_FILES = new Set([
|
|
637
|
+
// Flutter/Dart
|
|
638
|
+
"pubspec.yaml", "pubspec.lock",
|
|
639
|
+
// Node.js
|
|
640
|
+
"package.json", "pnpm-lock.yaml", "package-lock.json", "yarn.lock",
|
|
641
|
+
// .NET
|
|
642
|
+
"Directory.Packages.props", "Directory.Build.props", "nuget.config",
|
|
643
|
+
// Go
|
|
644
|
+
"go.mod", "go.sum",
|
|
645
|
+
// Rust
|
|
646
|
+
"Cargo.toml", "Cargo.lock",
|
|
647
|
+
// Python
|
|
648
|
+
"pyproject.toml", "requirements.txt", "poetry.lock",
|
|
649
|
+
]);
|
|
650
|
+
|
|
630
651
|
/**
|
|
631
652
|
* Recursively collect source files from a directory.
|
|
632
653
|
* Respects ignore patterns and extension filters.
|
|
@@ -660,7 +681,7 @@ function collectSourceFiles(dir, maxDepth = 10, currentDepth = 0) {
|
|
|
660
681
|
results.push(...collectSourceFiles(fullPath, maxDepth, currentDepth + 1));
|
|
661
682
|
} else if (entry.isFile()) {
|
|
662
683
|
const ext = path.extname(entry.name).toLowerCase();
|
|
663
|
-
if (SOURCE_EXTENSIONS.has(ext)) {
|
|
684
|
+
if (SOURCE_EXTENSIONS.has(ext) || MANIFEST_FILES.has(entry.name)) {
|
|
664
685
|
results.push(relFromRoot);
|
|
665
686
|
}
|
|
666
687
|
}
|
|
@@ -909,6 +930,17 @@ function main() {
|
|
|
909
930
|
}
|
|
910
931
|
const subprojectPaths = submodulePaths;
|
|
911
932
|
|
|
933
|
+
// Load previous cache for hash comparison (anti-stale detection)
|
|
934
|
+
let previousCache = null;
|
|
935
|
+
try {
|
|
936
|
+
const cachePath = path.join(ROOT, ".claude", ".detect-cache.json");
|
|
937
|
+
if (fs.existsSync(cachePath)) {
|
|
938
|
+
previousCache = JSON.parse(fs.readFileSync(cachePath, "utf-8"));
|
|
939
|
+
}
|
|
940
|
+
} catch {
|
|
941
|
+
// no previous cache — treat all as changed
|
|
942
|
+
}
|
|
943
|
+
|
|
912
944
|
// 2. Filter to only those with a CLAUDE.md, then build subproject entries
|
|
913
945
|
const subprojects = [];
|
|
914
946
|
const detectedAgentsSet = new Set();
|
|
@@ -944,6 +976,10 @@ function main() {
|
|
|
944
976
|
// Detect git dirty state (uncommitted source file changes)
|
|
945
977
|
const gitDirty = getGitDirtyFiles(normalizedPath);
|
|
946
978
|
|
|
979
|
+
// Compare current hash against previous cache to detect stale state
|
|
980
|
+
const prevHash = previousCache?.sourceHashes?.[name];
|
|
981
|
+
const hashChanged = !prevHash || prevHash !== sourceHashes[name];
|
|
982
|
+
|
|
947
983
|
subprojects.push({
|
|
948
984
|
name,
|
|
949
985
|
path: normalizedPath,
|
|
@@ -951,6 +987,7 @@ function main() {
|
|
|
951
987
|
agent,
|
|
952
988
|
commands,
|
|
953
989
|
stackSummary,
|
|
990
|
+
hashChanged,
|
|
954
991
|
...(gitDirty.dirty ? { gitDirty: true, gitDirtyCount: gitDirty.files.length } : {}),
|
|
955
992
|
});
|
|
956
993
|
}
|