awesome-slash 4.2.0 → 4.2.2
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/.claude-plugin/marketplace.json +13 -13
- package/.claude-plugin/plugin.json +1 -1
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +13 -6
- package/README.md +0 -14
- package/adapters/codex/skills/audit-project-agents/SKILL.md +1 -1
- package/adapters/codex/skills/ship-ci-review-loop/SKILL.md +1 -1
- package/adapters/codex/skills/ship-deployment/SKILL.md +1 -1
- package/adapters/opencode/commands/audit-project-agents.md +11 -0
- package/adapters/opencode/commands/ship-ci-review-loop.md +21 -1
- package/adapters/opencode/commands/ship-deployment.md +5 -0
- package/adapters/opencode/skills/agnix/SKILL.md +1 -1
- package/adapters/opencode/skills/consult/SKILL.md +1 -1
- package/adapters/opencode/skills/deslop/SKILL.md +1 -1
- package/adapters/opencode/skills/discover-tasks/SKILL.md +1 -1
- package/adapters/opencode/skills/drift-analysis/SKILL.md +1 -1
- package/adapters/opencode/skills/enhance-agent-prompts/SKILL.md +1 -1
- package/adapters/opencode/skills/enhance-claude-memory/SKILL.md +1 -1
- package/adapters/opencode/skills/enhance-cross-file/SKILL.md +1 -1
- package/adapters/opencode/skills/enhance-docs/SKILL.md +1 -1
- package/adapters/opencode/skills/enhance-hooks/SKILL.md +1 -1
- package/adapters/opencode/skills/enhance-orchestrator/SKILL.md +1 -1
- package/adapters/opencode/skills/enhance-plugins/SKILL.md +1 -1
- package/adapters/opencode/skills/enhance-prompts/SKILL.md +1 -1
- package/adapters/opencode/skills/enhance-skills/SKILL.md +1 -1
- package/adapters/opencode/skills/learn/SKILL.md +1 -1
- package/adapters/opencode/skills/perf-analyzer/SKILL.md +1 -1
- package/adapters/opencode/skills/perf-baseline-manager/SKILL.md +1 -1
- package/adapters/opencode/skills/perf-benchmarker/SKILL.md +1 -1
- package/adapters/opencode/skills/perf-code-paths/SKILL.md +1 -1
- package/adapters/opencode/skills/perf-investigation-logger/SKILL.md +1 -1
- package/adapters/opencode/skills/perf-profiler/SKILL.md +1 -1
- package/adapters/opencode/skills/perf-theory-gatherer/SKILL.md +1 -1
- package/adapters/opencode/skills/perf-theory-tester/SKILL.md +1 -1
- package/adapters/opencode/skills/sync-docs/SKILL.md +1 -1
- package/adapters/opencode/skills/validate-delivery/SKILL.md +1 -1
- package/bin/cli.js +4 -0
- package/lib/enhance/docs-patterns.js +1 -1
- package/lib/enhance/fixer.js +38 -13
- package/lib/enhance/projectmemory-analyzer.js +17 -9
- package/lib/enhance/projectmemory-patterns.js +2 -2
- package/lib/enhance/prompt-patterns.js +31 -28
- package/lib/enhance/security-patterns.js +6 -6
- package/lib/package.json +0 -3
- package/lib/patterns/slop-analyzers.js +1 -1
- package/package.json +1 -1
- package/plugins/agnix/.claude-plugin/plugin.json +1 -1
- package/plugins/agnix/skills/agnix/SKILL.md +1 -1
- package/plugins/audit-project/.claude-plugin/plugin.json +1 -1
- package/plugins/audit-project/commands/audit-project-agents.md +5 -0
- package/plugins/audit-project/lib/enhance/docs-patterns.js +1 -1
- package/plugins/audit-project/lib/enhance/fixer.js +38 -13
- package/plugins/audit-project/lib/enhance/projectmemory-analyzer.js +17 -9
- package/plugins/audit-project/lib/enhance/projectmemory-patterns.js +2 -2
- package/plugins/audit-project/lib/enhance/prompt-patterns.js +31 -28
- package/plugins/audit-project/lib/enhance/security-patterns.js +6 -6
- package/plugins/audit-project/lib/patterns/slop-analyzers.js +1 -1
- package/plugins/consult/.claude-plugin/plugin.json +1 -1
- package/plugins/consult/skills/consult/SKILL.md +1 -1
- package/plugins/deslop/.claude-plugin/plugin.json +1 -1
- package/plugins/deslop/lib/enhance/docs-patterns.js +1 -1
- package/plugins/deslop/lib/enhance/fixer.js +38 -13
- package/plugins/deslop/lib/enhance/projectmemory-analyzer.js +17 -9
- package/plugins/deslop/lib/enhance/projectmemory-patterns.js +2 -2
- package/plugins/deslop/lib/enhance/prompt-patterns.js +31 -28
- package/plugins/deslop/lib/enhance/security-patterns.js +6 -6
- package/plugins/deslop/lib/patterns/slop-analyzers.js +1 -1
- package/plugins/deslop/skills/deslop/SKILL.md +1 -1
- package/plugins/drift-detect/.claude-plugin/plugin.json +1 -1
- package/plugins/drift-detect/lib/enhance/docs-patterns.js +1 -1
- package/plugins/drift-detect/lib/enhance/fixer.js +38 -13
- package/plugins/drift-detect/lib/enhance/projectmemory-analyzer.js +17 -9
- package/plugins/drift-detect/lib/enhance/projectmemory-patterns.js +2 -2
- package/plugins/drift-detect/lib/enhance/prompt-patterns.js +31 -28
- package/plugins/drift-detect/lib/enhance/security-patterns.js +6 -6
- package/plugins/drift-detect/lib/patterns/slop-analyzers.js +1 -1
- package/plugins/drift-detect/skills/drift-analysis/SKILL.md +1 -1
- package/plugins/enhance/.claude-plugin/plugin.json +1 -1
- package/plugins/enhance/lib/enhance/docs-patterns.js +1 -1
- package/plugins/enhance/lib/enhance/fixer.js +38 -13
- package/plugins/enhance/lib/enhance/projectmemory-analyzer.js +17 -9
- package/plugins/enhance/lib/enhance/projectmemory-patterns.js +2 -2
- package/plugins/enhance/lib/enhance/prompt-patterns.js +31 -28
- package/plugins/enhance/lib/enhance/security-patterns.js +6 -6
- package/plugins/enhance/lib/patterns/slop-analyzers.js +1 -1
- package/plugins/enhance/skills/enhance-agent-prompts/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-claude-memory/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-cross-file/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-docs/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-hooks/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-orchestrator/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-plugins/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-prompts/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-skills/SKILL.md +1 -1
- package/plugins/learn/.claude-plugin/plugin.json +1 -1
- package/plugins/learn/lib/enhance/docs-patterns.js +1 -1
- package/plugins/learn/lib/enhance/fixer.js +38 -13
- package/plugins/learn/lib/enhance/projectmemory-analyzer.js +17 -9
- package/plugins/learn/lib/enhance/projectmemory-patterns.js +2 -2
- package/plugins/learn/lib/enhance/prompt-patterns.js +31 -28
- package/plugins/learn/lib/enhance/security-patterns.js +6 -6
- package/plugins/learn/lib/patterns/slop-analyzers.js +1 -1
- package/plugins/learn/skills/learn/SKILL.md +1 -1
- package/plugins/next-task/.claude-plugin/plugin.json +1 -1
- package/plugins/next-task/lib/enhance/docs-patterns.js +1 -1
- package/plugins/next-task/lib/enhance/fixer.js +38 -13
- package/plugins/next-task/lib/enhance/projectmemory-analyzer.js +17 -9
- package/plugins/next-task/lib/enhance/projectmemory-patterns.js +2 -2
- package/plugins/next-task/lib/enhance/prompt-patterns.js +31 -28
- package/plugins/next-task/lib/enhance/security-patterns.js +6 -6
- package/plugins/next-task/lib/patterns/slop-analyzers.js +1 -1
- package/plugins/next-task/skills/discover-tasks/SKILL.md +1 -1
- package/plugins/next-task/skills/validate-delivery/SKILL.md +1 -1
- package/plugins/perf/.claude-plugin/plugin.json +1 -1
- package/plugins/perf/lib/enhance/docs-patterns.js +1 -1
- package/plugins/perf/lib/enhance/fixer.js +38 -13
- package/plugins/perf/lib/enhance/projectmemory-analyzer.js +17 -9
- package/plugins/perf/lib/enhance/projectmemory-patterns.js +2 -2
- package/plugins/perf/lib/enhance/prompt-patterns.js +31 -28
- package/plugins/perf/lib/enhance/security-patterns.js +6 -6
- package/plugins/perf/lib/patterns/slop-analyzers.js +1 -1
- package/plugins/perf/skills/perf-analyzer/SKILL.md +1 -1
- package/plugins/perf/skills/perf-baseline-manager/SKILL.md +1 -1
- package/plugins/perf/skills/perf-benchmarker/SKILL.md +1 -1
- package/plugins/perf/skills/perf-code-paths/SKILL.md +1 -1
- package/plugins/perf/skills/perf-investigation-logger/SKILL.md +1 -1
- package/plugins/perf/skills/perf-profiler/SKILL.md +1 -1
- package/plugins/perf/skills/perf-theory-gatherer/SKILL.md +1 -1
- package/plugins/perf/skills/perf-theory-tester/SKILL.md +1 -1
- package/plugins/repo-map/.claude-plugin/plugin.json +1 -1
- package/plugins/repo-map/lib/enhance/docs-patterns.js +1 -1
- package/plugins/repo-map/lib/enhance/fixer.js +38 -13
- package/plugins/repo-map/lib/enhance/projectmemory-analyzer.js +17 -9
- package/plugins/repo-map/lib/enhance/projectmemory-patterns.js +2 -2
- package/plugins/repo-map/lib/enhance/prompt-patterns.js +31 -28
- package/plugins/repo-map/lib/enhance/security-patterns.js +6 -6
- package/plugins/repo-map/lib/patterns/slop-analyzers.js +1 -1
- package/plugins/ship/.claude-plugin/plugin.json +1 -1
- package/plugins/ship/commands/ship-ci-review-loop.md +5 -0
- package/plugins/ship/commands/ship-deployment.md +5 -0
- package/plugins/ship/lib/enhance/docs-patterns.js +1 -1
- package/plugins/ship/lib/enhance/fixer.js +38 -13
- package/plugins/ship/lib/enhance/projectmemory-analyzer.js +17 -9
- package/plugins/ship/lib/enhance/projectmemory-patterns.js +2 -2
- package/plugins/ship/lib/enhance/prompt-patterns.js +31 -28
- package/plugins/ship/lib/enhance/security-patterns.js +6 -6
- package/plugins/ship/lib/patterns/slop-analyzers.js +1 -1
- package/plugins/sync-docs/.claude-plugin/plugin.json +1 -1
- package/plugins/sync-docs/lib/enhance/docs-patterns.js +1 -1
- package/plugins/sync-docs/lib/enhance/fixer.js +38 -13
- package/plugins/sync-docs/lib/enhance/projectmemory-analyzer.js +17 -9
- package/plugins/sync-docs/lib/enhance/projectmemory-patterns.js +2 -2
- package/plugins/sync-docs/lib/enhance/prompt-patterns.js +31 -28
- package/plugins/sync-docs/lib/enhance/security-patterns.js +6 -6
- package/plugins/sync-docs/lib/patterns/slop-analyzers.js +1 -1
- package/plugins/sync-docs/skills/sync-docs/SKILL.md +1 -1
- package/scripts/gen-adapters.js +10 -0
- package/scripts/generate-docs.js +1 -1
- package/scripts/preflight.js +1 -2
- package/scripts/stamp-version.js +0 -5
- package/site/content.json +8 -1
|
@@ -29,7 +29,7 @@ const LOOKS_LIKE_JSON_CONTENT = /[:,]/;
|
|
|
29
29
|
const NOT_JSON_KEYWORDS = /(function|const|let|var|if|for|while|class)\b/;
|
|
30
30
|
// JS patterns require syntax context (not just keywords that might appear in JSON strings)
|
|
31
31
|
const LOOKS_LIKE_JS = /\b(function\s*\(|const\s+\w+\s*=|let\s+\w+\s*=|var\s+\w+\s*=|=>\s*[{(]|async\s+function|await\s+\w|class\s+\w+\s*{|import\s+\{|export\s+(const|function|class|default)|require\s*\()/;
|
|
32
|
-
const LOOKS_LIKE_PYTHON = /\b(def\s+\w+|import\s+\w+|from\s+\w+\s+import|class\s+\w+:|if\s
|
|
32
|
+
const LOOKS_LIKE_PYTHON = /\b(def\s+\w+|import\s+\w+|from\s+\w+\s+import|class\s+\w+:|if\s[^:\n]*:|\s{4}|print\()\b/;
|
|
33
33
|
|
|
34
34
|
// Memoization caches for performance (keyed by content hash)
|
|
35
35
|
let _lastContent = null;
|
|
@@ -220,7 +220,7 @@ const promptPatterns = {
|
|
|
220
220
|
// Skip lines listing vague terms as documentation
|
|
221
221
|
if (/vague\s*(instructions?|terms?|language|patterns?)\s*[:"]/.test(trimmed)) return false;
|
|
222
222
|
// Skip lines with quoted lists of vague words
|
|
223
|
-
if (
|
|
223
|
+
if (trimmed.includes('usually') && trimmed.includes('sometimes') && /["']/.test(trimmed)) return false;
|
|
224
224
|
return true;
|
|
225
225
|
});
|
|
226
226
|
const filteredContent = lines.join('\n');
|
|
@@ -331,7 +331,11 @@ const promptPatterns = {
|
|
|
331
331
|
if (!content || typeof content !== 'string') return null;
|
|
332
332
|
|
|
333
333
|
// Skip workflow orchestrators that spawn agents/skills rather than produce output directly
|
|
334
|
-
const
|
|
334
|
+
const lc = content.toLowerCase();
|
|
335
|
+
const isOrchestrator = /##\s*Phase\s+\d+/i.test(content) || content.includes('Task({') ||
|
|
336
|
+
(lc.includes('spawn') && lc.includes('agent')) || content.includes('subagent_type') ||
|
|
337
|
+
content.includes('await Task(') || (lc.includes('invoke') && lc.includes('skill')) ||
|
|
338
|
+
(/\bSkill\b/.test(content) && lc.includes('tool'));
|
|
335
339
|
if (isOrchestrator) return null;
|
|
336
340
|
|
|
337
341
|
// Skip reference docs and hooks (not prompts that produce conversational output)
|
|
@@ -590,7 +594,9 @@ const promptPatterns = {
|
|
|
590
594
|
if (isNonPrompt) return null;
|
|
591
595
|
|
|
592
596
|
// Skip workflow orchestrators and command files
|
|
593
|
-
const
|
|
597
|
+
const lc2 = content.toLowerCase();
|
|
598
|
+
const isOrchestrator = /##\s*Phase\s+\d+/i.test(content) || content.includes('Task({') ||
|
|
599
|
+
(lc2.includes('spawn') && lc2.includes('agent')) || content.includes('subagent_type');
|
|
594
600
|
if (isOrchestrator) return null;
|
|
595
601
|
|
|
596
602
|
// Check for example indicators
|
|
@@ -793,12 +799,12 @@ const promptPatterns = {
|
|
|
793
799
|
/\b(?:highest|lowest)\s+priority\b/i,
|
|
794
800
|
/\b(?:first|second|third)\s+priority\b/i,
|
|
795
801
|
// Numbered rules section (implicit priority order)
|
|
796
|
-
|
|
802
|
+
/##[ \t]*(?:critical|important)[ \t]*rules?[ \t]*\n[ \t]*1\.\s/i,
|
|
797
803
|
// Precedence language
|
|
798
804
|
/\btakes?\s+precedence\b/i,
|
|
799
805
|
/\boverride[sd]?\b/i,
|
|
800
806
|
// Ordered constraint list
|
|
801
|
-
|
|
807
|
+
/##[ \t]*constraints?[ \t]*\n[ \t]*1\.\s/i
|
|
802
808
|
];
|
|
803
809
|
|
|
804
810
|
for (const pattern of priorityIndicators) {
|
|
@@ -846,7 +852,8 @@ const promptPatterns = {
|
|
|
846
852
|
|
|
847
853
|
// Skip if this is documentation ABOUT CoT (describes the anti-pattern)
|
|
848
854
|
// These files explain why step-by-step is redundant, not actually use it
|
|
849
|
-
|
|
855
|
+
const lcContent = content.toLowerCase();
|
|
856
|
+
if (/step[- ]by[- ]step/i.test(content) && lcContent.includes('redundant')) {
|
|
850
857
|
return null;
|
|
851
858
|
}
|
|
852
859
|
|
|
@@ -961,7 +968,7 @@ const promptPatterns = {
|
|
|
961
968
|
// Check if requests JSON (exclude CLI flags and function descriptions)
|
|
962
969
|
// Exclude: "--output json", "analyzer returns JSON", "function returns JSON"
|
|
963
970
|
const requestsJson = (
|
|
964
|
-
(/\b(?:respond|output|return)\
|
|
971
|
+
(/\b(?:respond|output|return)[ \t]+(?:(?:with|in|as)[ \t]+)?JSON\b/i.test(content) &&
|
|
965
972
|
!/--output\s+json/i.test(content) &&
|
|
966
973
|
!/(?:analyzer|function|method)\s+returns?\s+JSON/i.test(content))
|
|
967
974
|
) ||
|
|
@@ -971,18 +978,18 @@ const promptPatterns = {
|
|
|
971
978
|
|
|
972
979
|
// Check if provides schema or example
|
|
973
980
|
const hasSchema = /\bproperties\b.{1,200}\btype\b/is.test(content) ||
|
|
974
|
-
|
|
981
|
+
(content.includes('```json') && content.includes('{')) ||
|
|
975
982
|
/<json[_-]?schema>/i.test(content) ||
|
|
976
983
|
// JSON in JavaScript/TypeScript code blocks (quoted keys)
|
|
977
|
-
/```(?:javascript|js|typescript|ts)\
|
|
984
|
+
(/```(?:javascript|js|typescript|ts)\b/.test(content) && /\{\s*"[a-zA-Z]+"/i.test(content)) ||
|
|
978
985
|
// JavaScript object literal assignment (const x = { prop: ... })
|
|
979
|
-
|
|
986
|
+
(/\b(?:const|let|var)\b/.test(content) && /=\s*\{/.test(content)) ||
|
|
980
987
|
// JSON example with quoted property names in prose
|
|
981
|
-
/\{
|
|
988
|
+
/\{"[a-zA-Z_]+"[ \t]*:/i.test(content) || /\{\n[ \t]*"[a-zA-Z_]+"[ \t]*:/i.test(content) ||
|
|
982
989
|
// Inline schema description: { prop, prop, prop } or { prop: type, ... }
|
|
983
|
-
/\{\
|
|
990
|
+
/\{[ \t]*[a-zA-Z_]+[ \t]*,[ \t]*[a-zA-Z_]+[ \t]*,[ \t]*[a-zA-Z_]+/i.test(content) ||
|
|
984
991
|
// Interface-style: { prop: value } patterns with multiple lines
|
|
985
|
-
/\{\
|
|
992
|
+
/\{\n[ \t]+[a-zA-Z_]+[ \t]*:[ \t]*[\[\{"']/i.test(content);
|
|
986
993
|
|
|
987
994
|
if (!hasSchema) {
|
|
988
995
|
return {
|
|
@@ -1133,19 +1140,15 @@ const promptPatterns = {
|
|
|
1133
1140
|
if (!creationTasks.test(content)) return null;
|
|
1134
1141
|
|
|
1135
1142
|
// Check for pattern reference indicators
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
for (const pattern of patternRefs) {
|
|
1146
|
-
if (pattern.test(content)) {
|
|
1147
|
-
return null;
|
|
1148
|
-
}
|
|
1143
|
+
// Use string-based checks to avoid ReDoS from overlapping optional groups
|
|
1144
|
+
const lcRef = content.toLowerCase();
|
|
1145
|
+
if (/\blike\s+\S+\b/i.test(content) ||
|
|
1146
|
+
lcRef.includes('similar to') ||
|
|
1147
|
+
(lcRef.includes('follow') && lcRef.includes('pattern')) ||
|
|
1148
|
+
(lcRef.includes('see ') && lcRef.includes('example')) ||
|
|
1149
|
+
(lcRef.includes('look at')) ||
|
|
1150
|
+
(/\.(?:js|ts|py)\b/.test(content) && lcRef.includes('example'))) {
|
|
1151
|
+
return null;
|
|
1149
1152
|
}
|
|
1150
1153
|
|
|
1151
1154
|
return {
|
|
@@ -1386,7 +1389,7 @@ const promptPatterns = {
|
|
|
1386
1389
|
if (codeBlockLines.has(lineNum)) continue;
|
|
1387
1390
|
|
|
1388
1391
|
const line = lines[i];
|
|
1389
|
-
const match = line.match(/^(#{1,6})\
|
|
1392
|
+
const match = line.match(/^(#{1,6})[ \t]+(\S.*)$/);
|
|
1390
1393
|
if (match) {
|
|
1391
1394
|
headings.push({
|
|
1392
1395
|
level: match[1].length,
|
|
@@ -27,7 +27,7 @@ const securityPatterns = {
|
|
|
27
27
|
if (!frontmatterMatch) return null;
|
|
28
28
|
|
|
29
29
|
const frontmatter = frontmatterMatch[1];
|
|
30
|
-
const toolsMatch = frontmatter.match(/^tools
|
|
30
|
+
const toolsMatch = frontmatter.match(/^tools:[ \t]*(\S.*)?$/m);
|
|
31
31
|
if (!toolsMatch) return null;
|
|
32
32
|
|
|
33
33
|
const tools = toolsMatch[1];
|
|
@@ -60,8 +60,8 @@ const securityPatterns = {
|
|
|
60
60
|
|
|
61
61
|
for (let i = 0; i < lines.length; i++) {
|
|
62
62
|
const line = lines[i];
|
|
63
|
-
// Look for shell commands with interpolation
|
|
64
|
-
if (
|
|
63
|
+
// Look for shell commands with interpolation (string checks avoid ReDoS)
|
|
64
|
+
if (/\b(?:exec|spawn|system|shell)\b|`|Bash/i.test(line) && /[(`]/.test(line) && line.includes('${')) {
|
|
65
65
|
issues.push({
|
|
66
66
|
issue: 'Command injection risk via string interpolation',
|
|
67
67
|
fix: 'Validate and escape user input before shell execution',
|
|
@@ -91,8 +91,8 @@ const securityPatterns = {
|
|
|
91
91
|
|
|
92
92
|
for (let i = 0; i < lines.length; i++) {
|
|
93
93
|
const line = lines[i];
|
|
94
|
-
// Look for user-controlled paths with ../
|
|
95
|
-
if (
|
|
94
|
+
// Look for user-controlled paths with ../ (string checks avoid ReDoS)
|
|
95
|
+
if (/\b(?:path|file|dir)\b/i.test(line) && line.includes('$') && line.includes('../')) {
|
|
96
96
|
issues.push({
|
|
97
97
|
issue: 'Path traversal risk - user input may contain ../',
|
|
98
98
|
fix: 'Validate paths and use path.resolve() with base directory check',
|
|
@@ -181,7 +181,7 @@ const securityPatterns = {
|
|
|
181
181
|
if (!frontmatterMatch) return null;
|
|
182
182
|
|
|
183
183
|
const frontmatter = frontmatterMatch[1];
|
|
184
|
-
const toolsMatch = frontmatter.match(/^tools
|
|
184
|
+
const toolsMatch = frontmatter.match(/^tools:[ \t]*(\S.*)?$/m);
|
|
185
185
|
if (!toolsMatch) return null;
|
|
186
186
|
|
|
187
187
|
const tools = toolsMatch[1];
|
|
@@ -1803,7 +1803,7 @@ function analyzeDeadCode(content, options = {}) {
|
|
|
1803
1803
|
// Skip if termination is part of a one-line conditional (e.g., "if (x) return;")
|
|
1804
1804
|
// These don't make subsequent code unreachable
|
|
1805
1805
|
if (/^\s*(if|elif|else\s+if)\s*\(/.test(trimmed) ||
|
|
1806
|
-
|
|
1806
|
+
/^[ \t]*if\s[^:\n]*:/.test(trimmed)) {
|
|
1807
1807
|
continue;
|
|
1808
1808
|
}
|
|
1809
1809
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: drift-analysis
|
|
3
3
|
description: Use when the user asks about plan drift, reality check, comparing docs to code, project state analysis, roadmap alignment, implementation gaps, or needs guidance on identifying discrepancies between documented plans and actual implementation state.
|
|
4
|
-
version: 4.2.
|
|
4
|
+
version: 4.2.2
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Drift Analysis
|
|
@@ -418,7 +418,7 @@ const docsPatterns = {
|
|
|
418
418
|
}
|
|
419
419
|
|
|
420
420
|
// Check for very long lists that could be tables
|
|
421
|
-
const longLists = content.match(/(?:^[-*]\
|
|
421
|
+
const longLists = content.match(/(?:^[-*][ \t]+\S[^\n]*\n){10,}/gm);
|
|
422
422
|
if (longLists) {
|
|
423
423
|
suggestions.push('Long lists (10+ items) might be more efficient as tables');
|
|
424
424
|
}
|
|
@@ -179,7 +179,7 @@ function applyAtPath(obj, pathStr, fixFn) {
|
|
|
179
179
|
const part = parts[i];
|
|
180
180
|
if (part.includes('[')) {
|
|
181
181
|
// Array access
|
|
182
|
-
const match = part.match(
|
|
182
|
+
const match = part.match(/^((?!__proto__|constructor|prototype)[a-zA-Z_]\w*)\[(\d{1,10})\]$/);
|
|
183
183
|
if (match) {
|
|
184
184
|
current = current[match[1]][parseInt(match[2], 10)];
|
|
185
185
|
}
|
|
@@ -190,7 +190,7 @@ function applyAtPath(obj, pathStr, fixFn) {
|
|
|
190
190
|
|
|
191
191
|
const lastPart = parts[parts.length - 1];
|
|
192
192
|
if (lastPart.includes('[')) {
|
|
193
|
-
const match = lastPart.match(
|
|
193
|
+
const match = lastPart.match(/^((?!__proto__|constructor|prototype)[a-zA-Z_]\w*)\[(\d{1,10})\]$/);
|
|
194
194
|
if (match) {
|
|
195
195
|
current[match[1]][parseInt(match[2], 10)] = fixFn(current[match[1]][parseInt(match[2], 10)]);
|
|
196
196
|
}
|
|
@@ -403,7 +403,7 @@ function fixInconsistentHeadings(content) {
|
|
|
403
403
|
|
|
404
404
|
if (inCodeBlock) continue;
|
|
405
405
|
|
|
406
|
-
const headingMatch = line.match(/^(#{1,6})\
|
|
406
|
+
const headingMatch = line.match(/^(#{1,6})[ \t]+(\S.*)$/);
|
|
407
407
|
if (headingMatch) {
|
|
408
408
|
const currentLevel = headingMatch[1].length;
|
|
409
409
|
const headingText = headingMatch[2];
|
|
@@ -535,6 +535,37 @@ Why bad: [explanation]
|
|
|
535
535
|
return content.trim() + exampleSection;
|
|
536
536
|
}
|
|
537
537
|
|
|
538
|
+
/**
|
|
539
|
+
* Wrap a markdown section (heading to next heading/separator) in XML tags.
|
|
540
|
+
* Uses line-by-line scanning to avoid ReDoS from [\s\S]*? with lookaheads.
|
|
541
|
+
*/
|
|
542
|
+
function wrapSection(text, headingPattern, tagName) {
|
|
543
|
+
const lines = text.split('\n');
|
|
544
|
+
let sectionStart = -1;
|
|
545
|
+
for (let i = 0; i < lines.length; i++) {
|
|
546
|
+
if (sectionStart === -1) {
|
|
547
|
+
if (headingPattern.test(lines[i])) {
|
|
548
|
+
sectionStart = i;
|
|
549
|
+
}
|
|
550
|
+
} else {
|
|
551
|
+
// End section at next heading or horizontal rule
|
|
552
|
+
if (/^#{1,6}\s/.test(lines[i]) || /^---/.test(lines[i])) {
|
|
553
|
+
const before = lines.slice(0, sectionStart);
|
|
554
|
+
const section = lines.slice(sectionStart, i);
|
|
555
|
+
const after = lines.slice(i);
|
|
556
|
+
return [...before, `<${tagName}>`, ...section, `</${tagName}>`, ...after].join('\n');
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
// Section runs to end of content
|
|
561
|
+
if (sectionStart !== -1) {
|
|
562
|
+
const before = lines.slice(0, sectionStart);
|
|
563
|
+
const section = lines.slice(sectionStart);
|
|
564
|
+
return [...before, `<${tagName}>`, ...section, `</${tagName}>`].join('\n');
|
|
565
|
+
}
|
|
566
|
+
return text;
|
|
567
|
+
}
|
|
568
|
+
|
|
538
569
|
/**
|
|
539
570
|
* Add XML structure tags to complex prompt
|
|
540
571
|
* @param {string} content - Prompt content
|
|
@@ -551,17 +582,11 @@ function fixMissingXmlStructure(content) {
|
|
|
551
582
|
// Wrap role section if exists
|
|
552
583
|
let result = content;
|
|
553
584
|
|
|
554
|
-
// Find and wrap role section
|
|
555
|
-
result = result
|
|
556
|
-
/^(##\s*(?:your\s+)?role\s*\n)([\s\S]*?)(?=\n##|\n---|\Z)/im,
|
|
557
|
-
'<role>\n$1$2</role>\n'
|
|
558
|
-
);
|
|
585
|
+
// Find and wrap role section (use non-regex approach to avoid ReDoS)
|
|
586
|
+
result = wrapSection(result, /^##[ \t]*(?:your[ \t]+)?role[ \t]*$/im, 'role');
|
|
559
587
|
|
|
560
588
|
// Find and wrap constraints section
|
|
561
|
-
result = result
|
|
562
|
-
/^(##\s*(?:constraints?|rules?)\s*\n)([\s\S]*?)(?=\n##|\n---|\Z)/im,
|
|
563
|
-
'<constraints>\n$1$2</constraints>\n'
|
|
564
|
-
);
|
|
589
|
+
result = wrapSection(result, /^##[ \t]*(?:constraints?|rules?)[ \t]*$/im, 'constraints');
|
|
565
590
|
|
|
566
591
|
return result;
|
|
567
592
|
}
|
|
@@ -622,7 +647,7 @@ function fixMissingTriggerPhrase(content) {
|
|
|
622
647
|
// Check if already has trigger phrase
|
|
623
648
|
if (!/use when user asks/i.test(descLine)) {
|
|
624
649
|
// Extract current description
|
|
625
|
-
const match = descLine.match(/^description
|
|
650
|
+
const match = descLine.match(/^description:[ \t]*(\S.*)$/);
|
|
626
651
|
if (match) {
|
|
627
652
|
const currentDesc = match[1].trim();
|
|
628
653
|
// Add trigger phrase
|
|
@@ -43,17 +43,25 @@ function extractFileReferences(content) {
|
|
|
43
43
|
|
|
44
44
|
const references = [];
|
|
45
45
|
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
46
|
+
// Extract markdown links [text](path) using indexOf scanning (ReDoS-safe)
|
|
47
|
+
let pos = 0;
|
|
48
|
+
while (pos < content.length) {
|
|
49
|
+
const openBracket = content.indexOf('[', pos);
|
|
50
|
+
if (openBracket === -1) break;
|
|
51
|
+
const closeBracket = content.indexOf(']', openBracket + 1);
|
|
52
|
+
if (closeBracket === -1) break;
|
|
53
|
+
if (content[closeBracket + 1] === '(') {
|
|
54
|
+
const closeParen = content.indexOf(')', closeBracket + 2);
|
|
55
|
+
if (closeParen !== -1 && closeParen - closeBracket - 2 <= 500) {
|
|
56
|
+
const href = content.substring(closeBracket + 2, closeParen);
|
|
57
|
+
if (!href.startsWith('http') && !href.startsWith('#') && !href.startsWith('mailto:')) {
|
|
58
|
+
references.push(href.split('#')[0]); // Remove anchor
|
|
59
|
+
}
|
|
60
|
+
pos = closeParen + 1;
|
|
61
|
+
continue;
|
|
55
62
|
}
|
|
56
63
|
}
|
|
64
|
+
pos = openBracket + 1;
|
|
57
65
|
}
|
|
58
66
|
|
|
59
67
|
// Match backtick paths: `path/to/file.ext` or `file.ext` (root files)
|
|
@@ -57,7 +57,7 @@ const projectMemoryPatterns = {
|
|
|
57
57
|
const hasArchitecture = /##\s+architecture/i.test(content);
|
|
58
58
|
const hasStructure = /##\s+(?:project\s+)?structure/i.test(content);
|
|
59
59
|
const hasOverview = /##\s+overview/i.test(content);
|
|
60
|
-
const hasDirectoryTree =
|
|
60
|
+
const hasDirectoryTree = content.includes('```') && /├──|└──|lib\/|src\//.test(content);
|
|
61
61
|
|
|
62
62
|
if (!hasArchitecture && !hasStructure && !hasOverview && !hasDirectoryTree) {
|
|
63
63
|
return {
|
|
@@ -85,7 +85,7 @@ const projectMemoryPatterns = {
|
|
|
85
85
|
const hasCommands = /##\s+(?:key\s+)?commands/i.test(content);
|
|
86
86
|
const hasScripts = /##\s+scripts/i.test(content);
|
|
87
87
|
const hasUsage = /##\s+usage/i.test(content);
|
|
88
|
-
const hasCodeBlocks = /```(?:bash|sh|shell)
|
|
88
|
+
const hasCodeBlocks = /```(?:bash|sh|shell)/i.test(content) && /\b(?:npm|yarn|pnpm|git|make)\b/i.test(content);
|
|
89
89
|
|
|
90
90
|
if (!hasCommands && !hasScripts && !hasUsage && !hasCodeBlocks) {
|
|
91
91
|
return {
|
|
@@ -29,7 +29,7 @@ const LOOKS_LIKE_JSON_CONTENT = /[:,]/;
|
|
|
29
29
|
const NOT_JSON_KEYWORDS = /(function|const|let|var|if|for|while|class)\b/;
|
|
30
30
|
// JS patterns require syntax context (not just keywords that might appear in JSON strings)
|
|
31
31
|
const LOOKS_LIKE_JS = /\b(function\s*\(|const\s+\w+\s*=|let\s+\w+\s*=|var\s+\w+\s*=|=>\s*[{(]|async\s+function|await\s+\w|class\s+\w+\s*{|import\s+\{|export\s+(const|function|class|default)|require\s*\()/;
|
|
32
|
-
const LOOKS_LIKE_PYTHON = /\b(def\s+\w+|import\s+\w+|from\s+\w+\s+import|class\s+\w+:|if\s
|
|
32
|
+
const LOOKS_LIKE_PYTHON = /\b(def\s+\w+|import\s+\w+|from\s+\w+\s+import|class\s+\w+:|if\s[^:\n]*:|\s{4}|print\()\b/;
|
|
33
33
|
|
|
34
34
|
// Memoization caches for performance (keyed by content hash)
|
|
35
35
|
let _lastContent = null;
|
|
@@ -220,7 +220,7 @@ const promptPatterns = {
|
|
|
220
220
|
// Skip lines listing vague terms as documentation
|
|
221
221
|
if (/vague\s*(instructions?|terms?|language|patterns?)\s*[:"]/.test(trimmed)) return false;
|
|
222
222
|
// Skip lines with quoted lists of vague words
|
|
223
|
-
if (
|
|
223
|
+
if (trimmed.includes('usually') && trimmed.includes('sometimes') && /["']/.test(trimmed)) return false;
|
|
224
224
|
return true;
|
|
225
225
|
});
|
|
226
226
|
const filteredContent = lines.join('\n');
|
|
@@ -331,7 +331,11 @@ const promptPatterns = {
|
|
|
331
331
|
if (!content || typeof content !== 'string') return null;
|
|
332
332
|
|
|
333
333
|
// Skip workflow orchestrators that spawn agents/skills rather than produce output directly
|
|
334
|
-
const
|
|
334
|
+
const lc = content.toLowerCase();
|
|
335
|
+
const isOrchestrator = /##\s*Phase\s+\d+/i.test(content) || content.includes('Task({') ||
|
|
336
|
+
(lc.includes('spawn') && lc.includes('agent')) || content.includes('subagent_type') ||
|
|
337
|
+
content.includes('await Task(') || (lc.includes('invoke') && lc.includes('skill')) ||
|
|
338
|
+
(/\bSkill\b/.test(content) && lc.includes('tool'));
|
|
335
339
|
if (isOrchestrator) return null;
|
|
336
340
|
|
|
337
341
|
// Skip reference docs and hooks (not prompts that produce conversational output)
|
|
@@ -590,7 +594,9 @@ const promptPatterns = {
|
|
|
590
594
|
if (isNonPrompt) return null;
|
|
591
595
|
|
|
592
596
|
// Skip workflow orchestrators and command files
|
|
593
|
-
const
|
|
597
|
+
const lc2 = content.toLowerCase();
|
|
598
|
+
const isOrchestrator = /##\s*Phase\s+\d+/i.test(content) || content.includes('Task({') ||
|
|
599
|
+
(lc2.includes('spawn') && lc2.includes('agent')) || content.includes('subagent_type');
|
|
594
600
|
if (isOrchestrator) return null;
|
|
595
601
|
|
|
596
602
|
// Check for example indicators
|
|
@@ -793,12 +799,12 @@ const promptPatterns = {
|
|
|
793
799
|
/\b(?:highest|lowest)\s+priority\b/i,
|
|
794
800
|
/\b(?:first|second|third)\s+priority\b/i,
|
|
795
801
|
// Numbered rules section (implicit priority order)
|
|
796
|
-
|
|
802
|
+
/##[ \t]*(?:critical|important)[ \t]*rules?[ \t]*\n[ \t]*1\.\s/i,
|
|
797
803
|
// Precedence language
|
|
798
804
|
/\btakes?\s+precedence\b/i,
|
|
799
805
|
/\boverride[sd]?\b/i,
|
|
800
806
|
// Ordered constraint list
|
|
801
|
-
|
|
807
|
+
/##[ \t]*constraints?[ \t]*\n[ \t]*1\.\s/i
|
|
802
808
|
];
|
|
803
809
|
|
|
804
810
|
for (const pattern of priorityIndicators) {
|
|
@@ -846,7 +852,8 @@ const promptPatterns = {
|
|
|
846
852
|
|
|
847
853
|
// Skip if this is documentation ABOUT CoT (describes the anti-pattern)
|
|
848
854
|
// These files explain why step-by-step is redundant, not actually use it
|
|
849
|
-
|
|
855
|
+
const lcContent = content.toLowerCase();
|
|
856
|
+
if (/step[- ]by[- ]step/i.test(content) && lcContent.includes('redundant')) {
|
|
850
857
|
return null;
|
|
851
858
|
}
|
|
852
859
|
|
|
@@ -961,7 +968,7 @@ const promptPatterns = {
|
|
|
961
968
|
// Check if requests JSON (exclude CLI flags and function descriptions)
|
|
962
969
|
// Exclude: "--output json", "analyzer returns JSON", "function returns JSON"
|
|
963
970
|
const requestsJson = (
|
|
964
|
-
(/\b(?:respond|output|return)\
|
|
971
|
+
(/\b(?:respond|output|return)[ \t]+(?:(?:with|in|as)[ \t]+)?JSON\b/i.test(content) &&
|
|
965
972
|
!/--output\s+json/i.test(content) &&
|
|
966
973
|
!/(?:analyzer|function|method)\s+returns?\s+JSON/i.test(content))
|
|
967
974
|
) ||
|
|
@@ -971,18 +978,18 @@ const promptPatterns = {
|
|
|
971
978
|
|
|
972
979
|
// Check if provides schema or example
|
|
973
980
|
const hasSchema = /\bproperties\b.{1,200}\btype\b/is.test(content) ||
|
|
974
|
-
|
|
981
|
+
(content.includes('```json') && content.includes('{')) ||
|
|
975
982
|
/<json[_-]?schema>/i.test(content) ||
|
|
976
983
|
// JSON in JavaScript/TypeScript code blocks (quoted keys)
|
|
977
|
-
/```(?:javascript|js|typescript|ts)\
|
|
984
|
+
(/```(?:javascript|js|typescript|ts)\b/.test(content) && /\{\s*"[a-zA-Z]+"/i.test(content)) ||
|
|
978
985
|
// JavaScript object literal assignment (const x = { prop: ... })
|
|
979
|
-
|
|
986
|
+
(/\b(?:const|let|var)\b/.test(content) && /=\s*\{/.test(content)) ||
|
|
980
987
|
// JSON example with quoted property names in prose
|
|
981
|
-
/\{
|
|
988
|
+
/\{"[a-zA-Z_]+"[ \t]*:/i.test(content) || /\{\n[ \t]*"[a-zA-Z_]+"[ \t]*:/i.test(content) ||
|
|
982
989
|
// Inline schema description: { prop, prop, prop } or { prop: type, ... }
|
|
983
|
-
/\{\
|
|
990
|
+
/\{[ \t]*[a-zA-Z_]+[ \t]*,[ \t]*[a-zA-Z_]+[ \t]*,[ \t]*[a-zA-Z_]+/i.test(content) ||
|
|
984
991
|
// Interface-style: { prop: value } patterns with multiple lines
|
|
985
|
-
/\{\
|
|
992
|
+
/\{\n[ \t]+[a-zA-Z_]+[ \t]*:[ \t]*[\[\{"']/i.test(content);
|
|
986
993
|
|
|
987
994
|
if (!hasSchema) {
|
|
988
995
|
return {
|
|
@@ -1133,19 +1140,15 @@ const promptPatterns = {
|
|
|
1133
1140
|
if (!creationTasks.test(content)) return null;
|
|
1134
1141
|
|
|
1135
1142
|
// Check for pattern reference indicators
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
for (const pattern of patternRefs) {
|
|
1146
|
-
if (pattern.test(content)) {
|
|
1147
|
-
return null;
|
|
1148
|
-
}
|
|
1143
|
+
// Use string-based checks to avoid ReDoS from overlapping optional groups
|
|
1144
|
+
const lcRef = content.toLowerCase();
|
|
1145
|
+
if (/\blike\s+\S+\b/i.test(content) ||
|
|
1146
|
+
lcRef.includes('similar to') ||
|
|
1147
|
+
(lcRef.includes('follow') && lcRef.includes('pattern')) ||
|
|
1148
|
+
(lcRef.includes('see ') && lcRef.includes('example')) ||
|
|
1149
|
+
(lcRef.includes('look at')) ||
|
|
1150
|
+
(/\.(?:js|ts|py)\b/.test(content) && lcRef.includes('example'))) {
|
|
1151
|
+
return null;
|
|
1149
1152
|
}
|
|
1150
1153
|
|
|
1151
1154
|
return {
|
|
@@ -1386,7 +1389,7 @@ const promptPatterns = {
|
|
|
1386
1389
|
if (codeBlockLines.has(lineNum)) continue;
|
|
1387
1390
|
|
|
1388
1391
|
const line = lines[i];
|
|
1389
|
-
const match = line.match(/^(#{1,6})\
|
|
1392
|
+
const match = line.match(/^(#{1,6})[ \t]+(\S.*)$/);
|
|
1390
1393
|
if (match) {
|
|
1391
1394
|
headings.push({
|
|
1392
1395
|
level: match[1].length,
|
|
@@ -27,7 +27,7 @@ const securityPatterns = {
|
|
|
27
27
|
if (!frontmatterMatch) return null;
|
|
28
28
|
|
|
29
29
|
const frontmatter = frontmatterMatch[1];
|
|
30
|
-
const toolsMatch = frontmatter.match(/^tools
|
|
30
|
+
const toolsMatch = frontmatter.match(/^tools:[ \t]*(\S.*)?$/m);
|
|
31
31
|
if (!toolsMatch) return null;
|
|
32
32
|
|
|
33
33
|
const tools = toolsMatch[1];
|
|
@@ -60,8 +60,8 @@ const securityPatterns = {
|
|
|
60
60
|
|
|
61
61
|
for (let i = 0; i < lines.length; i++) {
|
|
62
62
|
const line = lines[i];
|
|
63
|
-
// Look for shell commands with interpolation
|
|
64
|
-
if (
|
|
63
|
+
// Look for shell commands with interpolation (string checks avoid ReDoS)
|
|
64
|
+
if (/\b(?:exec|spawn|system|shell)\b|`|Bash/i.test(line) && /[(`]/.test(line) && line.includes('${')) {
|
|
65
65
|
issues.push({
|
|
66
66
|
issue: 'Command injection risk via string interpolation',
|
|
67
67
|
fix: 'Validate and escape user input before shell execution',
|
|
@@ -91,8 +91,8 @@ const securityPatterns = {
|
|
|
91
91
|
|
|
92
92
|
for (let i = 0; i < lines.length; i++) {
|
|
93
93
|
const line = lines[i];
|
|
94
|
-
// Look for user-controlled paths with ../
|
|
95
|
-
if (
|
|
94
|
+
// Look for user-controlled paths with ../ (string checks avoid ReDoS)
|
|
95
|
+
if (/\b(?:path|file|dir)\b/i.test(line) && line.includes('$') && line.includes('../')) {
|
|
96
96
|
issues.push({
|
|
97
97
|
issue: 'Path traversal risk - user input may contain ../',
|
|
98
98
|
fix: 'Validate paths and use path.resolve() with base directory check',
|
|
@@ -181,7 +181,7 @@ const securityPatterns = {
|
|
|
181
181
|
if (!frontmatterMatch) return null;
|
|
182
182
|
|
|
183
183
|
const frontmatter = frontmatterMatch[1];
|
|
184
|
-
const toolsMatch = frontmatter.match(/^tools
|
|
184
|
+
const toolsMatch = frontmatter.match(/^tools:[ \t]*(\S.*)?$/m);
|
|
185
185
|
if (!toolsMatch) return null;
|
|
186
186
|
|
|
187
187
|
const tools = toolsMatch[1];
|
|
@@ -1803,7 +1803,7 @@ function analyzeDeadCode(content, options = {}) {
|
|
|
1803
1803
|
// Skip if termination is part of a one-line conditional (e.g., "if (x) return;")
|
|
1804
1804
|
// These don't make subsequent code unreachable
|
|
1805
1805
|
if (/^\s*(if|elif|else\s+if)\s*\(/.test(trimmed) ||
|
|
1806
|
-
|
|
1806
|
+
/^[ \t]*if\s[^:\n]*:/.test(trimmed)) {
|
|
1807
1807
|
continue;
|
|
1808
1808
|
}
|
|
1809
1809
|
|