webmcp-cli 1.0.0 → 1.2.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.
- package/dist/agent/features/agent-simulator.d.ts +67 -0
- package/dist/agent/features/agent-simulator.js +368 -0
- package/dist/agent/features/agent-simulator.js.map +1 -0
- package/dist/agent/features/index.d.ts +8 -0
- package/dist/agent/features/index.js +9 -0
- package/dist/agent/features/index.js.map +1 -0
- package/dist/agent/features/simulation-judge.d.ts +78 -0
- package/dist/agent/features/simulation-judge.js +276 -0
- package/dist/agent/features/simulation-judge.js.map +1 -0
- package/dist/agent/features/test-case-generator.d.ts +35 -0
- package/dist/agent/features/test-case-generator.js +257 -0
- package/dist/agent/features/test-case-generator.js.map +1 -0
- package/dist/agent/index.d.ts +7 -0
- package/dist/agent/index.js +10 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/llm-client.d.ts +76 -0
- package/dist/agent/llm-client.js +198 -0
- package/dist/agent/llm-client.js.map +1 -0
- package/dist/audit/run-single-page-audit.d.ts +41 -0
- package/dist/audit/run-single-page-audit.js +103 -0
- package/dist/audit/run-single-page-audit.js.map +1 -0
- package/dist/bin/webmcp.d.ts +5 -0
- package/dist/bin/webmcp.js +14 -0
- package/dist/bin/webmcp.js.map +1 -0
- package/dist/browser/audit-runner.d.ts +30 -0
- package/dist/browser/audit-runner.js +77 -0
- package/dist/browser/audit-runner.js.map +1 -0
- package/dist/browser/index.d.ts +6 -0
- package/dist/browser/index.js +7 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/interceptor.d.ts +68 -0
- package/dist/browser/interceptor.js +257 -0
- package/dist/browser/interceptor.js.map +1 -0
- package/dist/browser/playwright.d.ts +98 -0
- package/dist/browser/playwright.js +158 -0
- package/dist/browser/playwright.js.map +1 -0
- package/dist/cli/commands/audit.d.ts +12 -0
- package/dist/cli/commands/audit.js +349 -0
- package/dist/cli/commands/audit.js.map +1 -0
- package/dist/cli/commands/interactive.d.ts +10 -0
- package/dist/cli/commands/interactive.js +34 -0
- package/dist/cli/commands/interactive.js.map +1 -0
- package/dist/cli/index.d.ts +17 -0
- package/dist/cli/index.js +84 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/options/parse-audit-options.d.ts +12 -0
- package/dist/cli/options/parse-audit-options.js +64 -0
- package/dist/cli/options/parse-audit-options.js.map +1 -0
- package/dist/core/constants.d.ts +102 -0
- package/dist/core/constants.js +214 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/types/audit.d.ts +260 -0
- package/dist/core/types/audit.js +5 -0
- package/dist/core/types/audit.js.map +1 -0
- package/dist/core/types/index.d.ts +6 -0
- package/dist/core/types/index.js +7 -0
- package/dist/core/types/index.js.map +1 -0
- package/dist/core/types/rule.d.ts +190 -0
- package/dist/core/types/rule.js +26 -0
- package/dist/core/types/rule.js.map +1 -0
- package/dist/core/types/tool.d.ts +312 -0
- package/dist/core/types/tool.js +6 -0
- package/dist/core/types/tool.js.map +1 -0
- package/dist/detection/declarative.d.ts +27 -0
- package/dist/detection/declarative.js +343 -0
- package/dist/detection/declarative.js.map +1 -0
- package/dist/detection/imperative.d.ts +38 -0
- package/dist/detection/imperative.js +99 -0
- package/dist/detection/imperative.js.map +1 -0
- package/dist/detection/index.d.ts +5 -0
- package/dist/detection/index.js +6 -0
- package/dist/detection/index.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/advice-service.d.ts +38 -0
- package/dist/llm/advice-service.js +243 -0
- package/dist/llm/advice-service.js.map +1 -0
- package/dist/llm/evaluator.d.ts +89 -0
- package/dist/llm/evaluator.js +274 -0
- package/dist/llm/evaluator.js.map +1 -0
- package/dist/llm/index.d.ts +11 -0
- package/dist/llm/index.js +15 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/llm/json-response.d.ts +12 -0
- package/dist/llm/json-response.js +67 -0
- package/dist/llm/json-response.js.map +1 -0
- package/dist/llm/providers/mock.d.ts +29 -0
- package/dist/llm/providers/mock.js +324 -0
- package/dist/llm/providers/mock.js.map +1 -0
- package/dist/llm/providers/openrouter.d.ts +53 -0
- package/dist/llm/providers/openrouter.js +321 -0
- package/dist/llm/providers/openrouter.js.map +1 -0
- package/dist/llm/request-cache.d.ts +28 -0
- package/dist/llm/request-cache.js +99 -0
- package/dist/llm/request-cache.js.map +1 -0
- package/dist/llm/types.d.ts +233 -0
- package/dist/llm/types.js +7 -0
- package/dist/llm/types.js.map +1 -0
- package/dist/rules/best-practices/BP-001.d.ts +11 -0
- package/dist/rules/best-practices/BP-001.js +56 -0
- package/dist/rules/best-practices/BP-001.js.map +1 -0
- package/dist/rules/best-practices/BP-002.d.ts +11 -0
- package/dist/rules/best-practices/BP-002.js +63 -0
- package/dist/rules/best-practices/BP-002.js.map +1 -0
- package/dist/rules/best-practices/BP-003.d.ts +11 -0
- package/dist/rules/best-practices/BP-003.js +68 -0
- package/dist/rules/best-practices/BP-003.js.map +1 -0
- package/dist/rules/coverage/COV-001.d.ts +8 -0
- package/dist/rules/coverage/COV-001.js +51 -0
- package/dist/rules/coverage/COV-001.js.map +1 -0
- package/dist/rules/description/DESC-003.d.ts +13 -0
- package/dist/rules/description/DESC-003.js +96 -0
- package/dist/rules/description/DESC-003.js.map +1 -0
- package/dist/rules/description/DESC-004.d.ts +8 -0
- package/dist/rules/description/DESC-004.js +61 -0
- package/dist/rules/description/DESC-004.js.map +1 -0
- package/dist/rules/description/DESC-005.d.ts +12 -0
- package/dist/rules/description/DESC-005.js +70 -0
- package/dist/rules/description/DESC-005.js.map +1 -0
- package/dist/rules/description/index.d.ts +4 -0
- package/dist/rules/description/index.js +5 -0
- package/dist/rules/description/index.js.map +1 -0
- package/dist/rules/implementation/IMP-001.d.ts +10 -0
- package/dist/rules/implementation/IMP-001.js +36 -0
- package/dist/rules/implementation/IMP-001.js.map +1 -0
- package/dist/rules/implementation/IMP-003.d.ts +9 -0
- package/dist/rules/implementation/IMP-003.js +45 -0
- package/dist/rules/implementation/IMP-003.js.map +1 -0
- package/dist/rules/implementation/IMP-004.d.ts +9 -0
- package/dist/rules/implementation/IMP-004.js +48 -0
- package/dist/rules/implementation/IMP-004.js.map +1 -0
- package/dist/rules/implementation/IMP-005.d.ts +9 -0
- package/dist/rules/implementation/IMP-005.js +54 -0
- package/dist/rules/implementation/IMP-005.js.map +1 -0
- package/dist/rules/implementation/IMP-007.d.ts +8 -0
- package/dist/rules/implementation/IMP-007.js +79 -0
- package/dist/rules/implementation/IMP-007.js.map +1 -0
- package/dist/rules/implementation/IMP-013.d.ts +9 -0
- package/dist/rules/implementation/IMP-013.js +55 -0
- package/dist/rules/implementation/IMP-013.js.map +1 -0
- package/dist/rules/implementation/index.d.ts +9 -0
- package/dist/rules/implementation/index.js +10 -0
- package/dist/rules/implementation/index.js.map +1 -0
- package/dist/rules/index.d.ts +51 -0
- package/dist/rules/index.js +100 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/llm/LLM-001.d.ts +14 -0
- package/dist/rules/llm/LLM-001.js +78 -0
- package/dist/rules/llm/LLM-001.js.map +1 -0
- package/dist/rules/llm/LLM-002.d.ts +14 -0
- package/dist/rules/llm/LLM-002.js +77 -0
- package/dist/rules/llm/LLM-002.js.map +1 -0
- package/dist/rules/llm/LLM-003.d.ts +16 -0
- package/dist/rules/llm/LLM-003.js +82 -0
- package/dist/rules/llm/LLM-003.js.map +1 -0
- package/dist/rules/llm/LLM-004.d.ts +14 -0
- package/dist/rules/llm/LLM-004.js +87 -0
- package/dist/rules/llm/LLM-004.js.map +1 -0
- package/dist/rules/llm/LLM-005.d.ts +16 -0
- package/dist/rules/llm/LLM-005.js +105 -0
- package/dist/rules/llm/LLM-005.js.map +1 -0
- package/dist/rules/llm/index.d.ts +10 -0
- package/dist/rules/llm/index.js +11 -0
- package/dist/rules/llm/index.js.map +1 -0
- package/dist/rules/runner.d.ts +54 -0
- package/dist/rules/runner.js +138 -0
- package/dist/rules/runner.js.map +1 -0
- package/dist/rules/schema/SCHEMA-001.d.ts +9 -0
- package/dist/rules/schema/SCHEMA-001.js +57 -0
- package/dist/rules/schema/SCHEMA-001.js.map +1 -0
- package/dist/rules/schema/SCHEMA-002.d.ts +9 -0
- package/dist/rules/schema/SCHEMA-002.js +59 -0
- package/dist/rules/schema/SCHEMA-002.js.map +1 -0
- package/dist/rules/schema/SCHEMA-003.d.ts +10 -0
- package/dist/rules/schema/SCHEMA-003.js +66 -0
- package/dist/rules/schema/SCHEMA-003.js.map +1 -0
- package/dist/rules/schema/SCHEMA-011.d.ts +10 -0
- package/dist/rules/schema/SCHEMA-011.js +62 -0
- package/dist/rules/schema/SCHEMA-011.js.map +1 -0
- package/dist/rules/security/SEC-001.d.ts +12 -0
- package/dist/rules/security/SEC-001.js +66 -0
- package/dist/rules/security/SEC-001.js.map +1 -0
- package/dist/rules/utils/keywords.d.ts +35 -0
- package/dist/rules/utils/keywords.js +100 -0
- package/dist/rules/utils/keywords.js.map +1 -0
- package/dist/scoring/calculator.d.ts +27 -0
- package/dist/scoring/calculator.js +194 -0
- package/dist/scoring/calculator.js.map +1 -0
- package/dist/scoring/grades.d.ts +34 -0
- package/dist/scoring/grades.js +167 -0
- package/dist/scoring/grades.js.map +1 -0
- package/dist/scoring/index.d.ts +5 -0
- package/dist/scoring/index.js +6 -0
- package/dist/scoring/index.js.map +1 -0
- package/dist/ui/banner.d.ts +21 -0
- package/dist/ui/banner.js +60 -0
- package/dist/ui/banner.js.map +1 -0
- package/dist/ui/design-tokens.d.ts +23 -0
- package/dist/ui/design-tokens.js +58 -0
- package/dist/ui/design-tokens.js.map +1 -0
- package/dist/ui/findings.d.ts +23 -0
- package/dist/ui/findings.js +190 -0
- package/dist/ui/findings.js.map +1 -0
- package/dist/ui/index.d.ts +9 -0
- package/dist/ui/index.js +10 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/ink/App.d.ts +14 -0
- package/dist/ui/ink/App.js +113 -0
- package/dist/ui/ink/App.js.map +1 -0
- package/dist/ui/ink/FullScreenLayout.d.ts +16 -0
- package/dist/ui/ink/FullScreenLayout.js +29 -0
- package/dist/ui/ink/FullScreenLayout.js.map +1 -0
- package/dist/ui/ink/InteractiveApp.d.ts +28 -0
- package/dist/ui/ink/InteractiveApp.js +229 -0
- package/dist/ui/ink/InteractiveApp.js.map +1 -0
- package/dist/ui/ink/RealAuditApp.d.ts +19 -0
- package/dist/ui/ink/RealAuditApp.js +170 -0
- package/dist/ui/ink/RealAuditApp.js.map +1 -0
- package/dist/ui/ink/components/AnimatedProgressBar.d.ts +20 -0
- package/dist/ui/ink/components/AnimatedProgressBar.js +46 -0
- package/dist/ui/ink/components/AnimatedProgressBar.js.map +1 -0
- package/dist/ui/ink/components/AsciiLogo.d.ts +12 -0
- package/dist/ui/ink/components/AsciiLogo.js +35 -0
- package/dist/ui/ink/components/AsciiLogo.js.map +1 -0
- package/dist/ui/ink/components/CategoryBars.d.ts +18 -0
- package/dist/ui/ink/components/CategoryBars.js +18 -0
- package/dist/ui/ink/components/CategoryBars.js.map +1 -0
- package/dist/ui/ink/components/FindingsTable.d.ts +18 -0
- package/dist/ui/ink/components/FindingsTable.js +19 -0
- package/dist/ui/ink/components/FindingsTable.js.map +1 -0
- package/dist/ui/ink/components/Footer.d.ts +15 -0
- package/dist/ui/ink/components/Footer.js +20 -0
- package/dist/ui/ink/components/Footer.js.map +1 -0
- package/dist/ui/ink/components/Header.d.ts +11 -0
- package/dist/ui/ink/components/Header.js +12 -0
- package/dist/ui/ink/components/Header.js.map +1 -0
- package/dist/ui/ink/components/LinkList.d.ts +17 -0
- package/dist/ui/ink/components/LinkList.js +44 -0
- package/dist/ui/ink/components/LinkList.js.map +1 -0
- package/dist/ui/ink/components/Navigation.d.ts +26 -0
- package/dist/ui/ink/components/Navigation.js +62 -0
- package/dist/ui/ink/components/Navigation.js.map +1 -0
- package/dist/ui/ink/components/ProgressBar.d.ts +15 -0
- package/dist/ui/ink/components/ProgressBar.js +14 -0
- package/dist/ui/ink/components/ProgressBar.js.map +1 -0
- package/dist/ui/ink/components/ScoreCard.d.ts +30 -0
- package/dist/ui/ink/components/ScoreCard.js +26 -0
- package/dist/ui/ink/components/ScoreCard.js.map +1 -0
- package/dist/ui/ink/components/SimulationResults.d.ts +33 -0
- package/dist/ui/ink/components/SimulationResults.js +23 -0
- package/dist/ui/ink/components/SimulationResults.js.map +1 -0
- package/dist/ui/ink/components/Spinner.d.ts +11 -0
- package/dist/ui/ink/components/Spinner.js +12 -0
- package/dist/ui/ink/components/Spinner.js.map +1 -0
- package/dist/ui/ink/components/ToolCard.d.ts +23 -0
- package/dist/ui/ink/components/ToolCard.js +20 -0
- package/dist/ui/ink/components/ToolCard.js.map +1 -0
- package/dist/ui/ink/components/shared/Badge.d.ts +21 -0
- package/dist/ui/ink/components/shared/Badge.js +39 -0
- package/dist/ui/ink/components/shared/Badge.js.map +1 -0
- package/dist/ui/ink/components/shared/Card.d.ts +18 -0
- package/dist/ui/ink/components/shared/Card.js +11 -0
- package/dist/ui/ink/components/shared/Card.js.map +1 -0
- package/dist/ui/ink/components/shared/HelpOverlay.d.ts +10 -0
- package/dist/ui/ink/components/shared/HelpOverlay.js +28 -0
- package/dist/ui/ink/components/shared/HelpOverlay.js.map +1 -0
- package/dist/ui/ink/components/shared/LoadingWithTimeout.d.ts +11 -0
- package/dist/ui/ink/components/shared/LoadingWithTimeout.js +21 -0
- package/dist/ui/ink/components/shared/LoadingWithTimeout.js.map +1 -0
- package/dist/ui/ink/components/shared/Menu.d.ts +23 -0
- package/dist/ui/ink/components/shared/Menu.js +43 -0
- package/dist/ui/ink/components/shared/Menu.js.map +1 -0
- package/dist/ui/ink/components/shared/Table.d.ts +23 -0
- package/dist/ui/ink/components/shared/Table.js +40 -0
- package/dist/ui/ink/components/shared/Table.js.map +1 -0
- package/dist/ui/ink/components/views/CrawlingView.d.ts +12 -0
- package/dist/ui/ink/components/views/CrawlingView.js +34 -0
- package/dist/ui/ink/components/views/CrawlingView.js.map +1 -0
- package/dist/ui/ink/components/views/DashboardView.d.ts +21 -0
- package/dist/ui/ink/components/views/DashboardView.js +51 -0
- package/dist/ui/ink/components/views/DashboardView.js.map +1 -0
- package/dist/ui/ink/components/views/FindingDetailView.d.ts +16 -0
- package/dist/ui/ink/components/views/FindingDetailView.js +34 -0
- package/dist/ui/ink/components/views/FindingDetailView.js.map +1 -0
- package/dist/ui/ink/components/views/FindingsView.d.ts +16 -0
- package/dist/ui/ink/components/views/FindingsView.js +79 -0
- package/dist/ui/ink/components/views/FindingsView.js.map +1 -0
- package/dist/ui/ink/components/views/OnboardingView.d.ts +12 -0
- package/dist/ui/ink/components/views/OnboardingView.js +40 -0
- package/dist/ui/ink/components/views/OnboardingView.js.map +1 -0
- package/dist/ui/ink/components/views/SimulationView.d.ts +17 -0
- package/dist/ui/ink/components/views/SimulationView.js +53 -0
- package/dist/ui/ink/components/views/SimulationView.js.map +1 -0
- package/dist/ui/ink/components/views/TestCaseDetailView.d.ts +11 -0
- package/dist/ui/ink/components/views/TestCaseDetailView.js +53 -0
- package/dist/ui/ink/components/views/TestCaseDetailView.js.map +1 -0
- package/dist/ui/ink/components/views/ToolDetailView.d.ts +15 -0
- package/dist/ui/ink/components/views/ToolDetailView.js +25 -0
- package/dist/ui/ink/components/views/ToolDetailView.js.map +1 -0
- package/dist/ui/ink/components/views/ToolsView.d.ts +15 -0
- package/dist/ui/ink/components/views/ToolsView.js +43 -0
- package/dist/ui/ink/components/views/ToolsView.js.map +1 -0
- package/dist/ui/ink/demo.d.ts +6 -0
- package/dist/ui/ink/demo.js +254 -0
- package/dist/ui/ink/demo.js.map +1 -0
- package/dist/ui/ink/hooks/useAnimation.d.ts +29 -0
- package/dist/ui/ink/hooks/useAnimation.js +89 -0
- package/dist/ui/ink/hooks/useAnimation.js.map +1 -0
- package/dist/ui/ink/hooks/useAudit.d.ts +69 -0
- package/dist/ui/ink/hooks/useAudit.js +99 -0
- package/dist/ui/ink/hooks/useAudit.js.map +1 -0
- package/dist/ui/ink/hooks/useCrawlAnimation.d.ts +19 -0
- package/dist/ui/ink/hooks/useCrawlAnimation.js +204 -0
- package/dist/ui/ink/hooks/useCrawlAnimation.js.map +1 -0
- package/dist/ui/ink/hooks/useKeyboardNav.d.ts +23 -0
- package/dist/ui/ink/hooks/useKeyboardNav.js +81 -0
- package/dist/ui/ink/hooks/useKeyboardNav.js.map +1 -0
- package/dist/ui/ink/hooks/useNavigation.d.ts +16 -0
- package/dist/ui/ink/hooks/useNavigation.js +42 -0
- package/dist/ui/ink/hooks/useNavigation.js.map +1 -0
- package/dist/ui/ink/hooks/useTerminalSize.d.ts +10 -0
- package/dist/ui/ink/hooks/useTerminalSize.js +29 -0
- package/dist/ui/ink/hooks/useTerminalSize.js.map +1 -0
- package/dist/ui/ink/index.d.ts +43 -0
- package/dist/ui/ink/index.js +50 -0
- package/dist/ui/ink/index.js.map +1 -0
- package/dist/ui/ink/render.d.ts +24 -0
- package/dist/ui/ink/render.js +14 -0
- package/dist/ui/ink/render.js.map +1 -0
- package/dist/ui/ink/theme.d.ts +37 -0
- package/dist/ui/ink/theme.js +38 -0
- package/dist/ui/ink/theme.js.map +1 -0
- package/dist/ui/ink/types.d.ts +77 -0
- package/dist/ui/ink/types.js +5 -0
- package/dist/ui/ink/types.js.map +1 -0
- package/dist/ui/score-display.d.ts +16 -0
- package/dist/ui/score-display.js +201 -0
- package/dist/ui/score-display.js.map +1 -0
- package/dist/ui/spinner.d.ts +45 -0
- package/dist/ui/spinner.js +112 -0
- package/dist/ui/spinner.js.map +1 -0
- package/dist/ui/utils.d.ts +13 -0
- package/dist/ui/utils.js +25 -0
- package/dist/ui/utils.js.map +1 -0
- package/package.json +61 -9
- package/index.js +0 -105
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM Types
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for LLM-based rule evaluation.
|
|
5
|
+
*/
|
|
6
|
+
import type { DetectedTool } from '../core/types/tool.js';
|
|
7
|
+
/**
|
|
8
|
+
* LLM Provider configuration
|
|
9
|
+
*/
|
|
10
|
+
export interface LLMConfig {
|
|
11
|
+
/**
|
|
12
|
+
* API key for the LLM provider
|
|
13
|
+
*/
|
|
14
|
+
apiKey: string;
|
|
15
|
+
/**
|
|
16
|
+
* Model identifier (e.g., 'anthropic/claude-sonnet-4.5')
|
|
17
|
+
*/
|
|
18
|
+
model: string;
|
|
19
|
+
/**
|
|
20
|
+
* Base URL for the API (e.g., OpenRouter endpoint)
|
|
21
|
+
*/
|
|
22
|
+
baseUrl?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Temperature for generation (0-1)
|
|
25
|
+
*/
|
|
26
|
+
temperature?: number;
|
|
27
|
+
/**
|
|
28
|
+
* Maximum tokens to generate
|
|
29
|
+
*/
|
|
30
|
+
maxTokens?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Context provided to LLM for evaluation
|
|
34
|
+
*/
|
|
35
|
+
export interface EvaluationContext {
|
|
36
|
+
/**
|
|
37
|
+
* The tool being evaluated
|
|
38
|
+
*/
|
|
39
|
+
tool: DetectedTool;
|
|
40
|
+
/**
|
|
41
|
+
* The specific question/prompt for evaluation
|
|
42
|
+
*/
|
|
43
|
+
question: string;
|
|
44
|
+
/**
|
|
45
|
+
* Evaluation criteria to check
|
|
46
|
+
*/
|
|
47
|
+
criteria: string[];
|
|
48
|
+
/**
|
|
49
|
+
* Additional context (e.g., other tools on the page)
|
|
50
|
+
*/
|
|
51
|
+
additionalContext?: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Result from LLM evaluation
|
|
55
|
+
*/
|
|
56
|
+
export interface EvaluationResult {
|
|
57
|
+
/**
|
|
58
|
+
* Whether the evaluation passed
|
|
59
|
+
*/
|
|
60
|
+
passed: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Score from 0-10
|
|
63
|
+
*/
|
|
64
|
+
score: number;
|
|
65
|
+
/**
|
|
66
|
+
* LLM's reasoning for the evaluation
|
|
67
|
+
*/
|
|
68
|
+
reasoning: string;
|
|
69
|
+
/**
|
|
70
|
+
* Specific issues found
|
|
71
|
+
*/
|
|
72
|
+
issues?: string[];
|
|
73
|
+
/**
|
|
74
|
+
* Suggestions for improvement
|
|
75
|
+
*/
|
|
76
|
+
suggestions?: string[];
|
|
77
|
+
/**
|
|
78
|
+
* Raw LLM response (for debugging)
|
|
79
|
+
*/
|
|
80
|
+
rawResponse?: string;
|
|
81
|
+
/**
|
|
82
|
+
* Whether this result came from cache
|
|
83
|
+
*/
|
|
84
|
+
cached?: boolean;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Description quality evaluation context
|
|
88
|
+
*/
|
|
89
|
+
export interface DescriptionEvalContext {
|
|
90
|
+
/**
|
|
91
|
+
* Tool name
|
|
92
|
+
*/
|
|
93
|
+
name: string;
|
|
94
|
+
/**
|
|
95
|
+
* Tool description
|
|
96
|
+
*/
|
|
97
|
+
description: string;
|
|
98
|
+
/**
|
|
99
|
+
* Input schema (stringified)
|
|
100
|
+
*/
|
|
101
|
+
inputSchema?: string;
|
|
102
|
+
/**
|
|
103
|
+
* What aspect to evaluate
|
|
104
|
+
*/
|
|
105
|
+
aspect: 'clarity' | 'specificity' | 'positive-framing' | 'completeness' | 'steering' | 'atomicity' | 'similarity' | 'all';
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Full description quality report
|
|
109
|
+
*/
|
|
110
|
+
export interface DescriptionQualityReport {
|
|
111
|
+
/**
|
|
112
|
+
* Overall quality score (0-100)
|
|
113
|
+
*/
|
|
114
|
+
overallScore: number;
|
|
115
|
+
/**
|
|
116
|
+
* Individual aspect scores
|
|
117
|
+
*/
|
|
118
|
+
aspects: {
|
|
119
|
+
clarity: EvaluationResult;
|
|
120
|
+
specificity: EvaluationResult;
|
|
121
|
+
positiveFraming: EvaluationResult;
|
|
122
|
+
completeness: EvaluationResult;
|
|
123
|
+
steeringPerformance: EvaluationResult;
|
|
124
|
+
atomicity: EvaluationResult;
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Overall assessment
|
|
128
|
+
*/
|
|
129
|
+
summary: string;
|
|
130
|
+
/**
|
|
131
|
+
* Top priority improvements
|
|
132
|
+
*/
|
|
133
|
+
priorityImprovements: string[];
|
|
134
|
+
/**
|
|
135
|
+
* Suggested rewritten description
|
|
136
|
+
*/
|
|
137
|
+
suggestedDescription?: string;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* LLM Provider interface
|
|
141
|
+
*/
|
|
142
|
+
export interface LLMProvider {
|
|
143
|
+
/**
|
|
144
|
+
* Provider name
|
|
145
|
+
*/
|
|
146
|
+
name: string;
|
|
147
|
+
/**
|
|
148
|
+
* Send a prompt and get a response
|
|
149
|
+
*/
|
|
150
|
+
complete(prompt: string, systemPrompt?: string): Promise<string>;
|
|
151
|
+
/**
|
|
152
|
+
* Evaluate a tool description
|
|
153
|
+
*/
|
|
154
|
+
evaluateDescription(context: DescriptionEvalContext): Promise<EvaluationResult>;
|
|
155
|
+
/**
|
|
156
|
+
* Get a full quality report for a tool
|
|
157
|
+
*/
|
|
158
|
+
getQualityReport(tool: DetectedTool): Promise<DescriptionQualityReport>;
|
|
159
|
+
/**
|
|
160
|
+
* Check if the provider is available (has valid credentials)
|
|
161
|
+
*/
|
|
162
|
+
isAvailable(): boolean;
|
|
163
|
+
}
|
|
164
|
+
export interface EvaluationCacheEntry {
|
|
165
|
+
kind: 'evaluation';
|
|
166
|
+
result: EvaluationResult;
|
|
167
|
+
timestamp: number;
|
|
168
|
+
inputHash: string;
|
|
169
|
+
}
|
|
170
|
+
export interface ReportCacheEntry {
|
|
171
|
+
kind: 'report';
|
|
172
|
+
result: DescriptionQualityReport;
|
|
173
|
+
timestamp: number;
|
|
174
|
+
inputHash: string;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Cache entry for LLM evaluations/reports.
|
|
178
|
+
*/
|
|
179
|
+
export type CacheEntry = EvaluationCacheEntry | ReportCacheEntry;
|
|
180
|
+
/**
|
|
181
|
+
* Cache storage structure
|
|
182
|
+
*/
|
|
183
|
+
export interface LLMCache {
|
|
184
|
+
/**
|
|
185
|
+
* Version for cache invalidation
|
|
186
|
+
*/
|
|
187
|
+
version: number;
|
|
188
|
+
/**
|
|
189
|
+
* Cached entries by key
|
|
190
|
+
*/
|
|
191
|
+
entries: Record<string, CacheEntry>;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Evaluation types for different rules
|
|
195
|
+
*/
|
|
196
|
+
export type EvaluationType = 'desc-specific-verb' | 'desc-positive-framing' | 'desc-explains-what' | 'desc-explains-when' | 'bp-atomic-tool' | 'steering-quality' | 'instruction-similarity' | 'param-clarity' | 'full-quality';
|
|
197
|
+
/**
|
|
198
|
+
* LLM-generated smart advice for a finding
|
|
199
|
+
*/
|
|
200
|
+
export interface SmartAdvice {
|
|
201
|
+
currentState: {
|
|
202
|
+
description: string;
|
|
203
|
+
problemAreas: string[];
|
|
204
|
+
agentImpact: string;
|
|
205
|
+
};
|
|
206
|
+
enhanced: {
|
|
207
|
+
suggestedFix: string;
|
|
208
|
+
explanation: string;
|
|
209
|
+
codeExample?: string;
|
|
210
|
+
};
|
|
211
|
+
benefits: {
|
|
212
|
+
title: string;
|
|
213
|
+
items: string[];
|
|
214
|
+
};
|
|
215
|
+
confidence: number;
|
|
216
|
+
cached?: boolean;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Finding with optional smart advice attached
|
|
220
|
+
*/
|
|
221
|
+
export interface FindingWithAdvice {
|
|
222
|
+
id: string;
|
|
223
|
+
ruleId: string;
|
|
224
|
+
severity: 'critical' | 'warning' | 'info';
|
|
225
|
+
message: string;
|
|
226
|
+
tool?: string;
|
|
227
|
+
page?: string;
|
|
228
|
+
fix?: string;
|
|
229
|
+
scoreImpact?: number;
|
|
230
|
+
advice?: SmartAdvice;
|
|
231
|
+
adviceLoading?: boolean;
|
|
232
|
+
adviceError?: string;
|
|
233
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/llm/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BP-001: Annotations Present
|
|
3
|
+
*
|
|
4
|
+
* Checks if tools have an annotations object defined.
|
|
5
|
+
* Annotations provide important hints about tool behavior
|
|
6
|
+
* (readOnlyHint, destructiveHint, etc.) that help agents
|
|
7
|
+
* make better decisions.
|
|
8
|
+
*/
|
|
9
|
+
import type { Rule } from '../../core/types/rule.js';
|
|
10
|
+
export declare const BP_001: Rule;
|
|
11
|
+
export default BP_001;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BP-001: Annotations Present
|
|
3
|
+
*
|
|
4
|
+
* Checks if tools have an annotations object defined.
|
|
5
|
+
* Annotations provide important hints about tool behavior
|
|
6
|
+
* (readOnlyHint, destructiveHint, etc.) that help agents
|
|
7
|
+
* make better decisions.
|
|
8
|
+
*/
|
|
9
|
+
import { createRuleResult } from '../runner.js';
|
|
10
|
+
export const BP_001 = {
|
|
11
|
+
id: 'BP-001',
|
|
12
|
+
category: 'best-practices',
|
|
13
|
+
name: 'Annotations Present',
|
|
14
|
+
description: 'Tools should have an annotations object for behavior hints',
|
|
15
|
+
severity: 'info',
|
|
16
|
+
maxScore: 5,
|
|
17
|
+
async check(context) {
|
|
18
|
+
const tools = context.tools;
|
|
19
|
+
if (tools.length === 0) {
|
|
20
|
+
return createRuleResult('BP-001', 5, {
|
|
21
|
+
passed: true,
|
|
22
|
+
score: 5,
|
|
23
|
+
message: 'No tools detected (rule not applicable)',
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
const toolsWithoutAnnotations = [];
|
|
27
|
+
for (const tool of tools) {
|
|
28
|
+
if (!tool.annotations || Object.keys(tool.annotations).length === 0) {
|
|
29
|
+
toolsWithoutAnnotations.push(tool.name);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (toolsWithoutAnnotations.length === 0) {
|
|
33
|
+
return createRuleResult('BP-001', 5, {
|
|
34
|
+
passed: true,
|
|
35
|
+
score: 5,
|
|
36
|
+
message: `All ${tools.length} tool(s) have annotations defined`,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
// Deduct 1 point per tool missing annotations, minimum 0
|
|
40
|
+
const penalty = Math.min(toolsWithoutAnnotations.length, 5);
|
|
41
|
+
const score = Math.max(0, 5 - penalty);
|
|
42
|
+
return createRuleResult('BP-001', 5, {
|
|
43
|
+
passed: false,
|
|
44
|
+
score,
|
|
45
|
+
message: `${toolsWithoutAnnotations.length} tool(s) missing annotations`,
|
|
46
|
+
details: toolsWithoutAnnotations.map((name) => `Tool "${name}" has no annotations object`),
|
|
47
|
+
suggestions: [
|
|
48
|
+
'Add annotations object with readOnlyHint, destructiveHint, etc.',
|
|
49
|
+
'Example: { annotations: { readOnlyHint: true } }',
|
|
50
|
+
],
|
|
51
|
+
affectedTools: toolsWithoutAnnotations,
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
export default BP_001;
|
|
56
|
+
//# sourceMappingURL=BP-001.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BP-001.js","sourceRoot":"","sources":["../../../src/rules/best-practices/BP-001.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,CAAC,MAAM,MAAM,GAAS;IAC1B,EAAE,EAAE,QAAQ;IACZ,QAAQ,EAAE,gBAAgB;IAC1B,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EAAE,4DAA4D;IACzE,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,CAAC;IAEX,KAAK,CAAC,KAAK,CAAC,OAAoB;QAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAE5B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,gBAAgB,CAAC,QAAQ,EAAE,CAAC,EAAE;gBACnC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,yCAAyC;aACnD,CAAC,CAAC;QACL,CAAC;QAED,MAAM,uBAAuB,GAAa,EAAE,CAAC;QAE7C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACpE,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;QAED,IAAI,uBAAuB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzC,OAAO,gBAAgB,CAAC,QAAQ,EAAE,CAAC,EAAE;gBACnC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,OAAO,KAAK,CAAC,MAAM,mCAAmC;aAChE,CAAC,CAAC;QACL,CAAC;QAED,yDAAyD;QACzD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,uBAAuB,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC;QAEvC,OAAO,gBAAgB,CAAC,QAAQ,EAAE,CAAC,EAAE;YACnC,MAAM,EAAE,KAAK;YACb,KAAK;YACL,OAAO,EAAE,GAAG,uBAAuB,CAAC,MAAM,8BAA8B;YACxE,OAAO,EAAE,uBAAuB,CAAC,GAAG,CAClC,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,IAAI,6BAA6B,CACrD;YACD,WAAW,EAAE;gBACX,iEAAiE;gBACjE,kDAAkD;aACnD;YACD,aAAa,EAAE,uBAAuB;SACvC,CAAC,CAAC;IACL,CAAC;CACF,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BP-002: Destructive Hint Used
|
|
3
|
+
*
|
|
4
|
+
* Checks if tools with destructive-sounding names/descriptions
|
|
5
|
+
* have the destructiveHint annotation set to true.
|
|
6
|
+
*
|
|
7
|
+
* Destructive operations include: delete, remove, purchase, cancel, etc.
|
|
8
|
+
*/
|
|
9
|
+
import type { Rule } from '../../core/types/rule.js';
|
|
10
|
+
export declare const BP_002: Rule;
|
|
11
|
+
export default BP_002;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BP-002: Destructive Hint Used
|
|
3
|
+
*
|
|
4
|
+
* Checks if tools with destructive-sounding names/descriptions
|
|
5
|
+
* have the destructiveHint annotation set to true.
|
|
6
|
+
*
|
|
7
|
+
* Destructive operations include: delete, remove, purchase, cancel, etc.
|
|
8
|
+
*/
|
|
9
|
+
import { createRuleResult } from '../runner.js';
|
|
10
|
+
import { DESTRUCTIVE_KEYWORDS, hasKeyword, findMatchedKeywords, } from '../utils/keywords.js';
|
|
11
|
+
export const BP_002 = {
|
|
12
|
+
id: 'BP-002',
|
|
13
|
+
category: 'best-practices',
|
|
14
|
+
name: 'Destructive Hint Used',
|
|
15
|
+
description: 'Tools with destructive operations should have destructiveHint: true',
|
|
16
|
+
severity: 'warning',
|
|
17
|
+
maxScore: 8,
|
|
18
|
+
async check(context) {
|
|
19
|
+
const tools = context.tools;
|
|
20
|
+
if (tools.length === 0) {
|
|
21
|
+
return createRuleResult('BP-002', 8, {
|
|
22
|
+
passed: true,
|
|
23
|
+
score: 8,
|
|
24
|
+
message: 'No tools detected (rule not applicable)',
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
const violations = [];
|
|
28
|
+
for (const tool of tools) {
|
|
29
|
+
const textToSearch = `${tool.name} ${tool.description}`;
|
|
30
|
+
if (hasKeyword(textToSearch, DESTRUCTIVE_KEYWORDS)) {
|
|
31
|
+
// Check if destructiveHint is set
|
|
32
|
+
const hasDestructiveHint = tool.annotations?.destructiveHint === true;
|
|
33
|
+
if (!hasDestructiveHint) {
|
|
34
|
+
const matchedKeywords = findMatchedKeywords(textToSearch, DESTRUCTIVE_KEYWORDS);
|
|
35
|
+
violations.push({ name: tool.name, keywords: matchedKeywords });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (violations.length === 0) {
|
|
40
|
+
return createRuleResult('BP-002', 8, {
|
|
41
|
+
passed: true,
|
|
42
|
+
score: 8,
|
|
43
|
+
message: 'All destructive-looking tools have destructiveHint annotation',
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
// Deduct 2 points per violation
|
|
47
|
+
const penalty = violations.length * 2;
|
|
48
|
+
const score = Math.max(0, 8 - penalty);
|
|
49
|
+
return createRuleResult('BP-002', 8, {
|
|
50
|
+
passed: false,
|
|
51
|
+
score,
|
|
52
|
+
message: `${violations.length} tool(s) with destructive keywords missing destructiveHint`,
|
|
53
|
+
details: violations.map((v) => `Tool "${v.name}" contains keywords [${v.keywords.join(', ')}] but lacks destructiveHint: true`),
|
|
54
|
+
suggestions: [
|
|
55
|
+
'Add destructiveHint: true to annotations for tools that modify/delete data',
|
|
56
|
+
'Example: { annotations: { destructiveHint: true } }',
|
|
57
|
+
],
|
|
58
|
+
affectedTools: violations.map((v) => v.name),
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
export default BP_002;
|
|
63
|
+
//# sourceMappingURL=BP-002.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BP-002.js","sourceRoot":"","sources":["../../../src/rules/best-practices/BP-002.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EACL,oBAAoB,EACpB,UAAU,EACV,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,CAAC,MAAM,MAAM,GAAS;IAC1B,EAAE,EAAE,QAAQ;IACZ,QAAQ,EAAE,gBAAgB;IAC1B,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EAAE,qEAAqE;IAClF,QAAQ,EAAE,SAAS;IACnB,QAAQ,EAAE,CAAC;IAEX,KAAK,CAAC,KAAK,CAAC,OAAoB;QAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAE5B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,gBAAgB,CAAC,QAAQ,EAAE,CAAC,EAAE;gBACnC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,yCAAyC;aACnD,CAAC,CAAC;QACL,CAAC;QAED,MAAM,UAAU,GAA2C,EAAE,CAAC;QAE9D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,YAAY,GAAG,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YAExD,IAAI,UAAU,CAAC,YAAY,EAAE,oBAAoB,CAAC,EAAE,CAAC;gBACnD,kCAAkC;gBAClC,MAAM,kBAAkB,GAAG,IAAI,CAAC,WAAW,EAAE,eAAe,KAAK,IAAI,CAAC;gBAEtE,IAAI,CAAC,kBAAkB,EAAE,CAAC;oBACxB,MAAM,eAAe,GAAG,mBAAmB,CACzC,YAAY,EACZ,oBAAoB,CACrB,CAAC;oBACF,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,eAAe,EAAE,CAAC,CAAC;gBAClE,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO,gBAAgB,CAAC,QAAQ,EAAE,CAAC,EAAE;gBACnC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,+DAA+D;aACzE,CAAC,CAAC;QACL,CAAC;QAED,gCAAgC;QAChC,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;QACtC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC;QAEvC,OAAO,gBAAgB,CAAC,QAAQ,EAAE,CAAC,EAAE;YACnC,MAAM,EAAE,KAAK;YACb,KAAK;YACL,OAAO,EAAE,GAAG,UAAU,CAAC,MAAM,4DAA4D;YACzF,OAAO,EAAE,UAAU,CAAC,GAAG,CACrB,CAAC,CAAC,EAAE,EAAE,CACJ,SAAS,CAAC,CAAC,IAAI,wBAAwB,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,mCAAmC,CAClG;YACD,WAAW,EAAE;gBACX,4EAA4E;gBAC5E,qDAAqD;aACtD;YACD,aAAa,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SAC7C,CAAC,CAAC;IACL,CAAC;CACF,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BP-003: ReadOnly Hint Consistency
|
|
3
|
+
*
|
|
4
|
+
* Checks if tools with read-only-sounding names/descriptions
|
|
5
|
+
* have the readOnlyHint annotation set to true.
|
|
6
|
+
*
|
|
7
|
+
* Read-only operations include: get, search, list, fetch, view, etc.
|
|
8
|
+
*/
|
|
9
|
+
import type { Rule } from '../../core/types/rule.js';
|
|
10
|
+
export declare const BP_003: Rule;
|
|
11
|
+
export default BP_003;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BP-003: ReadOnly Hint Consistency
|
|
3
|
+
*
|
|
4
|
+
* Checks if tools with read-only-sounding names/descriptions
|
|
5
|
+
* have the readOnlyHint annotation set to true.
|
|
6
|
+
*
|
|
7
|
+
* Read-only operations include: get, search, list, fetch, view, etc.
|
|
8
|
+
*/
|
|
9
|
+
import { createRuleResult } from '../runner.js';
|
|
10
|
+
import { READONLY_KEYWORDS, DESTRUCTIVE_KEYWORDS, hasKeyword, findMatchedKeywords, } from '../utils/keywords.js';
|
|
11
|
+
export const BP_003 = {
|
|
12
|
+
id: 'BP-003',
|
|
13
|
+
category: 'best-practices',
|
|
14
|
+
name: 'ReadOnly Hint Consistency',
|
|
15
|
+
description: 'Tools with read-only operations should have readOnlyHint: true',
|
|
16
|
+
severity: 'info',
|
|
17
|
+
maxScore: 5,
|
|
18
|
+
async check(context) {
|
|
19
|
+
const tools = context.tools;
|
|
20
|
+
if (tools.length === 0) {
|
|
21
|
+
return createRuleResult('BP-003', 5, {
|
|
22
|
+
passed: true,
|
|
23
|
+
score: 5,
|
|
24
|
+
message: 'No tools detected (rule not applicable)',
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
const violations = [];
|
|
28
|
+
for (const tool of tools) {
|
|
29
|
+
const textToSearch = `${tool.name} ${tool.description}`;
|
|
30
|
+
// Check if tool looks read-only
|
|
31
|
+
if (hasKeyword(textToSearch, READONLY_KEYWORDS)) {
|
|
32
|
+
// Skip if it also has destructive keywords (ambiguous)
|
|
33
|
+
if (hasKeyword(textToSearch, DESTRUCTIVE_KEYWORDS)) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
// Check if readOnlyHint is set
|
|
37
|
+
const hasReadOnlyHint = tool.annotations?.readOnlyHint === true;
|
|
38
|
+
if (!hasReadOnlyHint) {
|
|
39
|
+
const matchedKeywords = findMatchedKeywords(textToSearch, READONLY_KEYWORDS);
|
|
40
|
+
violations.push({ name: tool.name, keywords: matchedKeywords });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (violations.length === 0) {
|
|
45
|
+
return createRuleResult('BP-003', 5, {
|
|
46
|
+
passed: true,
|
|
47
|
+
score: 5,
|
|
48
|
+
message: 'All read-only-looking tools have readOnlyHint annotation',
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
// Deduct 1 point per violation
|
|
52
|
+
const penalty = Math.min(violations.length, 5);
|
|
53
|
+
const score = Math.max(0, 5 - penalty);
|
|
54
|
+
return createRuleResult('BP-003', 5, {
|
|
55
|
+
passed: false,
|
|
56
|
+
score,
|
|
57
|
+
message: `${violations.length} tool(s) with read-only keywords missing readOnlyHint`,
|
|
58
|
+
details: violations.map((v) => `Tool "${v.name}" contains keywords [${v.keywords.join(', ')}] but lacks readOnlyHint: true`),
|
|
59
|
+
suggestions: [
|
|
60
|
+
'Add readOnlyHint: true to annotations for tools that only read data',
|
|
61
|
+
'Example: { annotations: { readOnlyHint: true } }',
|
|
62
|
+
],
|
|
63
|
+
affectedTools: violations.map((v) => v.name),
|
|
64
|
+
});
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
export default BP_003;
|
|
68
|
+
//# sourceMappingURL=BP-003.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BP-003.js","sourceRoot":"","sources":["../../../src/rules/best-practices/BP-003.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,UAAU,EACV,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,CAAC,MAAM,MAAM,GAAS;IAC1B,EAAE,EAAE,QAAQ;IACZ,QAAQ,EAAE,gBAAgB;IAC1B,IAAI,EAAE,2BAA2B;IACjC,WAAW,EAAE,gEAAgE;IAC7E,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,CAAC;IAEX,KAAK,CAAC,KAAK,CAAC,OAAoB;QAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAE5B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,gBAAgB,CAAC,QAAQ,EAAE,CAAC,EAAE;gBACnC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,yCAAyC;aACnD,CAAC,CAAC;QACL,CAAC;QAED,MAAM,UAAU,GAA2C,EAAE,CAAC;QAE9D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,YAAY,GAAG,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YAExD,gCAAgC;YAChC,IAAI,UAAU,CAAC,YAAY,EAAE,iBAAiB,CAAC,EAAE,CAAC;gBAChD,uDAAuD;gBACvD,IAAI,UAAU,CAAC,YAAY,EAAE,oBAAoB,CAAC,EAAE,CAAC;oBACnD,SAAS;gBACX,CAAC;gBAED,+BAA+B;gBAC/B,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,EAAE,YAAY,KAAK,IAAI,CAAC;gBAEhE,IAAI,CAAC,eAAe,EAAE,CAAC;oBACrB,MAAM,eAAe,GAAG,mBAAmB,CACzC,YAAY,EACZ,iBAAiB,CAClB,CAAC;oBACF,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,eAAe,EAAE,CAAC,CAAC;gBAClE,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO,gBAAgB,CAAC,QAAQ,EAAE,CAAC,EAAE;gBACnC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,0DAA0D;aACpE,CAAC,CAAC;QACL,CAAC;QAED,+BAA+B;QAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC;QAEvC,OAAO,gBAAgB,CAAC,QAAQ,EAAE,CAAC,EAAE;YACnC,MAAM,EAAE,KAAK;YACb,KAAK;YACL,OAAO,EAAE,GAAG,UAAU,CAAC,MAAM,uDAAuD;YACpF,OAAO,EAAE,UAAU,CAAC,GAAG,CACrB,CAAC,CAAC,EAAE,EAAE,CACJ,SAAS,CAAC,CAAC,IAAI,wBAAwB,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,gCAAgC,CAC/F;YACD,WAAW,EAAE;gBACX,qEAAqE;gBACrE,kDAAkD;aACnD;YACD,aAAa,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SAC7C,CAAC,CAAC;IACL,CAAC;CACF,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* COV-001: Form Coverage
|
|
3
|
+
*
|
|
4
|
+
* Checks if all interactive forms on the page are exposed as MCP tools.
|
|
5
|
+
* Unregistered forms represent missed opportunities for tool coverage.
|
|
6
|
+
*/
|
|
7
|
+
import type { Rule } from '../../core/types/rule.js';
|
|
8
|
+
export declare const COV_001: Rule;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* COV-001: Form Coverage
|
|
3
|
+
*
|
|
4
|
+
* Checks if all interactive forms on the page are exposed as MCP tools.
|
|
5
|
+
* Unregistered forms represent missed opportunities for tool coverage.
|
|
6
|
+
*/
|
|
7
|
+
import { createRuleResult } from '../runner.js';
|
|
8
|
+
export const COV_001 = {
|
|
9
|
+
id: 'COV-001',
|
|
10
|
+
category: 'coverage',
|
|
11
|
+
name: 'Form Coverage',
|
|
12
|
+
description: 'All interactive forms should be exposed as MCP tools',
|
|
13
|
+
severity: 'warning',
|
|
14
|
+
maxScore: 5,
|
|
15
|
+
async check(context) {
|
|
16
|
+
const { tools, opportunities } = context;
|
|
17
|
+
if (tools.length === 0 && opportunities.length === 0) {
|
|
18
|
+
return createRuleResult('COV-001', 5, {
|
|
19
|
+
passed: true,
|
|
20
|
+
score: 5,
|
|
21
|
+
message: 'No tools or forms detected (rule not applicable)',
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
if (opportunities.length === 0) {
|
|
25
|
+
return createRuleResult('COV-001', 5, {
|
|
26
|
+
passed: true,
|
|
27
|
+
score: 5,
|
|
28
|
+
message: 'All detected forms are covered by MCP tools',
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
const totalForms = tools.length + opportunities.length;
|
|
32
|
+
const coverageRatio = tools.length / totalForms;
|
|
33
|
+
const score = Math.round(coverageRatio * 5);
|
|
34
|
+
const passed = opportunities.length === 0;
|
|
35
|
+
const uncoveredNames = opportunities.map((o) => o.contextClues.submitText ||
|
|
36
|
+
o.contextClues.ariaLabel ||
|
|
37
|
+
o.contextClues.formId ||
|
|
38
|
+
o.contextClues.formAction ||
|
|
39
|
+
'unnamed form');
|
|
40
|
+
return createRuleResult('COV-001', 5, {
|
|
41
|
+
passed,
|
|
42
|
+
score,
|
|
43
|
+
message: `${tools.length}/${totalForms} forms covered (${Math.round(coverageRatio * 100)}%)`,
|
|
44
|
+
details: uncoveredNames.map((n) => `Uncovered form: ${n}`),
|
|
45
|
+
suggestions: opportunities.length > 0
|
|
46
|
+
? ['Register uncovered forms as MCP tools to improve coverage']
|
|
47
|
+
: undefined,
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=COV-001.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"COV-001.js","sourceRoot":"","sources":["../../../src/rules/coverage/COV-001.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,CAAC,MAAM,OAAO,GAAS;IAC3B,EAAE,EAAE,SAAS;IACb,QAAQ,EAAE,UAAU;IACpB,IAAI,EAAE,eAAe;IACrB,WAAW,EAAE,sDAAsD;IACnE,QAAQ,EAAE,SAAS;IACnB,QAAQ,EAAE,CAAC;IAEX,KAAK,CAAC,KAAK,CAAC,OAAoB;QAC9B,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC;QAEzC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrD,OAAO,gBAAgB,CAAC,SAAS,EAAE,CAAC,EAAE;gBACpC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,kDAAkD;aAC5D,CAAC,CAAC;QACL,CAAC;QAED,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO,gBAAgB,CAAC,SAAS,EAAE,CAAC,EAAE;gBACpC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,6CAA6C;aACvD,CAAC,CAAC;QACL,CAAC;QAED,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC;QACvD,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC;QAChD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,KAAK,CAAC,CAAC;QAE1C,MAAM,cAAc,GAAG,aAAa,CAAC,GAAG,CACtC,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,YAAY,CAAC,UAAU;YACzB,CAAC,CAAC,YAAY,CAAC,SAAS;YACxB,CAAC,CAAC,YAAY,CAAC,MAAM;YACrB,CAAC,CAAC,YAAY,CAAC,UAAU;YACzB,cAAc,CACjB,CAAC;QAEF,OAAO,gBAAgB,CAAC,SAAS,EAAE,CAAC,EAAE;YACpC,MAAM;YACN,KAAK;YACL,OAAO,EAAE,GAAG,KAAK,CAAC,MAAM,IAAI,UAAU,mBAAmB,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,GAAG,CAAC,IAAI;YAC5F,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,mBAAmB,CAAC,EAAE,CAAC;YAC1D,WAAW,EACT,aAAa,CAAC,MAAM,GAAG,CAAC;gBACtB,CAAC,CAAC,CAAC,2DAA2D,CAAC;gBAC/D,CAAC,CAAC,SAAS;SAChB,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DESC-003: Name Kebab Case
|
|
3
|
+
*
|
|
4
|
+
* Checks if tool names follow snake_case or kebab-case convention.
|
|
5
|
+
* Consistent naming helps agents recognize tools and improves
|
|
6
|
+
* overall API quality.
|
|
7
|
+
*
|
|
8
|
+
* Valid: search_flights, search-flights, search
|
|
9
|
+
* Invalid: searchFlights, SearchFlights
|
|
10
|
+
*/
|
|
11
|
+
import type { Rule } from '../../core/types/rule.js';
|
|
12
|
+
export declare const DESC_003: Rule;
|
|
13
|
+
export default DESC_003;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DESC-003: Name Kebab Case
|
|
3
|
+
*
|
|
4
|
+
* Checks if tool names follow snake_case or kebab-case convention.
|
|
5
|
+
* Consistent naming helps agents recognize tools and improves
|
|
6
|
+
* overall API quality.
|
|
7
|
+
*
|
|
8
|
+
* Valid: search_flights, search-flights, search
|
|
9
|
+
* Invalid: searchFlights, SearchFlights
|
|
10
|
+
*/
|
|
11
|
+
import { createRuleResult } from '../runner.js';
|
|
12
|
+
/**
|
|
13
|
+
* Check if a name is in valid format (snake_case, kebab-case, or single word lowercase)
|
|
14
|
+
*/
|
|
15
|
+
function isValidToolName(name) {
|
|
16
|
+
// Allow snake_case, kebab-case, or single lowercase word
|
|
17
|
+
// Pattern: lowercase letters, numbers, underscores, and hyphens only
|
|
18
|
+
// Must not have consecutive separators or start/end with separator
|
|
19
|
+
const validPattern = /^[a-z][a-z0-9]*([_-][a-z0-9]+)*$/;
|
|
20
|
+
return validPattern.test(name);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Detect the naming convention used
|
|
24
|
+
*/
|
|
25
|
+
function detectNamingIssue(name) {
|
|
26
|
+
if (/[A-Z]/.test(name)) {
|
|
27
|
+
if (/^[A-Z]/.test(name)) {
|
|
28
|
+
return 'PascalCase';
|
|
29
|
+
}
|
|
30
|
+
return 'camelCase';
|
|
31
|
+
}
|
|
32
|
+
if (name.includes(' ')) {
|
|
33
|
+
return 'contains spaces';
|
|
34
|
+
}
|
|
35
|
+
if (/^[_-]|[_-]$/.test(name)) {
|
|
36
|
+
return 'starts or ends with separator';
|
|
37
|
+
}
|
|
38
|
+
if (/[_-]{2,}/.test(name)) {
|
|
39
|
+
return 'consecutive separators';
|
|
40
|
+
}
|
|
41
|
+
return 'invalid format';
|
|
42
|
+
}
|
|
43
|
+
export const DESC_003 = {
|
|
44
|
+
id: 'DESC-003',
|
|
45
|
+
category: 'description',
|
|
46
|
+
name: 'Name Kebab Case',
|
|
47
|
+
description: 'Tool names should use snake_case or kebab-case convention',
|
|
48
|
+
severity: 'warning',
|
|
49
|
+
maxScore: 5,
|
|
50
|
+
async check(context) {
|
|
51
|
+
const tools = context.tools;
|
|
52
|
+
if (tools.length === 0) {
|
|
53
|
+
return createRuleResult('DESC-003', 5, {
|
|
54
|
+
passed: true,
|
|
55
|
+
score: 5,
|
|
56
|
+
message: 'No tools detected (rule not applicable)',
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
const violations = [];
|
|
60
|
+
for (const tool of tools) {
|
|
61
|
+
if (!tool.name)
|
|
62
|
+
continue;
|
|
63
|
+
if (!isValidToolName(tool.name)) {
|
|
64
|
+
violations.push({
|
|
65
|
+
name: tool.name,
|
|
66
|
+
issue: detectNamingIssue(tool.name),
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (violations.length === 0) {
|
|
71
|
+
return createRuleResult('DESC-003', 5, {
|
|
72
|
+
passed: true,
|
|
73
|
+
score: 5,
|
|
74
|
+
message: 'All tool names follow proper naming conventions',
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
// Deduct 1 point per violation
|
|
78
|
+
const penalty = Math.min(violations.length, 5);
|
|
79
|
+
const score = Math.max(0, 5 - penalty);
|
|
80
|
+
return createRuleResult('DESC-003', 5, {
|
|
81
|
+
passed: false,
|
|
82
|
+
score,
|
|
83
|
+
message: `${violations.length} tool(s) have naming convention issues`,
|
|
84
|
+
details: violations.map((v) => `Tool "${v.name}" uses ${v.issue}`),
|
|
85
|
+
suggestions: [
|
|
86
|
+
'Use snake_case: search_flights, get_user_profile',
|
|
87
|
+
'Or use kebab-case: search-flights, get-user-profile',
|
|
88
|
+
'Avoid camelCase or PascalCase for tool names',
|
|
89
|
+
'Consistent naming improves tool discoverability',
|
|
90
|
+
],
|
|
91
|
+
affectedTools: violations.map((v) => v.name),
|
|
92
|
+
});
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
export default DESC_003;
|
|
96
|
+
//# sourceMappingURL=DESC-003.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DESC-003.js","sourceRoot":"","sources":["../../../src/rules/description/DESC-003.ts"],"names":[],"mappings":"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"}
|