@dotsetlabs/bellwether 0.10.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/CHANGELOG.md +291 -0
- package/LICENSE +21 -0
- package/README.md +739 -0
- package/dist/auth/credentials.d.ts +64 -0
- package/dist/auth/credentials.js +218 -0
- package/dist/auth/index.d.ts +6 -0
- package/dist/auth/index.js +6 -0
- package/dist/auth/keychain.d.ts +64 -0
- package/dist/auth/keychain.js +268 -0
- package/dist/baseline/ab-testing.d.ts +80 -0
- package/dist/baseline/ab-testing.js +236 -0
- package/dist/baseline/ai-compatibility-scorer.d.ts +95 -0
- package/dist/baseline/ai-compatibility-scorer.js +606 -0
- package/dist/baseline/calibration.d.ts +77 -0
- package/dist/baseline/calibration.js +136 -0
- package/dist/baseline/category-matching.d.ts +85 -0
- package/dist/baseline/category-matching.js +289 -0
- package/dist/baseline/change-impact-analyzer.d.ts +98 -0
- package/dist/baseline/change-impact-analyzer.js +592 -0
- package/dist/baseline/comparator.d.ts +64 -0
- package/dist/baseline/comparator.js +916 -0
- package/dist/baseline/confidence.d.ts +55 -0
- package/dist/baseline/confidence.js +122 -0
- package/dist/baseline/converter.d.ts +61 -0
- package/dist/baseline/converter.js +585 -0
- package/dist/baseline/dependency-analyzer.d.ts +89 -0
- package/dist/baseline/dependency-analyzer.js +567 -0
- package/dist/baseline/deprecation-tracker.d.ts +133 -0
- package/dist/baseline/deprecation-tracker.js +322 -0
- package/dist/baseline/diff.d.ts +55 -0
- package/dist/baseline/diff.js +1584 -0
- package/dist/baseline/documentation-scorer.d.ts +205 -0
- package/dist/baseline/documentation-scorer.js +466 -0
- package/dist/baseline/embeddings.d.ts +118 -0
- package/dist/baseline/embeddings.js +251 -0
- package/dist/baseline/error-analyzer.d.ts +198 -0
- package/dist/baseline/error-analyzer.js +721 -0
- package/dist/baseline/evaluation/evaluator.d.ts +42 -0
- package/dist/baseline/evaluation/evaluator.js +323 -0
- package/dist/baseline/evaluation/expanded-dataset.d.ts +45 -0
- package/dist/baseline/evaluation/expanded-dataset.js +1164 -0
- package/dist/baseline/evaluation/golden-dataset.d.ts +58 -0
- package/dist/baseline/evaluation/golden-dataset.js +717 -0
- package/dist/baseline/evaluation/index.d.ts +15 -0
- package/dist/baseline/evaluation/index.js +15 -0
- package/dist/baseline/evaluation/types.d.ts +186 -0
- package/dist/baseline/evaluation/types.js +8 -0
- package/dist/baseline/external-dependency-detector.d.ts +181 -0
- package/dist/baseline/external-dependency-detector.js +524 -0
- package/dist/baseline/golden-output.d.ts +162 -0
- package/dist/baseline/golden-output.js +636 -0
- package/dist/baseline/health-scorer.d.ts +174 -0
- package/dist/baseline/health-scorer.js +451 -0
- package/dist/baseline/incremental-checker.d.ts +97 -0
- package/dist/baseline/incremental-checker.js +174 -0
- package/dist/baseline/index.d.ts +31 -0
- package/dist/baseline/index.js +42 -0
- package/dist/baseline/migration-generator.d.ts +137 -0
- package/dist/baseline/migration-generator.js +554 -0
- package/dist/baseline/migrations.d.ts +60 -0
- package/dist/baseline/migrations.js +197 -0
- package/dist/baseline/performance-tracker.d.ts +214 -0
- package/dist/baseline/performance-tracker.js +577 -0
- package/dist/baseline/pr-comment-generator.d.ts +117 -0
- package/dist/baseline/pr-comment-generator.js +546 -0
- package/dist/baseline/response-fingerprint.d.ts +127 -0
- package/dist/baseline/response-fingerprint.js +728 -0
- package/dist/baseline/response-schema-tracker.d.ts +129 -0
- package/dist/baseline/response-schema-tracker.js +420 -0
- package/dist/baseline/risk-scorer.d.ts +54 -0
- package/dist/baseline/risk-scorer.js +434 -0
- package/dist/baseline/saver.d.ts +89 -0
- package/dist/baseline/saver.js +554 -0
- package/dist/baseline/scenario-generator.d.ts +151 -0
- package/dist/baseline/scenario-generator.js +905 -0
- package/dist/baseline/schema-compare.d.ts +86 -0
- package/dist/baseline/schema-compare.js +557 -0
- package/dist/baseline/schema-evolution.d.ts +189 -0
- package/dist/baseline/schema-evolution.js +467 -0
- package/dist/baseline/semantic.d.ts +203 -0
- package/dist/baseline/semantic.js +908 -0
- package/dist/baseline/synonyms.d.ts +60 -0
- package/dist/baseline/synonyms.js +386 -0
- package/dist/baseline/telemetry.d.ts +165 -0
- package/dist/baseline/telemetry.js +294 -0
- package/dist/baseline/test-pruner.d.ts +120 -0
- package/dist/baseline/test-pruner.js +387 -0
- package/dist/baseline/types.d.ts +449 -0
- package/dist/baseline/types.js +5 -0
- package/dist/baseline/version.d.ts +138 -0
- package/dist/baseline/version.js +206 -0
- package/dist/cache/index.d.ts +5 -0
- package/dist/cache/index.js +5 -0
- package/dist/cache/response-cache.d.ts +151 -0
- package/dist/cache/response-cache.js +287 -0
- package/dist/ci/index.d.ts +60 -0
- package/dist/ci/index.js +342 -0
- package/dist/cli/commands/auth.d.ts +12 -0
- package/dist/cli/commands/auth.js +352 -0
- package/dist/cli/commands/badge.d.ts +3 -0
- package/dist/cli/commands/badge.js +74 -0
- package/dist/cli/commands/baseline-accept.d.ts +15 -0
- package/dist/cli/commands/baseline-accept.js +178 -0
- package/dist/cli/commands/baseline-migrate.d.ts +12 -0
- package/dist/cli/commands/baseline-migrate.js +164 -0
- package/dist/cli/commands/baseline.d.ts +14 -0
- package/dist/cli/commands/baseline.js +449 -0
- package/dist/cli/commands/beta.d.ts +10 -0
- package/dist/cli/commands/beta.js +231 -0
- package/dist/cli/commands/check.d.ts +11 -0
- package/dist/cli/commands/check.js +820 -0
- package/dist/cli/commands/cloud/badge.d.ts +3 -0
- package/dist/cli/commands/cloud/badge.js +74 -0
- package/dist/cli/commands/cloud/diff.d.ts +6 -0
- package/dist/cli/commands/cloud/diff.js +79 -0
- package/dist/cli/commands/cloud/history.d.ts +6 -0
- package/dist/cli/commands/cloud/history.js +102 -0
- package/dist/cli/commands/cloud/link.d.ts +9 -0
- package/dist/cli/commands/cloud/link.js +119 -0
- package/dist/cli/commands/cloud/login.d.ts +7 -0
- package/dist/cli/commands/cloud/login.js +499 -0
- package/dist/cli/commands/cloud/projects.d.ts +6 -0
- package/dist/cli/commands/cloud/projects.js +44 -0
- package/dist/cli/commands/cloud/shared.d.ts +7 -0
- package/dist/cli/commands/cloud/shared.js +42 -0
- package/dist/cli/commands/cloud/teams.d.ts +8 -0
- package/dist/cli/commands/cloud/teams.js +169 -0
- package/dist/cli/commands/cloud/upload.d.ts +8 -0
- package/dist/cli/commands/cloud/upload.js +181 -0
- package/dist/cli/commands/contract.d.ts +11 -0
- package/dist/cli/commands/contract.js +280 -0
- package/dist/cli/commands/discover.d.ts +3 -0
- package/dist/cli/commands/discover.js +82 -0
- package/dist/cli/commands/eval.d.ts +9 -0
- package/dist/cli/commands/eval.js +187 -0
- package/dist/cli/commands/explore.d.ts +11 -0
- package/dist/cli/commands/explore.js +437 -0
- package/dist/cli/commands/feedback.d.ts +9 -0
- package/dist/cli/commands/feedback.js +174 -0
- package/dist/cli/commands/golden.d.ts +12 -0
- package/dist/cli/commands/golden.js +407 -0
- package/dist/cli/commands/history.d.ts +10 -0
- package/dist/cli/commands/history.js +202 -0
- package/dist/cli/commands/init.d.ts +9 -0
- package/dist/cli/commands/init.js +219 -0
- package/dist/cli/commands/interview.d.ts +3 -0
- package/dist/cli/commands/interview.js +903 -0
- package/dist/cli/commands/link.d.ts +10 -0
- package/dist/cli/commands/link.js +169 -0
- package/dist/cli/commands/login.d.ts +7 -0
- package/dist/cli/commands/login.js +499 -0
- package/dist/cli/commands/preset.d.ts +33 -0
- package/dist/cli/commands/preset.js +297 -0
- package/dist/cli/commands/profile.d.ts +33 -0
- package/dist/cli/commands/profile.js +286 -0
- package/dist/cli/commands/registry.d.ts +11 -0
- package/dist/cli/commands/registry.js +146 -0
- package/dist/cli/commands/shared.d.ts +79 -0
- package/dist/cli/commands/shared.js +196 -0
- package/dist/cli/commands/teams.d.ts +8 -0
- package/dist/cli/commands/teams.js +169 -0
- package/dist/cli/commands/test.d.ts +9 -0
- package/dist/cli/commands/test.js +500 -0
- package/dist/cli/commands/upload.d.ts +8 -0
- package/dist/cli/commands/upload.js +223 -0
- package/dist/cli/commands/validate-config.d.ts +6 -0
- package/dist/cli/commands/validate-config.js +35 -0
- package/dist/cli/commands/verify.d.ts +11 -0
- package/dist/cli/commands/verify.js +283 -0
- package/dist/cli/commands/watch.d.ts +12 -0
- package/dist/cli/commands/watch.js +253 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.js +178 -0
- package/dist/cli/interactive.d.ts +47 -0
- package/dist/cli/interactive.js +216 -0
- package/dist/cli/output/terminal-reporter.d.ts +19 -0
- package/dist/cli/output/terminal-reporter.js +104 -0
- package/dist/cli/output.d.ts +226 -0
- package/dist/cli/output.js +438 -0
- package/dist/cli/utils/env.d.ts +5 -0
- package/dist/cli/utils/env.js +14 -0
- package/dist/cli/utils/progress.d.ts +59 -0
- package/dist/cli/utils/progress.js +206 -0
- package/dist/cli/utils/server-context.d.ts +10 -0
- package/dist/cli/utils/server-context.js +36 -0
- package/dist/cloud/auth.d.ts +144 -0
- package/dist/cloud/auth.js +374 -0
- package/dist/cloud/client.d.ts +24 -0
- package/dist/cloud/client.js +65 -0
- package/dist/cloud/http-client.d.ts +38 -0
- package/dist/cloud/http-client.js +215 -0
- package/dist/cloud/index.d.ts +23 -0
- package/dist/cloud/index.js +25 -0
- package/dist/cloud/mock-client.d.ts +107 -0
- package/dist/cloud/mock-client.js +545 -0
- package/dist/cloud/types.d.ts +515 -0
- package/dist/cloud/types.js +15 -0
- package/dist/config/defaults.d.ts +160 -0
- package/dist/config/defaults.js +169 -0
- package/dist/config/loader.d.ts +24 -0
- package/dist/config/loader.js +122 -0
- package/dist/config/template.d.ts +42 -0
- package/dist/config/template.js +647 -0
- package/dist/config/validator.d.ts +2112 -0
- package/dist/config/validator.js +658 -0
- package/dist/constants/cloud.d.ts +107 -0
- package/dist/constants/cloud.js +110 -0
- package/dist/constants/core.d.ts +521 -0
- package/dist/constants/core.js +556 -0
- package/dist/constants/testing.d.ts +1283 -0
- package/dist/constants/testing.js +1568 -0
- package/dist/constants.d.ts +10 -0
- package/dist/constants.js +10 -0
- package/dist/contract/index.d.ts +6 -0
- package/dist/contract/index.js +5 -0
- package/dist/contract/validator.d.ts +177 -0
- package/dist/contract/validator.js +574 -0
- package/dist/cost/index.d.ts +6 -0
- package/dist/cost/index.js +5 -0
- package/dist/cost/tracker.d.ts +134 -0
- package/dist/cost/tracker.js +313 -0
- package/dist/discovery/discovery.d.ts +16 -0
- package/dist/discovery/discovery.js +173 -0
- package/dist/discovery/types.d.ts +51 -0
- package/dist/discovery/types.js +2 -0
- package/dist/docs/agents.d.ts +3 -0
- package/dist/docs/agents.js +995 -0
- package/dist/docs/contract.d.ts +51 -0
- package/dist/docs/contract.js +1681 -0
- package/dist/docs/generator.d.ts +4 -0
- package/dist/docs/generator.js +4 -0
- package/dist/docs/html-reporter.d.ts +9 -0
- package/dist/docs/html-reporter.js +757 -0
- package/dist/docs/index.d.ts +10 -0
- package/dist/docs/index.js +11 -0
- package/dist/docs/junit-reporter.d.ts +18 -0
- package/dist/docs/junit-reporter.js +210 -0
- package/dist/docs/report.d.ts +14 -0
- package/dist/docs/report.js +44 -0
- package/dist/docs/sarif-reporter.d.ts +19 -0
- package/dist/docs/sarif-reporter.js +335 -0
- package/dist/docs/shared.d.ts +35 -0
- package/dist/docs/shared.js +162 -0
- package/dist/docs/templates.d.ts +12 -0
- package/dist/docs/templates.js +76 -0
- package/dist/errors/index.d.ts +6 -0
- package/dist/errors/index.js +6 -0
- package/dist/errors/retry.d.ts +92 -0
- package/dist/errors/retry.js +323 -0
- package/dist/errors/types.d.ts +321 -0
- package/dist/errors/types.js +584 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +32 -0
- package/dist/interview/dependency-resolver.d.ts +11 -0
- package/dist/interview/dependency-resolver.js +32 -0
- package/dist/interview/interviewer.d.ts +232 -0
- package/dist/interview/interviewer.js +1939 -0
- package/dist/interview/mock-response-generator.d.ts +7 -0
- package/dist/interview/mock-response-generator.js +102 -0
- package/dist/interview/orchestrator.d.ts +237 -0
- package/dist/interview/orchestrator.js +1296 -0
- package/dist/interview/rate-limiter.d.ts +15 -0
- package/dist/interview/rate-limiter.js +55 -0
- package/dist/interview/response-validator.d.ts +10 -0
- package/dist/interview/response-validator.js +132 -0
- package/dist/interview/schema-inferrer.d.ts +8 -0
- package/dist/interview/schema-inferrer.js +71 -0
- package/dist/interview/schema-test-generator.d.ts +71 -0
- package/dist/interview/schema-test-generator.js +834 -0
- package/dist/interview/smart-value-generator.d.ts +155 -0
- package/dist/interview/smart-value-generator.js +554 -0
- package/dist/interview/stateful-test-runner.d.ts +19 -0
- package/dist/interview/stateful-test-runner.js +106 -0
- package/dist/interview/types.d.ts +561 -0
- package/dist/interview/types.js +2 -0
- package/dist/llm/anthropic.d.ts +41 -0
- package/dist/llm/anthropic.js +355 -0
- package/dist/llm/client.d.ts +123 -0
- package/dist/llm/client.js +42 -0
- package/dist/llm/factory.d.ts +38 -0
- package/dist/llm/factory.js +145 -0
- package/dist/llm/fallback.d.ts +140 -0
- package/dist/llm/fallback.js +379 -0
- package/dist/llm/index.d.ts +18 -0
- package/dist/llm/index.js +15 -0
- package/dist/llm/ollama.d.ts +37 -0
- package/dist/llm/ollama.js +330 -0
- package/dist/llm/openai.d.ts +25 -0
- package/dist/llm/openai.js +320 -0
- package/dist/llm/token-budget.d.ts +161 -0
- package/dist/llm/token-budget.js +395 -0
- package/dist/logging/logger.d.ts +70 -0
- package/dist/logging/logger.js +130 -0
- package/dist/metrics/collector.d.ts +106 -0
- package/dist/metrics/collector.js +547 -0
- package/dist/metrics/index.d.ts +7 -0
- package/dist/metrics/index.js +7 -0
- package/dist/metrics/prometheus.d.ts +20 -0
- package/dist/metrics/prometheus.js +241 -0
- package/dist/metrics/types.d.ts +209 -0
- package/dist/metrics/types.js +5 -0
- package/dist/persona/builtins.d.ts +54 -0
- package/dist/persona/builtins.js +219 -0
- package/dist/persona/index.d.ts +8 -0
- package/dist/persona/index.js +8 -0
- package/dist/persona/loader.d.ts +30 -0
- package/dist/persona/loader.js +190 -0
- package/dist/persona/types.d.ts +144 -0
- package/dist/persona/types.js +5 -0
- package/dist/persona/validation.d.ts +94 -0
- package/dist/persona/validation.js +332 -0
- package/dist/prompts/index.d.ts +5 -0
- package/dist/prompts/index.js +5 -0
- package/dist/prompts/templates.d.ts +180 -0
- package/dist/prompts/templates.js +431 -0
- package/dist/registry/client.d.ts +49 -0
- package/dist/registry/client.js +191 -0
- package/dist/registry/index.d.ts +7 -0
- package/dist/registry/index.js +6 -0
- package/dist/registry/types.d.ts +140 -0
- package/dist/registry/types.js +6 -0
- package/dist/scenarios/evaluator.d.ts +43 -0
- package/dist/scenarios/evaluator.js +206 -0
- package/dist/scenarios/index.d.ts +10 -0
- package/dist/scenarios/index.js +9 -0
- package/dist/scenarios/loader.d.ts +20 -0
- package/dist/scenarios/loader.js +285 -0
- package/dist/scenarios/types.d.ts +153 -0
- package/dist/scenarios/types.js +8 -0
- package/dist/security/index.d.ts +17 -0
- package/dist/security/index.js +18 -0
- package/dist/security/payloads.d.ts +61 -0
- package/dist/security/payloads.js +268 -0
- package/dist/security/security-tester.d.ts +42 -0
- package/dist/security/security-tester.js +582 -0
- package/dist/security/types.d.ts +166 -0
- package/dist/security/types.js +8 -0
- package/dist/transport/base-transport.d.ts +59 -0
- package/dist/transport/base-transport.js +38 -0
- package/dist/transport/http-transport.d.ts +67 -0
- package/dist/transport/http-transport.js +238 -0
- package/dist/transport/mcp-client.d.ts +141 -0
- package/dist/transport/mcp-client.js +496 -0
- package/dist/transport/sse-transport.d.ts +88 -0
- package/dist/transport/sse-transport.js +316 -0
- package/dist/transport/stdio-transport.d.ts +43 -0
- package/dist/transport/stdio-transport.js +238 -0
- package/dist/transport/types.d.ts +125 -0
- package/dist/transport/types.js +16 -0
- package/dist/utils/concurrency.d.ts +123 -0
- package/dist/utils/concurrency.js +213 -0
- package/dist/utils/formatters.d.ts +16 -0
- package/dist/utils/formatters.js +37 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/jsonpath.d.ts +87 -0
- package/dist/utils/jsonpath.js +326 -0
- package/dist/utils/markdown.d.ts +113 -0
- package/dist/utils/markdown.js +265 -0
- package/dist/utils/network.d.ts +14 -0
- package/dist/utils/network.js +17 -0
- package/dist/utils/sanitize.d.ts +92 -0
- package/dist/utils/sanitize.js +191 -0
- package/dist/utils/semantic.d.ts +194 -0
- package/dist/utils/semantic.js +1051 -0
- package/dist/utils/smart-truncate.d.ts +94 -0
- package/dist/utils/smart-truncate.js +361 -0
- package/dist/utils/timeout.d.ts +153 -0
- package/dist/utils/timeout.js +205 -0
- package/dist/utils/yaml-parser.d.ts +58 -0
- package/dist/utils/yaml-parser.js +86 -0
- package/dist/validation/index.d.ts +32 -0
- package/dist/validation/index.js +32 -0
- package/dist/validation/semantic-test-generator.d.ts +50 -0
- package/dist/validation/semantic-test-generator.js +176 -0
- package/dist/validation/semantic-types.d.ts +66 -0
- package/dist/validation/semantic-types.js +94 -0
- package/dist/validation/semantic-validator.d.ts +38 -0
- package/dist/validation/semantic-validator.js +340 -0
- package/dist/verification/index.d.ts +6 -0
- package/dist/verification/index.js +5 -0
- package/dist/verification/types.d.ts +133 -0
- package/dist/verification/types.js +5 -0
- package/dist/verification/verifier.d.ts +30 -0
- package/dist/verification/verifier.js +309 -0
- package/dist/version.d.ts +19 -0
- package/dist/version.js +48 -0
- package/dist/workflow/auto-generator.d.ts +27 -0
- package/dist/workflow/auto-generator.js +513 -0
- package/dist/workflow/discovery.d.ts +40 -0
- package/dist/workflow/discovery.js +195 -0
- package/dist/workflow/executor.d.ts +82 -0
- package/dist/workflow/executor.js +611 -0
- package/dist/workflow/index.d.ts +10 -0
- package/dist/workflow/index.js +10 -0
- package/dist/workflow/loader.d.ts +24 -0
- package/dist/workflow/loader.js +194 -0
- package/dist/workflow/state-tracker.d.ts +98 -0
- package/dist/workflow/state-tracker.js +424 -0
- package/dist/workflow/types.d.ts +337 -0
- package/dist/workflow/types.js +5 -0
- package/package.json +94 -0
- package/schemas/bellwether-check.schema.json +651 -0
|
@@ -0,0 +1,585 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Baseline format converter.
|
|
3
|
+
*
|
|
4
|
+
* Converts between local BehavioralBaseline format and cloud BellwetherBaseline format.
|
|
5
|
+
*
|
|
6
|
+
* ## Severity Type Mappings
|
|
7
|
+
*
|
|
8
|
+
* The codebase uses three different severity type systems for different contexts:
|
|
9
|
+
*
|
|
10
|
+
* ### ChangeSeverity (baseline/types.ts)
|
|
11
|
+
* Used for drift detection change classification. Maps to CLI exit codes.
|
|
12
|
+
* Values: 'none' | 'info' | 'warning' | 'breaking'
|
|
13
|
+
*
|
|
14
|
+
* ### ErrorSeverity (errors/types.ts)
|
|
15
|
+
* Used for error severity classification in error handling.
|
|
16
|
+
* Values: 'low' | 'medium' | 'high' | 'critical'
|
|
17
|
+
*
|
|
18
|
+
* ### CloudAssertionSeverity (cloud/types.ts)
|
|
19
|
+
* Used for cloud assertions and PersonaFinding severity levels.
|
|
20
|
+
* Values: 'info' | 'low' | 'medium' | 'high' | 'critical'
|
|
21
|
+
*
|
|
22
|
+
* ### Conversion Mappings
|
|
23
|
+
*
|
|
24
|
+
* ChangeSeverity → CloudAssertionSeverity:
|
|
25
|
+
* - 'none' → 'info' (no change, informational)
|
|
26
|
+
* - 'info' → 'low' (minor changes)
|
|
27
|
+
* - 'warning' → 'medium' (moderate changes)
|
|
28
|
+
* - 'breaking' → 'critical' (breaking changes)
|
|
29
|
+
*
|
|
30
|
+
* CloudAssertionSeverity → ChangeSeverity (for display/filtering):
|
|
31
|
+
* - 'info' → 'info'
|
|
32
|
+
* - 'low' → 'info'
|
|
33
|
+
* - 'medium' → 'warning'
|
|
34
|
+
* - 'high' → 'warning'
|
|
35
|
+
* - 'critical' → 'breaking'
|
|
36
|
+
*/
|
|
37
|
+
import { createHash } from 'crypto';
|
|
38
|
+
import { analyzeResponses } from './response-fingerprint.js';
|
|
39
|
+
import { getBaselineVersion } from './version.js';
|
|
40
|
+
import { VERSION } from '../version.js';
|
|
41
|
+
/**
|
|
42
|
+
* Map ChangeSeverity to CloudAssertionSeverity.
|
|
43
|
+
* Used when converting local baselines to cloud format.
|
|
44
|
+
*/
|
|
45
|
+
export const CHANGE_TO_CLOUD_SEVERITY = {
|
|
46
|
+
none: 'info',
|
|
47
|
+
info: 'low',
|
|
48
|
+
warning: 'medium',
|
|
49
|
+
breaking: 'critical',
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Map CloudAssertionSeverity to ChangeSeverity.
|
|
53
|
+
* Used when filtering or displaying cloud data locally.
|
|
54
|
+
*/
|
|
55
|
+
export const CLOUD_TO_CHANGE_SEVERITY = {
|
|
56
|
+
info: 'info',
|
|
57
|
+
low: 'info',
|
|
58
|
+
medium: 'warning',
|
|
59
|
+
high: 'warning',
|
|
60
|
+
critical: 'breaking',
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Hash a string using SHA-256.
|
|
64
|
+
*/
|
|
65
|
+
function hashString(input) {
|
|
66
|
+
return createHash('sha256').update(input).digest('hex').slice(0, 16);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Convert a local BehavioralAssertion to cloud CloudAssertion format.
|
|
70
|
+
*
|
|
71
|
+
* Mapping:
|
|
72
|
+
* - isPositive=true + security aspect → 'requires' (critical security requirement)
|
|
73
|
+
* - isPositive=true + other aspect → 'expects' (expected behavior)
|
|
74
|
+
* - isPositive=false + security aspect → 'warns' (security warning)
|
|
75
|
+
* - isPositive=false + other aspect → 'notes' (limitation/note)
|
|
76
|
+
*/
|
|
77
|
+
function convertAssertion(assertion) {
|
|
78
|
+
// Determine assertion type based on isPositive and aspect
|
|
79
|
+
let type;
|
|
80
|
+
if (assertion.isPositive) {
|
|
81
|
+
type = assertion.aspect === 'security' ? 'requires' : 'expects';
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
type = assertion.aspect === 'security' ? 'warns' : 'notes';
|
|
85
|
+
}
|
|
86
|
+
// Determine severity based on aspect and content
|
|
87
|
+
let severity = 'info';
|
|
88
|
+
const lowerAssertion = assertion.assertion.toLowerCase();
|
|
89
|
+
if (assertion.aspect === 'security') {
|
|
90
|
+
if (lowerAssertion.includes('critical') ||
|
|
91
|
+
lowerAssertion.includes('injection') ||
|
|
92
|
+
lowerAssertion.includes('rce')) {
|
|
93
|
+
severity = 'critical';
|
|
94
|
+
}
|
|
95
|
+
else if (lowerAssertion.includes('high') ||
|
|
96
|
+
lowerAssertion.includes('dangerous') ||
|
|
97
|
+
lowerAssertion.includes('exploit')) {
|
|
98
|
+
severity = 'high';
|
|
99
|
+
}
|
|
100
|
+
else if (lowerAssertion.includes('medium') ||
|
|
101
|
+
lowerAssertion.includes('sensitive') ||
|
|
102
|
+
lowerAssertion.includes('leak')) {
|
|
103
|
+
severity = 'medium';
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
severity = 'low';
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else if (assertion.aspect === 'error_handling') {
|
|
110
|
+
severity = assertion.isPositive ? 'info' : 'low';
|
|
111
|
+
}
|
|
112
|
+
else if (assertion.aspect === 'performance') {
|
|
113
|
+
severity = 'medium';
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
type,
|
|
117
|
+
condition: assertion.assertion,
|
|
118
|
+
tool: assertion.tool,
|
|
119
|
+
severity,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Convert an array of BehavioralAssertions to CloudAssertions.
|
|
124
|
+
*/
|
|
125
|
+
function convertAssertions(assertions) {
|
|
126
|
+
return assertions.map(convertAssertion);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Derive baseline mode from result metadata.
|
|
130
|
+
* Returns 'check' for check mode results, 'explore' for explore mode results.
|
|
131
|
+
* Note: Baselines should only be created from check mode results,
|
|
132
|
+
* but explore uploads are still supported for documentation tracking.
|
|
133
|
+
*/
|
|
134
|
+
function deriveCloudMode(resultModel) {
|
|
135
|
+
// Check mode results have model === 'check'
|
|
136
|
+
if (resultModel === 'check')
|
|
137
|
+
return 'check';
|
|
138
|
+
// Everything else (explore mode with LLM model names) is explore
|
|
139
|
+
return 'explore';
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Convert a BehavioralBaseline to cloud BellwetherBaseline format.
|
|
143
|
+
*/
|
|
144
|
+
export function convertToCloudBaseline(baseline, discovery, interviewResult) {
|
|
145
|
+
// Derive mode from result metadata
|
|
146
|
+
const mode = deriveCloudMode(interviewResult?.metadata.model);
|
|
147
|
+
// Build metadata
|
|
148
|
+
const metadata = {
|
|
149
|
+
mode,
|
|
150
|
+
generatedAt: baseline.createdAt.toISOString(),
|
|
151
|
+
cliVersion: VERSION,
|
|
152
|
+
serverCommand: baseline.serverCommand,
|
|
153
|
+
serverName: baseline.server.name,
|
|
154
|
+
durationMs: interviewResult?.metadata.durationMs ?? 0,
|
|
155
|
+
personas: extractPersonas(interviewResult),
|
|
156
|
+
model: interviewResult?.metadata.model ?? 'unknown',
|
|
157
|
+
};
|
|
158
|
+
// Build server fingerprint
|
|
159
|
+
const server = {
|
|
160
|
+
name: baseline.server.name,
|
|
161
|
+
version: baseline.server.version,
|
|
162
|
+
protocolVersion: baseline.server.protocolVersion,
|
|
163
|
+
capabilities: baseline.server.capabilities,
|
|
164
|
+
};
|
|
165
|
+
// Build capabilities
|
|
166
|
+
const capabilities = buildCapabilities(baseline, discovery);
|
|
167
|
+
// Build interviews
|
|
168
|
+
const interviews = buildInterviews(interviewResult);
|
|
169
|
+
// Build tool profiles (with converted assertions)
|
|
170
|
+
const toolProfiles = baseline.tools.map(convertToolFingerprint);
|
|
171
|
+
// Build workflows
|
|
172
|
+
const workflows = baseline.workflowSignatures;
|
|
173
|
+
// Convert assertions to cloud format
|
|
174
|
+
const assertions = convertAssertions(baseline.assertions);
|
|
175
|
+
// Build content hash
|
|
176
|
+
const contentForHash = JSON.stringify({
|
|
177
|
+
metadata,
|
|
178
|
+
server,
|
|
179
|
+
capabilities,
|
|
180
|
+
interviews,
|
|
181
|
+
toolProfiles,
|
|
182
|
+
workflows,
|
|
183
|
+
assertions,
|
|
184
|
+
summary: baseline.summary,
|
|
185
|
+
});
|
|
186
|
+
const hash = hashString(contentForHash);
|
|
187
|
+
return {
|
|
188
|
+
version: getBaselineVersion(),
|
|
189
|
+
metadata,
|
|
190
|
+
server,
|
|
191
|
+
capabilities,
|
|
192
|
+
interviews,
|
|
193
|
+
toolProfiles,
|
|
194
|
+
workflows,
|
|
195
|
+
assertions,
|
|
196
|
+
summary: baseline.summary,
|
|
197
|
+
hash,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Extract persona names from interview result.
|
|
202
|
+
*/
|
|
203
|
+
function extractPersonas(result) {
|
|
204
|
+
if (!result?.metadata.personas) {
|
|
205
|
+
return ['technical_writer']; // Default persona
|
|
206
|
+
}
|
|
207
|
+
return result.metadata.personas.map((p) => p.id);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Build capabilities from baseline and discovery.
|
|
211
|
+
*/
|
|
212
|
+
function buildCapabilities(baseline, discovery) {
|
|
213
|
+
// Build tool capabilities
|
|
214
|
+
// Prefer discovery schema, fall back to stored inputSchema from baseline
|
|
215
|
+
// Include response fingerprinting data from baseline
|
|
216
|
+
const tools = baseline.tools.map((tool) => ({
|
|
217
|
+
name: tool.name,
|
|
218
|
+
description: tool.description,
|
|
219
|
+
inputSchema: discovery
|
|
220
|
+
? getToolSchema(discovery, tool.name)
|
|
221
|
+
: (tool.inputSchema ?? {}),
|
|
222
|
+
schemaHash: tool.schemaHash,
|
|
223
|
+
// Response fingerprinting (check mode enhancement)
|
|
224
|
+
responseFingerprint: tool.responseFingerprint,
|
|
225
|
+
inferredOutputSchema: tool.inferredOutputSchema,
|
|
226
|
+
errorPatterns: tool.errorPatterns,
|
|
227
|
+
}));
|
|
228
|
+
// Build resource capabilities (from discovery if available)
|
|
229
|
+
let resources;
|
|
230
|
+
// Note: Resources would come from discovery.resources if we had them
|
|
231
|
+
// Build prompt capabilities (from discovery if available)
|
|
232
|
+
let prompts;
|
|
233
|
+
if (discovery?.prompts && discovery.prompts.length > 0) {
|
|
234
|
+
prompts = discovery.prompts.map((p) => ({
|
|
235
|
+
name: p.name,
|
|
236
|
+
description: p.description,
|
|
237
|
+
arguments: p.arguments?.map((a) => ({
|
|
238
|
+
name: a.name,
|
|
239
|
+
description: a.description,
|
|
240
|
+
required: a.required,
|
|
241
|
+
})),
|
|
242
|
+
}));
|
|
243
|
+
}
|
|
244
|
+
return {
|
|
245
|
+
tools,
|
|
246
|
+
resources,
|
|
247
|
+
prompts,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Get tool schema from discovery.
|
|
252
|
+
*/
|
|
253
|
+
function getToolSchema(discovery, toolName) {
|
|
254
|
+
const tool = discovery.tools.find((t) => t.name === toolName);
|
|
255
|
+
return tool?.inputSchema ?? {};
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Build interview summaries from interview result.
|
|
259
|
+
*/
|
|
260
|
+
function buildInterviews(result) {
|
|
261
|
+
if (!result?.metadata.personas) {
|
|
262
|
+
// Create a default technical_writer interview
|
|
263
|
+
const totalQuestions = result?.toolProfiles.reduce((sum, p) => sum + p.interactions.length, 0) ?? 0;
|
|
264
|
+
return [
|
|
265
|
+
{
|
|
266
|
+
persona: 'technical_writer',
|
|
267
|
+
toolsInterviewed: result?.toolProfiles.length ?? 0,
|
|
268
|
+
questionsAsked: totalQuestions,
|
|
269
|
+
findings: extractFindings(result?.toolProfiles ?? []),
|
|
270
|
+
},
|
|
271
|
+
];
|
|
272
|
+
}
|
|
273
|
+
// Build interviews per persona
|
|
274
|
+
return result.metadata.personas.map((persona) => {
|
|
275
|
+
const personaInteractions = result.toolProfiles.flatMap((profile) => profile.interactions.filter((i) => i.personaId === persona.id));
|
|
276
|
+
const toolsWithPersonaInteractions = new Set(personaInteractions.map((i) => i.toolName));
|
|
277
|
+
return {
|
|
278
|
+
persona: persona.id,
|
|
279
|
+
toolsInterviewed: toolsWithPersonaInteractions.size,
|
|
280
|
+
questionsAsked: persona.questionsAsked,
|
|
281
|
+
findings: extractFindingsForPersona(result.toolProfiles, persona.id),
|
|
282
|
+
};
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Extract findings from tool profiles.
|
|
287
|
+
*/
|
|
288
|
+
function extractFindings(toolProfiles) {
|
|
289
|
+
const findings = [];
|
|
290
|
+
for (const profile of toolProfiles) {
|
|
291
|
+
// Add security findings
|
|
292
|
+
for (const note of profile.securityNotes) {
|
|
293
|
+
findings.push({
|
|
294
|
+
tool: profile.name,
|
|
295
|
+
category: 'security',
|
|
296
|
+
severity: classifySeverity(note),
|
|
297
|
+
description: note,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
// Add limitation findings
|
|
301
|
+
for (const limitation of profile.limitations) {
|
|
302
|
+
findings.push({
|
|
303
|
+
tool: profile.name,
|
|
304
|
+
category: 'reliability',
|
|
305
|
+
severity: 'low',
|
|
306
|
+
description: limitation,
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
// Add behavioral findings (first few as behavior category)
|
|
310
|
+
for (const note of profile.behavioralNotes.slice(0, 3)) {
|
|
311
|
+
findings.push({
|
|
312
|
+
tool: profile.name,
|
|
313
|
+
category: 'behavior',
|
|
314
|
+
severity: 'info',
|
|
315
|
+
description: note,
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return findings;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Extract findings for a specific persona.
|
|
323
|
+
*/
|
|
324
|
+
function extractFindingsForPersona(toolProfiles, personaId) {
|
|
325
|
+
const findings = [];
|
|
326
|
+
for (const profile of toolProfiles) {
|
|
327
|
+
const personaFindings = profile.findingsByPersona?.find((f) => f.personaId === personaId);
|
|
328
|
+
if (!personaFindings)
|
|
329
|
+
continue;
|
|
330
|
+
// Add security findings
|
|
331
|
+
for (const note of personaFindings.securityNotes) {
|
|
332
|
+
findings.push({
|
|
333
|
+
tool: profile.name,
|
|
334
|
+
category: 'security',
|
|
335
|
+
severity: classifySeverity(note),
|
|
336
|
+
description: note,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
// Add limitation findings
|
|
340
|
+
for (const limitation of personaFindings.limitations) {
|
|
341
|
+
findings.push({
|
|
342
|
+
tool: profile.name,
|
|
343
|
+
category: 'reliability',
|
|
344
|
+
severity: 'low',
|
|
345
|
+
description: limitation,
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
// Add behavioral findings
|
|
349
|
+
for (const note of personaFindings.behavioralNotes.slice(0, 3)) {
|
|
350
|
+
findings.push({
|
|
351
|
+
tool: profile.name,
|
|
352
|
+
category: 'behavior',
|
|
353
|
+
severity: 'info',
|
|
354
|
+
description: note,
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return findings;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Classify severity based on note content.
|
|
362
|
+
*/
|
|
363
|
+
function classifySeverity(note) {
|
|
364
|
+
const lowerNote = note.toLowerCase();
|
|
365
|
+
if (lowerNote.includes('critical') ||
|
|
366
|
+
lowerNote.includes('severe') ||
|
|
367
|
+
lowerNote.includes('injection') ||
|
|
368
|
+
lowerNote.includes('rce') ||
|
|
369
|
+
lowerNote.includes('remote code')) {
|
|
370
|
+
return 'critical';
|
|
371
|
+
}
|
|
372
|
+
if (lowerNote.includes('high') ||
|
|
373
|
+
lowerNote.includes('dangerous') ||
|
|
374
|
+
lowerNote.includes('exploit') ||
|
|
375
|
+
lowerNote.includes('bypass')) {
|
|
376
|
+
return 'high';
|
|
377
|
+
}
|
|
378
|
+
if (lowerNote.includes('medium') ||
|
|
379
|
+
lowerNote.includes('moderate') ||
|
|
380
|
+
lowerNote.includes('sensitive') ||
|
|
381
|
+
lowerNote.includes('leak')) {
|
|
382
|
+
return 'medium';
|
|
383
|
+
}
|
|
384
|
+
if (lowerNote.includes('low') ||
|
|
385
|
+
lowerNote.includes('minor') ||
|
|
386
|
+
lowerNote.includes('potential')) {
|
|
387
|
+
return 'low';
|
|
388
|
+
}
|
|
389
|
+
return 'info';
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Convert ToolFingerprint to CloudToolProfile.
|
|
393
|
+
*/
|
|
394
|
+
function convertToolFingerprint(tool) {
|
|
395
|
+
return {
|
|
396
|
+
name: tool.name,
|
|
397
|
+
description: tool.description,
|
|
398
|
+
schemaHash: tool.schemaHash,
|
|
399
|
+
assertions: convertAssertions(tool.assertions),
|
|
400
|
+
securityNotes: tool.securityNotes,
|
|
401
|
+
limitations: tool.limitations,
|
|
402
|
+
behavioralNotes: tool.assertions
|
|
403
|
+
.filter((a) => a.aspect === 'response_format' && a.isPositive)
|
|
404
|
+
.map((a) => a.assertion),
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Create a BellwetherBaseline directly from InterviewResult.
|
|
409
|
+
*
|
|
410
|
+
* This is the preferred method when you have fresh interview results.
|
|
411
|
+
*/
|
|
412
|
+
export function createCloudBaseline(result, serverCommand) {
|
|
413
|
+
// Derive mode from result metadata
|
|
414
|
+
const mode = deriveCloudMode(result.metadata.model);
|
|
415
|
+
// Build metadata
|
|
416
|
+
const metadata = {
|
|
417
|
+
mode,
|
|
418
|
+
generatedAt: new Date().toISOString(),
|
|
419
|
+
cliVersion: VERSION,
|
|
420
|
+
serverCommand,
|
|
421
|
+
serverName: result.discovery.serverInfo.name,
|
|
422
|
+
durationMs: result.metadata.durationMs,
|
|
423
|
+
personas: result.metadata.personas?.map((p) => p.id) ?? ['technical_writer'],
|
|
424
|
+
model: result.metadata.model ?? 'unknown',
|
|
425
|
+
};
|
|
426
|
+
// Build server fingerprint
|
|
427
|
+
const server = {
|
|
428
|
+
name: result.discovery.serverInfo.name,
|
|
429
|
+
version: result.discovery.serverInfo.version,
|
|
430
|
+
protocolVersion: result.discovery.protocolVersion,
|
|
431
|
+
capabilities: buildCapabilityList(result.discovery),
|
|
432
|
+
};
|
|
433
|
+
// Build response fingerprint map from tool profiles
|
|
434
|
+
const fingerprintMap = new Map();
|
|
435
|
+
for (const profile of result.toolProfiles) {
|
|
436
|
+
const responseData = profile.interactions.map(i => ({
|
|
437
|
+
response: i.response,
|
|
438
|
+
error: i.error,
|
|
439
|
+
}));
|
|
440
|
+
fingerprintMap.set(profile.name, analyzeResponses(responseData));
|
|
441
|
+
}
|
|
442
|
+
// Build capabilities (including response fingerprinting)
|
|
443
|
+
const tools = result.discovery.tools.map((tool) => {
|
|
444
|
+
const analysis = fingerprintMap.get(tool.name);
|
|
445
|
+
return {
|
|
446
|
+
name: tool.name,
|
|
447
|
+
description: tool.description ?? '',
|
|
448
|
+
inputSchema: tool.inputSchema ?? {},
|
|
449
|
+
schemaHash: hashString(JSON.stringify(tool.inputSchema ?? {})),
|
|
450
|
+
// Response fingerprinting (check mode enhancement)
|
|
451
|
+
responseFingerprint: analysis?.fingerprint,
|
|
452
|
+
inferredOutputSchema: analysis?.inferredSchema,
|
|
453
|
+
errorPatterns: analysis?.errorPatterns.length ? analysis.errorPatterns : undefined,
|
|
454
|
+
};
|
|
455
|
+
});
|
|
456
|
+
const prompts = result.discovery.prompts.length > 0
|
|
457
|
+
? result.discovery.prompts.map((p) => ({
|
|
458
|
+
name: p.name,
|
|
459
|
+
description: p.description,
|
|
460
|
+
arguments: p.arguments?.map((a) => ({
|
|
461
|
+
name: a.name,
|
|
462
|
+
description: a.description,
|
|
463
|
+
required: a.required,
|
|
464
|
+
})),
|
|
465
|
+
}))
|
|
466
|
+
: undefined;
|
|
467
|
+
// Build interviews
|
|
468
|
+
const interviews = buildInterviews(result);
|
|
469
|
+
// Build tool profiles (with converted assertions)
|
|
470
|
+
const toolProfiles = result.toolProfiles.map((profile) => ({
|
|
471
|
+
name: profile.name,
|
|
472
|
+
description: profile.description,
|
|
473
|
+
schemaHash: hashString(JSON.stringify(result.discovery.tools.find((t) => t.name === profile.name)?.inputSchema ?? {})),
|
|
474
|
+
assertions: convertAssertions(extractToolAssertions(profile)),
|
|
475
|
+
securityNotes: profile.securityNotes,
|
|
476
|
+
limitations: profile.limitations,
|
|
477
|
+
behavioralNotes: profile.behavioralNotes,
|
|
478
|
+
}));
|
|
479
|
+
// Build workflows
|
|
480
|
+
const workflows = result.workflowResults?.map((wr) => ({
|
|
481
|
+
id: wr.workflow.id,
|
|
482
|
+
name: wr.workflow.name,
|
|
483
|
+
toolSequence: wr.workflow.steps.map((s) => s.tool),
|
|
484
|
+
succeeded: wr.success,
|
|
485
|
+
summary: wr.summary,
|
|
486
|
+
}));
|
|
487
|
+
// Build assertions (convert to cloud format)
|
|
488
|
+
const assertions = convertAssertions(extractAllAssertions(result));
|
|
489
|
+
// Build content hash
|
|
490
|
+
const contentForHash = JSON.stringify({
|
|
491
|
+
metadata,
|
|
492
|
+
server,
|
|
493
|
+
capabilities: { tools, prompts },
|
|
494
|
+
interviews,
|
|
495
|
+
toolProfiles,
|
|
496
|
+
workflows,
|
|
497
|
+
assertions,
|
|
498
|
+
summary: result.summary,
|
|
499
|
+
});
|
|
500
|
+
const hash = hashString(contentForHash);
|
|
501
|
+
return {
|
|
502
|
+
version: getBaselineVersion(),
|
|
503
|
+
metadata,
|
|
504
|
+
server,
|
|
505
|
+
capabilities: { tools, prompts },
|
|
506
|
+
interviews,
|
|
507
|
+
toolProfiles,
|
|
508
|
+
workflows,
|
|
509
|
+
assertions,
|
|
510
|
+
summary: result.summary,
|
|
511
|
+
hash,
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Build capability list from discovery.
|
|
516
|
+
*/
|
|
517
|
+
function buildCapabilityList(discovery) {
|
|
518
|
+
const capabilities = [];
|
|
519
|
+
if (discovery.capabilities.tools)
|
|
520
|
+
capabilities.push('tools');
|
|
521
|
+
if (discovery.capabilities.prompts)
|
|
522
|
+
capabilities.push('prompts');
|
|
523
|
+
if (discovery.capabilities.resources)
|
|
524
|
+
capabilities.push('resources');
|
|
525
|
+
if (discovery.capabilities.logging)
|
|
526
|
+
capabilities.push('logging');
|
|
527
|
+
return capabilities;
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* Extract behavioral assertions from a tool profile.
|
|
531
|
+
*/
|
|
532
|
+
function extractToolAssertions(profile) {
|
|
533
|
+
const assertions = [];
|
|
534
|
+
// Behavioral notes as positive assertions
|
|
535
|
+
for (const note of profile.behavioralNotes) {
|
|
536
|
+
assertions.push({
|
|
537
|
+
tool: profile.name,
|
|
538
|
+
aspect: 'response_format',
|
|
539
|
+
assertion: note,
|
|
540
|
+
isPositive: true,
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
// Limitations as negative assertions
|
|
544
|
+
for (const limitation of profile.limitations) {
|
|
545
|
+
assertions.push({
|
|
546
|
+
tool: profile.name,
|
|
547
|
+
aspect: 'error_handling',
|
|
548
|
+
assertion: limitation,
|
|
549
|
+
isPositive: false,
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
// Security notes as security assertions
|
|
553
|
+
for (const secNote of profile.securityNotes) {
|
|
554
|
+
assertions.push({
|
|
555
|
+
tool: profile.name,
|
|
556
|
+
aspect: 'security',
|
|
557
|
+
assertion: secNote,
|
|
558
|
+
isPositive: !secNote.toLowerCase().includes('risk') &&
|
|
559
|
+
!secNote.toLowerCase().includes('vulnerab') &&
|
|
560
|
+
!secNote.toLowerCase().includes('dangerous'),
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
return assertions;
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Extract all assertions from interview result.
|
|
567
|
+
*/
|
|
568
|
+
function extractAllAssertions(result) {
|
|
569
|
+
const assertions = [];
|
|
570
|
+
// Extract from each tool
|
|
571
|
+
for (const profile of result.toolProfiles) {
|
|
572
|
+
assertions.push(...extractToolAssertions(profile));
|
|
573
|
+
}
|
|
574
|
+
// Add overall limitations as server assertions
|
|
575
|
+
for (const limitation of result.limitations) {
|
|
576
|
+
assertions.push({
|
|
577
|
+
tool: 'server',
|
|
578
|
+
aspect: 'error_handling',
|
|
579
|
+
assertion: limitation,
|
|
580
|
+
isPositive: false,
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
return assertions;
|
|
584
|
+
}
|
|
585
|
+
//# sourceMappingURL=converter.js.map
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-Tool Dependency Analyzer.
|
|
3
|
+
*
|
|
4
|
+
* Analyzes tool descriptions and schemas to identify dependencies
|
|
5
|
+
* between tools, enabling better testing strategies and documentation.
|
|
6
|
+
*
|
|
7
|
+
* Detection strategies:
|
|
8
|
+
* 1. Description analysis - mentions of other tool names
|
|
9
|
+
* 2. Parameter name matching - params that match output field names
|
|
10
|
+
* 3. Resource reference patterns - common ID/token patterns
|
|
11
|
+
* 4. Workflow step order - sequence implied by tool naming
|
|
12
|
+
*/
|
|
13
|
+
import type { MCPTool } from '../transport/types.js';
|
|
14
|
+
/**
|
|
15
|
+
* A dependency edge between two tools.
|
|
16
|
+
*/
|
|
17
|
+
export interface DependencyEdge {
|
|
18
|
+
/** Source tool that provides data */
|
|
19
|
+
from: string;
|
|
20
|
+
/** Target tool that consumes data */
|
|
21
|
+
to: string;
|
|
22
|
+
/** Type of dependency relationship */
|
|
23
|
+
type: DependencyType;
|
|
24
|
+
/** Confidence level of this dependency detection (0-1) */
|
|
25
|
+
confidence: number;
|
|
26
|
+
/** Description of the relationship */
|
|
27
|
+
description: string;
|
|
28
|
+
/** Which field/parameter creates the dependency */
|
|
29
|
+
field?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Types of dependencies between tools.
|
|
33
|
+
*/
|
|
34
|
+
export type DependencyType = 'mention' | 'output_input' | 'resource_ref' | 'sequence' | 'shared_resource';
|
|
35
|
+
/**
|
|
36
|
+
* Full dependency graph for a set of tools.
|
|
37
|
+
*/
|
|
38
|
+
export interface DependencyGraph {
|
|
39
|
+
/** All dependency edges */
|
|
40
|
+
edges: DependencyEdge[];
|
|
41
|
+
/** Tools grouped by layer (no dependencies -> most dependencies) */
|
|
42
|
+
layers: string[][];
|
|
43
|
+
/** Tools with no dependencies (entry points) */
|
|
44
|
+
entryPoints: string[];
|
|
45
|
+
/** Tools with no dependents (terminal operations) */
|
|
46
|
+
terminalPoints: string[];
|
|
47
|
+
/** Detected cycles (if any) */
|
|
48
|
+
cycles: string[][];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Statistics about the dependency graph.
|
|
52
|
+
*/
|
|
53
|
+
export interface DependencyStats {
|
|
54
|
+
/** Total number of edges */
|
|
55
|
+
totalEdges: number;
|
|
56
|
+
/** Edges by type */
|
|
57
|
+
byType: Record<DependencyType, number>;
|
|
58
|
+
/** Average dependencies per tool */
|
|
59
|
+
avgDependencies: number;
|
|
60
|
+
/** Maximum dependency chain length */
|
|
61
|
+
maxChainLength: number;
|
|
62
|
+
/** Tools with most dependencies */
|
|
63
|
+
mostDependent: Array<{
|
|
64
|
+
tool: string;
|
|
65
|
+
count: number;
|
|
66
|
+
}>;
|
|
67
|
+
/** Tools most depended upon */
|
|
68
|
+
mostDependedUpon: Array<{
|
|
69
|
+
tool: string;
|
|
70
|
+
count: number;
|
|
71
|
+
}>;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Analyze dependencies between tools.
|
|
75
|
+
*/
|
|
76
|
+
export declare function analyzeDependencies(tools: MCPTool[]): DependencyGraph;
|
|
77
|
+
/**
|
|
78
|
+
* Calculate statistics about the dependency graph.
|
|
79
|
+
*/
|
|
80
|
+
export declare function calculateDependencyStats(graph: DependencyGraph): DependencyStats;
|
|
81
|
+
/**
|
|
82
|
+
* Generate a Mermaid diagram for the dependency graph.
|
|
83
|
+
*/
|
|
84
|
+
export declare function generateDependencyMermaid(graph: DependencyGraph): string;
|
|
85
|
+
/**
|
|
86
|
+
* Generate markdown documentation for dependencies.
|
|
87
|
+
*/
|
|
88
|
+
export declare function generateDependencyMarkdown(graph: DependencyGraph, stats: DependencyStats): string;
|
|
89
|
+
//# sourceMappingURL=dependency-analyzer.d.ts.map
|