agentsys 5.0.3 → 5.1.0
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 +21 -14
- package/.claude-plugin/plugin.json +1 -1
- package/AGENTS.md +2 -1
- package/CHANGELOG.md +18 -0
- package/README.md +7 -6
- package/adapters/codex/skills/agnix/SKILL.md +0 -1
- package/adapters/codex/skills/audit-project/SKILL.md +0 -1
- package/adapters/codex/skills/audit-project-agents/SKILL.md +0 -1
- package/adapters/codex/skills/audit-project-github/SKILL.md +0 -1
- package/adapters/codex/skills/consult/SKILL.md +132 -57
- package/adapters/codex/skills/debate/SKILL.md +214 -0
- package/adapters/codex/skills/delivery-approval/SKILL.md +0 -1
- package/adapters/codex/skills/deslop/SKILL.md +0 -1
- package/adapters/codex/skills/drift-detect/SKILL.md +0 -1
- package/adapters/codex/skills/enhance/SKILL.md +0 -1
- package/adapters/codex/skills/learn/SKILL.md +0 -1
- package/adapters/codex/skills/next-task/SKILL.md +0 -1
- package/adapters/codex/skills/perf/SKILL.md +0 -1
- package/adapters/codex/skills/repo-map/SKILL.md +0 -1
- package/adapters/codex/skills/ship/SKILL.md +0 -1
- package/adapters/codex/skills/ship-ci-review-loop/SKILL.md +0 -1
- package/adapters/codex/skills/ship-deployment/SKILL.md +0 -1
- package/adapters/codex/skills/ship-error-handling/SKILL.md +0 -1
- package/adapters/codex/skills/sync-docs/SKILL.md +0 -1
- package/adapters/opencode/agents/agent-enhancer.md +0 -1
- package/adapters/opencode/agents/agnix-agent.md +0 -1
- package/adapters/opencode/agents/ci-fixer.md +0 -1
- package/adapters/opencode/agents/ci-monitor.md +0 -1
- package/adapters/opencode/agents/claudemd-enhancer.md +0 -1
- package/adapters/opencode/agents/consult-agent.md +122 -30
- package/adapters/opencode/agents/cross-file-enhancer.md +0 -1
- package/adapters/opencode/agents/debate-orchestrator.md +169 -0
- package/adapters/opencode/agents/delivery-validator.md +0 -1
- package/adapters/opencode/agents/deslop-agent.md +0 -1
- package/adapters/opencode/agents/docs-enhancer.md +0 -1
- package/adapters/opencode/agents/exploration-agent.md +0 -1
- package/adapters/opencode/agents/hooks-enhancer.md +0 -1
- package/adapters/opencode/agents/implementation-agent.md +0 -1
- package/adapters/opencode/agents/learn-agent.md +0 -1
- package/adapters/opencode/agents/map-validator.md +0 -1
- package/adapters/opencode/agents/perf-analyzer.md +0 -1
- package/adapters/opencode/agents/perf-code-paths.md +0 -1
- package/adapters/opencode/agents/perf-investigation-logger.md +0 -1
- package/adapters/opencode/agents/perf-orchestrator.md +0 -1
- package/adapters/opencode/agents/perf-theory-gatherer.md +0 -1
- package/adapters/opencode/agents/perf-theory-tester.md +0 -1
- package/adapters/opencode/agents/plan-synthesizer.md +0 -1
- package/adapters/opencode/agents/planning-agent.md +0 -1
- package/adapters/opencode/agents/plugin-enhancer.md +0 -1
- package/adapters/opencode/agents/prompt-enhancer.md +0 -1
- package/adapters/opencode/agents/simple-fixer.md +0 -1
- package/adapters/opencode/agents/skills-enhancer.md +0 -1
- package/adapters/opencode/agents/sync-docs-agent.md +0 -1
- package/adapters/opencode/agents/task-discoverer.md +0 -1
- package/adapters/opencode/agents/test-coverage-checker.md +0 -1
- package/adapters/opencode/agents/worktree-manager.md +0 -1
- package/adapters/opencode/commands/agnix.md +0 -1
- package/adapters/opencode/commands/audit-project-agents.md +0 -1
- package/adapters/opencode/commands/audit-project-github.md +0 -1
- package/adapters/opencode/commands/audit-project.md +0 -1
- package/adapters/opencode/commands/consult.md +133 -57
- package/adapters/opencode/commands/debate.md +224 -0
- package/adapters/opencode/commands/delivery-approval.md +0 -1
- package/adapters/opencode/commands/deslop.md +0 -1
- package/adapters/opencode/commands/drift-detect.md +0 -1
- package/adapters/opencode/commands/enhance.md +0 -1
- package/adapters/opencode/commands/learn.md +0 -1
- package/adapters/opencode/commands/next-task.md +0 -1
- package/adapters/opencode/commands/perf.md +0 -1
- package/adapters/opencode/commands/repo-map.md +0 -1
- package/adapters/opencode/commands/ship-ci-review-loop.md +0 -1
- package/adapters/opencode/commands/ship-deployment.md +0 -1
- package/adapters/opencode/commands/ship-error-handling.md +0 -1
- package/adapters/opencode/commands/ship.md +0 -1
- package/adapters/opencode/commands/sync-docs.md +0 -1
- package/adapters/opencode/skills/agnix/SKILL.md +1 -2
- package/adapters/opencode/skills/consult/SKILL.md +33 -23
- package/adapters/opencode/skills/debate/SKILL.md +245 -0
- package/adapters/opencode/skills/deslop/SKILL.md +1 -2
- package/adapters/opencode/skills/discover-tasks/SKILL.md +1 -2
- package/adapters/opencode/skills/drift-analysis/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-agent-prompts/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-claude-memory/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-cross-file/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-docs/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-hooks/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-orchestrator/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-plugins/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-prompts/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-skills/SKILL.md +1 -2
- package/adapters/opencode/skills/learn/SKILL.md +1 -2
- package/adapters/opencode/skills/orchestrate-review/SKILL.md +0 -1
- package/adapters/opencode/skills/perf-analyzer/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-baseline-manager/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-benchmarker/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-code-paths/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-investigation-logger/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-profiler/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-theory-gatherer/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-theory-tester/SKILL.md +1 -2
- package/adapters/opencode/skills/repo-mapping/SKILL.md +1 -2
- package/adapters/opencode/skills/sync-docs/SKILL.md +1 -2
- package/adapters/opencode/skills/validate-delivery/SKILL.md +1 -2
- package/lib/adapter-transforms.js +24 -4
- 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/lib/adapter-transforms.js +24 -4
- package/plugins/consult/.claude-plugin/plugin.json +1 -1
- package/plugins/consult/agents/consult-agent.md +122 -29
- package/plugins/consult/commands/consult.md +135 -58
- package/plugins/consult/skills/consult/SKILL.md +31 -20
- package/plugins/debate/.claude-plugin/plugin.json +21 -0
- package/plugins/debate/agents/debate-orchestrator.md +175 -0
- package/plugins/debate/commands/debate.md +221 -0
- package/plugins/debate/lib/adapter-transforms.js +298 -0
- package/plugins/debate/lib/collectors/codebase.js +392 -0
- package/plugins/debate/lib/collectors/docs-patterns.js +713 -0
- package/plugins/debate/lib/collectors/documentation.js +219 -0
- package/plugins/debate/lib/collectors/github.js +330 -0
- package/plugins/debate/lib/collectors/index.js +126 -0
- package/plugins/debate/lib/config/index.js +14 -0
- package/plugins/debate/lib/cross-platform/index.js +539 -0
- package/plugins/debate/lib/discovery/index.js +352 -0
- package/plugins/debate/lib/drift-detect/collectors.js +37 -0
- package/plugins/debate/lib/enhance/agent-analyzer.js +421 -0
- package/plugins/debate/lib/enhance/agent-patterns.js +571 -0
- package/plugins/debate/lib/enhance/auto-suppression.js +622 -0
- package/plugins/debate/lib/enhance/benchmark.js +417 -0
- package/plugins/debate/lib/enhance/cross-file-analyzer.js +930 -0
- package/plugins/debate/lib/enhance/cross-file-patterns.js +370 -0
- package/plugins/debate/lib/enhance/docs-analyzer.js +325 -0
- package/plugins/debate/lib/enhance/docs-patterns.js +671 -0
- package/plugins/debate/lib/enhance/fixer.js +721 -0
- package/plugins/debate/lib/enhance/hook-analyzer.js +135 -0
- package/plugins/debate/lib/enhance/hook-patterns.js +40 -0
- package/plugins/debate/lib/enhance/index.js +127 -0
- package/plugins/debate/lib/enhance/plugin-analyzer.js +402 -0
- package/plugins/debate/lib/enhance/plugin-patterns.js +326 -0
- package/plugins/debate/lib/enhance/projectmemory-analyzer.js +551 -0
- package/plugins/debate/lib/enhance/projectmemory-patterns.js +617 -0
- package/plugins/debate/lib/enhance/prompt-analyzer.js +457 -0
- package/plugins/debate/lib/enhance/prompt-patterns.js +1484 -0
- package/plugins/debate/lib/enhance/reporter.js +1348 -0
- package/plugins/debate/lib/enhance/security-patterns.js +284 -0
- package/plugins/debate/lib/enhance/skill-analyzer.js +182 -0
- package/plugins/debate/lib/enhance/skill-patterns.js +147 -0
- package/plugins/debate/lib/enhance/suppression.js +352 -0
- package/plugins/debate/lib/enhance/tool-patterns.js +373 -0
- package/plugins/debate/lib/index.js +270 -0
- package/plugins/debate/lib/patterns/cli-enhancers.js +611 -0
- package/plugins/debate/lib/patterns/pipeline.js +948 -0
- package/plugins/debate/lib/patterns/review-patterns.js +558 -0
- package/plugins/debate/lib/patterns/slop-analyzers.js +2305 -0
- package/plugins/debate/lib/patterns/slop-patterns.js +1187 -0
- package/plugins/debate/lib/perf/analyzer/index.js +22 -0
- package/plugins/debate/lib/perf/argument-parser.js +105 -0
- package/plugins/debate/lib/perf/baseline-comparator.js +50 -0
- package/plugins/debate/lib/perf/baseline-store.js +127 -0
- package/plugins/debate/lib/perf/benchmark-runner.js +404 -0
- package/plugins/debate/lib/perf/breaking-point-finder.js +52 -0
- package/plugins/debate/lib/perf/breaking-point-runner.js +60 -0
- package/plugins/debate/lib/perf/checkpoint.js +123 -0
- package/plugins/debate/lib/perf/code-paths.js +86 -0
- package/plugins/debate/lib/perf/consolidation.js +37 -0
- package/plugins/debate/lib/perf/constraint-runner.js +71 -0
- package/plugins/debate/lib/perf/experiment-runner.js +32 -0
- package/plugins/debate/lib/perf/index.js +41 -0
- package/plugins/debate/lib/perf/investigation-state.js +874 -0
- package/plugins/debate/lib/perf/optimization-runner.js +79 -0
- package/plugins/debate/lib/perf/profilers/go.js +22 -0
- package/plugins/debate/lib/perf/profilers/index.js +46 -0
- package/plugins/debate/lib/perf/profilers/java.js +23 -0
- package/plugins/debate/lib/perf/profilers/node.js +27 -0
- package/plugins/debate/lib/perf/profilers/python.js +23 -0
- package/plugins/debate/lib/perf/profilers/rust.js +23 -0
- package/plugins/debate/lib/perf/profiling-runner.js +75 -0
- package/plugins/debate/lib/perf/schemas.js +140 -0
- package/plugins/debate/lib/platform/detect-platform.js +413 -0
- package/plugins/debate/lib/platform/detection-configs.js +93 -0
- package/plugins/debate/lib/platform/state-dir.js +132 -0
- package/plugins/debate/lib/platform/verify-tools.js +182 -0
- package/plugins/debate/lib/repo-map/cache.js +152 -0
- package/plugins/debate/lib/repo-map/concurrency.js +29 -0
- package/plugins/debate/lib/repo-map/index.js +222 -0
- package/plugins/debate/lib/repo-map/installer.js +212 -0
- package/plugins/debate/lib/repo-map/queries/go.js +27 -0
- package/plugins/debate/lib/repo-map/queries/index.js +100 -0
- package/plugins/debate/lib/repo-map/queries/java.js +38 -0
- package/plugins/debate/lib/repo-map/queries/javascript.js +55 -0
- package/plugins/debate/lib/repo-map/queries/python.js +24 -0
- package/plugins/debate/lib/repo-map/queries/rust.js +73 -0
- package/plugins/debate/lib/repo-map/queries/typescript.js +38 -0
- package/plugins/debate/lib/repo-map/runner.js +1364 -0
- package/plugins/debate/lib/repo-map/updater.js +562 -0
- package/plugins/debate/lib/repo-map/usage-analyzer.js +407 -0
- package/plugins/debate/lib/schemas/plugin-manifest.schema.json +57 -0
- package/plugins/debate/lib/schemas/validator.js +247 -0
- package/plugins/debate/lib/sources/custom-handler.js +199 -0
- package/plugins/debate/lib/sources/policy-questions.js +246 -0
- package/plugins/debate/lib/sources/source-cache.js +165 -0
- package/plugins/debate/lib/state/workflow-state.js +576 -0
- package/plugins/debate/lib/types/agent-frontmatter.d.ts +134 -0
- package/plugins/debate/lib/types/command-frontmatter.d.ts +107 -0
- package/plugins/debate/lib/types/hook-frontmatter.d.ts +115 -0
- package/plugins/debate/lib/types/index.d.ts +84 -0
- package/plugins/debate/lib/types/plugin-manifest.d.ts +102 -0
- package/plugins/debate/lib/types/skill-frontmatter.d.ts +89 -0
- package/plugins/debate/lib/utils/atomic-write.js +94 -0
- package/plugins/debate/lib/utils/cache-manager.js +159 -0
- package/plugins/debate/lib/utils/command-parser.js +0 -0
- package/plugins/debate/lib/utils/context-optimizer.js +300 -0
- package/plugins/debate/lib/utils/deprecation.js +37 -0
- package/plugins/debate/lib/utils/shell-escape.js +88 -0
- package/plugins/debate/lib/utils/state-helpers.js +61 -0
- package/plugins/debate/skills/debate/SKILL.md +264 -0
- package/plugins/deslop/.claude-plugin/plugin.json +1 -1
- package/plugins/deslop/lib/adapter-transforms.js +24 -4
- package/plugins/deslop/skills/deslop/SKILL.md +1 -1
- package/plugins/drift-detect/.claude-plugin/plugin.json +1 -1
- package/plugins/drift-detect/lib/adapter-transforms.js +24 -4
- package/plugins/drift-detect/skills/drift-analysis/SKILL.md +1 -1
- package/plugins/enhance/.claude-plugin/plugin.json +1 -1
- package/plugins/enhance/lib/adapter-transforms.js +24 -4
- 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/agents/learn-agent.md +1 -1
- package/plugins/learn/lib/adapter-transforms.js +24 -4
- package/plugins/learn/skills/learn/SKILL.md +1 -1
- package/plugins/next-task/.claude-plugin/plugin.json +1 -1
- package/plugins/next-task/agents/exploration-agent.md +1 -1
- package/plugins/next-task/lib/adapter-transforms.js +24 -4
- 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/adapter-transforms.js +24 -4
- 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/adapter-transforms.js +24 -4
- package/plugins/ship/.claude-plugin/plugin.json +1 -1
- package/plugins/ship/lib/adapter-transforms.js +24 -4
- package/plugins/sync-docs/.claude-plugin/plugin.json +1 -1
- package/plugins/sync-docs/lib/adapter-transforms.js +24 -4
- package/plugins/sync-docs/skills/sync-docs/SKILL.md +1 -1
- package/scripts/gen-adapters.js +6 -7
- package/scripts/generate-docs.js +4 -2
- package/scripts/plugins.txt +1 -0
- package/site/content.json +6 -6
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Suppression System for /enhance
|
|
3
|
+
* Handles inline comments and config file suppressions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Default suppression config
|
|
11
|
+
*/
|
|
12
|
+
const DEFAULT_CONFIG = {
|
|
13
|
+
ignore: {
|
|
14
|
+
patterns: [],
|
|
15
|
+
files: [],
|
|
16
|
+
rules: {}
|
|
17
|
+
},
|
|
18
|
+
severity: {}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// Maximum config file size (1MB) to prevent DoS via large files
|
|
22
|
+
const MAX_CONFIG_SIZE = 1024 * 1024;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Load suppression config from project root
|
|
26
|
+
* @param {string} projectRoot - Path to project root
|
|
27
|
+
* @returns {Object} Merged config
|
|
28
|
+
*/
|
|
29
|
+
function loadConfig(projectRoot) {
|
|
30
|
+
const configPaths = [
|
|
31
|
+
path.join(projectRoot, '.enhancerc.json'),
|
|
32
|
+
path.join(projectRoot, '.enhancerc'),
|
|
33
|
+
path.join(projectRoot, 'enhance.config.json')
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
for (const configPath of configPaths) {
|
|
37
|
+
if (fs.existsSync(configPath)) {
|
|
38
|
+
try {
|
|
39
|
+
// Check file size before reading to prevent DoS
|
|
40
|
+
const stats = fs.statSync(configPath);
|
|
41
|
+
if (stats.size > MAX_CONFIG_SIZE) {
|
|
42
|
+
console.error(`[WARN] Config file too large (${stats.size} bytes), using defaults`);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const content = fs.readFileSync(configPath, 'utf8');
|
|
46
|
+
const userConfig = JSON.parse(content);
|
|
47
|
+
return mergeConfig(DEFAULT_CONFIG, userConfig);
|
|
48
|
+
} catch (err) {
|
|
49
|
+
// Invalid config, use defaults
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return DEFAULT_CONFIG;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Merge user config with defaults
|
|
59
|
+
* @param {Object} defaults - Default config
|
|
60
|
+
* @param {Object} user - User config
|
|
61
|
+
* @returns {Object} Merged config
|
|
62
|
+
*/
|
|
63
|
+
function mergeConfig(defaults, user) {
|
|
64
|
+
return {
|
|
65
|
+
ignore: {
|
|
66
|
+
patterns: [...(defaults.ignore.patterns || []), ...(user.ignore?.patterns || [])],
|
|
67
|
+
files: [...(defaults.ignore.files || []), ...(user.ignore?.files || [])],
|
|
68
|
+
rules: { ...(defaults.ignore.rules || {}), ...(user.ignore?.rules || {}) }
|
|
69
|
+
},
|
|
70
|
+
severity: { ...(defaults.severity || {}), ...(user.severity || {}) }
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Extract inline suppressions from content
|
|
76
|
+
* Supports:
|
|
77
|
+
* - <!-- enhance:ignore pattern_id -->
|
|
78
|
+
* - // enhance:ignore pattern_id
|
|
79
|
+
* - # enhance:ignore pattern_id
|
|
80
|
+
*
|
|
81
|
+
* @param {string} content - File content
|
|
82
|
+
* @returns {Set<string>} Set of suppressed pattern IDs
|
|
83
|
+
*/
|
|
84
|
+
function extractInlineSuppressions(content) {
|
|
85
|
+
if (!content || typeof content !== 'string') return new Set();
|
|
86
|
+
|
|
87
|
+
const suppressions = new Set();
|
|
88
|
+
|
|
89
|
+
// HTML/Markdown comments
|
|
90
|
+
const htmlPattern = /<!--\s*enhance:ignore\s+(\S+)\s*-->/gi;
|
|
91
|
+
let match;
|
|
92
|
+
while ((match = htmlPattern.exec(content)) !== null) {
|
|
93
|
+
suppressions.add(match[1].toLowerCase());
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// JS/TS comments
|
|
97
|
+
const jsPattern = /\/\/\s*enhance:ignore\s+(\S+)/gi;
|
|
98
|
+
while ((match = jsPattern.exec(content)) !== null) {
|
|
99
|
+
suppressions.add(match[1].toLowerCase());
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Python/Shell comments
|
|
103
|
+
const pyPattern = /#\s*enhance:ignore\s+(\S+)/gi;
|
|
104
|
+
while ((match = pyPattern.exec(content)) !== null) {
|
|
105
|
+
suppressions.add(match[1].toLowerCase());
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return suppressions;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Check if a finding should be suppressed
|
|
113
|
+
* @param {Object} finding - The finding to check
|
|
114
|
+
* @param {Object} config - Suppression config
|
|
115
|
+
* @param {Set<string>} inlineSuppressions - Inline suppressions for this file
|
|
116
|
+
* @param {string} filePath - Path to file being analyzed
|
|
117
|
+
* @param {string} projectRoot - Project root path
|
|
118
|
+
* @returns {Object|null} Suppression info if suppressed, null otherwise
|
|
119
|
+
*/
|
|
120
|
+
function shouldSuppress(finding, config, inlineSuppressions, filePath, projectRoot) {
|
|
121
|
+
const patternId = (finding.patternId || finding.id || '').toLowerCase();
|
|
122
|
+
|
|
123
|
+
// Check inline suppressions
|
|
124
|
+
if (inlineSuppressions.has(patternId)) {
|
|
125
|
+
return {
|
|
126
|
+
reason: 'inline',
|
|
127
|
+
patternId,
|
|
128
|
+
source: 'inline comment'
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Check config pattern suppressions
|
|
133
|
+
if (config.ignore.patterns.includes(patternId)) {
|
|
134
|
+
return {
|
|
135
|
+
reason: 'config',
|
|
136
|
+
patternId,
|
|
137
|
+
source: 'config: ignore.patterns'
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Check config rule suppressions
|
|
142
|
+
const ruleConfig = config.ignore.rules[patternId];
|
|
143
|
+
if (ruleConfig) {
|
|
144
|
+
if (ruleConfig.severity === 'off' || ruleConfig === 'off') {
|
|
145
|
+
return {
|
|
146
|
+
reason: 'config',
|
|
147
|
+
patternId,
|
|
148
|
+
source: `config: ignore.rules.${patternId}`,
|
|
149
|
+
userReason: ruleConfig.reason
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Check file pattern suppressions
|
|
155
|
+
if (filePath && projectRoot) {
|
|
156
|
+
const relativePath = path.relative(projectRoot, filePath).replace(/\\/g, '/');
|
|
157
|
+
for (const filePattern of config.ignore.files) {
|
|
158
|
+
if (matchGlob(relativePath, filePattern)) {
|
|
159
|
+
return {
|
|
160
|
+
reason: 'config',
|
|
161
|
+
patternId,
|
|
162
|
+
source: `config: ignore.files (${filePattern})`
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Check auto-learned suppressions
|
|
169
|
+
if (config.auto_learned?.patterns?.[patternId]) {
|
|
170
|
+
const autoRule = config.auto_learned.patterns[patternId];
|
|
171
|
+
const relativePath = filePath && projectRoot
|
|
172
|
+
? path.relative(projectRoot, filePath).replace(/\\/g, '/')
|
|
173
|
+
: filePath;
|
|
174
|
+
|
|
175
|
+
// Check if this file is in the auto-learned list
|
|
176
|
+
const fileMatch = autoRule.files?.some(f => {
|
|
177
|
+
// Support both exact match and glob patterns
|
|
178
|
+
if (f === relativePath || f === filePath) return true;
|
|
179
|
+
return matchGlob(relativePath || '', f);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
if (fileMatch) {
|
|
183
|
+
return {
|
|
184
|
+
reason: 'auto_learned',
|
|
185
|
+
patternId,
|
|
186
|
+
source: 'auto-learned suppression',
|
|
187
|
+
confidence: autoRule.confidence,
|
|
188
|
+
note: autoRule.reason
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Simple glob matching (supports * and **)
|
|
198
|
+
* @param {string} filePath - File path to match
|
|
199
|
+
* @param {string} pattern - Glob pattern
|
|
200
|
+
* @returns {boolean} True if matches
|
|
201
|
+
*/
|
|
202
|
+
function matchGlob(filePath, pattern) {
|
|
203
|
+
// Convert glob to regex
|
|
204
|
+
// First escape backslashes, then other special regex chars, then convert glob patterns
|
|
205
|
+
const regexStr = pattern
|
|
206
|
+
.replace(/\\/g, '\\\\')
|
|
207
|
+
.replace(/\./g, '\\.')
|
|
208
|
+
.replace(/\*\*/g, '.*')
|
|
209
|
+
.replace(/\*/g, '[^/]*');
|
|
210
|
+
|
|
211
|
+
const regex = new RegExp(`^${regexStr}$`);
|
|
212
|
+
return regex.test(filePath);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Apply severity overrides from config
|
|
217
|
+
* @param {Object} finding - Finding to check
|
|
218
|
+
* @param {Object} config - Suppression config
|
|
219
|
+
* @returns {string} Adjusted certainty level
|
|
220
|
+
*/
|
|
221
|
+
function applySeverityOverride(finding, config) {
|
|
222
|
+
const patternId = (finding.patternId || finding.id || '').toLowerCase();
|
|
223
|
+
|
|
224
|
+
// Check config severity overrides
|
|
225
|
+
if (config.severity[patternId]) {
|
|
226
|
+
const override = config.severity[patternId];
|
|
227
|
+
if (['HIGH', 'MEDIUM', 'LOW'].includes(override.toUpperCase())) {
|
|
228
|
+
return override.toUpperCase();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Check rule-level severity
|
|
233
|
+
const ruleConfig = config.ignore.rules[patternId];
|
|
234
|
+
if (ruleConfig && ruleConfig.severity && ruleConfig.severity !== 'off') {
|
|
235
|
+
if (['HIGH', 'MEDIUM', 'LOW'].includes(ruleConfig.severity.toUpperCase())) {
|
|
236
|
+
return ruleConfig.severity.toUpperCase();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return finding.certainty;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Filter findings with suppression tracking
|
|
245
|
+
* @param {Array} findings - All findings
|
|
246
|
+
* @param {Object} config - Suppression config
|
|
247
|
+
* @param {string} projectRoot - Project root path
|
|
248
|
+
* @param {Map<string, string>} fileContents - Map of file path to content (for inline suppression extraction)
|
|
249
|
+
* @returns {Object} { active: [], suppressed: [] }
|
|
250
|
+
*/
|
|
251
|
+
function filterFindings(findings, config, projectRoot, fileContents = new Map()) {
|
|
252
|
+
const active = [];
|
|
253
|
+
const suppressed = [];
|
|
254
|
+
|
|
255
|
+
// Cache inline suppressions per file
|
|
256
|
+
const inlineSuppressionsCache = new Map();
|
|
257
|
+
|
|
258
|
+
for (const finding of findings) {
|
|
259
|
+
const filePath = finding.file || finding.filePath;
|
|
260
|
+
|
|
261
|
+
// Get inline suppressions for this file
|
|
262
|
+
let inlineSuppressions;
|
|
263
|
+
if (inlineSuppressionsCache.has(filePath)) {
|
|
264
|
+
inlineSuppressions = inlineSuppressionsCache.get(filePath);
|
|
265
|
+
} else {
|
|
266
|
+
const content = fileContents.get(filePath);
|
|
267
|
+
inlineSuppressions = content ? extractInlineSuppressions(content) : new Set();
|
|
268
|
+
inlineSuppressionsCache.set(filePath, inlineSuppressions);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Check if suppressed
|
|
272
|
+
const suppression = shouldSuppress(finding, config, inlineSuppressions, filePath, projectRoot);
|
|
273
|
+
|
|
274
|
+
if (suppression) {
|
|
275
|
+
suppressed.push({
|
|
276
|
+
...finding,
|
|
277
|
+
reason: suppression.reason,
|
|
278
|
+
confidence: suppression.confidence,
|
|
279
|
+
note: suppression.note,
|
|
280
|
+
suppression
|
|
281
|
+
});
|
|
282
|
+
} else {
|
|
283
|
+
// Apply severity override
|
|
284
|
+
const adjustedCertainty = applySeverityOverride(finding, config);
|
|
285
|
+
active.push({
|
|
286
|
+
...finding,
|
|
287
|
+
certainty: adjustedCertainty,
|
|
288
|
+
originalCertainty: finding.certainty !== adjustedCertainty ? finding.certainty : undefined
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return { active, suppressed };
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Generate suppression summary for report
|
|
298
|
+
* @param {Array} suppressed - Suppressed findings
|
|
299
|
+
* @returns {string} Summary markdown
|
|
300
|
+
*/
|
|
301
|
+
function generateSuppressionSummary(suppressed) {
|
|
302
|
+
if (!suppressed || suppressed.length === 0) {
|
|
303
|
+
return '';
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const lines = [];
|
|
307
|
+
lines.push('## Suppressed Findings');
|
|
308
|
+
lines.push('');
|
|
309
|
+
lines.push(`**${suppressed.length} findings suppressed**`);
|
|
310
|
+
lines.push('');
|
|
311
|
+
|
|
312
|
+
// Group by suppression source
|
|
313
|
+
const bySource = {};
|
|
314
|
+
for (const finding of suppressed) {
|
|
315
|
+
const source = finding.suppression?.source || 'unknown';
|
|
316
|
+
if (!bySource[source]) bySource[source] = [];
|
|
317
|
+
bySource[source].push(finding);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
lines.push('| Source | Pattern | Count |');
|
|
321
|
+
lines.push('|--------|---------|-------|');
|
|
322
|
+
|
|
323
|
+
for (const [source, findings] of Object.entries(bySource)) {
|
|
324
|
+
// Group by pattern within source
|
|
325
|
+
const byPattern = {};
|
|
326
|
+
for (const f of findings) {
|
|
327
|
+
const pattern = f.suppression?.patternId || 'unknown';
|
|
328
|
+
byPattern[pattern] = (byPattern[pattern] || 0) + 1;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
for (const [pattern, count] of Object.entries(byPattern)) {
|
|
332
|
+
lines.push(`| ${source} | ${pattern} | ${count} |`);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
lines.push('');
|
|
337
|
+
lines.push('*Use `--show-suppressed` to see full details*');
|
|
338
|
+
lines.push('');
|
|
339
|
+
|
|
340
|
+
return lines.join('\n');
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
module.exports = {
|
|
344
|
+
loadConfig,
|
|
345
|
+
extractInlineSuppressions,
|
|
346
|
+
shouldSuppress,
|
|
347
|
+
applySeverityOverride,
|
|
348
|
+
filterFindings,
|
|
349
|
+
generateSuppressionSummary,
|
|
350
|
+
matchGlob,
|
|
351
|
+
DEFAULT_CONFIG
|
|
352
|
+
};
|