agentsys 5.0.2 → 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 +24 -1
- 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 +133 -59
- 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 +123 -31
- 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 +134 -59
- 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 +41 -27
- 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 +123 -30
- package/plugins/consult/commands/consult.md +136 -60
- package/plugins/consult/skills/consult/SKILL.md +39 -24
- 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,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook analyzer for /enhance.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const { hookPatterns } = require('./hook-patterns');
|
|
8
|
+
const { parseMarkdownFrontmatter } = require('./agent-analyzer');
|
|
9
|
+
|
|
10
|
+
function analyzeHook(hookPath) {
|
|
11
|
+
const results = {
|
|
12
|
+
hookName: path.basename(hookPath, '.md'),
|
|
13
|
+
hookPath,
|
|
14
|
+
structureIssues: []
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
if (!fs.existsSync(hookPath)) {
|
|
18
|
+
results.structureIssues.push({
|
|
19
|
+
issue: 'File not found',
|
|
20
|
+
file: hookPath,
|
|
21
|
+
certainty: 'HIGH',
|
|
22
|
+
patternId: 'file_not_found'
|
|
23
|
+
});
|
|
24
|
+
return results;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let content = '';
|
|
28
|
+
try {
|
|
29
|
+
content = fs.readFileSync(hookPath, 'utf8');
|
|
30
|
+
} catch (err) {
|
|
31
|
+
results.structureIssues.push({
|
|
32
|
+
issue: `Failed to read file: ${err.message}`,
|
|
33
|
+
file: hookPath,
|
|
34
|
+
certainty: 'HIGH',
|
|
35
|
+
patternId: 'read_error'
|
|
36
|
+
});
|
|
37
|
+
return results;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const missingFm = hookPatterns.missing_frontmatter.check(content);
|
|
41
|
+
if (missingFm) {
|
|
42
|
+
results.structureIssues.push({
|
|
43
|
+
...missingFm,
|
|
44
|
+
file: hookPath,
|
|
45
|
+
certainty: hookPatterns.missing_frontmatter.certainty,
|
|
46
|
+
patternId: hookPatterns.missing_frontmatter.id
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const { frontmatter } = parseMarkdownFrontmatter(content);
|
|
51
|
+
const missingName = hookPatterns.missing_name.check(frontmatter);
|
|
52
|
+
if (missingName) {
|
|
53
|
+
results.structureIssues.push({
|
|
54
|
+
...missingName,
|
|
55
|
+
file: hookPath,
|
|
56
|
+
certainty: hookPatterns.missing_name.certainty,
|
|
57
|
+
patternId: hookPatterns.missing_name.id
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const missingDescription = hookPatterns.missing_description.check(frontmatter);
|
|
62
|
+
if (missingDescription) {
|
|
63
|
+
results.structureIssues.push({
|
|
64
|
+
...missingDescription,
|
|
65
|
+
file: hookPath,
|
|
66
|
+
certainty: hookPatterns.missing_description.certainty,
|
|
67
|
+
patternId: hookPatterns.missing_description.id
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return results;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function analyzeAllHooks(hooksDir) {
|
|
75
|
+
const results = [];
|
|
76
|
+
if (!fs.existsSync(hooksDir)) return results;
|
|
77
|
+
|
|
78
|
+
const hookFiles = [];
|
|
79
|
+
const skipDirs = new Set(['node_modules', '.git', 'dist', 'build', 'out', 'target']);
|
|
80
|
+
|
|
81
|
+
function walk(dir) {
|
|
82
|
+
let entries;
|
|
83
|
+
try {
|
|
84
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
85
|
+
} catch (err) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
for (const entry of entries) {
|
|
90
|
+
const fullPath = path.join(dir, entry.name);
|
|
91
|
+
if (entry.isDirectory()) {
|
|
92
|
+
if (!skipDirs.has(entry.name)) {
|
|
93
|
+
walk(fullPath);
|
|
94
|
+
}
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (!entry.isFile() || !entry.name.endsWith('.md')) continue;
|
|
99
|
+
const parts = fullPath.split(path.sep);
|
|
100
|
+
if (parts.includes('hooks')) {
|
|
101
|
+
hookFiles.push(fullPath);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
walk(hooksDir);
|
|
107
|
+
|
|
108
|
+
for (const file of hookFiles) {
|
|
109
|
+
results.push(analyzeHook(file));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return results;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function analyze(options = {}) {
|
|
116
|
+
const {
|
|
117
|
+
hook,
|
|
118
|
+
hooksDir = 'plugins/enhance/hooks'
|
|
119
|
+
} = options;
|
|
120
|
+
|
|
121
|
+
if (hook) {
|
|
122
|
+
const hookPath = hook.endsWith('.md')
|
|
123
|
+
? hook
|
|
124
|
+
: path.join(hooksDir, `${hook}.md`);
|
|
125
|
+
return analyzeHook(hookPath);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return analyzeAllHooks(hooksDir);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
module.exports = {
|
|
132
|
+
analyzeHook,
|
|
133
|
+
analyzeAllHooks,
|
|
134
|
+
analyze
|
|
135
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook patterns for /enhance.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const hookPatterns = {
|
|
6
|
+
missing_frontmatter: {
|
|
7
|
+
id: 'missing_frontmatter',
|
|
8
|
+
certainty: 'HIGH',
|
|
9
|
+
check(content) {
|
|
10
|
+
if (!content || !content.trim().startsWith('---')) {
|
|
11
|
+
return { issue: 'Missing YAML frontmatter in hook file' };
|
|
12
|
+
}
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
missing_name: {
|
|
17
|
+
id: 'missing_name',
|
|
18
|
+
certainty: 'HIGH',
|
|
19
|
+
check(frontmatter) {
|
|
20
|
+
if (!frontmatter || !frontmatter.name) {
|
|
21
|
+
return { issue: 'Missing name in hook frontmatter' };
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
missing_description: {
|
|
27
|
+
id: 'missing_description',
|
|
28
|
+
certainty: 'HIGH',
|
|
29
|
+
check(frontmatter) {
|
|
30
|
+
if (!frontmatter || !frontmatter.description) {
|
|
31
|
+
return { issue: 'Missing description in hook frontmatter' };
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
module.exports = {
|
|
39
|
+
hookPatterns
|
|
40
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
const pluginAnalyzer = require('./plugin-analyzer');
|
|
2
|
+
const pluginPatterns = require('./plugin-patterns');
|
|
3
|
+
const toolPatterns = require('./tool-patterns');
|
|
4
|
+
const securityPatterns = require('./security-patterns');
|
|
5
|
+
const agentAnalyzer = require('./agent-analyzer');
|
|
6
|
+
const agentPatterns = require('./agent-patterns');
|
|
7
|
+
const docsAnalyzer = require('./docs-analyzer');
|
|
8
|
+
const docsPatterns = require('./docs-patterns');
|
|
9
|
+
const projectmemoryAnalyzer = require('./projectmemory-analyzer');
|
|
10
|
+
const projectmemoryPatterns = require('./projectmemory-patterns');
|
|
11
|
+
const promptAnalyzer = require('./prompt-analyzer');
|
|
12
|
+
const promptPatterns = require('./prompt-patterns');
|
|
13
|
+
const hookAnalyzer = require('./hook-analyzer');
|
|
14
|
+
const skillAnalyzer = require('./skill-analyzer');
|
|
15
|
+
const crossFileAnalyzer = require('./cross-file-analyzer');
|
|
16
|
+
const crossFilePatterns = require('./cross-file-patterns');
|
|
17
|
+
const reporter = require('./reporter');
|
|
18
|
+
const fixer = require('./fixer');
|
|
19
|
+
const suppression = require('./suppression');
|
|
20
|
+
const autoSuppression = require('./auto-suppression');
|
|
21
|
+
const benchmark = require('./benchmark');
|
|
22
|
+
|
|
23
|
+
module.exports = {
|
|
24
|
+
// Main analyzers
|
|
25
|
+
pluginAnalyzer,
|
|
26
|
+
agentAnalyzer,
|
|
27
|
+
docsAnalyzer,
|
|
28
|
+
projectmemoryAnalyzer,
|
|
29
|
+
promptAnalyzer,
|
|
30
|
+
hookAnalyzer,
|
|
31
|
+
skillAnalyzer,
|
|
32
|
+
crossFileAnalyzer,
|
|
33
|
+
|
|
34
|
+
// Pattern modules
|
|
35
|
+
pluginPatterns,
|
|
36
|
+
toolPatterns,
|
|
37
|
+
securityPatterns,
|
|
38
|
+
agentPatterns,
|
|
39
|
+
docsPatterns,
|
|
40
|
+
projectmemoryPatterns,
|
|
41
|
+
promptPatterns,
|
|
42
|
+
crossFilePatterns,
|
|
43
|
+
|
|
44
|
+
// Output modules
|
|
45
|
+
reporter,
|
|
46
|
+
fixer,
|
|
47
|
+
suppression,
|
|
48
|
+
autoSuppression,
|
|
49
|
+
benchmark,
|
|
50
|
+
|
|
51
|
+
// Convenience exports - Plugin
|
|
52
|
+
analyze: pluginAnalyzer.analyze,
|
|
53
|
+
analyzePlugin: pluginAnalyzer.analyzePlugin,
|
|
54
|
+
analyzeAllPlugins: pluginAnalyzer.analyzeAllPlugins,
|
|
55
|
+
applyFixes: pluginAnalyzer.applyFixes,
|
|
56
|
+
generateReport: pluginAnalyzer.generateReport,
|
|
57
|
+
|
|
58
|
+
// Convenience exports - Agent
|
|
59
|
+
analyzeAgent: agentAnalyzer.analyzeAgent,
|
|
60
|
+
analyzeAllAgents: agentAnalyzer.analyzeAllAgents,
|
|
61
|
+
agentApplyFixes: agentAnalyzer.applyFixes,
|
|
62
|
+
agentGenerateReport: agentAnalyzer.generateReport,
|
|
63
|
+
|
|
64
|
+
// Convenience exports - Docs
|
|
65
|
+
analyzeDoc: docsAnalyzer.analyzeDoc,
|
|
66
|
+
analyzeAllDocs: docsAnalyzer.analyzeAllDocs,
|
|
67
|
+
docsApplyFixes: docsAnalyzer.applyFixes,
|
|
68
|
+
docsGenerateReport: docsAnalyzer.generateReport,
|
|
69
|
+
|
|
70
|
+
// Convenience exports - Project Memory (CLAUDE.md/AGENTS.md)
|
|
71
|
+
analyzeProjectMemory: projectmemoryAnalyzer.analyze,
|
|
72
|
+
analyzeClaudeMd: projectmemoryAnalyzer.analyze, // Alias for familiarity
|
|
73
|
+
findProjectMemoryFile: projectmemoryAnalyzer.findProjectMemoryFile,
|
|
74
|
+
projectMemoryApplyFixes: projectmemoryAnalyzer.applyFixes,
|
|
75
|
+
projectMemoryGenerateReport: projectmemoryAnalyzer.generateReport,
|
|
76
|
+
|
|
77
|
+
// Convenience exports - Prompt
|
|
78
|
+
analyzePrompt: promptAnalyzer.analyzePrompt,
|
|
79
|
+
analyzeAllPrompts: promptAnalyzer.analyzeAllPrompts,
|
|
80
|
+
promptApplyFixes: promptAnalyzer.applyFixes,
|
|
81
|
+
promptGenerateReport: promptAnalyzer.generateReport,
|
|
82
|
+
|
|
83
|
+
// Convenience exports - Hooks
|
|
84
|
+
analyzeHook: hookAnalyzer.analyzeHook,
|
|
85
|
+
analyzeAllHooks: hookAnalyzer.analyzeAllHooks,
|
|
86
|
+
hooksAnalyze: hookAnalyzer.analyze,
|
|
87
|
+
|
|
88
|
+
// Convenience exports - Skills
|
|
89
|
+
analyzeSkill: skillAnalyzer.analyzeSkill,
|
|
90
|
+
analyzeAllSkills: skillAnalyzer.analyzeAllSkills,
|
|
91
|
+
skillsAnalyze: skillAnalyzer.analyze,
|
|
92
|
+
|
|
93
|
+
// Convenience exports - Cross-File Analysis
|
|
94
|
+
analyzeCrossFile: crossFileAnalyzer.analyze,
|
|
95
|
+
analyzeToolConsistency: crossFileAnalyzer.analyzeToolConsistency,
|
|
96
|
+
analyzeWorkflowCompleteness: crossFileAnalyzer.analyzeWorkflowCompleteness,
|
|
97
|
+
analyzePromptConsistency: crossFileAnalyzer.analyzePromptConsistency,
|
|
98
|
+
analyzeSkillAlignment: crossFileAnalyzer.analyzeSkillAlignment,
|
|
99
|
+
loadKnownTools: crossFilePatterns.loadKnownTools,
|
|
100
|
+
|
|
101
|
+
// Convenience exports - Orchestrator
|
|
102
|
+
generateOrchestratorReport: reporter.generateOrchestratorReport,
|
|
103
|
+
deduplicateOrchestratorFindings: reporter.deduplicateOrchestratorFindings,
|
|
104
|
+
|
|
105
|
+
// Convenience exports - Suppression
|
|
106
|
+
loadSuppressionConfig: suppression.loadConfig,
|
|
107
|
+
filterFindings: suppression.filterFindings,
|
|
108
|
+
extractInlineSuppressions: suppression.extractInlineSuppressions,
|
|
109
|
+
generateSuppressionSummary: suppression.generateSuppressionSummary,
|
|
110
|
+
|
|
111
|
+
// Convenience exports - Auto-Suppression
|
|
112
|
+
isLikelyFalsePositive: autoSuppression.isLikelyFalsePositive,
|
|
113
|
+
getProjectId: autoSuppression.getProjectId,
|
|
114
|
+
loadAutoSuppressions: autoSuppression.loadAutoSuppressions,
|
|
115
|
+
saveAutoSuppressions: autoSuppression.saveAutoSuppressions,
|
|
116
|
+
clearAutoSuppressions: autoSuppression.clearAutoSuppressions,
|
|
117
|
+
mergeSuppressions: autoSuppression.mergeSuppressions,
|
|
118
|
+
analyzeForAutoSuppression: autoSuppression.analyzeForAutoSuppression,
|
|
119
|
+
exportAutoSuppressions: autoSuppression.exportAutoSuppressions,
|
|
120
|
+
importAutoSuppressions: autoSuppression.importAutoSuppressions,
|
|
121
|
+
|
|
122
|
+
// Convenience exports - Benchmark
|
|
123
|
+
runPatternBenchmarks: benchmark.runPatternBenchmarks,
|
|
124
|
+
runFixBenchmarks: benchmark.runFixBenchmarks,
|
|
125
|
+
generateBenchmarkReport: benchmark.generateReport,
|
|
126
|
+
assertBenchmarkThresholds: benchmark.assertThresholds
|
|
127
|
+
};
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Analyzer
|
|
3
|
+
* Main orchestrator for plugin structure and tool use analysis
|
|
4
|
+
*
|
|
5
|
+
* @author Avi Fenesh
|
|
6
|
+
* @license MIT
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const pluginPatterns = require('./plugin-patterns');
|
|
12
|
+
const toolPatterns = require('./tool-patterns');
|
|
13
|
+
const securityPatterns = require('./security-patterns');
|
|
14
|
+
const reporter = require('./reporter');
|
|
15
|
+
const fixer = require('./fixer');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Find nearest package.json by walking up directory tree
|
|
19
|
+
* @param {string} startPath - Starting directory path
|
|
20
|
+
* @param {number} maxLevels - Maximum levels to traverse (default: 5)
|
|
21
|
+
* @returns {string|null} Path to package.json or null if not found
|
|
22
|
+
*/
|
|
23
|
+
function findNearestPackageJson(startPath, maxLevels = 5) {
|
|
24
|
+
let currentPath = path.resolve(startPath);
|
|
25
|
+
|
|
26
|
+
for (let i = 0; i < maxLevels; i++) {
|
|
27
|
+
const packageJsonPath = path.join(currentPath, 'package.json');
|
|
28
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
29
|
+
return packageJsonPath;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const parentPath = path.dirname(currentPath);
|
|
33
|
+
if (parentPath === currentPath) {
|
|
34
|
+
// Reached root
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
currentPath = parentPath;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Analyze a single plugin
|
|
45
|
+
* @param {string} pluginPath - Path to plugin directory
|
|
46
|
+
* @param {Object} options - Analysis options
|
|
47
|
+
* @param {boolean} options.verbose - Include LOW certainty issues
|
|
48
|
+
* @returns {Object} Analysis results
|
|
49
|
+
*/
|
|
50
|
+
async function analyzePlugin(pluginPath, options = {}) {
|
|
51
|
+
const results = {
|
|
52
|
+
pluginName: path.basename(pluginPath),
|
|
53
|
+
pluginPath,
|
|
54
|
+
filesScanned: 0,
|
|
55
|
+
toolIssues: [],
|
|
56
|
+
structureIssues: [],
|
|
57
|
+
securityIssues: []
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Find plugin.json
|
|
61
|
+
const pluginJsonPath = path.join(pluginPath, '.claude-plugin', 'plugin.json');
|
|
62
|
+
const altPluginJsonPath = path.join(pluginPath, 'plugin.json');
|
|
63
|
+
|
|
64
|
+
let pluginJson = null;
|
|
65
|
+
let pluginJsonFile = null;
|
|
66
|
+
|
|
67
|
+
if (fs.existsSync(pluginJsonPath)) {
|
|
68
|
+
try {
|
|
69
|
+
pluginJson = JSON.parse(fs.readFileSync(pluginJsonPath, 'utf8'));
|
|
70
|
+
pluginJsonFile = pluginJsonPath;
|
|
71
|
+
results.filesScanned++;
|
|
72
|
+
} catch (err) {
|
|
73
|
+
results.structureIssues.push({
|
|
74
|
+
issue: 'Failed to parse plugin.json',
|
|
75
|
+
file: pluginJsonPath,
|
|
76
|
+
detail: err.message,
|
|
77
|
+
certainty: 'HIGH',
|
|
78
|
+
patternId: 'malformed_plugin_json'
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
} else if (fs.existsSync(altPluginJsonPath)) {
|
|
82
|
+
try {
|
|
83
|
+
pluginJson = JSON.parse(fs.readFileSync(altPluginJsonPath, 'utf8'));
|
|
84
|
+
pluginJsonFile = altPluginJsonPath;
|
|
85
|
+
results.filesScanned++;
|
|
86
|
+
} catch (err) {
|
|
87
|
+
results.structureIssues.push({
|
|
88
|
+
issue: 'Failed to parse plugin.json',
|
|
89
|
+
file: altPluginJsonPath,
|
|
90
|
+
detail: err.message,
|
|
91
|
+
certainty: 'HIGH',
|
|
92
|
+
patternId: 'malformed_plugin_json'
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Check package.json for version comparison (walk up to find it)
|
|
98
|
+
const packageJsonPath = findNearestPackageJson(pluginPath);
|
|
99
|
+
let packageJson = null;
|
|
100
|
+
if (packageJsonPath) {
|
|
101
|
+
try {
|
|
102
|
+
packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
103
|
+
} catch (err) {
|
|
104
|
+
// Non-critical - version comparison will just be skipped
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Analyze plugin.json structure
|
|
109
|
+
if (pluginJson) {
|
|
110
|
+
results.pluginName = pluginJson.name || results.pluginName;
|
|
111
|
+
|
|
112
|
+
// Check required fields
|
|
113
|
+
const reqFieldsPattern = pluginPatterns.pluginPatterns.missing_required_plugin_fields;
|
|
114
|
+
const reqResult = reqFieldsPattern.check(pluginJson);
|
|
115
|
+
if (reqResult) {
|
|
116
|
+
results.structureIssues.push({
|
|
117
|
+
...reqResult,
|
|
118
|
+
file: pluginJsonFile,
|
|
119
|
+
certainty: reqFieldsPattern.certainty,
|
|
120
|
+
patternId: reqFieldsPattern.id
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Check version format
|
|
125
|
+
const versionPattern = pluginPatterns.pluginPatterns.invalid_version_format;
|
|
126
|
+
const versionResult = versionPattern.check(pluginJson);
|
|
127
|
+
if (versionResult) {
|
|
128
|
+
results.structureIssues.push({
|
|
129
|
+
...versionResult,
|
|
130
|
+
file: pluginJsonFile,
|
|
131
|
+
certainty: versionPattern.certainty,
|
|
132
|
+
patternId: versionPattern.id
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Check version mismatch
|
|
137
|
+
if (packageJson) {
|
|
138
|
+
const mismatchPattern = pluginPatterns.pluginPatterns.version_mismatch;
|
|
139
|
+
const mismatchResult = mismatchPattern.check(pluginJson, packageJson);
|
|
140
|
+
if (mismatchResult) {
|
|
141
|
+
results.structureIssues.push({
|
|
142
|
+
...mismatchResult,
|
|
143
|
+
file: pluginJsonFile,
|
|
144
|
+
filePath: pluginJsonFile,
|
|
145
|
+
certainty: mismatchPattern.certainty,
|
|
146
|
+
patternId: mismatchPattern.id,
|
|
147
|
+
autoFixFn: (pj) => fixer.fixVersionMismatch(pj, packageJson.version)
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Check tool overexposure
|
|
153
|
+
const overexposurePattern = pluginPatterns.pluginPatterns.tool_overexposure;
|
|
154
|
+
const overexposureResult = overexposurePattern.check(pluginJson);
|
|
155
|
+
if (overexposureResult && (options.verbose || overexposurePattern.certainty !== 'LOW')) {
|
|
156
|
+
results.structureIssues.push({
|
|
157
|
+
...overexposureResult,
|
|
158
|
+
file: pluginJsonFile,
|
|
159
|
+
certainty: overexposurePattern.certainty,
|
|
160
|
+
patternId: overexposurePattern.id
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Analyze commands
|
|
165
|
+
if (pluginJson.commands) {
|
|
166
|
+
for (let idx = 0; idx < pluginJson.commands.length; idx++) {
|
|
167
|
+
const cmd = pluginJson.commands[idx];
|
|
168
|
+
const cmdIssues = analyzeCommand(cmd, pluginJsonFile, idx);
|
|
169
|
+
results.toolIssues.push(...cmdIssues);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Analyze agent files
|
|
175
|
+
const agentsDir = path.join(pluginPath, 'agents');
|
|
176
|
+
if (fs.existsSync(agentsDir)) {
|
|
177
|
+
const agentFiles = fs.readdirSync(agentsDir).filter(f => f.endsWith('.md'));
|
|
178
|
+
|
|
179
|
+
for (const agentFile of agentFiles) {
|
|
180
|
+
const agentPath = path.join(agentsDir, agentFile);
|
|
181
|
+
const content = fs.readFileSync(agentPath, 'utf8');
|
|
182
|
+
results.filesScanned++;
|
|
183
|
+
|
|
184
|
+
// Security checks
|
|
185
|
+
const secIssues = securityPatterns.checkSecurity(content, agentPath);
|
|
186
|
+
results.securityIssues.push(...secIssues.map(i => ({
|
|
187
|
+
...i,
|
|
188
|
+
file: agentPath
|
|
189
|
+
})));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Analyze command files
|
|
194
|
+
const commandsDir = path.join(pluginPath, 'commands');
|
|
195
|
+
if (fs.existsSync(commandsDir)) {
|
|
196
|
+
const commandFiles = fs.readdirSync(commandsDir).filter(f => f.endsWith('.md'));
|
|
197
|
+
|
|
198
|
+
for (const cmdFile of commandFiles) {
|
|
199
|
+
const cmdPath = path.join(commandsDir, cmdFile);
|
|
200
|
+
const content = fs.readFileSync(cmdPath, 'utf8');
|
|
201
|
+
results.filesScanned++;
|
|
202
|
+
|
|
203
|
+
// Security checks
|
|
204
|
+
const secIssues = securityPatterns.checkSecurity(content, cmdPath);
|
|
205
|
+
results.securityIssues.push(...secIssues.map(i => ({
|
|
206
|
+
...i,
|
|
207
|
+
file: cmdPath
|
|
208
|
+
})));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return results;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Analyze a command definition
|
|
217
|
+
* @private
|
|
218
|
+
* @param {Object} cmd - Command definition
|
|
219
|
+
* @param {string} filePath - Path to plugin.json
|
|
220
|
+
* @param {number} cmdIndex - Index of command in commands array
|
|
221
|
+
*/
|
|
222
|
+
function analyzeCommand(cmd, filePath, cmdIndex) {
|
|
223
|
+
const issues = [];
|
|
224
|
+
|
|
225
|
+
// Check description
|
|
226
|
+
const descPattern = pluginPatterns.pluginPatterns.missing_tool_description;
|
|
227
|
+
const descResult = descPattern.check(cmd);
|
|
228
|
+
if (descResult) {
|
|
229
|
+
issues.push({
|
|
230
|
+
...descResult,
|
|
231
|
+
tool: cmd.name,
|
|
232
|
+
file: filePath,
|
|
233
|
+
certainty: descPattern.certainty,
|
|
234
|
+
patternId: descPattern.id
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Check parameters schema
|
|
239
|
+
if (cmd.parameters) {
|
|
240
|
+
// Missing additionalProperties
|
|
241
|
+
const addPropsPattern = pluginPatterns.pluginPatterns.missing_additional_properties;
|
|
242
|
+
const addPropsResult = addPropsPattern.check(cmd.parameters);
|
|
243
|
+
if (addPropsResult) {
|
|
244
|
+
issues.push({
|
|
245
|
+
...addPropsResult,
|
|
246
|
+
tool: cmd.name,
|
|
247
|
+
file: filePath,
|
|
248
|
+
filePath: filePath,
|
|
249
|
+
schemaPath: `commands[${cmdIndex}].parameters`,
|
|
250
|
+
certainty: addPropsPattern.certainty,
|
|
251
|
+
patternId: addPropsPattern.id,
|
|
252
|
+
autoFixFn: fixer.fixAdditionalProperties
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Missing required
|
|
257
|
+
const reqPattern = pluginPatterns.pluginPatterns.missing_required_fields;
|
|
258
|
+
const reqResult = reqPattern.check(cmd.parameters);
|
|
259
|
+
if (reqResult) {
|
|
260
|
+
issues.push({
|
|
261
|
+
...reqResult,
|
|
262
|
+
tool: cmd.name,
|
|
263
|
+
file: filePath,
|
|
264
|
+
filePath: filePath,
|
|
265
|
+
schemaPath: `commands[${cmdIndex}].parameters`,
|
|
266
|
+
certainty: reqPattern.certainty,
|
|
267
|
+
patternId: reqPattern.id,
|
|
268
|
+
autoFixFn: fixer.fixRequiredFields
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Deep nesting
|
|
273
|
+
const nestPattern = pluginPatterns.pluginPatterns.deep_nesting;
|
|
274
|
+
const nestResult = nestPattern.check(cmd.parameters);
|
|
275
|
+
if (nestResult) {
|
|
276
|
+
issues.push({
|
|
277
|
+
...nestResult,
|
|
278
|
+
tool: cmd.name,
|
|
279
|
+
file: filePath,
|
|
280
|
+
certainty: nestPattern.certainty,
|
|
281
|
+
patternId: nestPattern.id
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Run tool pattern checks
|
|
286
|
+
const toolIssues = toolPatterns.analyzeTool({
|
|
287
|
+
name: cmd.name,
|
|
288
|
+
description: cmd.description,
|
|
289
|
+
inputSchema: cmd.parameters
|
|
290
|
+
});
|
|
291
|
+
issues.push(...toolIssues.map(i => ({
|
|
292
|
+
...i,
|
|
293
|
+
file: filePath
|
|
294
|
+
})));
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return issues;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Analyze all plugins in a directory
|
|
302
|
+
* @param {string} pluginsDir - Path to plugins directory
|
|
303
|
+
* @param {Object} options - Analysis options
|
|
304
|
+
* @returns {Array} Array of analysis results
|
|
305
|
+
*/
|
|
306
|
+
async function analyzeAllPlugins(pluginsDir, options = {}) {
|
|
307
|
+
const results = [];
|
|
308
|
+
|
|
309
|
+
if (!fs.existsSync(pluginsDir)) {
|
|
310
|
+
return results;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const pluginDirs = fs.readdirSync(pluginsDir, { withFileTypes: true })
|
|
314
|
+
.filter(d => d.isDirectory())
|
|
315
|
+
.map(d => d.name);
|
|
316
|
+
|
|
317
|
+
for (const pluginName of pluginDirs) {
|
|
318
|
+
const pluginPath = path.join(pluginsDir, pluginName);
|
|
319
|
+
const result = await analyzePlugin(pluginPath, options);
|
|
320
|
+
results.push(result);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return results;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Main analyze function
|
|
328
|
+
* @param {Object} options - Analysis options
|
|
329
|
+
* @param {string} options.plugin - Specific plugin name (optional)
|
|
330
|
+
* @param {string} options.pluginsDir - Path to plugins directory
|
|
331
|
+
* @param {boolean} options.verbose - Include LOW certainty issues
|
|
332
|
+
* @returns {Object} Analysis results
|
|
333
|
+
*/
|
|
334
|
+
async function analyze(options = {}) {
|
|
335
|
+
const {
|
|
336
|
+
plugin,
|
|
337
|
+
pluginsDir = 'plugins',
|
|
338
|
+
verbose = false
|
|
339
|
+
} = options;
|
|
340
|
+
|
|
341
|
+
if (plugin) {
|
|
342
|
+
// Analyze single plugin
|
|
343
|
+
const pluginPath = path.join(pluginsDir, plugin);
|
|
344
|
+
return analyzePlugin(pluginPath, { verbose });
|
|
345
|
+
} else {
|
|
346
|
+
// Analyze all plugins
|
|
347
|
+
return analyzeAllPlugins(pluginsDir, { verbose });
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Apply fixes to analysis results
|
|
353
|
+
* @param {Object|Array} results - Analysis results
|
|
354
|
+
* @param {Object} options - Fix options
|
|
355
|
+
* @returns {Object} Fix results
|
|
356
|
+
*/
|
|
357
|
+
async function applyFixes(results, options = {}) {
|
|
358
|
+
// Collect all issues
|
|
359
|
+
let allIssues = [];
|
|
360
|
+
|
|
361
|
+
if (Array.isArray(results)) {
|
|
362
|
+
for (const r of results) {
|
|
363
|
+
allIssues.push(...(r.toolIssues || []));
|
|
364
|
+
allIssues.push(...(r.structureIssues || []));
|
|
365
|
+
allIssues.push(...(r.securityIssues || []));
|
|
366
|
+
}
|
|
367
|
+
} else {
|
|
368
|
+
allIssues.push(...(results.toolIssues || []));
|
|
369
|
+
allIssues.push(...(results.structureIssues || []));
|
|
370
|
+
allIssues.push(...(results.securityIssues || []));
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return fixer.applyFixes(allIssues, options);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Generate report from analysis results
|
|
378
|
+
* @param {Object|Array} results - Analysis results
|
|
379
|
+
* @param {Object} options - Report options
|
|
380
|
+
* @returns {string} Markdown report
|
|
381
|
+
*/
|
|
382
|
+
function generateReport(results, options = {}) {
|
|
383
|
+
if (Array.isArray(results)) {
|
|
384
|
+
return reporter.generateSummaryReport(results, options);
|
|
385
|
+
} else {
|
|
386
|
+
return reporter.generateReport(results, options);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
module.exports = {
|
|
391
|
+
analyze,
|
|
392
|
+
analyzePlugin,
|
|
393
|
+
analyzeAllPlugins,
|
|
394
|
+
applyFixes,
|
|
395
|
+
generateReport,
|
|
396
|
+
// Re-export sub-modules
|
|
397
|
+
pluginPatterns: pluginPatterns.pluginPatterns,
|
|
398
|
+
toolPatterns: toolPatterns.toolPatterns,
|
|
399
|
+
securityPatterns: securityPatterns.securityPatterns,
|
|
400
|
+
reporter,
|
|
401
|
+
fixer
|
|
402
|
+
};
|