agent-security-scanner-mcp 3.20.1 → 4.0.1

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.
Files changed (124) hide show
  1. package/README.md +102 -12
  2. package/code-review-agent/.env.example +8 -0
  3. package/code-review-agent/README.md +142 -0
  4. package/code-review-agent/TODO.md +149 -0
  5. package/code-review-agent/bin/cr-agent.ts +313 -0
  6. package/code-review-agent/dist/bin/cr-agent.d.ts +3 -0
  7. package/code-review-agent/dist/bin/cr-agent.d.ts.map +1 -0
  8. package/code-review-agent/dist/bin/cr-agent.js +299 -0
  9. package/code-review-agent/dist/bin/cr-agent.js.map +1 -0
  10. package/code-review-agent/dist/src/analyzer/engine.d.ts +16 -0
  11. package/code-review-agent/dist/src/analyzer/engine.d.ts.map +1 -0
  12. package/code-review-agent/dist/src/analyzer/engine.js +298 -0
  13. package/code-review-agent/dist/src/analyzer/engine.js.map +1 -0
  14. package/code-review-agent/dist/src/analyzer/intent.d.ts +10 -0
  15. package/code-review-agent/dist/src/analyzer/intent.d.ts.map +1 -0
  16. package/code-review-agent/dist/src/analyzer/intent.js +40 -0
  17. package/code-review-agent/dist/src/analyzer/intent.js.map +1 -0
  18. package/code-review-agent/dist/src/analyzer/semantic.d.ts +19 -0
  19. package/code-review-agent/dist/src/analyzer/semantic.d.ts.map +1 -0
  20. package/code-review-agent/dist/src/analyzer/semantic.js +150 -0
  21. package/code-review-agent/dist/src/analyzer/semantic.js.map +1 -0
  22. package/code-review-agent/dist/src/context/assembler.d.ts +16 -0
  23. package/code-review-agent/dist/src/context/assembler.d.ts.map +1 -0
  24. package/code-review-agent/dist/src/context/assembler.js +135 -0
  25. package/code-review-agent/dist/src/context/assembler.js.map +1 -0
  26. package/code-review-agent/dist/src/context/file.d.ts +6 -0
  27. package/code-review-agent/dist/src/context/file.d.ts.map +1 -0
  28. package/code-review-agent/dist/src/context/file.js +139 -0
  29. package/code-review-agent/dist/src/context/file.js.map +1 -0
  30. package/code-review-agent/dist/src/context/project.d.ts +4 -0
  31. package/code-review-agent/dist/src/context/project.d.ts.map +1 -0
  32. package/code-review-agent/dist/src/context/project.js +252 -0
  33. package/code-review-agent/dist/src/context/project.js.map +1 -0
  34. package/code-review-agent/dist/src/graph/dependency.d.ts +11 -0
  35. package/code-review-agent/dist/src/graph/dependency.d.ts.map +1 -0
  36. package/code-review-agent/dist/src/graph/dependency.js +102 -0
  37. package/code-review-agent/dist/src/graph/dependency.js.map +1 -0
  38. package/code-review-agent/dist/src/graph/resolver.d.ts +9 -0
  39. package/code-review-agent/dist/src/graph/resolver.d.ts.map +1 -0
  40. package/code-review-agent/dist/src/graph/resolver.js +124 -0
  41. package/code-review-agent/dist/src/graph/resolver.js.map +1 -0
  42. package/code-review-agent/dist/src/index.d.ts +21 -0
  43. package/code-review-agent/dist/src/index.d.ts.map +1 -0
  44. package/code-review-agent/dist/src/index.js +21 -0
  45. package/code-review-agent/dist/src/index.js.map +1 -0
  46. package/code-review-agent/dist/src/llm/anthropic.d.ts +13 -0
  47. package/code-review-agent/dist/src/llm/anthropic.d.ts.map +1 -0
  48. package/code-review-agent/dist/src/llm/anthropic.js +83 -0
  49. package/code-review-agent/dist/src/llm/anthropic.js.map +1 -0
  50. package/code-review-agent/dist/src/llm/claude-cli.d.ts +13 -0
  51. package/code-review-agent/dist/src/llm/claude-cli.d.ts.map +1 -0
  52. package/code-review-agent/dist/src/llm/claude-cli.js +141 -0
  53. package/code-review-agent/dist/src/llm/claude-cli.js.map +1 -0
  54. package/code-review-agent/dist/src/llm/openai.d.ts +13 -0
  55. package/code-review-agent/dist/src/llm/openai.d.ts.map +1 -0
  56. package/code-review-agent/dist/src/llm/openai.js +78 -0
  57. package/code-review-agent/dist/src/llm/openai.js.map +1 -0
  58. package/code-review-agent/dist/src/llm/provider.d.ts +18 -0
  59. package/code-review-agent/dist/src/llm/provider.d.ts.map +1 -0
  60. package/code-review-agent/dist/src/llm/provider.js +11 -0
  61. package/code-review-agent/dist/src/llm/provider.js.map +1 -0
  62. package/code-review-agent/dist/src/llm/router.d.ts +14 -0
  63. package/code-review-agent/dist/src/llm/router.d.ts.map +1 -0
  64. package/code-review-agent/dist/src/llm/router.js +67 -0
  65. package/code-review-agent/dist/src/llm/router.js.map +1 -0
  66. package/code-review-agent/dist/src/llm/schemas.d.ts +18 -0
  67. package/code-review-agent/dist/src/llm/schemas.d.ts.map +1 -0
  68. package/code-review-agent/dist/src/llm/schemas.js +91 -0
  69. package/code-review-agent/dist/src/llm/schemas.js.map +1 -0
  70. package/code-review-agent/dist/src/types/analysis.d.ts +56 -0
  71. package/code-review-agent/dist/src/types/analysis.d.ts.map +1 -0
  72. package/code-review-agent/dist/src/types/analysis.js +2 -0
  73. package/code-review-agent/dist/src/types/analysis.js.map +1 -0
  74. package/code-review-agent/dist/src/types/config.d.ts +24 -0
  75. package/code-review-agent/dist/src/types/config.d.ts.map +1 -0
  76. package/code-review-agent/dist/src/types/config.js +42 -0
  77. package/code-review-agent/dist/src/types/config.js.map +1 -0
  78. package/code-review-agent/dist/src/types/findings.d.ts +236 -0
  79. package/code-review-agent/dist/src/types/findings.d.ts.map +1 -0
  80. package/code-review-agent/dist/src/types/findings.js +64 -0
  81. package/code-review-agent/dist/src/types/findings.js.map +1 -0
  82. package/code-review-agent/package.json +36 -0
  83. package/code-review-agent/src/analyzer/engine.ts +374 -0
  84. package/code-review-agent/src/analyzer/intent.ts +49 -0
  85. package/code-review-agent/src/analyzer/semantic.ts +222 -0
  86. package/code-review-agent/src/context/assembler.ts +165 -0
  87. package/code-review-agent/src/context/file.ts +145 -0
  88. package/code-review-agent/src/context/project.ts +253 -0
  89. package/code-review-agent/src/graph/dependency.ts +116 -0
  90. package/code-review-agent/src/graph/resolver.ts +138 -0
  91. package/code-review-agent/src/index.ts +58 -0
  92. package/code-review-agent/src/llm/anthropic.ts +106 -0
  93. package/code-review-agent/src/llm/claude-cli.ts +187 -0
  94. package/code-review-agent/src/llm/openai.ts +95 -0
  95. package/code-review-agent/src/llm/provider.ts +33 -0
  96. package/code-review-agent/src/llm/router.ts +86 -0
  97. package/code-review-agent/src/llm/schemas.ts +125 -0
  98. package/code-review-agent/src/types/analysis.ts +62 -0
  99. package/code-review-agent/src/types/config.ts +72 -0
  100. package/code-review-agent/src/types/findings.ts +81 -0
  101. package/code-review-agent/tests/analyzer/engine.test.ts +194 -0
  102. package/code-review-agent/tests/analyzer/intent.test.ts +76 -0
  103. package/code-review-agent/tests/analyzer/semantic.test.ts +131 -0
  104. package/code-review-agent/tests/context/file.test.ts +21 -0
  105. package/code-review-agent/tests/context/project.test.ts +20 -0
  106. package/code-review-agent/tests/fixtures/safe-build-tool/README.md +19 -0
  107. package/code-review-agent/tests/fixtures/safe-build-tool/builder.js +52 -0
  108. package/code-review-agent/tests/fixtures/safe-file-manager/README.md +16 -0
  109. package/code-review-agent/tests/fixtures/safe-file-manager/organizer.py +70 -0
  110. package/code-review-agent/tests/fixtures/vuln-api-server/README.md +17 -0
  111. package/code-review-agent/tests/fixtures/vuln-api-server/server.js +52 -0
  112. package/code-review-agent/tests/fixtures/vuln-ecommerce/README.md +18 -0
  113. package/code-review-agent/tests/fixtures/vuln-ecommerce/checkout.js +63 -0
  114. package/code-review-agent/tests/graph/dependency.test.ts +136 -0
  115. package/code-review-agent/tests/helpers/mock-provider.ts +48 -0
  116. package/code-review-agent/tests/llm/claude-cli.test.ts +251 -0
  117. package/code-review-agent/tests/llm/router.test.ts +77 -0
  118. package/code-review-agent/tests/llm/schemas.test.ts +142 -0
  119. package/code-review-agent/tsconfig.json +20 -0
  120. package/code-review-agent/vitest.config.ts +11 -0
  121. package/openclaw.plugin.json +1 -1
  122. package/package.json +15 -4
  123. package/scripts/postinstall.js +43 -4
  124. package/server.json +2 -2
@@ -0,0 +1,313 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Suppress Node.js deprecation warnings (e.g. punycode from dependencies)
4
+ process.removeAllListeners('warning');
5
+
6
+ import * as fs from 'node:fs';
7
+ import * as path from 'node:path';
8
+ import { Command } from 'commander';
9
+ import chalk from 'chalk';
10
+ import { AnalysisEngine } from '../src/analyzer/engine.js';
11
+ import { IntentProfiler } from '../src/analyzer/intent.js';
12
+ import { ModelRouter } from '../src/llm/router.js';
13
+ import { DependencyGraphBuilder } from '../src/graph/dependency.js';
14
+ import { buildProjectContext } from '../src/context/project.js';
15
+ import { loadConfig, resolveOptions } from '../src/types/config.js';
16
+ import type { AnalysisOptions } from '../src/types/config.js';
17
+ import type { AnalysisResult, Finding } from '../src/index.js';
18
+
19
+ const program = new Command();
20
+
21
+ program
22
+ .name('cr-agent')
23
+ .description('LLM-powered semantic code review agent')
24
+ .version('0.1.0');
25
+
26
+ program
27
+ .command('analyze')
28
+ .description('Analyze a file or directory for bugs and vulnerabilities')
29
+ .argument('<target>', 'File or directory to analyze')
30
+ .option('-p, --provider <provider>', 'LLM provider (anthropic|openai|claude-cli)')
31
+ .option('-m, --model <model>', 'Model to use for analysis')
32
+ .option('--triage-model <model>', 'Model to use for triage')
33
+ .option('-c, --confidence <threshold>', 'Confidence threshold (0-1)', parseFloat)
34
+ .option('-f, --format <format>', 'Output format (text|json|sarif)')
35
+ .option('-v, --verbose', 'Verbose output')
36
+ .option('--exclude <patterns...>', 'Patterns to exclude')
37
+ .option('--concurrency <limit>', 'Concurrency limit', parseInt)
38
+ .action(async (target: string, flags: Record<string, unknown>) => {
39
+ try {
40
+ // Resolve project root from target, not cwd
41
+ const resolvedTarget = path.resolve(target);
42
+ const targetProjectRoot = fs.statSync(resolvedTarget).isDirectory()
43
+ ? resolvedTarget
44
+ : findProjectRoot(resolvedTarget);
45
+ const config = loadConfig(targetProjectRoot);
46
+ const options = resolveOptions(
47
+ {
48
+ provider: flags.provider as AnalysisOptions['provider'] | undefined,
49
+ model: flags.model as string | undefined,
50
+ triageModel: flags.triageModel as string | undefined,
51
+ confidenceThreshold: flags.confidence as number | undefined,
52
+ format: (flags.format as AnalysisOptions['format']) ?? 'text',
53
+ verbose: flags.verbose as boolean | undefined,
54
+ exclude: flags.exclude as string[] | undefined,
55
+ concurrencyLimit: flags.concurrency as number | undefined,
56
+ projectRoot: targetProjectRoot,
57
+ },
58
+ config,
59
+ );
60
+
61
+ const showProgress = options.format === 'text';
62
+ let lastStep = '';
63
+ const engine = new AnalysisEngine(options, showProgress ? (step, detail) => {
64
+ const icons: Record<string, string> = {
65
+ discover: '[1/7 discover]',
66
+ context: '[2/7 context ]',
67
+ intent: '[3/7 intent ]',
68
+ graph: '[4/7 graph ]',
69
+ triage: '[5/7 triage ]',
70
+ analyze: '[6/7 analyze ]',
71
+ finalize: '[7/7 finalize]',
72
+ done: '[ done ]',
73
+ };
74
+ const label = icons[step] ?? `[${step}]`;
75
+ if (step !== lastStep) {
76
+ // New stage — print on a new line, keep it visible
77
+ if (lastStep) process.stderr.write('\n');
78
+ lastStep = step;
79
+ process.stderr.write(`${chalk.cyan(label)} ${detail ?? ''}`);
80
+ } else {
81
+ // Same stage — overwrite the current line with updated detail
82
+ process.stderr.write(`\r\x1b[K${chalk.dim(label)} ${detail ?? ''}`);
83
+ }
84
+ if (step === 'done') process.stderr.write('\n');
85
+ } : undefined);
86
+ const result = await engine.analyze(target);
87
+
88
+ if (options.format === 'json') {
89
+ console.log(JSON.stringify(result, null, 2));
90
+ } else if (options.format === 'sarif') {
91
+ console.log(JSON.stringify(toSarif(result), null, 2));
92
+ } else {
93
+ printTextResult(result, options.verbose);
94
+ }
95
+
96
+ process.exit(result.findings.some((f) => f.severity === 'critical' || f.severity === 'high') ? 1 : 0);
97
+ } catch (err) {
98
+ // Never leak full prompt/context in error output
99
+ const msg = err instanceof Error ? err.message : String(err);
100
+ const safeLine = msg.split('\n')[0].slice(0, 300);
101
+ process.stderr.write('\n');
102
+ console.error(chalk.red(`Error: ${safeLine}`));
103
+ process.exit(2);
104
+ }
105
+ });
106
+
107
+ program
108
+ .command('intent')
109
+ .description('Show the intent profile for a project')
110
+ .argument('<dir>', 'Project directory')
111
+ .option('-p, --provider <provider>', 'LLM provider (anthropic|openai|claude-cli)')
112
+ .option('-m, --model <model>', 'Model to use')
113
+ .action(async (dir: string, flags: Record<string, unknown>) => {
114
+ try {
115
+ const config = loadConfig(dir);
116
+ const options = resolveOptions(
117
+ {
118
+ provider: flags.provider as AnalysisOptions['provider'] | undefined,
119
+ model: flags.model as string | undefined,
120
+ projectRoot: dir,
121
+ },
122
+ config,
123
+ );
124
+
125
+ const router = new ModelRouter(options);
126
+ const profiler = new IntentProfiler(router.getAnalysisProvider());
127
+ const projectContext = buildProjectContext(dir);
128
+ const intent = await profiler.profile(projectContext);
129
+
130
+ console.log(chalk.bold('\nIntent Profile'));
131
+ console.log(chalk.cyan('Purpose: ') + intent.purpose);
132
+ console.log(chalk.cyan('Risk Domain: ') + intent.riskDomain);
133
+ console.log(chalk.cyan('Framework: ') + intent.framework);
134
+ console.log(chalk.green('\nExpected Behaviors:'));
135
+ for (const b of intent.expectedBehaviors) {
136
+ console.log(` + ${b}`);
137
+ }
138
+ console.log(chalk.red('\nUnexpected Behaviors:'));
139
+ for (const b of intent.unexpectedBehaviors) {
140
+ console.log(` - ${b}`);
141
+ }
142
+ } catch (err) {
143
+ const msg = err instanceof Error ? err.message : String(err);
144
+ console.error(chalk.red(`Error: ${msg.split('\n')[0].slice(0, 300)}`));
145
+ process.exit(2);
146
+ }
147
+ });
148
+
149
+ program
150
+ .command('graph')
151
+ .description('Show the dependency graph for a project')
152
+ .argument('<dir>', 'Project directory')
153
+ .action((dir: string) => {
154
+ const builder = new DependencyGraphBuilder(dir);
155
+
156
+ // Discover entry files — support all languages the engine supports
157
+ const codeExtRe = /\.(js|mjs|cjs|jsx|ts|tsx|py|go|rs|java|rb|php|c|cpp|h|hpp|cs|swift|kt)$/;
158
+ const excludeSet = new Set(['node_modules', 'dist', '.git', 'vendor', '__pycache__', 'venv', '.venv']);
159
+ const entries: string[] = [];
160
+ const walkGraph = (d: string) => {
161
+ let dirEntries: import('node:fs').Dirent[];
162
+ try { dirEntries = fs.readdirSync(d, { withFileTypes: true }); } catch { return; }
163
+ for (const entry of dirEntries) {
164
+ if (excludeSet.has(entry.name) || entry.name.startsWith('.')) continue;
165
+ const full = path.join(d, entry.name);
166
+ if (entry.isDirectory()) walkGraph(full);
167
+ else if (codeExtRe.test(entry.name)) entries.push(full);
168
+ }
169
+ };
170
+ walkGraph(dir);
171
+
172
+ const graph = builder.build(entries.map((e: string) => path.relative(dir, e)));
173
+
174
+ console.log(chalk.bold(`\nDependency Graph (${graph.nodes.size} files)\n`));
175
+ for (const [file, node] of graph.nodes) {
176
+ console.log(chalk.cyan(file));
177
+ if (node.imports.length > 0) {
178
+ console.log(` imports: ${node.imports.join(', ')}`);
179
+ }
180
+ if (node.importedBy.length > 0) {
181
+ console.log(` imported by: ${node.importedBy.join(', ')}`);
182
+ }
183
+ }
184
+ });
185
+
186
+ program.parse();
187
+
188
+ // --- Output formatting ---
189
+
190
+ function printTextResult(result: AnalysisResult, verbose: boolean): void {
191
+ const { findings, intentProfile, stats } = result;
192
+
193
+ if (intentProfile) {
194
+ console.log(chalk.bold('\nIntent Profile'));
195
+ console.log(` Purpose: ${intentProfile.purpose}`);
196
+ console.log(` Domain: ${intentProfile.riskDomain}`);
197
+ console.log('');
198
+ }
199
+
200
+ if (findings.length === 0) {
201
+ console.log(chalk.green('\nNo findings above confidence threshold.\n'));
202
+ } else {
203
+ console.log(chalk.bold(`\n${findings.length} Finding(s)\n`));
204
+ for (const f of findings) {
205
+ printFinding(f, verbose);
206
+ }
207
+ }
208
+
209
+ console.log(chalk.bold('Stats'));
210
+ console.log(` Files analyzed: ${stats.filesAnalyzed}`);
211
+ console.log(` Files skipped: ${stats.filesSkipped}`);
212
+ console.log(` Total findings: ${stats.totalFindings}`);
213
+ console.log(` Tokens used: ${stats.totalTokensUsed.toLocaleString()}`);
214
+ console.log(` Estimated cost: $${stats.estimatedCost.toFixed(4)}`);
215
+ console.log(` Duration: ${(stats.durationMs / 1000).toFixed(1)}s`);
216
+ console.log('');
217
+ }
218
+
219
+ function printFinding(f: Finding, verbose: boolean): void {
220
+ const severityColors: Record<string, (s: string) => string> = {
221
+ critical: chalk.bgRed.white.bold,
222
+ high: chalk.red.bold,
223
+ medium: chalk.yellow,
224
+ low: chalk.blue,
225
+ info: chalk.gray,
226
+ };
227
+
228
+ const colorFn = severityColors[f.severity] ?? chalk.white;
229
+ const badge = colorFn(` ${f.severity.toUpperCase()} `);
230
+ const alignment =
231
+ f.intentAlignment === 'violates-intent' ? chalk.red('VIOLATES INTENT') :
232
+ f.intentAlignment === 'matches-intent' ? chalk.green('MATCHES INTENT') :
233
+ chalk.gray('UNCLEAR');
234
+
235
+ console.log(`${badge} ${f.title}`);
236
+ console.log(` ${chalk.dim(`${f.location.file}:${f.location.startLine}-${f.location.endLine}`)} ${alignment} confidence: ${f.confidence}`);
237
+ console.log(` ${chalk.dim(f.category)}${f.cwe ? ` | ${f.cwe}` : ''}`);
238
+
239
+ if (verbose) {
240
+ console.log(` ${chalk.dim('Reasoning:')} ${f.reasoning}`);
241
+ console.log(` ${chalk.dim('Action:')} ${f.suggestedAction}`);
242
+ }
243
+
244
+ console.log('');
245
+ }
246
+
247
+ function findProjectRoot(filePath: string): string {
248
+ const markers = ['package.json', 'pyproject.toml', 'go.mod', 'Cargo.toml', 'requirements.txt', '.git', '.cr-agent.json'];
249
+ let dir = path.dirname(path.resolve(filePath));
250
+ while (dir !== path.dirname(dir)) {
251
+ if (markers.some((m) => { try { fs.statSync(path.join(dir, m)); return true; } catch { return false; } })) {
252
+ return dir;
253
+ }
254
+ dir = path.dirname(dir);
255
+ }
256
+ return path.dirname(path.resolve(filePath));
257
+ }
258
+
259
+ function toSarif(result: AnalysisResult): object {
260
+ return {
261
+ $schema: 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json',
262
+ version: '2.1.0',
263
+ runs: [
264
+ {
265
+ tool: {
266
+ driver: {
267
+ name: 'cr-agent',
268
+ version: '0.1.0',
269
+ informationUri: 'https://github.com/sinewaveai/agent-security-scanner-mcp',
270
+ rules: result.findings.map((f, i) => ({
271
+ id: `CR${String(i + 1).padStart(3, '0')}`,
272
+ name: f.title.replace(/\s+/g, ''),
273
+ shortDescription: { text: f.title },
274
+ fullDescription: { text: f.reasoning },
275
+ defaultConfiguration: {
276
+ level: f.severity === 'critical' || f.severity === 'high' ? 'error' :
277
+ f.severity === 'medium' ? 'warning' : 'note',
278
+ },
279
+ properties: {
280
+ category: f.category,
281
+ intentAlignment: f.intentAlignment,
282
+ },
283
+ })),
284
+ },
285
+ },
286
+ results: result.findings.map((f, i) => ({
287
+ ruleId: `CR${String(i + 1).padStart(3, '0')}`,
288
+ level: f.severity === 'critical' || f.severity === 'high' ? 'error' :
289
+ f.severity === 'medium' ? 'warning' : 'note',
290
+ message: { text: f.reasoning },
291
+ locations: [
292
+ {
293
+ physicalLocation: {
294
+ artifactLocation: { uri: f.location.file },
295
+ region: {
296
+ startLine: f.location.startLine,
297
+ endLine: f.location.endLine,
298
+ },
299
+ },
300
+ },
301
+ ],
302
+ properties: {
303
+ confidence: f.confidence,
304
+ intentAlignment: f.intentAlignment,
305
+ suggestedAction: f.suggestedAction,
306
+ cwe: f.cwe,
307
+ owasp: f.owasp,
308
+ },
309
+ })),
310
+ },
311
+ ],
312
+ };
313
+ }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cr-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cr-agent.d.ts","sourceRoot":"","sources":["../../bin/cr-agent.ts"],"names":[],"mappings":""}
@@ -0,0 +1,299 @@
1
+ #!/usr/bin/env node
2
+ // Suppress Node.js deprecation warnings (e.g. punycode from dependencies)
3
+ process.removeAllListeners('warning');
4
+ import * as fs from 'node:fs';
5
+ import * as path from 'node:path';
6
+ import { Command } from 'commander';
7
+ import chalk from 'chalk';
8
+ import { AnalysisEngine } from '../src/analyzer/engine.js';
9
+ import { IntentProfiler } from '../src/analyzer/intent.js';
10
+ import { ModelRouter } from '../src/llm/router.js';
11
+ import { DependencyGraphBuilder } from '../src/graph/dependency.js';
12
+ import { buildProjectContext } from '../src/context/project.js';
13
+ import { loadConfig, resolveOptions } from '../src/types/config.js';
14
+ const program = new Command();
15
+ program
16
+ .name('cr-agent')
17
+ .description('LLM-powered semantic code review agent')
18
+ .version('0.1.0');
19
+ program
20
+ .command('analyze')
21
+ .description('Analyze a file or directory for bugs and vulnerabilities')
22
+ .argument('<target>', 'File or directory to analyze')
23
+ .option('-p, --provider <provider>', 'LLM provider (anthropic|openai|claude-cli)')
24
+ .option('-m, --model <model>', 'Model to use for analysis')
25
+ .option('--triage-model <model>', 'Model to use for triage')
26
+ .option('-c, --confidence <threshold>', 'Confidence threshold (0-1)', parseFloat)
27
+ .option('-f, --format <format>', 'Output format (text|json|sarif)')
28
+ .option('-v, --verbose', 'Verbose output')
29
+ .option('--exclude <patterns...>', 'Patterns to exclude')
30
+ .option('--concurrency <limit>', 'Concurrency limit', parseInt)
31
+ .action(async (target, flags) => {
32
+ try {
33
+ // Resolve project root from target, not cwd
34
+ const resolvedTarget = path.resolve(target);
35
+ const targetProjectRoot = fs.statSync(resolvedTarget).isDirectory()
36
+ ? resolvedTarget
37
+ : findProjectRoot(resolvedTarget);
38
+ const config = loadConfig(targetProjectRoot);
39
+ const options = resolveOptions({
40
+ provider: flags.provider,
41
+ model: flags.model,
42
+ triageModel: flags.triageModel,
43
+ confidenceThreshold: flags.confidence,
44
+ format: flags.format ?? 'text',
45
+ verbose: flags.verbose,
46
+ exclude: flags.exclude,
47
+ concurrencyLimit: flags.concurrency,
48
+ projectRoot: targetProjectRoot,
49
+ }, config);
50
+ const showProgress = options.format === 'text';
51
+ let lastStep = '';
52
+ const engine = new AnalysisEngine(options, showProgress ? (step, detail) => {
53
+ const icons = {
54
+ discover: '[1/7 discover]',
55
+ context: '[2/7 context ]',
56
+ intent: '[3/7 intent ]',
57
+ graph: '[4/7 graph ]',
58
+ triage: '[5/7 triage ]',
59
+ analyze: '[6/7 analyze ]',
60
+ finalize: '[7/7 finalize]',
61
+ done: '[ done ]',
62
+ };
63
+ const label = icons[step] ?? `[${step}]`;
64
+ if (step !== lastStep) {
65
+ // New stage — print on a new line, keep it visible
66
+ if (lastStep)
67
+ process.stderr.write('\n');
68
+ lastStep = step;
69
+ process.stderr.write(`${chalk.cyan(label)} ${detail ?? ''}`);
70
+ }
71
+ else {
72
+ // Same stage — overwrite the current line with updated detail
73
+ process.stderr.write(`\r\x1b[K${chalk.dim(label)} ${detail ?? ''}`);
74
+ }
75
+ if (step === 'done')
76
+ process.stderr.write('\n');
77
+ } : undefined);
78
+ const result = await engine.analyze(target);
79
+ if (options.format === 'json') {
80
+ console.log(JSON.stringify(result, null, 2));
81
+ }
82
+ else if (options.format === 'sarif') {
83
+ console.log(JSON.stringify(toSarif(result), null, 2));
84
+ }
85
+ else {
86
+ printTextResult(result, options.verbose);
87
+ }
88
+ process.exit(result.findings.some((f) => f.severity === 'critical' || f.severity === 'high') ? 1 : 0);
89
+ }
90
+ catch (err) {
91
+ // Never leak full prompt/context in error output
92
+ const msg = err instanceof Error ? err.message : String(err);
93
+ const safeLine = msg.split('\n')[0].slice(0, 300);
94
+ process.stderr.write('\n');
95
+ console.error(chalk.red(`Error: ${safeLine}`));
96
+ process.exit(2);
97
+ }
98
+ });
99
+ program
100
+ .command('intent')
101
+ .description('Show the intent profile for a project')
102
+ .argument('<dir>', 'Project directory')
103
+ .option('-p, --provider <provider>', 'LLM provider (anthropic|openai|claude-cli)')
104
+ .option('-m, --model <model>', 'Model to use')
105
+ .action(async (dir, flags) => {
106
+ try {
107
+ const config = loadConfig(dir);
108
+ const options = resolveOptions({
109
+ provider: flags.provider,
110
+ model: flags.model,
111
+ projectRoot: dir,
112
+ }, config);
113
+ const router = new ModelRouter(options);
114
+ const profiler = new IntentProfiler(router.getAnalysisProvider());
115
+ const projectContext = buildProjectContext(dir);
116
+ const intent = await profiler.profile(projectContext);
117
+ console.log(chalk.bold('\nIntent Profile'));
118
+ console.log(chalk.cyan('Purpose: ') + intent.purpose);
119
+ console.log(chalk.cyan('Risk Domain: ') + intent.riskDomain);
120
+ console.log(chalk.cyan('Framework: ') + intent.framework);
121
+ console.log(chalk.green('\nExpected Behaviors:'));
122
+ for (const b of intent.expectedBehaviors) {
123
+ console.log(` + ${b}`);
124
+ }
125
+ console.log(chalk.red('\nUnexpected Behaviors:'));
126
+ for (const b of intent.unexpectedBehaviors) {
127
+ console.log(` - ${b}`);
128
+ }
129
+ }
130
+ catch (err) {
131
+ const msg = err instanceof Error ? err.message : String(err);
132
+ console.error(chalk.red(`Error: ${msg.split('\n')[0].slice(0, 300)}`));
133
+ process.exit(2);
134
+ }
135
+ });
136
+ program
137
+ .command('graph')
138
+ .description('Show the dependency graph for a project')
139
+ .argument('<dir>', 'Project directory')
140
+ .action((dir) => {
141
+ const builder = new DependencyGraphBuilder(dir);
142
+ // Discover entry files — support all languages the engine supports
143
+ const codeExtRe = /\.(js|mjs|cjs|jsx|ts|tsx|py|go|rs|java|rb|php|c|cpp|h|hpp|cs|swift|kt)$/;
144
+ const excludeSet = new Set(['node_modules', 'dist', '.git', 'vendor', '__pycache__', 'venv', '.venv']);
145
+ const entries = [];
146
+ const walkGraph = (d) => {
147
+ let dirEntries;
148
+ try {
149
+ dirEntries = fs.readdirSync(d, { withFileTypes: true });
150
+ }
151
+ catch {
152
+ return;
153
+ }
154
+ for (const entry of dirEntries) {
155
+ if (excludeSet.has(entry.name) || entry.name.startsWith('.'))
156
+ continue;
157
+ const full = path.join(d, entry.name);
158
+ if (entry.isDirectory())
159
+ walkGraph(full);
160
+ else if (codeExtRe.test(entry.name))
161
+ entries.push(full);
162
+ }
163
+ };
164
+ walkGraph(dir);
165
+ const graph = builder.build(entries.map((e) => path.relative(dir, e)));
166
+ console.log(chalk.bold(`\nDependency Graph (${graph.nodes.size} files)\n`));
167
+ for (const [file, node] of graph.nodes) {
168
+ console.log(chalk.cyan(file));
169
+ if (node.imports.length > 0) {
170
+ console.log(` imports: ${node.imports.join(', ')}`);
171
+ }
172
+ if (node.importedBy.length > 0) {
173
+ console.log(` imported by: ${node.importedBy.join(', ')}`);
174
+ }
175
+ }
176
+ });
177
+ program.parse();
178
+ // --- Output formatting ---
179
+ function printTextResult(result, verbose) {
180
+ const { findings, intentProfile, stats } = result;
181
+ if (intentProfile) {
182
+ console.log(chalk.bold('\nIntent Profile'));
183
+ console.log(` Purpose: ${intentProfile.purpose}`);
184
+ console.log(` Domain: ${intentProfile.riskDomain}`);
185
+ console.log('');
186
+ }
187
+ if (findings.length === 0) {
188
+ console.log(chalk.green('\nNo findings above confidence threshold.\n'));
189
+ }
190
+ else {
191
+ console.log(chalk.bold(`\n${findings.length} Finding(s)\n`));
192
+ for (const f of findings) {
193
+ printFinding(f, verbose);
194
+ }
195
+ }
196
+ console.log(chalk.bold('Stats'));
197
+ console.log(` Files analyzed: ${stats.filesAnalyzed}`);
198
+ console.log(` Files skipped: ${stats.filesSkipped}`);
199
+ console.log(` Total findings: ${stats.totalFindings}`);
200
+ console.log(` Tokens used: ${stats.totalTokensUsed.toLocaleString()}`);
201
+ console.log(` Estimated cost: $${stats.estimatedCost.toFixed(4)}`);
202
+ console.log(` Duration: ${(stats.durationMs / 1000).toFixed(1)}s`);
203
+ console.log('');
204
+ }
205
+ function printFinding(f, verbose) {
206
+ const severityColors = {
207
+ critical: chalk.bgRed.white.bold,
208
+ high: chalk.red.bold,
209
+ medium: chalk.yellow,
210
+ low: chalk.blue,
211
+ info: chalk.gray,
212
+ };
213
+ const colorFn = severityColors[f.severity] ?? chalk.white;
214
+ const badge = colorFn(` ${f.severity.toUpperCase()} `);
215
+ const alignment = f.intentAlignment === 'violates-intent' ? chalk.red('VIOLATES INTENT') :
216
+ f.intentAlignment === 'matches-intent' ? chalk.green('MATCHES INTENT') :
217
+ chalk.gray('UNCLEAR');
218
+ console.log(`${badge} ${f.title}`);
219
+ console.log(` ${chalk.dim(`${f.location.file}:${f.location.startLine}-${f.location.endLine}`)} ${alignment} confidence: ${f.confidence}`);
220
+ console.log(` ${chalk.dim(f.category)}${f.cwe ? ` | ${f.cwe}` : ''}`);
221
+ if (verbose) {
222
+ console.log(` ${chalk.dim('Reasoning:')} ${f.reasoning}`);
223
+ console.log(` ${chalk.dim('Action:')} ${f.suggestedAction}`);
224
+ }
225
+ console.log('');
226
+ }
227
+ function findProjectRoot(filePath) {
228
+ const markers = ['package.json', 'pyproject.toml', 'go.mod', 'Cargo.toml', 'requirements.txt', '.git', '.cr-agent.json'];
229
+ let dir = path.dirname(path.resolve(filePath));
230
+ while (dir !== path.dirname(dir)) {
231
+ if (markers.some((m) => { try {
232
+ fs.statSync(path.join(dir, m));
233
+ return true;
234
+ }
235
+ catch {
236
+ return false;
237
+ } })) {
238
+ return dir;
239
+ }
240
+ dir = path.dirname(dir);
241
+ }
242
+ return path.dirname(path.resolve(filePath));
243
+ }
244
+ function toSarif(result) {
245
+ return {
246
+ $schema: 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json',
247
+ version: '2.1.0',
248
+ runs: [
249
+ {
250
+ tool: {
251
+ driver: {
252
+ name: 'cr-agent',
253
+ version: '0.1.0',
254
+ informationUri: 'https://github.com/sinewaveai/agent-security-scanner-mcp',
255
+ rules: result.findings.map((f, i) => ({
256
+ id: `CR${String(i + 1).padStart(3, '0')}`,
257
+ name: f.title.replace(/\s+/g, ''),
258
+ shortDescription: { text: f.title },
259
+ fullDescription: { text: f.reasoning },
260
+ defaultConfiguration: {
261
+ level: f.severity === 'critical' || f.severity === 'high' ? 'error' :
262
+ f.severity === 'medium' ? 'warning' : 'note',
263
+ },
264
+ properties: {
265
+ category: f.category,
266
+ intentAlignment: f.intentAlignment,
267
+ },
268
+ })),
269
+ },
270
+ },
271
+ results: result.findings.map((f, i) => ({
272
+ ruleId: `CR${String(i + 1).padStart(3, '0')}`,
273
+ level: f.severity === 'critical' || f.severity === 'high' ? 'error' :
274
+ f.severity === 'medium' ? 'warning' : 'note',
275
+ message: { text: f.reasoning },
276
+ locations: [
277
+ {
278
+ physicalLocation: {
279
+ artifactLocation: { uri: f.location.file },
280
+ region: {
281
+ startLine: f.location.startLine,
282
+ endLine: f.location.endLine,
283
+ },
284
+ },
285
+ },
286
+ ],
287
+ properties: {
288
+ confidence: f.confidence,
289
+ intentAlignment: f.intentAlignment,
290
+ suggestedAction: f.suggestedAction,
291
+ cwe: f.cwe,
292
+ owasp: f.owasp,
293
+ },
294
+ })),
295
+ },
296
+ ],
297
+ };
298
+ }
299
+ //# sourceMappingURL=cr-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cr-agent.js","sourceRoot":"","sources":["../../bin/cr-agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { AnalysisResult } from '../types/analysis.js';
2
+ import type { AnalysisOptions } from '../types/config.js';
3
+ export type ProgressCallback = (step: string, detail?: string) => void;
4
+ export declare class AnalysisEngine {
5
+ private options;
6
+ private router;
7
+ private onProgress;
8
+ constructor(options: AnalysisOptions, onProgress?: ProgressCallback);
9
+ analyze(targetPath: string): Promise<AnalysisResult>;
10
+ private discoverFiles;
11
+ private dedup;
12
+ private mergeOverlapping;
13
+ private countBySeverity;
14
+ private runParallel;
15
+ }
16
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/analyzer/engine.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAuB1D,MAAM,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;AAEvE,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,UAAU,CAAmB;gBAEzB,OAAO,EAAE,eAAe,EAAE,UAAU,CAAC,EAAE,gBAAgB;IAM7D,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAyM1D,OAAO,CAAC,aAAa;IAsCrB,OAAO,CAAC,KAAK;IAoBb,OAAO,CAAC,gBAAgB;IAuCxB,OAAO,CAAC,eAAe;YAQT,WAAW;CAuB1B"}