codeprobe 0.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/LICENSE +21 -0
- package/README.md +406 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +104 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/ab.d.ts +7 -0
- package/dist/commands/ab.d.ts.map +1 -0
- package/dist/commands/ab.js +230 -0
- package/dist/commands/ab.js.map +1 -0
- package/dist/commands/agents.d.ts +10 -0
- package/dist/commands/agents.d.ts.map +1 -0
- package/dist/commands/agents.js +326 -0
- package/dist/commands/agents.js.map +1 -0
- package/dist/commands/autotest.d.ts +10 -0
- package/dist/commands/autotest.d.ts.map +1 -0
- package/dist/commands/autotest.js +408 -0
- package/dist/commands/autotest.js.map +1 -0
- package/dist/commands/benchmark.d.ts +6 -0
- package/dist/commands/benchmark.d.ts.map +1 -0
- package/dist/commands/benchmark.js +215 -0
- package/dist/commands/benchmark.js.map +1 -0
- package/dist/commands/check.d.ts +10 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +333 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/context.d.ts +16 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +219 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/cost.d.ts +9 -0
- package/dist/commands/cost.d.ts.map +1 -0
- package/dist/commands/cost.js +142 -0
- package/dist/commands/cost.js.map +1 -0
- package/dist/commands/dashboard.d.ts +10 -0
- package/dist/commands/dashboard.d.ts.map +1 -0
- package/dist/commands/dashboard.js +462 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/diff.d.ts +6 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +118 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/doctor.d.ts +12 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +203 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/explain.d.ts +7 -0
- package/dist/commands/explain.d.ts.map +1 -0
- package/dist/commands/explain.js +164 -0
- package/dist/commands/explain.js.map +1 -0
- package/dist/commands/flaky.d.ts +10 -0
- package/dist/commands/flaky.d.ts.map +1 -0
- package/dist/commands/flaky.js +141 -0
- package/dist/commands/flaky.js.map +1 -0
- package/dist/commands/generateClaudeMd.d.ts +11 -0
- package/dist/commands/generateClaudeMd.d.ts.map +1 -0
- package/dist/commands/generateClaudeMd.js +278 -0
- package/dist/commands/generateClaudeMd.js.map +1 -0
- package/dist/commands/generateRules.d.ts +11 -0
- package/dist/commands/generateRules.d.ts.map +1 -0
- package/dist/commands/generateRules.js +413 -0
- package/dist/commands/generateRules.js.map +1 -0
- package/dist/commands/heatmap.d.ts +7 -0
- package/dist/commands/heatmap.d.ts.map +1 -0
- package/dist/commands/heatmap.js +117 -0
- package/dist/commands/heatmap.js.map +1 -0
- package/dist/commands/history.d.ts +13 -0
- package/dist/commands/history.d.ts.map +1 -0
- package/dist/commands/history.js +113 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/hooks.d.ts +9 -0
- package/dist/commands/hooks.d.ts.map +1 -0
- package/dist/commands/hooks.js +199 -0
- package/dist/commands/hooks.js.map +1 -0
- package/dist/commands/improve.d.ts +7 -0
- package/dist/commands/improve.d.ts.map +1 -0
- package/dist/commands/improve.js +192 -0
- package/dist/commands/improve.js.map +1 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +270 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/installHook.d.ts +9 -0
- package/dist/commands/installHook.d.ts.map +1 -0
- package/dist/commands/installHook.js +78 -0
- package/dist/commands/installHook.js.map +1 -0
- package/dist/commands/lint.d.ts +6 -0
- package/dist/commands/lint.d.ts.map +1 -0
- package/dist/commands/lint.js +237 -0
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/map.d.ts +9 -0
- package/dist/commands/map.d.ts.map +1 -0
- package/dist/commands/map.js +114 -0
- package/dist/commands/map.js.map +1 -0
- package/dist/commands/mcp.d.ts +6 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +151 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/models.d.ts +9 -0
- package/dist/commands/models.d.ts.map +1 -0
- package/dist/commands/models.js +89 -0
- package/dist/commands/models.js.map +1 -0
- package/dist/commands/pack.d.ts +10 -0
- package/dist/commands/pack.d.ts.map +1 -0
- package/dist/commands/pack.js +248 -0
- package/dist/commands/pack.js.map +1 -0
- package/dist/commands/recommend.d.ts +10 -0
- package/dist/commands/recommend.d.ts.map +1 -0
- package/dist/commands/recommend.js +472 -0
- package/dist/commands/recommend.js.map +1 -0
- package/dist/commands/regression.d.ts +10 -0
- package/dist/commands/regression.d.ts.map +1 -0
- package/dist/commands/regression.js +212 -0
- package/dist/commands/regression.js.map +1 -0
- package/dist/commands/repl.d.ts +9 -0
- package/dist/commands/repl.d.ts.map +1 -0
- package/dist/commands/repl.js +245 -0
- package/dist/commands/repl.js.map +1 -0
- package/dist/commands/scan.d.ts +10 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +352 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/score.d.ts +10 -0
- package/dist/commands/score.d.ts.map +1 -0
- package/dist/commands/score.js +192 -0
- package/dist/commands/score.js.map +1 -0
- package/dist/commands/security.d.ts +10 -0
- package/dist/commands/security.d.ts.map +1 -0
- package/dist/commands/security.js +211 -0
- package/dist/commands/security.js.map +1 -0
- package/dist/commands/simulate.d.ts +7 -0
- package/dist/commands/simulate.d.ts.map +1 -0
- package/dist/commands/simulate.js +149 -0
- package/dist/commands/simulate.js.map +1 -0
- package/dist/commands/summary.d.ts +9 -0
- package/dist/commands/summary.d.ts.map +1 -0
- package/dist/commands/summary.js +271 -0
- package/dist/commands/summary.js.map +1 -0
- package/dist/commands/test.d.ts +9 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +219 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/commands/ui.d.ts +8 -0
- package/dist/commands/ui.d.ts.map +1 -0
- package/dist/commands/ui.js +222 -0
- package/dist/commands/ui.js.map +1 -0
- package/dist/commands/validate.d.ts +7 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +254 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/commands/workflow.d.ts +39 -0
- package/dist/commands/workflow.d.ts.map +1 -0
- package/dist/commands/workflow.js +309 -0
- package/dist/commands/workflow.js.map +1 -0
- package/dist/core/__tests__/contextAnalyzer.test.d.ts +2 -0
- package/dist/core/__tests__/contextAnalyzer.test.d.ts.map +1 -0
- package/dist/core/__tests__/contextAnalyzer.test.js +48 -0
- package/dist/core/__tests__/contextAnalyzer.test.js.map +1 -0
- package/dist/core/__tests__/promptLinter.test.d.ts +2 -0
- package/dist/core/__tests__/promptLinter.test.d.ts.map +1 -0
- package/dist/core/__tests__/promptLinter.test.js +74 -0
- package/dist/core/__tests__/promptLinter.test.js.map +1 -0
- package/dist/core/__tests__/promptRunner.test.d.ts +2 -0
- package/dist/core/__tests__/promptRunner.test.d.ts.map +1 -0
- package/dist/core/__tests__/promptRunner.test.js +84 -0
- package/dist/core/__tests__/promptRunner.test.js.map +1 -0
- package/dist/core/__tests__/securityScanner.test.d.ts +2 -0
- package/dist/core/__tests__/securityScanner.test.d.ts.map +1 -0
- package/dist/core/__tests__/securityScanner.test.js +39 -0
- package/dist/core/__tests__/securityScanner.test.js.map +1 -0
- package/dist/core/agentTracer.d.ts +21 -0
- package/dist/core/agentTracer.d.ts.map +1 -0
- package/dist/core/agentTracer.js +355 -0
- package/dist/core/agentTracer.js.map +1 -0
- package/dist/core/anthropicClient.d.ts +26 -0
- package/dist/core/anthropicClient.d.ts.map +1 -0
- package/dist/core/anthropicClient.js +62 -0
- package/dist/core/anthropicClient.js.map +1 -0
- package/dist/core/benchmarkRunner.d.ts +25 -0
- package/dist/core/benchmarkRunner.d.ts.map +1 -0
- package/dist/core/benchmarkRunner.js +182 -0
- package/dist/core/benchmarkRunner.js.map +1 -0
- package/dist/core/contextAnalyzer.d.ts +19 -0
- package/dist/core/contextAnalyzer.d.ts.map +1 -0
- package/dist/core/contextAnalyzer.js +221 -0
- package/dist/core/contextAnalyzer.js.map +1 -0
- package/dist/core/contextPacker.d.ts +26 -0
- package/dist/core/contextPacker.d.ts.map +1 -0
- package/dist/core/contextPacker.js +358 -0
- package/dist/core/contextPacker.js.map +1 -0
- package/dist/core/datasetRunner.d.ts +10 -0
- package/dist/core/datasetRunner.d.ts.map +1 -0
- package/dist/core/datasetRunner.js +130 -0
- package/dist/core/datasetRunner.js.map +1 -0
- package/dist/core/doctorRunner.d.ts +24 -0
- package/dist/core/doctorRunner.d.ts.map +1 -0
- package/dist/core/doctorRunner.js +278 -0
- package/dist/core/doctorRunner.js.map +1 -0
- package/dist/core/hookScanner.d.ts +24 -0
- package/dist/core/hookScanner.d.ts.map +1 -0
- package/dist/core/hookScanner.js +226 -0
- package/dist/core/hookScanner.js.map +1 -0
- package/dist/core/mcpScanner.d.ts +22 -0
- package/dist/core/mcpScanner.d.ts.map +1 -0
- package/dist/core/mcpScanner.js +290 -0
- package/dist/core/mcpScanner.js.map +1 -0
- package/dist/core/modelRegistry.d.ts +35 -0
- package/dist/core/modelRegistry.d.ts.map +1 -0
- package/dist/core/modelRegistry.js +97 -0
- package/dist/core/modelRegistry.js.map +1 -0
- package/dist/core/promptDiff.d.ts +25 -0
- package/dist/core/promptDiff.d.ts.map +1 -0
- package/dist/core/promptDiff.js +130 -0
- package/dist/core/promptDiff.js.map +1 -0
- package/dist/core/promptExplainer.d.ts +17 -0
- package/dist/core/promptExplainer.d.ts.map +1 -0
- package/dist/core/promptExplainer.js +334 -0
- package/dist/core/promptExplainer.js.map +1 -0
- package/dist/core/promptImprover.d.ts +19 -0
- package/dist/core/promptImprover.d.ts.map +1 -0
- package/dist/core/promptImprover.js +260 -0
- package/dist/core/promptImprover.js.map +1 -0
- package/dist/core/promptLinter.d.ts +24 -0
- package/dist/core/promptLinter.d.ts.map +1 -0
- package/dist/core/promptLinter.js +319 -0
- package/dist/core/promptLinter.js.map +1 -0
- package/dist/core/promptRunner.d.ts +31 -0
- package/dist/core/promptRunner.d.ts.map +1 -0
- package/dist/core/promptRunner.js +427 -0
- package/dist/core/promptRunner.js.map +1 -0
- package/dist/core/providers/anthropic.d.ts +10 -0
- package/dist/core/providers/anthropic.d.ts.map +1 -0
- package/dist/core/providers/anthropic.js +26 -0
- package/dist/core/providers/anthropic.js.map +1 -0
- package/dist/core/providers/base.d.ts +22 -0
- package/dist/core/providers/base.d.ts.map +1 -0
- package/dist/core/providers/base.js +2 -0
- package/dist/core/providers/base.js.map +1 -0
- package/dist/core/providers/factory.d.ts +7 -0
- package/dist/core/providers/factory.d.ts.map +1 -0
- package/dist/core/providers/factory.js +42 -0
- package/dist/core/providers/factory.js.map +1 -0
- package/dist/core/providers/google.d.ts +10 -0
- package/dist/core/providers/google.d.ts.map +1 -0
- package/dist/core/providers/google.js +47 -0
- package/dist/core/providers/google.js.map +1 -0
- package/dist/core/providers/openai.d.ts +19 -0
- package/dist/core/providers/openai.d.ts.map +1 -0
- package/dist/core/providers/openai.js +54 -0
- package/dist/core/providers/openai.js.map +1 -0
- package/dist/core/regressionRunner.d.ts +11 -0
- package/dist/core/regressionRunner.d.ts.map +1 -0
- package/dist/core/regressionRunner.js +116 -0
- package/dist/core/regressionRunner.js.map +1 -0
- package/dist/core/repositorySimulator.d.ts +17 -0
- package/dist/core/repositorySimulator.d.ts.map +1 -0
- package/dist/core/repositorySimulator.js +104 -0
- package/dist/core/repositorySimulator.js.map +1 -0
- package/dist/core/scorer.d.ts +30 -0
- package/dist/core/scorer.d.ts.map +1 -0
- package/dist/core/scorer.js +317 -0
- package/dist/core/scorer.js.map +1 -0
- package/dist/core/securityScanner.d.ts +23 -0
- package/dist/core/securityScanner.d.ts.map +1 -0
- package/dist/core/securityScanner.js +216 -0
- package/dist/core/securityScanner.js.map +1 -0
- package/dist/core/skillValidator.d.ts +41 -0
- package/dist/core/skillValidator.d.ts.map +1 -0
- package/dist/core/skillValidator.js +235 -0
- package/dist/core/skillValidator.js.map +1 -0
- package/dist/core/testHistory.d.ts +44 -0
- package/dist/core/testHistory.d.ts.map +1 -0
- package/dist/core/testHistory.js +91 -0
- package/dist/core/testHistory.js.map +1 -0
- package/dist/tokenizers/claudeTokenizer.d.ts +26 -0
- package/dist/tokenizers/claudeTokenizer.d.ts.map +1 -0
- package/dist/tokenizers/claudeTokenizer.js +83 -0
- package/dist/tokenizers/claudeTokenizer.js.map +1 -0
- package/dist/types/agent.d.ts +26 -0
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/agent.js +5 -0
- package/dist/types/agent.js.map +1 -0
- package/dist/types/config.d.ts +30 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +5 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/context.d.ts +77 -0
- package/dist/types/context.d.ts.map +1 -0
- package/dist/types/context.js +5 -0
- package/dist/types/context.js.map +1 -0
- package/dist/types/dataset.d.ts +26 -0
- package/dist/types/dataset.d.ts.map +1 -0
- package/dist/types/dataset.js +5 -0
- package/dist/types/dataset.js.map +1 -0
- package/dist/types/diagnostics.d.ts +31 -0
- package/dist/types/diagnostics.d.ts.map +1 -0
- package/dist/types/diagnostics.js +5 -0
- package/dist/types/diagnostics.js.map +1 -0
- package/dist/types/prompt.d.ts +53 -0
- package/dist/types/prompt.d.ts.map +1 -0
- package/dist/types/prompt.js +5 -0
- package/dist/types/prompt.js.map +1 -0
- package/dist/types/results.d.ts +42 -0
- package/dist/types/results.d.ts.map +1 -0
- package/dist/types/results.js +5 -0
- package/dist/types/results.js.map +1 -0
- package/dist/ui/dashboard.d.ts +57 -0
- package/dist/ui/dashboard.d.ts.map +1 -0
- package/dist/ui/dashboard.js +644 -0
- package/dist/ui/dashboard.js.map +1 -0
- package/dist/utils/__tests__/hashing.test.d.ts +2 -0
- package/dist/utils/__tests__/hashing.test.d.ts.map +1 -0
- package/dist/utils/__tests__/hashing.test.js +28 -0
- package/dist/utils/__tests__/hashing.test.js.map +1 -0
- package/dist/utils/__tests__/output.test.d.ts +2 -0
- package/dist/utils/__tests__/output.test.d.ts.map +1 -0
- package/dist/utils/__tests__/output.test.js +62 -0
- package/dist/utils/__tests__/output.test.js.map +1 -0
- package/dist/utils/cache.d.ts +29 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +87 -0
- package/dist/utils/cache.js.map +1 -0
- package/dist/utils/config.d.ts +15 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +61 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/errors.d.ts +43 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +83 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/fs.d.ts +44 -0
- package/dist/utils/fs.d.ts.map +1 -0
- package/dist/utils/fs.js +119 -0
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/hashing.d.ts +13 -0
- package/dist/utils/hashing.d.ts.map +1 -0
- package/dist/utils/hashing.js +18 -0
- package/dist/utils/hashing.js.map +1 -0
- package/dist/utils/logger.d.ts +32 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +76 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/output.d.ts +34 -0
- package/dist/utils/output.d.ts.map +1 -0
- package/dist/utils/output.js +99 -0
- package/dist/utils/output.js.map +1 -0
- package/dist/utils/paths.d.ts +33 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +51 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/spinner.d.ts +23 -0
- package/dist/utils/spinner.d.ts.map +1 -0
- package/dist/utils/spinner.js +79 -0
- package/dist/utils/spinner.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Doctor runner: environment and project diagnostics.
|
|
3
|
+
*
|
|
4
|
+
* Runs a series of checks to verify that the development environment
|
|
5
|
+
* and project structure are properly configured for codeprobe.
|
|
6
|
+
*/
|
|
7
|
+
import { stat, access, constants } from 'node:fs/promises';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { execFile } from 'node:child_process';
|
|
10
|
+
import { promisify } from 'node:util';
|
|
11
|
+
import { fileExists, isDirectory } from '../utils/fs.js';
|
|
12
|
+
import { resolveProjectRoot } from '../utils/paths.js';
|
|
13
|
+
const execFileAsync = promisify(execFile);
|
|
14
|
+
/**
|
|
15
|
+
* Parse a Node.js version string (e.g. "v18.17.0") into its major
|
|
16
|
+
* version number.
|
|
17
|
+
*/
|
|
18
|
+
function parseMajorVersion(versionStr) {
|
|
19
|
+
const match = /^v?(\d+)/.exec(versionStr.trim());
|
|
20
|
+
if (!match?.[1])
|
|
21
|
+
return null;
|
|
22
|
+
return parseInt(match[1], 10);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Check Node.js version >= 18.
|
|
26
|
+
*/
|
|
27
|
+
async function checkNodeVersion() {
|
|
28
|
+
const version = process.version;
|
|
29
|
+
const major = parseMajorVersion(version);
|
|
30
|
+
if (major === null) {
|
|
31
|
+
return {
|
|
32
|
+
name: 'Node.js version',
|
|
33
|
+
status: 'warn',
|
|
34
|
+
message: `Unable to parse Node.js version: ${version}`,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
if (major < 18) {
|
|
38
|
+
return {
|
|
39
|
+
name: 'Node.js version',
|
|
40
|
+
status: 'fail',
|
|
41
|
+
message: `Node.js ${version} is below the minimum required version (>=18).`,
|
|
42
|
+
details: 'Upgrade Node.js to version 18 or later: https://nodejs.org/',
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
name: 'Node.js version',
|
|
47
|
+
status: 'pass',
|
|
48
|
+
message: `Node.js ${version} meets the minimum requirement (>=18).`,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Check that the prompts/ directory exists.
|
|
53
|
+
*/
|
|
54
|
+
async function checkPromptsDir() {
|
|
55
|
+
const root = resolveProjectRoot();
|
|
56
|
+
const promptsDir = join(root, 'prompts');
|
|
57
|
+
if (await isDirectory(promptsDir)) {
|
|
58
|
+
return {
|
|
59
|
+
name: 'prompts/ directory',
|
|
60
|
+
status: 'pass',
|
|
61
|
+
message: 'prompts/ directory exists.',
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
name: 'prompts/ directory',
|
|
66
|
+
status: 'warn',
|
|
67
|
+
message: 'prompts/ directory not found.',
|
|
68
|
+
details: 'Create a prompts/ directory to store your prompt specification files.',
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Check that the datasets/ directory exists.
|
|
73
|
+
*/
|
|
74
|
+
async function checkDatasetsDir() {
|
|
75
|
+
const root = resolveProjectRoot();
|
|
76
|
+
const datasetsDir = join(root, 'datasets');
|
|
77
|
+
if (await isDirectory(datasetsDir)) {
|
|
78
|
+
return {
|
|
79
|
+
name: 'datasets/ directory',
|
|
80
|
+
status: 'pass',
|
|
81
|
+
message: 'datasets/ directory exists.',
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
name: 'datasets/ directory',
|
|
86
|
+
status: 'warn',
|
|
87
|
+
message: 'datasets/ directory not found.',
|
|
88
|
+
details: 'Create a datasets/ directory to store evaluation datasets (JSONL files).',
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Check that codeprobe.config.yaml exists.
|
|
93
|
+
*/
|
|
94
|
+
async function checkConfigFile() {
|
|
95
|
+
const root = resolveProjectRoot();
|
|
96
|
+
const configNames = [
|
|
97
|
+
'codeprobe.config.yaml',
|
|
98
|
+
'codeprobe.config.yml',
|
|
99
|
+
'.codeprobe.yaml',
|
|
100
|
+
'.codeprobe.yml',
|
|
101
|
+
// Backward compat: also check legacy config file names
|
|
102
|
+
'claude-test.config.yaml',
|
|
103
|
+
'claude-test.config.yml',
|
|
104
|
+
'.claude-test.yaml',
|
|
105
|
+
'.claude-test.yml',
|
|
106
|
+
];
|
|
107
|
+
for (const name of configNames) {
|
|
108
|
+
const configPath = join(root, name);
|
|
109
|
+
if (await fileExists(configPath)) {
|
|
110
|
+
return {
|
|
111
|
+
name: 'Configuration file',
|
|
112
|
+
status: 'pass',
|
|
113
|
+
message: `Configuration file found: ${name}`,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
name: 'Configuration file',
|
|
119
|
+
status: 'warn',
|
|
120
|
+
message: 'No codeprobe configuration file found.',
|
|
121
|
+
details: 'Create a codeprobe.config.yaml file to customize default settings. ' +
|
|
122
|
+
'Run with defaults if no configuration is needed.',
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Check that ANTHROPIC_API_KEY environment variable is set.
|
|
127
|
+
*/
|
|
128
|
+
async function checkApiKey() {
|
|
129
|
+
const key = process.env['ANTHROPIC_API_KEY'];
|
|
130
|
+
if (!key) {
|
|
131
|
+
return {
|
|
132
|
+
name: 'ANTHROPIC_API_KEY',
|
|
133
|
+
status: 'warn',
|
|
134
|
+
message: 'ANTHROPIC_API_KEY environment variable is not set.',
|
|
135
|
+
details: 'Set ANTHROPIC_API_KEY to enable live model calls. ' +
|
|
136
|
+
'Mock mode works without an API key.',
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
if (key.length < 10) {
|
|
140
|
+
return {
|
|
141
|
+
name: 'ANTHROPIC_API_KEY',
|
|
142
|
+
status: 'warn',
|
|
143
|
+
message: 'ANTHROPIC_API_KEY appears to be too short to be valid.',
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
name: 'ANTHROPIC_API_KEY',
|
|
148
|
+
status: 'pass',
|
|
149
|
+
message: 'ANTHROPIC_API_KEY is set.',
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Check that .cache/ directory exists and is writable.
|
|
154
|
+
*/
|
|
155
|
+
async function checkCacheDir() {
|
|
156
|
+
const root = resolveProjectRoot();
|
|
157
|
+
const cacheDir = join(root, '.cache');
|
|
158
|
+
if (!(await isDirectory(cacheDir))) {
|
|
159
|
+
// Check if it exists but is a file
|
|
160
|
+
if (await fileExists(cacheDir)) {
|
|
161
|
+
return {
|
|
162
|
+
name: '.cache/ directory',
|
|
163
|
+
status: 'fail',
|
|
164
|
+
message: '.cache exists but is not a directory.',
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
name: '.cache/ directory',
|
|
169
|
+
status: 'warn',
|
|
170
|
+
message: '.cache/ directory does not exist.',
|
|
171
|
+
details: 'The cache directory will be created automatically when caching is used. ' +
|
|
172
|
+
'You can also create it manually: mkdir .cache',
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
await access(cacheDir, constants.W_OK);
|
|
177
|
+
return {
|
|
178
|
+
name: '.cache/ directory',
|
|
179
|
+
status: 'pass',
|
|
180
|
+
message: '.cache/ directory exists and is writable.',
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return {
|
|
185
|
+
name: '.cache/ directory',
|
|
186
|
+
status: 'fail',
|
|
187
|
+
message: '.cache/ directory exists but is not writable.',
|
|
188
|
+
details: 'Check file permissions on the .cache/ directory.',
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Check that package.json exists in the project root.
|
|
194
|
+
*/
|
|
195
|
+
async function checkPackageJson() {
|
|
196
|
+
const root = resolveProjectRoot();
|
|
197
|
+
const pkgPath = join(root, 'package.json');
|
|
198
|
+
if (await fileExists(pkgPath)) {
|
|
199
|
+
return {
|
|
200
|
+
name: 'package.json',
|
|
201
|
+
status: 'pass',
|
|
202
|
+
message: 'package.json exists in the project root.',
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
name: 'package.json',
|
|
207
|
+
status: 'warn',
|
|
208
|
+
message: 'package.json not found in the project root.',
|
|
209
|
+
details: 'A package.json is recommended for managing dependencies.',
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Check that TypeScript is installed and accessible.
|
|
214
|
+
*/
|
|
215
|
+
async function checkTypeScript() {
|
|
216
|
+
try {
|
|
217
|
+
const { stdout } = await execFileAsync('npx', ['tsc', '--version'], {
|
|
218
|
+
timeout: 10000,
|
|
219
|
+
});
|
|
220
|
+
const version = stdout.trim();
|
|
221
|
+
return {
|
|
222
|
+
name: 'TypeScript',
|
|
223
|
+
status: 'pass',
|
|
224
|
+
message: `TypeScript is installed: ${version}`,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
// Try checking node_modules directly
|
|
229
|
+
const root = resolveProjectRoot();
|
|
230
|
+
const tscPath = join(root, 'node_modules', '.bin', 'tsc');
|
|
231
|
+
try {
|
|
232
|
+
await stat(tscPath);
|
|
233
|
+
return {
|
|
234
|
+
name: 'TypeScript',
|
|
235
|
+
status: 'pass',
|
|
236
|
+
message: 'TypeScript is installed (found in node_modules).',
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
// Fall through to warn
|
|
241
|
+
}
|
|
242
|
+
return {
|
|
243
|
+
name: 'TypeScript',
|
|
244
|
+
status: 'warn',
|
|
245
|
+
message: 'TypeScript does not appear to be installed.',
|
|
246
|
+
details: 'Install TypeScript: npm install --save-dev typescript',
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Run all diagnostic checks and return the results.
|
|
252
|
+
*
|
|
253
|
+
* Checks:
|
|
254
|
+
* 1. Node.js version (>= 18)
|
|
255
|
+
* 2. prompts/ directory exists
|
|
256
|
+
* 3. datasets/ directory exists
|
|
257
|
+
* 4. codeprobe.config.yaml exists
|
|
258
|
+
* 5. ANTHROPIC_API_KEY env var is set
|
|
259
|
+
* 6. .cache/ directory exists/writable
|
|
260
|
+
* 7. package.json exists
|
|
261
|
+
* 8. TypeScript installed
|
|
262
|
+
*
|
|
263
|
+
* @returns Array of diagnostic check results.
|
|
264
|
+
*/
|
|
265
|
+
export async function runDiagnostics() {
|
|
266
|
+
const checks = await Promise.all([
|
|
267
|
+
checkNodeVersion(),
|
|
268
|
+
checkPromptsDir(),
|
|
269
|
+
checkDatasetsDir(),
|
|
270
|
+
checkConfigFile(),
|
|
271
|
+
checkApiKey(),
|
|
272
|
+
checkCacheDir(),
|
|
273
|
+
checkPackageJson(),
|
|
274
|
+
checkTypeScript(),
|
|
275
|
+
]);
|
|
276
|
+
return checks;
|
|
277
|
+
}
|
|
278
|
+
//# sourceMappingURL=doctorRunner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctorRunner.js","sourceRoot":"","sources":["../../src/core/doctorRunner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook scanner: detect hook-like assets in a repository.
|
|
3
|
+
*
|
|
4
|
+
* Looks for hook definitions in Claude Code configuration,
|
|
5
|
+
* package.json scripts, Husky, git hooks directories, and
|
|
6
|
+
* custom hooks directories.
|
|
7
|
+
*/
|
|
8
|
+
import type { HookInfo } from '../types/agent.js';
|
|
9
|
+
/**
|
|
10
|
+
* Scan a repository for hook-like assets.
|
|
11
|
+
*
|
|
12
|
+
* Detects hooks from multiple sources:
|
|
13
|
+
* - .claude/settings.json hooks configuration
|
|
14
|
+
* - .claude/hooks/ directory
|
|
15
|
+
* - hooks/ directory at repository root
|
|
16
|
+
* - package.json scripts with "hook" in the name
|
|
17
|
+
* - .husky/ directory (Husky git hooks)
|
|
18
|
+
* - .githooks/ directory (custom git hooks)
|
|
19
|
+
*
|
|
20
|
+
* @param rootPath Absolute path to the repository root.
|
|
21
|
+
* @returns Array of detected hook descriptions.
|
|
22
|
+
*/
|
|
23
|
+
export declare function scanForHooks(rootPath: string): Promise<HookInfo[]>;
|
|
24
|
+
//# sourceMappingURL=hookScanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hookScanner.d.ts","sourceRoot":"","sources":["../../src/core/hookScanner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAwMlD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAmBxE"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook scanner: detect hook-like assets in a repository.
|
|
3
|
+
*
|
|
4
|
+
* Looks for hook definitions in Claude Code configuration,
|
|
5
|
+
* package.json scripts, Husky, git hooks directories, and
|
|
6
|
+
* custom hooks directories.
|
|
7
|
+
*/
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { readFile, stat, readdir } from 'node:fs/promises';
|
|
10
|
+
/**
|
|
11
|
+
* Safely read and parse a JSON file. Returns null on failure.
|
|
12
|
+
*/
|
|
13
|
+
async function readJsonFile(filePath) {
|
|
14
|
+
try {
|
|
15
|
+
const content = await readFile(filePath, 'utf-8');
|
|
16
|
+
const parsed = JSON.parse(content);
|
|
17
|
+
if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
18
|
+
return parsed;
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* List files in a directory. Returns an empty array if the directory
|
|
28
|
+
* does not exist or is not accessible.
|
|
29
|
+
*/
|
|
30
|
+
async function listDirectory(dirPath) {
|
|
31
|
+
try {
|
|
32
|
+
const dirStat = await stat(dirPath);
|
|
33
|
+
if (!dirStat.isDirectory())
|
|
34
|
+
return [];
|
|
35
|
+
const entries = await readdir(dirPath);
|
|
36
|
+
return entries;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Scan .claude/settings.json for hook configurations.
|
|
44
|
+
*/
|
|
45
|
+
async function scanClaudeSettings(rootPath) {
|
|
46
|
+
const hooks = [];
|
|
47
|
+
const settingsPath = join(rootPath, '.claude', 'settings.json');
|
|
48
|
+
const data = await readJsonFile(settingsPath);
|
|
49
|
+
if (!data)
|
|
50
|
+
return hooks;
|
|
51
|
+
// Look for a "hooks" key in the settings
|
|
52
|
+
if (typeof data['hooks'] === 'object' && data['hooks'] !== null) {
|
|
53
|
+
const hooksObj = data['hooks'];
|
|
54
|
+
for (const [event, config] of Object.entries(hooksObj)) {
|
|
55
|
+
if (typeof config === 'string') {
|
|
56
|
+
hooks.push({
|
|
57
|
+
path: settingsPath,
|
|
58
|
+
type: 'claude-hook',
|
|
59
|
+
description: `Claude hook for event "${event}": ${config}`,
|
|
60
|
+
events: [event],
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
else if (typeof config === 'object' && config !== null) {
|
|
64
|
+
const configObj = config;
|
|
65
|
+
const command = typeof configObj['command'] === 'string'
|
|
66
|
+
? configObj['command']
|
|
67
|
+
: 'unknown';
|
|
68
|
+
hooks.push({
|
|
69
|
+
path: settingsPath,
|
|
70
|
+
type: 'claude-hook',
|
|
71
|
+
description: `Claude hook for event "${event}": ${command}`,
|
|
72
|
+
events: [event],
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return hooks;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Scan .claude/hooks/ directory for hook scripts.
|
|
81
|
+
*/
|
|
82
|
+
async function scanClaudeHooksDir(rootPath) {
|
|
83
|
+
const hooks = [];
|
|
84
|
+
const hooksDir = join(rootPath, '.claude', 'hooks');
|
|
85
|
+
const entries = await listDirectory(hooksDir);
|
|
86
|
+
for (const entry of entries) {
|
|
87
|
+
const fullPath = join(hooksDir, entry);
|
|
88
|
+
hooks.push({
|
|
89
|
+
path: fullPath,
|
|
90
|
+
type: 'claude-hook',
|
|
91
|
+
description: `Claude hook script: ${entry}`,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return hooks;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Scan hooks/ directory at repository root.
|
|
98
|
+
*/
|
|
99
|
+
async function scanRootHooksDir(rootPath) {
|
|
100
|
+
const hooks = [];
|
|
101
|
+
const hooksDir = join(rootPath, 'hooks');
|
|
102
|
+
const entries = await listDirectory(hooksDir);
|
|
103
|
+
for (const entry of entries) {
|
|
104
|
+
const fullPath = join(hooksDir, entry);
|
|
105
|
+
hooks.push({
|
|
106
|
+
path: fullPath,
|
|
107
|
+
type: 'project-hook',
|
|
108
|
+
description: `Hook script in hooks/ directory: ${entry}`,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return hooks;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Scan package.json for scripts with "hook" in their name.
|
|
115
|
+
*/
|
|
116
|
+
async function scanPackageJsonHooks(rootPath) {
|
|
117
|
+
const hooks = [];
|
|
118
|
+
const pkgPath = join(rootPath, 'package.json');
|
|
119
|
+
const data = await readJsonFile(pkgPath);
|
|
120
|
+
if (!data)
|
|
121
|
+
return hooks;
|
|
122
|
+
if (typeof data['scripts'] === 'object' && data['scripts'] !== null) {
|
|
123
|
+
const scripts = data['scripts'];
|
|
124
|
+
for (const [name, command] of Object.entries(scripts)) {
|
|
125
|
+
if (name.toLowerCase().includes('hook') && typeof command === 'string') {
|
|
126
|
+
hooks.push({
|
|
127
|
+
path: pkgPath,
|
|
128
|
+
type: 'npm-hook',
|
|
129
|
+
description: `npm script "${name}": ${command}`,
|
|
130
|
+
events: [name],
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return hooks;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Scan .husky/ directory for Husky git hooks.
|
|
139
|
+
*/
|
|
140
|
+
async function scanHuskyDir(rootPath) {
|
|
141
|
+
const hooks = [];
|
|
142
|
+
const huskyDir = join(rootPath, '.husky');
|
|
143
|
+
const entries = await listDirectory(huskyDir);
|
|
144
|
+
for (const entry of entries) {
|
|
145
|
+
// Skip husky internal files
|
|
146
|
+
if (entry === '_' || entry.startsWith('.'))
|
|
147
|
+
continue;
|
|
148
|
+
const fullPath = join(huskyDir, entry);
|
|
149
|
+
try {
|
|
150
|
+
const entryStat = await stat(fullPath);
|
|
151
|
+
if (!entryStat.isFile())
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
hooks.push({
|
|
158
|
+
path: fullPath,
|
|
159
|
+
type: 'husky-hook',
|
|
160
|
+
description: `Husky git hook: ${entry}`,
|
|
161
|
+
events: [entry],
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
return hooks;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Scan .githooks/ directory for custom git hooks.
|
|
168
|
+
*/
|
|
169
|
+
async function scanGitHooksDir(rootPath) {
|
|
170
|
+
const hooks = [];
|
|
171
|
+
const gitHooksDir = join(rootPath, '.githooks');
|
|
172
|
+
const entries = await listDirectory(gitHooksDir);
|
|
173
|
+
for (const entry of entries) {
|
|
174
|
+
const fullPath = join(gitHooksDir, entry);
|
|
175
|
+
try {
|
|
176
|
+
const entryStat = await stat(fullPath);
|
|
177
|
+
if (!entryStat.isFile())
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
hooks.push({
|
|
184
|
+
path: fullPath,
|
|
185
|
+
type: 'git-hook',
|
|
186
|
+
description: `Custom git hook: ${entry}`,
|
|
187
|
+
events: [entry],
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
return hooks;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Scan a repository for hook-like assets.
|
|
194
|
+
*
|
|
195
|
+
* Detects hooks from multiple sources:
|
|
196
|
+
* - .claude/settings.json hooks configuration
|
|
197
|
+
* - .claude/hooks/ directory
|
|
198
|
+
* - hooks/ directory at repository root
|
|
199
|
+
* - package.json scripts with "hook" in the name
|
|
200
|
+
* - .husky/ directory (Husky git hooks)
|
|
201
|
+
* - .githooks/ directory (custom git hooks)
|
|
202
|
+
*
|
|
203
|
+
* @param rootPath Absolute path to the repository root.
|
|
204
|
+
* @returns Array of detected hook descriptions.
|
|
205
|
+
*/
|
|
206
|
+
export async function scanForHooks(rootPath) {
|
|
207
|
+
// Verify root exists
|
|
208
|
+
try {
|
|
209
|
+
const rootStat = await stat(rootPath);
|
|
210
|
+
if (!rootStat.isDirectory())
|
|
211
|
+
return [];
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
return [];
|
|
215
|
+
}
|
|
216
|
+
const results = await Promise.all([
|
|
217
|
+
scanClaudeSettings(rootPath),
|
|
218
|
+
scanClaudeHooksDir(rootPath),
|
|
219
|
+
scanRootHooksDir(rootPath),
|
|
220
|
+
scanPackageJsonHooks(rootPath),
|
|
221
|
+
scanHuskyDir(rootPath),
|
|
222
|
+
scanGitHooksDir(rootPath),
|
|
223
|
+
]);
|
|
224
|
+
return results.flat();
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=hookScanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hookScanner.js","sourceRoot":"","sources":["../../src/core/hookScanner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAG3D;;GAEG;AACH,KAAK,UAAU,YAAY,CAAC,QAAgB;IAC1C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAClD,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC5C,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5E,OAAO,MAAiC,CAAC;QAC3C,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,aAAa,CAAC,OAAe;IAC1C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;QACpC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE;YAAE,OAAO,EAAE,CAAC;QACtC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;QACvC,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,kBAAkB,CAAC,QAAgB;IAChD,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;IAChE,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,YAAY,CAAC,CAAC;IAE9C,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IAExB,yCAAyC;IACzC,IAAI,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;QAChE,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAA4B,CAAC;QAE1D,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACvD,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;gBAC/B,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,YAAY;oBAClB,IAAI,EAAE,aAAa;oBACnB,WAAW,EAAE,0BAA0B,KAAK,MAAM,MAAM,EAAE;oBAC1D,MAAM,EAAE,CAAC,KAAK,CAAC;iBAChB,CAAC,CAAC;YACL,CAAC;iBAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACzD,MAAM,SAAS,GAAG,MAAiC,CAAC;gBACpD,MAAM,OAAO,GAAG,OAAO,SAAS,CAAC,SAAS,CAAC,KAAK,QAAQ;oBACtD,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;oBACtB,CAAC,CAAC,SAAS,CAAC;gBACd,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,YAAY;oBAClB,IAAI,EAAE,aAAa;oBACnB,WAAW,EAAE,0BAA0B,KAAK,MAAM,OAAO,EAAE;oBAC3D,MAAM,EAAE,CAAC,KAAK,CAAC;iBAChB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,kBAAkB,CAAC,QAAgB;IAChD,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAC;IAE9C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACvC,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,aAAa;YACnB,WAAW,EAAE,uBAAuB,KAAK,EAAE;SAC5C,CAAC,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,gBAAgB,CAAC,QAAgB;IAC9C,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAC;IAE9C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACvC,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,cAAc;YACpB,WAAW,EAAE,oCAAoC,KAAK,EAAE;SACzD,CAAC,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,oBAAoB,CAAC,QAAgB;IAClD,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,CAAC;IAEzC,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IAExB,IAAI,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,EAAE,CAAC;QACpE,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAA4B,CAAC;QAE3D,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YACtD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;gBACvE,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,UAAU;oBAChB,WAAW,EAAE,eAAe,IAAI,MAAM,OAAO,EAAE;oBAC/C,MAAM,EAAE,CAAC,IAAI,CAAC;iBACf,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,YAAY,CAAC,QAAgB;IAC1C,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAC;IAE9C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,4BAA4B;QAC5B,IAAI,KAAK,KAAK,GAAG,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAErD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACvC,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE;gBAAE,SAAS;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QAED,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,mBAAmB,KAAK,EAAE;YACvC,MAAM,EAAE,CAAC,KAAK,CAAC;SAChB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,eAAe,CAAC,QAAgB;IAC7C,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,WAAW,CAAC,CAAC;IAEjD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QAC1C,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE;gBAAE,SAAS;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QAED,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,UAAU;YAChB,WAAW,EAAE,oBAAoB,KAAK,EAAE;YACxC,MAAM,EAAE,CAAC,KAAK,CAAC;SAChB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,qBAAqB;IACrB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE;YAAE,OAAO,EAAE,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAChC,kBAAkB,CAAC,QAAQ,CAAC;QAC5B,kBAAkB,CAAC,QAAQ,CAAC;QAC5B,gBAAgB,CAAC,QAAQ,CAAC;QAC1B,oBAAoB,CAAC,QAAQ,CAAC;QAC9B,YAAY,CAAC,QAAQ,CAAC;QACtB,eAAe,CAAC,QAAQ,CAAC;KAC1B,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;AACxB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP (Model Context Protocol) scanner.
|
|
3
|
+
*
|
|
4
|
+
* Detects MCP-related configuration files, server definitions,
|
|
5
|
+
* and dependencies in a repository.
|
|
6
|
+
*/
|
|
7
|
+
import type { MCPAsset } from '../types/agent.js';
|
|
8
|
+
/**
|
|
9
|
+
* Scan a repository for MCP-related files and configurations.
|
|
10
|
+
*
|
|
11
|
+
* Detects:
|
|
12
|
+
* - .mcp.json, mcp.json root config files
|
|
13
|
+
* - .claude/mcp*.json config files
|
|
14
|
+
* - Files containing "mcpServers" or "mcp_servers" patterns
|
|
15
|
+
* - package.json MCP-related dependencies
|
|
16
|
+
* - Files referencing "ModelContextProtocol" or "@modelcontextprotocol"
|
|
17
|
+
*
|
|
18
|
+
* @param rootPath Absolute path to the repository root.
|
|
19
|
+
* @returns Array of detected MCP assets.
|
|
20
|
+
*/
|
|
21
|
+
export declare function scanForMCP(rootPath: string): Promise<MCPAsset[]>;
|
|
22
|
+
//# sourceMappingURL=mcpScanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpScanner.d.ts","sourceRoot":"","sources":["../../src/core/mcpScanner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAwQlD;;;;;;;;;;;;GAYG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CA+BtE"}
|