@documentation-robotics/cli 0.1.13 → 0.3.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/README.md +74 -2
- package/dist/analysis/relationship-classifier.js +2 -9
- package/dist/analysis/relationship-classifier.js.map +2 -2
- package/dist/analyzers/call-graph-utils.js +2 -2
- package/dist/analyzers/call-graph-utils.js.map +2 -2
- package/dist/analyzers/cards/build.js +171 -0
- package/dist/analyzers/cards/build.js.map +7 -0
- package/dist/analyzers/cards/classify.js +42 -0
- package/dist/analyzers/cards/classify.js.map +7 -0
- package/dist/analyzers/cards/edge-index.js +44 -0
- package/dist/analyzers/cards/edge-index.js.map +7 -0
- package/dist/analyzers/cards/facts.js +46 -0
- package/dist/analyzers/cards/facts.js.map +7 -0
- package/dist/analyzers/cards/graph.js +42 -0
- package/dist/analyzers/cards/graph.js.map +7 -0
- package/dist/analyzers/cards/index.js +8 -0
- package/dist/analyzers/cards/index.js.map +7 -0
- package/dist/analyzers/cards/tier0.js +18 -0
- package/dist/analyzers/cards/tier0.js.map +7 -0
- package/dist/analyzers/cards/types.js +1 -0
- package/dist/analyzers/cards/types.js.map +7 -0
- package/dist/analyzers/cbm-analyzer.js +195 -171
- package/dist/analyzers/cbm-analyzer.js.map +2 -2
- package/dist/analyzers/cbm-responses.js +336 -0
- package/dist/analyzers/cbm-responses.js.map +7 -0
- package/dist/analyzers/edge-relationships.js +45 -0
- package/dist/analyzers/edge-relationships.js.map +7 -0
- package/dist/analyzers/mapping-loader.js +9 -0
- package/dist/analyzers/mapping-loader.js.map +2 -2
- package/dist/analyzers/tier0-rules.js +153 -0
- package/dist/analyzers/tier0-rules.js.map +7 -0
- package/dist/analyzers/types.js.map +1 -1
- package/dist/analyzers/verify-engine.js +22 -19
- package/dist/analyzers/verify-engine.js.map +2 -2
- package/dist/audit/relationships/ai/prompts.js +10 -10
- package/dist/audit/relationships/ai/prompts.js.map +2 -2
- package/dist/audit/relationships/analysis/layer-templates.js +52 -52
- package/dist/audit/relationships/analysis/layer-templates.js.map +1 -1
- package/dist/cli.js +112 -28
- package/dist/cli.js.map +3 -3
- package/dist/coding-agents/agents/claude-code.js +3 -1
- package/dist/coding-agents/agents/claude-code.js.map +2 -2
- package/dist/coding-agents/claude-code-client.js +2 -1
- package/dist/coding-agents/claude-code-client.js.map +2 -2
- package/dist/coding-agents/copilot-client.js +17 -12
- package/dist/coding-agents/copilot-client.js.map +2 -2
- package/dist/coding-agents/default-permissions.js +152 -0
- package/dist/coding-agents/default-permissions.js.map +7 -0
- package/dist/coding-agents/drbot-mcp.js +167 -0
- package/dist/coding-agents/drbot-mcp.js.map +7 -0
- package/dist/commands/add.js +12 -7
- package/dist/commands/add.js.map +2 -2
- package/dist/commands/analyzer.js +134 -23
- package/dist/commands/analyzer.js.map +2 -2
- package/dist/commands/audit.js +6 -6
- package/dist/commands/audit.js.map +2 -2
- package/dist/commands/changeset-verify.js +55 -0
- package/dist/commands/changeset-verify.js.map +7 -0
- package/dist/commands/changeset.js +261 -147
- package/dist/commands/changeset.js.map +2 -2
- package/dist/commands/delete.js +52 -19
- package/dist/commands/delete.js.map +3 -3
- package/dist/commands/element.js +3 -2
- package/dist/commands/element.js.map +2 -2
- package/dist/commands/farm.js +773 -0
- package/dist/commands/farm.js.map +7 -0
- package/dist/commands/init.js +11 -1
- package/dist/commands/init.js.map +2 -2
- package/dist/commands/mcp.js +122 -0
- package/dist/commands/mcp.js.map +7 -0
- package/dist/commands/relationship.js +251 -47
- package/dist/commands/relationship.js.map +2 -2
- package/dist/commands/reports.js +1 -1
- package/dist/commands/reports.js.map +2 -2
- package/dist/commands/update.js +56 -24
- package/dist/commands/update.js.map +2 -2
- package/dist/commands/upgrade.js +99 -11
- package/dist/commands/upgrade.js.map +3 -3
- package/dist/commands/validate.js +41 -3
- package/dist/commands/validate.js.map +2 -2
- package/dist/commands/version.js +2 -2
- package/dist/commands/version.js.map +2 -2
- package/dist/commands/visualize.js +4 -3
- package/dist/commands/visualize.js.map +2 -2
- package/dist/config.js +83 -0
- package/dist/config.js.map +7 -0
- package/dist/core/annotation-store.js +138 -0
- package/dist/core/annotation-store.js.map +7 -0
- package/dist/core/catalog-migration.js +33 -0
- package/dist/core/catalog-migration.js.map +7 -0
- package/dist/core/changeset-analysis.js +421 -0
- package/dist/core/changeset-analysis.js.map +7 -0
- package/dist/core/changeset-base-index.js +153 -0
- package/dist/core/changeset-base-index.js.map +7 -0
- package/dist/core/changeset-brief-delta.js +102 -0
- package/dist/core/changeset-brief-delta.js.map +7 -0
- package/dist/core/changeset-graph.js +281 -0
- package/dist/core/changeset-graph.js.map +7 -0
- package/dist/core/changeset-only-guard.js +32 -0
- package/dist/core/changeset-only-guard.js.map +7 -0
- package/dist/core/changeset-summary.js +68 -0
- package/dist/core/changeset-summary.js.map +7 -0
- package/dist/core/changeset-validator.js +66 -20
- package/dist/core/changeset-validator.js.map +2 -2
- package/dist/core/changeset-verify.js +518 -0
- package/dist/core/changeset-verify.js.map +7 -0
- package/dist/core/changeset.js +56 -9
- package/dist/core/changeset.js.map +2 -2
- package/dist/core/element-type-migration.js +145 -0
- package/dist/core/element-type-migration.js.map +7 -0
- package/dist/core/farm-manifest.js +140 -0
- package/dist/core/farm-manifest.js.map +7 -0
- package/dist/core/farm-sync-engine.js +346 -0
- package/dist/core/farm-sync-engine.js.map +7 -0
- package/dist/core/farm-sync-state.js +167 -0
- package/dist/core/farm-sync-state.js.map +7 -0
- package/dist/core/manifest.js +6 -3
- package/dist/core/manifest.js.map +2 -2
- package/dist/core/migration-registry.js +84 -1
- package/dist/core/migration-registry.js.map +2 -2
- package/dist/core/model-upgrade.js +102 -0
- package/dist/core/model-upgrade.js.map +7 -0
- package/dist/core/model.js +257 -44
- package/dist/core/model.js.map +3 -3
- package/dist/core/mutation-handler.js +71 -6
- package/dist/core/mutation-handler.js.map +2 -2
- package/dist/core/relationship-migration-table.js +6639 -0
- package/dist/core/relationship-migration-table.js.map +7 -0
- package/dist/core/relationship-migration.js +272 -0
- package/dist/core/relationship-migration.js.map +7 -0
- package/dist/core/relationship-prune.js +49 -0
- package/dist/core/relationship-prune.js.map +7 -0
- package/dist/core/relationship-staging.js +68 -0
- package/dist/core/relationship-staging.js.map +7 -0
- package/dist/core/relationships.js +26 -4
- package/dist/core/relationships.js.map +2 -2
- package/dist/core/report-data-model.js +7 -13
- package/dist/core/report-data-model.js.map +2 -2
- package/dist/core/staged-changeset-storage.js +64 -17
- package/dist/core/staged-changeset-storage.js.map +2 -2
- package/dist/core/staged-source-reference.js +28 -0
- package/dist/core/staged-source-reference.js.map +7 -0
- package/dist/core/staging-area.js +83 -18
- package/dist/core/staging-area.js.map +2 -2
- package/dist/core/virtual-projection.js +14 -5
- package/dist/core/virtual-projection.js.map +2 -2
- package/dist/export/archimate-exporter.js +1 -0
- package/dist/export/archimate-exporter.js.map +2 -2
- package/dist/generated/compiled-validators.js +2 -2
- package/dist/generated/compiled-validators.js.map +2 -2
- package/dist/generated/layer-registry.js +16 -16
- package/dist/generated/layer-registry.js.map +2 -2
- package/dist/generated/node-types.js +186 -168
- package/dist/generated/node-types.js.map +2 -2
- package/dist/generated/relationship-index.js +2209 -7727
- package/dist/generated/relationship-index.js.map +2 -2
- package/dist/integrations/claude_code/agents/dr-architect.md +16 -3
- package/dist/integrations/claude_code/agents/dr-extractor.md +1 -1
- package/dist/integrations/claude_code/commands/dr-analyzer.md +565 -0
- package/dist/integrations/claude_code/commands/dr-map.md +13 -0
- package/dist/integrations/claude_code/commands/dr-plan.md +40 -0
- package/dist/integrations/claude_code/commands/dr-relate.md +106 -96
- package/dist/integrations/claude_code/commands/dr-verify.md +45 -2
- package/dist/integrations/claude_code/docs/END_TO_END_WALKTHROUGH.md +14 -0
- package/dist/integrations/claude_code/docs/MCP_SERVER.md +79 -0
- package/dist/integrations/claude_code/docs/QUICK_START.md +37 -8
- package/dist/integrations/claude_code/docs/README.md +52 -1
- package/dist/integrations/claude_code/skills/dr_01_motivation_layer/SKILL.md +93 -72
- package/dist/integrations/claude_code/skills/dr_02_business_layer/SKILL.md +163 -126
- package/dist/integrations/claude_code/skills/dr_03_product_layer/SKILL.md +161 -126
- package/dist/integrations/claude_code/skills/dr_04_security_layer/SKILL.md +153 -133
- package/dist/integrations/claude_code/skills/dr_05_application_layer/SKILL.md +129 -100
- package/dist/integrations/claude_code/skills/dr_06_technology_layer/SKILL.md +111 -94
- package/dist/integrations/claude_code/skills/dr_07_api_layer/SKILL.md +143 -157
- package/dist/integrations/claude_code/skills/dr_08_data_model_layer/SKILL.md +117 -33
- package/dist/integrations/claude_code/skills/dr_09_dataset_layer/SKILL.md +74 -25
- package/dist/integrations/claude_code/skills/dr_10_ux_layer/SKILL.md +88 -12
- package/dist/integrations/claude_code/skills/dr_11_navigation_layer/SKILL.md +83 -24
- package/dist/integrations/claude_code/skills/dr_12_apm_layer/SKILL.md +57 -12
- package/dist/integrations/claude_code/skills/dr_13_testing_layer/SKILL.md +92 -15
- package/dist/integrations/claude_code/skills/dr_change_planning/SKILL.md +119 -0
- package/dist/integrations/claude_code/skills/dr_changeset_reviewer/SKILL.md +3 -0
- package/dist/integrations/claude_code/skills/dr_engineering_guide/SKILL.md +1 -1
- package/dist/integrations/github_copilot/agents/dr-architect.md +1 -1
- package/dist/integrations/github_copilot/skills/dr_01_motivation_layer/SKILL.md +182 -102
- package/dist/integrations/github_copilot/skills/dr_02_business_layer/SKILL.md +266 -148
- package/dist/integrations/github_copilot/skills/dr_03_product_layer/SKILL.md +547 -86
- package/dist/integrations/github_copilot/skills/dr_04_security_layer/SKILL.md +164 -169
- package/dist/integrations/github_copilot/skills/dr_05_application_layer/SKILL.md +420 -150
- package/dist/integrations/github_copilot/skills/dr_06_technology_layer/SKILL.md +331 -138
- package/dist/integrations/github_copilot/skills/dr_07_api_layer/SKILL.md +265 -201
- package/dist/integrations/github_copilot/skills/dr_08_data_model_layer/SKILL.md +181 -58
- package/dist/integrations/github_copilot/skills/dr_09_dataset_layer/SKILL.md +209 -57
- package/dist/integrations/github_copilot/skills/dr_10_ux_layer/SKILL.md +277 -112
- package/dist/integrations/github_copilot/skills/dr_11_navigation_layer/SKILL.md +219 -70
- package/dist/integrations/github_copilot/skills/dr_12_apm_layer/SKILL.md +189 -105
- package/dist/integrations/github_copilot/skills/dr_13_testing_layer/SKILL.md +222 -102
- package/dist/integrations/github_copilot/skills/dr_change_planning/SKILL.md +119 -0
- package/dist/integrations/github_copilot/skills/dr_changeset_reviewer/SKILL.md +3 -0
- package/dist/integrations/hash-utils.js.map +2 -2
- package/dist/mcp/api-key-manager.js +111 -0
- package/dist/mcp/api-key-manager.js.map +7 -0
- package/dist/mcp/changeset-only.js +34 -0
- package/dist/mcp/changeset-only.js.map +7 -0
- package/dist/mcp/http-transport.js +176 -0
- package/dist/mcp/http-transport.js.map +7 -0
- package/dist/mcp/resource-registry.js +97 -0
- package/dist/mcp/resource-registry.js.map +7 -0
- package/dist/mcp/tool-registry.js +60 -0
- package/dist/mcp/tool-registry.js.map +7 -0
- package/dist/mcp/tools/annotation-create.js +39 -0
- package/dist/mcp/tools/annotation-create.js.map +7 -0
- package/dist/mcp/tools/annotation-delete.js +29 -0
- package/dist/mcp/tools/annotation-delete.js.map +7 -0
- package/dist/mcp/tools/annotation-get.js +29 -0
- package/dist/mcp/tools/annotation-get.js.map +7 -0
- package/dist/mcp/tools/annotation-list.js +24 -0
- package/dist/mcp/tools/annotation-list.js.map +7 -0
- package/dist/mcp/tools/annotation-reply.js +34 -0
- package/dist/mcp/tools/annotation-reply.js.map +7 -0
- package/dist/mcp/tools/annotation-shared.js +10 -0
- package/dist/mcp/tools/annotation-shared.js.map +7 -0
- package/dist/mcp/tools/annotation-update.js +39 -0
- package/dist/mcp/tools/annotation-update.js.map +7 -0
- package/dist/mcp/tools/changeset-analysis-tools.js +78 -0
- package/dist/mcp/tools/changeset-analysis-tools.js.map +7 -0
- package/dist/mcp/tools/changeset-editing.js +184 -0
- package/dist/mcp/tools/changeset-editing.js.map +7 -0
- package/dist/mcp/tools/changeset-lifecycle.js +83 -0
- package/dist/mcp/tools/changeset-lifecycle.js.map +7 -0
- package/dist/mcp/tools/changeset-list.js +33 -0
- package/dist/mcp/tools/changeset-list.js.map +7 -0
- package/dist/mcp/tools/changeset-shared.js +31 -0
- package/dist/mcp/tools/changeset-shared.js.map +7 -0
- package/dist/mcp/tools/changeset-show.js +55 -0
- package/dist/mcp/tools/changeset-show.js.map +7 -0
- package/dist/mcp/tools/changeset-verify.js +43 -0
- package/dist/mcp/tools/changeset-verify.js.map +7 -0
- package/dist/mcp/tools/chat-launch.js +50 -0
- package/dist/mcp/tools/chat-launch.js.map +7 -0
- package/dist/mcp/tools/chat-status.js +26 -0
- package/dist/mcp/tools/chat-status.js.map +7 -0
- package/dist/mcp/tools/index.js +65 -0
- package/dist/mcp/tools/index.js.map +7 -0
- package/dist/mcp/tools/model-add.js +107 -0
- package/dist/mcp/tools/model-add.js.map +7 -0
- package/dist/mcp/tools/model-delete.js +99 -0
- package/dist/mcp/tools/model-delete.js.map +7 -0
- package/dist/mcp/tools/model-export.js +72 -0
- package/dist/mcp/tools/model-export.js.map +7 -0
- package/dist/mcp/tools/model-info.js +51 -0
- package/dist/mcp/tools/model-info.js.map +7 -0
- package/dist/mcp/tools/model-list.js +53 -0
- package/dist/mcp/tools/model-list.js.map +7 -0
- package/dist/mcp/tools/model-reload.js +34 -0
- package/dist/mcp/tools/model-reload.js.map +7 -0
- package/dist/mcp/tools/model-search.js +102 -0
- package/dist/mcp/tools/model-search.js.map +7 -0
- package/dist/mcp/tools/model-show.js +68 -0
- package/dist/mcp/tools/model-show.js.map +7 -0
- package/dist/mcp/tools/model-stats.js +22 -0
- package/dist/mcp/tools/model-stats.js.map +7 -0
- package/dist/mcp/tools/model-trace.js +118 -0
- package/dist/mcp/tools/model-trace.js.map +7 -0
- package/dist/mcp/tools/model-update.js +121 -0
- package/dist/mcp/tools/model-update.js.map +7 -0
- package/dist/mcp/tools/model-validate.js +78 -0
- package/dist/mcp/tools/model-validate.js.map +7 -0
- package/dist/mcp/tools/relationship-tools.js +98 -0
- package/dist/mcp/tools/relationship-tools.js.map +7 -0
- package/dist/mcp/tools/shared.js +126 -0
- package/dist/mcp/tools/shared.js.map +7 -0
- package/dist/mcp/tools/spec-type.js +90 -0
- package/dist/mcp/tools/spec-type.js.map +7 -0
- package/dist/reports/model-layer-report-generator.js +5 -3
- package/dist/reports/model-layer-report-generator.js.map +2 -2
- package/dist/reports/model-readme-generator.js +116 -0
- package/dist/reports/model-readme-generator.js.map +7 -0
- package/dist/reports/model-report-data.js +37 -1
- package/dist/reports/model-report-data.js.map +2 -2
- package/dist/reports/model-report-orchestrator.js +29 -6
- package/dist/reports/model-report-orchestrator.js.map +2 -2
- package/dist/reports/model-report-utils.js +9 -0
- package/dist/reports/model-report-utils.js.map +7 -0
- package/dist/schemas/bundled/analyzers/cbm.json +1186 -68
- package/dist/schemas/bundled/analyzers/manifest.json +2 -2
- package/dist/schemas/bundled/api.json +1029 -1658
- package/dist/schemas/bundled/apm.json +499 -734
- package/dist/schemas/bundled/application.json +745 -370
- package/dist/schemas/bundled/base.json +3 -220
- package/dist/schemas/bundled/business.json +452 -366
- package/dist/schemas/bundled/data-model.json +403 -383
- package/dist/schemas/bundled/data-store.json +334 -558
- package/dist/schemas/bundled/manifest.json +18 -18
- package/dist/schemas/bundled/motivation.json +349 -368
- package/dist/schemas/bundled/navigation.json +415 -731
- package/dist/schemas/bundled/product.json +325 -159
- package/dist/schemas/bundled/security.json +864 -1232
- package/dist/schemas/bundled/technology.json +574 -703
- package/dist/schemas/bundled/testing.json +718 -1643
- package/dist/schemas/bundled/ux.json +739 -1352
- package/dist/server/schemas.js +8 -0
- package/dist/server/schemas.js.map +2 -2
- package/dist/server/server.js +234 -31
- package/dist/server/server.js.map +2 -2
- package/dist/server-entry.js +2 -1
- package/dist/server-entry.js.map +2 -2
- package/dist/telemetry/config.js +2 -40
- package/dist/telemetry/config.js.map +2 -2
- package/dist/telemetry/index.js +1 -1
- package/dist/types/index.js.map +2 -2
- package/dist/utils/ansi-suppressor.js +23 -0
- package/dist/utils/ansi-suppressor.js.map +7 -0
- package/dist/utils/attribute-patch.js +41 -0
- package/dist/utils/attribute-patch.js.map +7 -0
- package/dist/utils/color-utils.js +34 -0
- package/dist/utils/color-utils.js.map +7 -0
- package/dist/utils/element-reference-shape.js +15 -1
- package/dist/utils/element-reference-shape.js.map +3 -3
- package/dist/utils/error-hints.js +29 -0
- package/dist/utils/error-hints.js.map +7 -0
- package/dist/utils/errors.js +75 -10
- package/dist/utils/errors.js.map +2 -2
- package/dist/utils/globals.js +17 -1
- package/dist/utils/globals.js.map +2 -2
- package/dist/utils/project-paths.js +50 -3
- package/dist/utils/project-paths.js.map +2 -2
- package/dist/utils/reference-path-parser.js +49 -0
- package/dist/utils/reference-path-parser.js.map +7 -0
- package/dist/utils/source-reference.js +17 -10
- package/dist/utils/source-reference.js.map +2 -2
- package/dist/utils/spec-version.js +10 -2
- package/dist/utils/spec-version.js.map +2 -2
- package/dist/validators/composed-reference-validator.js +240 -0
- package/dist/validators/composed-reference-validator.js.map +7 -0
- package/dist/validators/reference-validator.js +57 -13
- package/dist/validators/reference-validator.js.map +3 -3
- package/dist/validators/relationship-schema-validator.js +33 -5
- package/dist/validators/relationship-schema-validator.js.map +3 -3
- package/dist/validators/schema-validator.js +27 -9
- package/dist/validators/schema-validator.js.map +2 -2
- package/dist/validators/types.js.map +1 -1
- package/dist/viewer/README.md +6 -6
- package/dist/viewer/assets/main-CxzcuU_o.js +84 -0
- package/dist/viewer/assets/main-j-7ULYpm.css +1 -0
- package/dist/viewer/index.html +2 -2
- package/dist/viewer/manifest.json +10 -10
- package/dist/viewer/version.json +1 -1
- package/package.json +7 -3
- package/dist/viewer/assets/main-B7AOQXXX.js +0 -81
- package/dist/viewer/assets/main-vdrFrG7q.css +0 -1
|
@@ -11,6 +11,11 @@ import { VerifyEngine } from "./verify-engine.js";
|
|
|
11
11
|
import { clampDepth, shapeCallGraphNode, determineEdgeType } from "./call-graph-utils.js";
|
|
12
12
|
import { evaluateHeuristic, capConfidence, matchPattern, getKnownHeuristicNames } from "./heuristic-utils.js";
|
|
13
13
|
import { toKebabCase } from "../utils/id-generator.js";
|
|
14
|
+
import { CbmTools, CbmToolError, ROUTE_HANDLERS_QUERY, attachRouteHandlers, nodeColumns, nodesFromQuery, relativeToRoot, routeHandlersFromQuery } from "./cbm-responses.js";
|
|
15
|
+
import { cbmCardGraph } from "./cards/graph.js";
|
|
16
|
+
import { classifyTier0, defaultLabels } from "./cards/classify.js";
|
|
17
|
+
import { CARD_FIELDS } from "./cards/build.js";
|
|
18
|
+
import { tier0RulesFrom } from "./tier0-rules.js";
|
|
14
19
|
const SOURCE_CODE_EXT_RE = /\.(ts|tsx|js|jsx|mjs|cjs|vue|svelte|py|go|rb|java|rs|php|cs|cpp|c|h|kt|swift|sh|bash)$/i;
|
|
15
20
|
function isLikelyHttpRoute(qualifiedName) {
|
|
16
21
|
const httpPath = qualifiedName.replace(/^__route__[A-Z]+__/, "");
|
|
@@ -24,21 +29,17 @@ function inferHttpPathFromFunctionName(name) {
|
|
|
24
29
|
const stripped = name.replace(/^(fetch|get|list|create|add|update|put|delete|remove|patch|merge|load|save|replace|post|submit|send|destroy)/i, ""), segment = toKebabCase(stripped || name);
|
|
25
30
|
return segment ? `/${segment}` : "/";
|
|
26
31
|
}
|
|
32
|
+
const SERVICE_SOURCE_TYPES = /* @__PURE__ */ new Set(["applicationfunction", "applicationcomponent", "applicationservice"]);
|
|
27
33
|
class CbmAnalyzer {
|
|
28
34
|
mapper;
|
|
29
35
|
testCodePatternWarned = !1;
|
|
30
36
|
warnedHeuristics = /* @__PURE__ */ new Set();
|
|
31
37
|
/**
|
|
32
|
-
*
|
|
38
|
+
* Test code detection when the mapping has no test_code_exclusion rule: the same test-file
|
|
39
|
+
* pattern as the mapping's rule and its tier0_test_file rule.
|
|
33
40
|
*/
|
|
34
41
|
static DEFAULT_TEST_PATTERNS = [
|
|
35
|
-
|
|
36
|
-
/\.spec\./,
|
|
37
|
-
/\/tests?\//,
|
|
38
|
-
/\/__tests__\//,
|
|
39
|
-
/\/test-/,
|
|
40
|
-
/\/fixtures?\//,
|
|
41
|
-
/\/__fixtures__\//
|
|
42
|
+
/((^|\/)(tests?|__tests__|__fixtures__|fixtures?)\/|(^|\/)test_[^/]*\.py$|(^|\/)conftest\.py$|_test\.(go|py)$|\.(test|spec)\.[cm]?[jt]sx?$|Tests?\.(java|kt)$)/
|
|
42
43
|
];
|
|
43
44
|
constructor(mapper) {
|
|
44
45
|
this.mapper = mapper;
|
|
@@ -171,10 +172,11 @@ class CbmAnalyzer {
|
|
|
171
172
|
* Checks if the project is indexed and whether the index is fresh relative to git HEAD.
|
|
172
173
|
*
|
|
173
174
|
* @param projectRoot Absolute path to the project root
|
|
175
|
+
* @param options Optional codebase configuration
|
|
174
176
|
* @returns Current status including detection, index state, and freshness
|
|
175
177
|
*/
|
|
176
|
-
async status(projectRoot) {
|
|
177
|
-
const detected = await this.detect(projectRoot), analyzerName = this.mapper.getAnalyzerName(), indexMeta = await readIndexMeta(projectRoot, analyzerName);
|
|
178
|
+
async status(projectRoot, options) {
|
|
179
|
+
const detected = await this.detect(projectRoot), effectiveCodebaseRoot = options?.codebaseRoot ?? projectRoot, analyzerName = this.mapper.getAnalyzerName(), indexMeta = await readIndexMeta(projectRoot, analyzerName);
|
|
178
180
|
if (!(indexMeta !== null))
|
|
179
181
|
return {
|
|
180
182
|
detected,
|
|
@@ -184,7 +186,7 @@ class CbmAnalyzer {
|
|
|
184
186
|
let fresh = !1;
|
|
185
187
|
try {
|
|
186
188
|
const currentHeadResult = spawnSync("git", ["rev-parse", "HEAD"], {
|
|
187
|
-
cwd:
|
|
189
|
+
cwd: effectiveCodebaseRoot,
|
|
188
190
|
stdio: "pipe",
|
|
189
191
|
encoding: "utf-8"
|
|
190
192
|
});
|
|
@@ -192,7 +194,11 @@ class CbmAnalyzer {
|
|
|
192
194
|
fresh = currentHeadResult.stdout.trim() === indexMeta.git_head;
|
|
193
195
|
else {
|
|
194
196
|
const gitError = currentHeadResult.stderr?.trim() || "git returned non-zero status";
|
|
195
|
-
handleWarning("Failed to check git freshness", [
|
|
197
|
+
options?.codebaseRoot ? handleWarning("Failed to check git freshness in codebase root", [
|
|
198
|
+
`Codebase root: ${effectiveCodebaseRoot}`,
|
|
199
|
+
`Git error: ${gitError}`,
|
|
200
|
+
"Index freshness cannot be determined - treating as stale"
|
|
201
|
+
]) : handleWarning("Failed to check git freshness", [
|
|
196
202
|
`Git error: ${gitError}`,
|
|
197
203
|
"Index freshness cannot be determined - treating as stale"
|
|
198
204
|
]), fresh = !1;
|
|
@@ -221,11 +227,11 @@ class CbmAnalyzer {
|
|
|
221
227
|
* Skips indexing if the index is fresh (git HEAD matches) unless --force is set.
|
|
222
228
|
*
|
|
223
229
|
* @param projectRoot Absolute path to the project root
|
|
224
|
-
* @param options Optional configuration
|
|
230
|
+
* @param options Optional configuration including force flag and codebase root
|
|
225
231
|
* @returns Index result with counts and metadata
|
|
226
232
|
*/
|
|
227
233
|
async index(projectRoot, options) {
|
|
228
|
-
const status = await this.status(projectRoot);
|
|
234
|
+
const effectiveCodebaseRoot = options?.codebaseRoot ?? projectRoot, status = await this.status(projectRoot, { codebaseRoot: effectiveCodebaseRoot });
|
|
229
235
|
if (status.indexed && status.fresh && !options?.force) {
|
|
230
236
|
handleWarning("Index is fresh. Use --force to reindex.", [
|
|
231
237
|
`Last indexed: ${status.last_indexed}`
|
|
@@ -252,10 +258,8 @@ class CbmAnalyzer {
|
|
|
252
258
|
name: "dr-cli",
|
|
253
259
|
version
|
|
254
260
|
});
|
|
255
|
-
const
|
|
256
|
-
if (
|
|
257
|
-
throw new CLIError("Invalid response from list_projects", ErrorCategory.SYSTEM, ["Ensure codebase-memory-mcp is properly installed and functional"]);
|
|
258
|
-
if ((Array.isArray(listProjectsResponse.projects) ? listProjectsResponse.projects : []).some((p) => p.root_path === projectRoot) && status.fresh && !options?.force) {
|
|
261
|
+
const tools = new CbmTools(client);
|
|
262
|
+
if ((await tools.listProjects()).some((p) => p.root_path === effectiveCodebaseRoot) && status.fresh && !options?.force) {
|
|
259
263
|
if (handleWarning("Project already indexed in CBM backend with fresh index.", ["Use --force to re-index the project"]), !status.index_meta)
|
|
260
264
|
throw new CLIError("Project exists in CBM backend but local metadata is missing", ErrorCategory.VALIDATION, [
|
|
261
265
|
"Use --force to re-index and regenerate metadata",
|
|
@@ -270,13 +274,14 @@ class CbmAnalyzer {
|
|
|
270
274
|
};
|
|
271
275
|
}
|
|
272
276
|
const headResult = spawnSync("git", ["rev-parse", "HEAD"], {
|
|
273
|
-
cwd:
|
|
277
|
+
cwd: effectiveCodebaseRoot,
|
|
274
278
|
stdio: "pipe",
|
|
275
279
|
encoding: "utf-8"
|
|
276
280
|
});
|
|
277
281
|
if (headResult.status !== 0)
|
|
278
282
|
throw new CLIError("Failed to get git HEAD", ErrorCategory.SYSTEM, [
|
|
279
|
-
"Ensure the
|
|
283
|
+
"Ensure the codebase root is a git repository",
|
|
284
|
+
`Codebase root: ${effectiveCodebaseRoot}`,
|
|
280
285
|
"Verify git is installed and functional",
|
|
281
286
|
`Error: ${headResult.stderr?.trim() || "unknown error"}`
|
|
282
287
|
]);
|
|
@@ -288,12 +293,7 @@ class CbmAnalyzer {
|
|
|
288
293
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
289
294
|
handleWarning("Failed to read active changeset", [`Error: ${errorMsg}`, "Continuing with indexing"]);
|
|
290
295
|
}
|
|
291
|
-
const indexResponse = await
|
|
292
|
-
repo_path: projectRoot
|
|
293
|
-
});
|
|
294
|
-
if (!indexResponse || typeof indexResponse != "object")
|
|
295
|
-
throw new CLIError("Invalid response from index_repository", ErrorCategory.SYSTEM, ["Ensure codebase-memory-mcp is properly installed and functional"]);
|
|
296
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString(), nodeCount = typeof indexResponse.nodes == "number" ? indexResponse.nodes : 0, edgeCount = typeof indexResponse.edges == "number" ? indexResponse.edges : 0;
|
|
296
|
+
const indexResponse = await tools.indexRepository(effectiveCodebaseRoot), timestamp = (/* @__PURE__ */ new Date()).toISOString(), nodeCount = typeof indexResponse.nodes == "number" ? indexResponse.nodes : 0, edgeCount = typeof indexResponse.edges == "number" ? indexResponse.edges : 0;
|
|
297
297
|
typeof indexResponse.nodes != "number" && handleWarning("Invalid node count from index_repository", [
|
|
298
298
|
`Expected number, got ${typeof indexResponse.nodes}: ${String(indexResponse.nodes)}`,
|
|
299
299
|
"Defaulting to 0 - index may be incomplete or corrupted"
|
|
@@ -318,26 +318,25 @@ class CbmAnalyzer {
|
|
|
318
318
|
}
|
|
319
319
|
}
|
|
320
320
|
/**
|
|
321
|
-
*
|
|
321
|
+
* Fetch Route nodes with their HANDLES-edge handlers attached.
|
|
322
322
|
*
|
|
323
|
-
*
|
|
324
|
-
*
|
|
323
|
+
* CBM Route nodes carry only `{ method, source }` and often no file (every fastapi route,
|
|
324
|
+
* for example); the handler function, its symbol, lines and file come from HANDLES edges.
|
|
325
|
+
* If the handler query fails the routes are returned as they are.
|
|
325
326
|
*
|
|
326
327
|
* @private
|
|
327
|
-
* @param response Raw response from search_graph MCP tool
|
|
328
|
-
* @returns Typed nodes array (may be empty if no results found)
|
|
329
|
-
* @throws CLIError if response structure is invalid
|
|
330
328
|
*/
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
329
|
+
async fetchRoutes(tools, projectName, label) {
|
|
330
|
+
const routes = await tools.searchGraph({ label, project: projectName });
|
|
331
|
+
try {
|
|
332
|
+
const handlers = routeHandlersFromQuery(await tools.queryGraph(ROUTE_HANDLERS_QUERY, projectName));
|
|
333
|
+
return attachRouteHandlers(routes, handlers);
|
|
334
|
+
} catch (error) {
|
|
335
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
336
|
+
return handleWarning("Could not read route handlers (HANDLES edges); routes lack handler details", [
|
|
337
|
+
`Error: ${errorMsg}`
|
|
338
|
+
]), routes;
|
|
339
|
+
}
|
|
341
340
|
}
|
|
342
341
|
/**
|
|
343
342
|
* Resolve the internal project name used by codebase-memory-mcp for a given root path.
|
|
@@ -346,12 +345,12 @@ class CbmAnalyzer {
|
|
|
346
345
|
* query tools require the internal `name`, not the absolute `root_path`.
|
|
347
346
|
* Falls back to the absolute path with a warning if the project is not found.
|
|
348
347
|
*/
|
|
349
|
-
async resolveProjectName(client,
|
|
350
|
-
const
|
|
348
|
+
async resolveProjectName(client, codebaseRoot) {
|
|
349
|
+
const match = (await (client instanceof CbmTools ? client : new CbmTools(client)).listProjects()).find((p) => p.root_path === codebaseRoot);
|
|
351
350
|
return match ? match.name : (handleWarning("Project not found in CBM backend; using absolute path as project identifier", [
|
|
352
|
-
`
|
|
351
|
+
`Codebase root: ${codebaseRoot}`,
|
|
353
352
|
"Run `dr analyzer index` to ensure the project is indexed"
|
|
354
|
-
]),
|
|
353
|
+
]), codebaseRoot);
|
|
355
354
|
}
|
|
356
355
|
/**
|
|
357
356
|
* Query for API endpoints/routes in the indexed project
|
|
@@ -360,11 +359,12 @@ class CbmAnalyzer {
|
|
|
360
359
|
* the analyzer's mapping, and filters based on test code exclusion rules.
|
|
361
360
|
*
|
|
362
361
|
* @param projectRoot Absolute path to the project root
|
|
362
|
+
* @param options Optional codebase configuration
|
|
363
363
|
* @returns Array of endpoint candidates with confidence and source info
|
|
364
364
|
* @throws CLIError if the project is not indexed
|
|
365
365
|
*/
|
|
366
|
-
async endpoints(projectRoot) {
|
|
367
|
-
const status = await this.status(projectRoot);
|
|
366
|
+
async endpoints(projectRoot, options) {
|
|
367
|
+
const effectiveCodebaseRoot = options?.codebaseRoot ?? projectRoot, status = await this.status(projectRoot, { codebaseRoot: effectiveCodebaseRoot });
|
|
368
368
|
if (!status.indexed)
|
|
369
369
|
throw new CLIError(`Project not indexed: ${projectRoot}`, ErrorCategory.NOT_FOUND, [
|
|
370
370
|
"Run `dr analyzer index` to index the project",
|
|
@@ -384,18 +384,14 @@ class CbmAnalyzer {
|
|
|
384
384
|
name: "dr-cli",
|
|
385
385
|
version
|
|
386
386
|
});
|
|
387
|
-
const projectName = await this.resolveProjectName(
|
|
388
|
-
label: routeMapping.cbm_label,
|
|
389
|
-
project: projectName
|
|
390
|
-
}), nodes = this.validateSearchResponse(searchResponse).filter((n) => /^__route__[A-Z]+__\//.test(String(n.qualified_name ?? ""))).filter((n) => isLikelyHttpRoute(String(n.qualified_name ?? ""))), candidates = [];
|
|
387
|
+
const tools = new CbmTools(client), projectName = await this.resolveProjectName(tools, effectiveCodebaseRoot), nodes = (await this.fetchRoutes(tools, projectName, routeMapping.cbm_label)).filter((n) => /^__route__[A-Z]+__\//.test(String(n.qualified_name ?? ""))).filter((n) => isLikelyHttpRoute(String(n.qualified_name ?? ""))), candidates = [];
|
|
391
388
|
for (const node of nodes) {
|
|
392
|
-
const candidate = await this.transformNodeToEndpoint(node, routeMapping,
|
|
389
|
+
const candidate = await this.transformNodeToEndpoint(node, routeMapping, effectiveCodebaseRoot);
|
|
393
390
|
candidate.source_file && (this.isTestCode(candidate) || candidates.push(candidate));
|
|
394
391
|
}
|
|
395
392
|
if (candidates.length === 0)
|
|
396
393
|
try {
|
|
397
|
-
const
|
|
398
|
-
query: `
|
|
394
|
+
const clientQuery = `
|
|
399
395
|
MATCH (n:Function)
|
|
400
396
|
WHERE (n.file_path CONTAINS 'client' OR n.file_path CONTAINS 'Client'
|
|
401
397
|
OR n.file_path CONTAINS 'Api' OR n.file_path CONTAINS 'Service'
|
|
@@ -406,21 +402,17 @@ class CbmAnalyzer {
|
|
|
406
402
|
OR n.name STARTS WITH 'delete' OR n.name STARTS WITH 'patch'
|
|
407
403
|
OR n.name STARTS WITH 'create' OR n.name STARTS WITH 'update'
|
|
408
404
|
OR n.name STARTS WITH 'list')
|
|
409
|
-
RETURN n
|
|
410
|
-
`,
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
const
|
|
415
|
-
|
|
416
|
-
const node = record.n;
|
|
417
|
-
if (!node || !node.file_path)
|
|
418
|
-
continue;
|
|
419
|
-
const candidate = this.shapeClientSideEndpoint(node, projectRoot);
|
|
420
|
-
candidate && !this.isTestCode(candidate) && candidates.push(candidate);
|
|
421
|
-
}
|
|
405
|
+
RETURN ${nodeColumns("n")}
|
|
406
|
+
`, clientNodes = nodesFromQuery(await tools.queryGraph(clientQuery, projectName));
|
|
407
|
+
for (const node of clientNodes) {
|
|
408
|
+
if (!node.file_path)
|
|
409
|
+
continue;
|
|
410
|
+
const candidate = this.shapeClientSideEndpoint(node, effectiveCodebaseRoot);
|
|
411
|
+
candidate && !this.isTestCode(candidate) && candidates.push(candidate);
|
|
422
412
|
}
|
|
423
|
-
} catch {
|
|
413
|
+
} catch (error) {
|
|
414
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
415
|
+
handleWarning("Client-side endpoint fallback skipped: query_graph failed", [`Error: ${errorMsg}`]);
|
|
424
416
|
}
|
|
425
417
|
return this.warnOnDuplicateIdFragments(candidates, (c) => c.suggested_id_fragment, (c) => c.source_symbol || c.source_file || "(unknown)"), candidates;
|
|
426
418
|
} finally {
|
|
@@ -436,11 +428,12 @@ class CbmAnalyzer {
|
|
|
436
428
|
*
|
|
437
429
|
* @param projectRoot Absolute path to the project root
|
|
438
430
|
* @param rawQuery Raw Cypher query string
|
|
431
|
+
* @param options Optional codebase configuration
|
|
439
432
|
* @returns Raw result from query_graph tool
|
|
440
433
|
* @throws CLIError if project not indexed or query_graph tool unavailable
|
|
441
434
|
*/
|
|
442
|
-
async query(projectRoot, rawQuery) {
|
|
443
|
-
const status = await this.status(projectRoot);
|
|
435
|
+
async query(projectRoot, rawQuery, options) {
|
|
436
|
+
const effectiveCodebaseRoot = options?.codebaseRoot ?? projectRoot, status = await this.status(projectRoot, { codebaseRoot: effectiveCodebaseRoot });
|
|
444
437
|
if (!status.indexed)
|
|
445
438
|
throw new CLIError(`Project not indexed: ${projectRoot}`, ErrorCategory.NOT_FOUND, [
|
|
446
439
|
"Run `dr analyzer index` to index the project",
|
|
@@ -457,13 +450,13 @@ class CbmAnalyzer {
|
|
|
457
450
|
name: "dr-cli",
|
|
458
451
|
version
|
|
459
452
|
});
|
|
460
|
-
const projectName = await this.resolveProjectName(
|
|
453
|
+
const tools = new CbmTools(client), projectName = await this.resolveProjectName(tools, effectiveCodebaseRoot);
|
|
461
454
|
try {
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
project: projectName
|
|
465
|
-
});
|
|
455
|
+
const result = await tools.queryGraph(rawQuery, projectName);
|
|
456
|
+
return { ...result, total: result.rows.length };
|
|
466
457
|
} catch (error) {
|
|
458
|
+
if (error instanceof CbmToolError)
|
|
459
|
+
throw new CLIError(`Query failed: ${error.detail}`, ErrorCategory.USER, error.suggestions);
|
|
467
460
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
468
461
|
throw errorMessage.includes("query_graph") || errorMessage.includes("Unknown method") ? new CLIError("query_graph not supported by this analyzer", ErrorCategory.USER, [
|
|
469
462
|
"The query_graph tool is optional in the CBM analyzer contract",
|
|
@@ -507,7 +500,7 @@ class CbmAnalyzer {
|
|
|
507
500
|
*
|
|
508
501
|
* @private
|
|
509
502
|
*/
|
|
510
|
-
async transformNodeToEndpoint(node, mapping,
|
|
503
|
+
async transformNodeToEndpoint(node, mapping, codebaseRoot) {
|
|
511
504
|
const properties = node.properties ?? {}, nodeId = String(node.name ?? node.id ?? "(unknown)");
|
|
512
505
|
let confidence = mapping.confidence;
|
|
513
506
|
const suggestedName = toKebabCase(String(properties.name ?? node.name ?? node.id ?? "")), suggestedIdFragment = suggestedName;
|
|
@@ -527,9 +520,9 @@ class CbmAnalyzer {
|
|
|
527
520
|
const handlerQualifiedName = String(properties.handler_name ?? properties.handler_qualified_name ?? ""), sourceSymbol = String(properties.symbol ?? properties.source_symbol ?? ""), sourceStartLine = Number(properties.start_line ?? 0), sourceEndLine = Number(properties.end_line ?? 0);
|
|
528
521
|
(!handlerQualifiedName || !sourceSymbol) && (confidence = capConfidence(confidence));
|
|
529
522
|
let sourceFile = String(node.file_path ?? properties.file_path ?? properties.source_file ?? "");
|
|
530
|
-
if (sourceFile &&
|
|
523
|
+
if (sourceFile && codebaseRoot)
|
|
531
524
|
try {
|
|
532
|
-
sourceFile =
|
|
525
|
+
sourceFile = relativeToRoot(codebaseRoot, sourceFile);
|
|
533
526
|
} catch (error) {
|
|
534
527
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
535
528
|
handleWarning(`Failed to compute relative path for ${nodeId}`, [
|
|
@@ -577,14 +570,14 @@ class CbmAnalyzer {
|
|
|
577
570
|
* Build a low-confidence EndpointCandidate from a client-side API function node.
|
|
578
571
|
* Used as a fallback when no server-side Route nodes are found (ISSUE-003).
|
|
579
572
|
*/
|
|
580
|
-
shapeClientSideEndpoint(node,
|
|
573
|
+
shapeClientSideEndpoint(node, codebaseRoot) {
|
|
581
574
|
const name = String(node.name ?? node.id ?? "");
|
|
582
575
|
if (!name)
|
|
583
576
|
return null;
|
|
584
577
|
let sourceFile = String(node.file_path ?? "");
|
|
585
|
-
if (sourceFile &&
|
|
578
|
+
if (sourceFile && codebaseRoot)
|
|
586
579
|
try {
|
|
587
|
-
sourceFile =
|
|
580
|
+
sourceFile = relativeToRoot(codebaseRoot, sourceFile);
|
|
588
581
|
} catch {
|
|
589
582
|
}
|
|
590
583
|
if (!sourceFile)
|
|
@@ -637,11 +630,12 @@ class CbmAnalyzer {
|
|
|
637
630
|
* at "medium" and excludes test files.
|
|
638
631
|
*
|
|
639
632
|
* @param projectRoot Absolute path to the project root
|
|
633
|
+
* @param options Optional codebase configuration
|
|
640
634
|
* @returns Array of service candidates with qualifying heuristics populated
|
|
641
635
|
* @throws CLIError if the project is not indexed
|
|
642
636
|
*/
|
|
643
|
-
async services(projectRoot) {
|
|
644
|
-
const status = await this.status(projectRoot);
|
|
637
|
+
async services(projectRoot, options) {
|
|
638
|
+
const effectiveCodebaseRoot = options?.codebaseRoot ?? projectRoot, status = await this.status(projectRoot, { codebaseRoot: effectiveCodebaseRoot });
|
|
645
639
|
if (!status.indexed)
|
|
646
640
|
throw new CLIError(`Project not indexed: ${projectRoot}`, ErrorCategory.NOT_FOUND, [
|
|
647
641
|
"Run `dr analyzer index` to index the project",
|
|
@@ -661,7 +655,7 @@ class CbmAnalyzer {
|
|
|
661
655
|
const nodeLabels = this.mapper.getNodeLabels(), applicationLabels = [];
|
|
662
656
|
for (const label of nodeLabels) {
|
|
663
657
|
const mapping = this.mapper.getNodeMapping(label);
|
|
664
|
-
mapping && mapping.dr_layer === "application" && applicationLabels.push(label);
|
|
658
|
+
mapping && mapping.dr_layer === "application" && SERVICE_SOURCE_TYPES.has(mapping.dr_element_type) && applicationLabels.push(label);
|
|
665
659
|
}
|
|
666
660
|
if (applicationLabels.length === 0)
|
|
667
661
|
return handleWarning("No application-layer labels found in analyzer mapping", [
|
|
@@ -669,18 +663,15 @@ class CbmAnalyzer {
|
|
|
669
663
|
"Services detection requires at least one mapped application-layer node type",
|
|
670
664
|
"Returning empty services list"
|
|
671
665
|
]), [];
|
|
672
|
-
const candidates = [], projectName = await this.resolveProjectName(
|
|
666
|
+
const candidates = [], tools = new CbmTools(client), projectName = await this.resolveProjectName(tools, effectiveCodebaseRoot), labelPriority = { Class: 0, Module: 1 };
|
|
673
667
|
applicationLabels.sort((a, b) => (labelPriority[a] ?? 99) - (labelPriority[b] ?? 99));
|
|
674
668
|
for (const label of applicationLabels) {
|
|
675
|
-
const
|
|
676
|
-
label,
|
|
677
|
-
project: projectName
|
|
678
|
-
}), nodes = this.validateSearchResponse(searchResponse), nodeMapping = this.mapper.getNodeMapping(label);
|
|
669
|
+
const nodes = await tools.searchGraph({ label, project: projectName }), nodeMapping = this.mapper.getNodeMapping(label);
|
|
679
670
|
if (!nodeMapping)
|
|
680
671
|
continue;
|
|
681
672
|
const promotionHeuristicNames = nodeMapping.promotion_heuristics || [];
|
|
682
673
|
for (const node of nodes) {
|
|
683
|
-
const candidate = await this.transformNodeToService(node, nodeMapping,
|
|
674
|
+
const candidate = await this.transformNodeToService(node, nodeMapping, effectiveCodebaseRoot, promotionHeuristicNames);
|
|
684
675
|
candidate.qualifying_heuristics.length > 0 && !this.isTestCode(candidate) && candidates.push(candidate);
|
|
685
676
|
}
|
|
686
677
|
}
|
|
@@ -700,12 +691,12 @@ class CbmAnalyzer {
|
|
|
700
691
|
*
|
|
701
692
|
* @private
|
|
702
693
|
*/
|
|
703
|
-
async transformNodeToService(node, mapping,
|
|
694
|
+
async transformNodeToService(node, mapping, codebaseRoot, promotionHeuristicNames) {
|
|
704
695
|
const properties = node.properties ?? {}, suggestedName = toKebabCase(String(properties.name ?? node.name ?? node.id ?? "")), suggestedIdFragment = suggestedName;
|
|
705
696
|
let sourceFile = node.file_path ?? "";
|
|
706
|
-
if (sourceFile &&
|
|
697
|
+
if (sourceFile && codebaseRoot)
|
|
707
698
|
try {
|
|
708
|
-
sourceFile =
|
|
699
|
+
sourceFile = relativeToRoot(codebaseRoot, sourceFile);
|
|
709
700
|
} catch (error) {
|
|
710
701
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
711
702
|
handleWarning(`Failed to compute relative path for ${String(node.name ?? node.id ?? "(unknown)")}`, [
|
|
@@ -795,11 +786,12 @@ class CbmAnalyzer {
|
|
|
795
786
|
* naming_indicators from the heuristic parameters. All candidates have confidence "low".
|
|
796
787
|
*
|
|
797
788
|
* @param projectRoot Absolute path to the project root
|
|
789
|
+
* @param options Optional codebase configuration
|
|
798
790
|
* @returns Array of datastore candidates aggregated by inferred datastore
|
|
799
791
|
* @throws CLIError if the project is not indexed
|
|
800
792
|
*/
|
|
801
|
-
async datastores(projectRoot) {
|
|
802
|
-
const status = await this.status(projectRoot);
|
|
793
|
+
async datastores(projectRoot, options) {
|
|
794
|
+
const effectiveCodebaseRoot = options?.codebaseRoot ?? projectRoot, status = await this.status(projectRoot, { codebaseRoot: effectiveCodebaseRoot });
|
|
803
795
|
if (!status.indexed)
|
|
804
796
|
throw new CLIError(`Project not indexed: ${projectRoot}`, ErrorCategory.NOT_FOUND, [
|
|
805
797
|
"Run `dr analyzer index` to index the project",
|
|
@@ -822,20 +814,17 @@ class CbmAnalyzer {
|
|
|
822
814
|
"The analyzer configuration is missing the datastore_detection heuristic",
|
|
823
815
|
"Run `npm run build:spec` to recompile the analyzer artifacts"
|
|
824
816
|
]);
|
|
825
|
-
const importPatterns = datastoreHeuristic.parameters?.patterns ?? [], namingIndicators = datastoreHeuristic.parameters?.naming_indicators ?? [], datastoreSignals = /* @__PURE__ */ new Map(), datastoreFirstSource = /* @__PURE__ */ new Map(), projectName = await this.resolveProjectName(
|
|
817
|
+
const importPatterns = datastoreHeuristic.parameters?.patterns ?? [], namingIndicators = datastoreHeuristic.parameters?.naming_indicators ?? [], datastoreSignals = /* @__PURE__ */ new Map(), datastoreFirstSource = /* @__PURE__ */ new Map(), tools = new CbmTools(client), projectName = await this.resolveProjectName(tools, effectiveCodebaseRoot);
|
|
826
818
|
let allNodes = [];
|
|
827
819
|
try {
|
|
828
|
-
const
|
|
829
|
-
query: `
|
|
820
|
+
const importsQuery = `
|
|
830
821
|
MATCH (n1)-[r:IMPORTS]->(n2)
|
|
831
|
-
RETURN DISTINCT n1
|
|
822
|
+
RETURN DISTINCT ${nodeColumns("n1")}
|
|
832
823
|
UNION
|
|
833
824
|
MATCH (n1)-[r:IMPORTS]->(n2)
|
|
834
|
-
RETURN DISTINCT n2
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
});
|
|
838
|
-
queryResponse && typeof queryResponse == "object" && Array.isArray(queryResponse.records) && (allNodes = (queryResponse.records || []).map((r) => r.node).filter((n) => n && typeof n == "object"));
|
|
825
|
+
RETURN DISTINCT ${nodeColumns("n2")}
|
|
826
|
+
`;
|
|
827
|
+
allNodes = nodesFromQuery(await tools.queryGraph(importsQuery, projectName));
|
|
839
828
|
} catch (error) {
|
|
840
829
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
841
830
|
handleWarning("query_graph tool failed; falling back to search_graph for datastore detection", [
|
|
@@ -845,13 +834,8 @@ class CbmAnalyzer {
|
|
|
845
834
|
"Ensure query_graph is supported by your analyzer version for best results"
|
|
846
835
|
]);
|
|
847
836
|
const nodeLabels = this.mapper.getNodeLabels();
|
|
848
|
-
for (const label of nodeLabels)
|
|
849
|
-
|
|
850
|
-
label,
|
|
851
|
-
project: projectName
|
|
852
|
-
}), nodes = this.validateSearchResponse(searchResponse);
|
|
853
|
-
allNodes.push(...nodes);
|
|
854
|
-
}
|
|
837
|
+
for (const label of nodeLabels)
|
|
838
|
+
allNodes.push(...await tools.searchGraph({ label, project: projectName }));
|
|
855
839
|
}
|
|
856
840
|
for (const node of allNodes) {
|
|
857
841
|
const filePath = node.file_path ?? "", importTargetName = String(node.label ?? node.properties?.name ?? node.id ?? "").toLowerCase();
|
|
@@ -874,9 +858,9 @@ class CbmAnalyzer {
|
|
|
874
858
|
]) : (datastoreSignals.set(datastoreName, []), datastoreFirstSource.set(datastoreName, importTargetName));
|
|
875
859
|
const signals = datastoreSignals.get(datastoreName);
|
|
876
860
|
let relativeFile = filePath;
|
|
877
|
-
if (filePath &&
|
|
861
|
+
if (filePath && effectiveCodebaseRoot)
|
|
878
862
|
try {
|
|
879
|
-
relativeFile =
|
|
863
|
+
relativeFile = relativeToRoot(effectiveCodebaseRoot, filePath);
|
|
880
864
|
} catch (error) {
|
|
881
865
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
882
866
|
handleWarning("Failed to compute relative path in datastore detection", [
|
|
@@ -925,8 +909,7 @@ class CbmAnalyzer {
|
|
|
925
909
|
}
|
|
926
910
|
const browserStorageTypes = ["local-storage", "session-storage"], browserStorageSignals = /* @__PURE__ */ new Map();
|
|
927
911
|
try {
|
|
928
|
-
const
|
|
929
|
-
query: `
|
|
912
|
+
const storageQuery = `
|
|
930
913
|
MATCH (n:Function)
|
|
931
914
|
WHERE n.file_path CONTAINS 'Store' OR n.file_path CONTAINS 'store'
|
|
932
915
|
OR n.file_path CONTAINS 'storage' OR n.file_path CONTAINS 'Storage'
|
|
@@ -934,24 +917,13 @@ class CbmAnalyzer {
|
|
|
934
917
|
OR n.file_path CONTAINS 'preference' OR n.file_path CONTAINS 'Preference'
|
|
935
918
|
OR n.file_path CONTAINS 'layout' OR n.file_path CONTAINS 'Layout'
|
|
936
919
|
OR n.file_path CONTAINS 'settings' OR n.file_path CONTAINS 'Settings'
|
|
937
|
-
RETURN n
|
|
938
|
-
`,
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
const
|
|
943
|
-
|
|
944
|
-
const node = record.n;
|
|
945
|
-
if (!node?.file_path)
|
|
946
|
-
continue;
|
|
947
|
-
let relFile = node.file_path;
|
|
948
|
-
try {
|
|
949
|
-
relFile = path.relative(projectRoot, node.file_path);
|
|
950
|
-
} catch {
|
|
951
|
-
}
|
|
952
|
-
const storageKey = /session/i.test(relFile) ? "session-storage" : "local-storage";
|
|
953
|
-
browserStorageSignals.has(storageKey) || browserStorageSignals.set(storageKey, /* @__PURE__ */ new Set()), browserStorageSignals.get(storageKey).add(relFile);
|
|
954
|
-
}
|
|
920
|
+
RETURN ${nodeColumns("n")}
|
|
921
|
+
`, storageNodes = nodesFromQuery(await tools.queryGraph(storageQuery, projectName));
|
|
922
|
+
for (const node of storageNodes) {
|
|
923
|
+
if (!node.file_path)
|
|
924
|
+
continue;
|
|
925
|
+
const relFile = relativeToRoot(effectiveCodebaseRoot, node.file_path), storageKey = /session/i.test(relFile) ? "session-storage" : "local-storage";
|
|
926
|
+
browserStorageSignals.has(storageKey) || browserStorageSignals.set(storageKey, /* @__PURE__ */ new Set()), browserStorageSignals.get(storageKey).add(relFile);
|
|
955
927
|
}
|
|
956
928
|
} catch {
|
|
957
929
|
}
|
|
@@ -1014,11 +986,12 @@ class CbmAnalyzer {
|
|
|
1014
986
|
* @param projectRoot Absolute path to the project root
|
|
1015
987
|
* @param qualifiedName Fully qualified symbol name (e.g., "com.example.UserService.getUser")
|
|
1016
988
|
* @param depth Maximum traversal depth (default 3, clamped to max 10)
|
|
989
|
+
* @param options Optional codebase configuration
|
|
1017
990
|
* @returns Array of callers in the call graph
|
|
1018
991
|
* @throws CLIError if project not indexed or analyzer not installed
|
|
1019
992
|
*/
|
|
1020
|
-
async callers(projectRoot, qualifiedName, depth) {
|
|
1021
|
-
return this.traceCallPath(projectRoot, qualifiedName, depth, "inbound");
|
|
993
|
+
async callers(projectRoot, qualifiedName, depth, options) {
|
|
994
|
+
return this.traceCallPath(projectRoot, qualifiedName, depth, "inbound", options);
|
|
1022
995
|
}
|
|
1023
996
|
/**
|
|
1024
997
|
* Query for callees of a specific function or symbol
|
|
@@ -1031,11 +1004,12 @@ class CbmAnalyzer {
|
|
|
1031
1004
|
* @param projectRoot Absolute path to the project root
|
|
1032
1005
|
* @param qualifiedName Fully qualified symbol name (e.g., "com.example.UserService.getUser")
|
|
1033
1006
|
* @param depth Maximum traversal depth (default 3, clamped to max 10)
|
|
1007
|
+
* @param options Optional codebase configuration
|
|
1034
1008
|
* @returns Array of callees in the call graph
|
|
1035
1009
|
* @throws CLIError if project not indexed or analyzer not installed
|
|
1036
1010
|
*/
|
|
1037
|
-
async callees(projectRoot, qualifiedName, depth) {
|
|
1038
|
-
return this.traceCallPath(projectRoot, qualifiedName, depth, "outbound");
|
|
1011
|
+
async callees(projectRoot, qualifiedName, depth, options) {
|
|
1012
|
+
return this.traceCallPath(projectRoot, qualifiedName, depth, "outbound", options);
|
|
1039
1013
|
}
|
|
1040
1014
|
/**
|
|
1041
1015
|
* Cypher fallback for call graph traversal when trace_path is unavailable.
|
|
@@ -1045,7 +1019,7 @@ class CbmAnalyzer {
|
|
|
1045
1019
|
*
|
|
1046
1020
|
* @private
|
|
1047
1021
|
*/
|
|
1048
|
-
async callGraphViaCypher(binaryPath, projectName, qualifiedName, direction, depth,
|
|
1022
|
+
async callGraphViaCypher(binaryPath, projectName, qualifiedName, direction, depth, codebaseRoot) {
|
|
1049
1023
|
const safeQN = qualifiedName.replace(/'/g, "''"), limit = Math.min(depth * 20, 100), cypher = direction === "inbound" ? `MATCH (caller)-[:CALLS]->(target) WHERE target.qualified_name = '${safeQN}' OR target.name = '${safeQN}' RETURN caller.id AS id, caller.qualified_name AS qualified_name, caller.file_path AS file_path LIMIT ${limit}` : `MATCH (source)-[:CALLS]->(callee) WHERE source.qualified_name = '${safeQN}' OR source.name = '${safeQN}' RETURN callee.id AS id, callee.qualified_name AS qualified_name, callee.file_path AS file_path LIMIT ${limit}`;
|
|
1050
1024
|
depth > 1 && handleWarning(`Cypher CALLS fallback: depth ${depth} requested but fallback only traverses 1 hop`, ["Multi-hop traversal requires trace_path support in the analyzer binary"]);
|
|
1051
1025
|
const client = new StdioClient();
|
|
@@ -1053,16 +1027,13 @@ class CbmAnalyzer {
|
|
|
1053
1027
|
client.spawn(binaryPath);
|
|
1054
1028
|
const version = await getCliVersion();
|
|
1055
1029
|
await client.initialize({ name: "dr-cli", version });
|
|
1056
|
-
const queryResponse = await client.
|
|
1057
|
-
|
|
1058
|
-
project: projectName
|
|
1059
|
-
}), cols = queryResponse?.columns ?? [];
|
|
1060
|
-
return (queryResponse?.rows ?? []).map((row) => {
|
|
1030
|
+
const queryResponse = await new CbmTools(client).queryGraph(cypher, projectName), cols = queryResponse.columns;
|
|
1031
|
+
return queryResponse.rows.map((row) => {
|
|
1061
1032
|
const obj = {};
|
|
1062
1033
|
return cols.forEach((col, i) => {
|
|
1063
1034
|
const key = col.includes(".") ? col.slice(col.lastIndexOf(".") + 1) : col;
|
|
1064
1035
|
obj[key] = row[i];
|
|
1065
|
-
}), shapeCallGraphNode(obj,
|
|
1036
|
+
}), shapeCallGraphNode(obj, codebaseRoot);
|
|
1066
1037
|
});
|
|
1067
1038
|
} catch (error) {
|
|
1068
1039
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
@@ -1082,8 +1053,8 @@ class CbmAnalyzer {
|
|
|
1082
1053
|
*
|
|
1083
1054
|
* @private
|
|
1084
1055
|
*/
|
|
1085
|
-
async traceCallPath(projectRoot, qualifiedName, depth, direction) {
|
|
1086
|
-
const status = await this.status(projectRoot);
|
|
1056
|
+
async traceCallPath(projectRoot, qualifiedName, depth, direction, options) {
|
|
1057
|
+
const effectiveCodebaseRoot = options?.codebaseRoot ?? projectRoot, status = await this.status(projectRoot, { codebaseRoot: effectiveCodebaseRoot });
|
|
1087
1058
|
if (!status.indexed)
|
|
1088
1059
|
throw new CLIError(`Project not indexed: ${projectRoot}`, ErrorCategory.NOT_FOUND, [
|
|
1089
1060
|
"Run `dr analyzer index` to index the project",
|
|
@@ -1100,25 +1071,37 @@ class CbmAnalyzer {
|
|
|
1100
1071
|
name: "dr-cli",
|
|
1101
1072
|
version
|
|
1102
1073
|
});
|
|
1103
|
-
const
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
`
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1074
|
+
const tools = new CbmTools(client), projectName = await this.resolveProjectName(tools, effectiveCodebaseRoot);
|
|
1075
|
+
let trace;
|
|
1076
|
+
try {
|
|
1077
|
+
trace = await tools.tracePath({
|
|
1078
|
+
function_name: qualifiedName,
|
|
1079
|
+
direction,
|
|
1080
|
+
depth: clampedDepth,
|
|
1081
|
+
project: projectName
|
|
1082
|
+
});
|
|
1083
|
+
} catch (error) {
|
|
1084
|
+
throw error instanceof CbmToolError && /not found/i.test(error.detail) ? new CLIError(`Symbol not found in the code graph: ${qualifiedName}`, ErrorCategory.NOT_FOUND, [
|
|
1085
|
+
...error.suggestions ?? [],
|
|
1086
|
+
"Pass the fully qualified name as CBM records it (see `dr analyzer services --json`)"
|
|
1087
|
+
]) : error;
|
|
1088
|
+
}
|
|
1089
|
+
if (!trace)
|
|
1090
|
+
return this.callGraphViaCypher(detection.binary_path, projectName, qualifiedName, direction, clampedDepth, effectiveCodebaseRoot);
|
|
1091
|
+
const nodes = trace.nodes, edges = trace.edges;
|
|
1092
|
+
if (trace.shape === "grouped" && nodes.length > 0)
|
|
1093
|
+
try {
|
|
1094
|
+
const files = await tools.filePathsOf(nodes.map((n) => String(n.qualified_name ?? "")), projectName);
|
|
1095
|
+
for (const node of nodes)
|
|
1096
|
+
node.file_path ??= files.get(String(node.qualified_name ?? ""));
|
|
1097
|
+
} catch (error) {
|
|
1098
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
1099
|
+
handleWarning("Could not look up source files for the call graph", [`Error: ${errorMsg}`]);
|
|
1100
|
+
}
|
|
1101
|
+
const validEdgeTypes = ["CALLS", ...this.mapper.getEdgeTypes().filter((t) => t !== "CALLS")], callGraphNodes = [];
|
|
1119
1102
|
for (const node of nodes) {
|
|
1120
|
-
const nodeQualifiedName = node.qualified_name || node.id;
|
|
1121
|
-
let callGraphNode = shapeCallGraphNode(node,
|
|
1103
|
+
const nodeQualifiedName = String(node.qualified_name || node.id || "");
|
|
1104
|
+
let callGraphNode = shapeCallGraphNode(node, effectiveCodebaseRoot);
|
|
1122
1105
|
const nodeDepth = typeof node.depth == "number" ? node.depth : 0, edgeType = determineEdgeType(nodeDepth, edges, nodeQualifiedName, validEdgeTypes);
|
|
1123
1106
|
callGraphNode.edge_type = edgeType, callGraphNodes.push(callGraphNode);
|
|
1124
1107
|
}
|
|
@@ -1156,6 +1139,50 @@ class CbmAnalyzer {
|
|
|
1156
1139
|
source_symbol: sourceSymbol
|
|
1157
1140
|
};
|
|
1158
1141
|
}
|
|
1142
|
+
/**
|
|
1143
|
+
* Tier-0 classification of the indexed project (`dr analyzer classify --tier0-only`).
|
|
1144
|
+
*
|
|
1145
|
+
* Builds a card for every candidate symbol (src/analyzers/cards) and applies the Tier-0 rules
|
|
1146
|
+
* from this analyzer's extraction heuristics. Reads the graph only: no model calls, no writes.
|
|
1147
|
+
*
|
|
1148
|
+
* @throws CLIError if the project is not indexed or the mapping has no Tier-0 rules
|
|
1149
|
+
*/
|
|
1150
|
+
async classify(projectRoot, options = {}) {
|
|
1151
|
+
const effectiveCodebaseRoot = options.codebaseRoot ?? projectRoot, rules = tier0RulesFrom(this.mapper.getHeuristics());
|
|
1152
|
+
if (rules.length === 0)
|
|
1153
|
+
throw new CLIError(`The ${this.name} analyzer mapping has no Tier-0 rules`, ErrorCategory.USER, [
|
|
1154
|
+
"Tier-0 rules are heuristics with a parameters.tier0 block in the analyzer's extraction-heuristics.json"
|
|
1155
|
+
]);
|
|
1156
|
+
if (options.labels?.length) {
|
|
1157
|
+
const known = /* @__PURE__ */ new Set([...this.mapper.getNodeLabels(), ...defaultLabels(rules), ...Object.keys(CARD_FIELDS)]), unknown = options.labels.filter((l) => !known.has(l));
|
|
1158
|
+
if (unknown.length)
|
|
1159
|
+
throw new CLIError(`Unknown label${unknown.length > 1 ? "s" : ""}: ${unknown.join(", ")}`, ErrorCategory.USER, [
|
|
1160
|
+
`Labels are case-sensitive; known labels: ${[...known].sort().join(", ")}`
|
|
1161
|
+
]);
|
|
1162
|
+
}
|
|
1163
|
+
const status = await this.status(projectRoot, { codebaseRoot: effectiveCodebaseRoot });
|
|
1164
|
+
if (!status.indexed)
|
|
1165
|
+
throw new CLIError(`Project not indexed: ${projectRoot}`, ErrorCategory.NOT_FOUND, [
|
|
1166
|
+
"Run `dr analyzer index` to index the project",
|
|
1167
|
+
"Ensure codebase-memory-mcp is installed and working"
|
|
1168
|
+
]);
|
|
1169
|
+
const detection = status.detected;
|
|
1170
|
+
if (!detection.installed)
|
|
1171
|
+
throw new CLIError("CBM analyzer not installed", ErrorCategory.NOT_FOUND, [
|
|
1172
|
+
"Install codebase-memory-mcp: npm install -g codebase-memory-mcp"
|
|
1173
|
+
]);
|
|
1174
|
+
const client = new StdioClient();
|
|
1175
|
+
try {
|
|
1176
|
+
client.spawn(detection.binary_path), await client.initialize({ name: "dr-cli", version: await getCliVersion() });
|
|
1177
|
+
const tools = new CbmTools(client), projectName = await this.resolveProjectName(tools, effectiveCodebaseRoot);
|
|
1178
|
+
return await classifyTier0(cbmCardGraph(tools, projectName), rules, this.name, {
|
|
1179
|
+
sourceRoot: effectiveCodebaseRoot,
|
|
1180
|
+
...options
|
|
1181
|
+
});
|
|
1182
|
+
} finally {
|
|
1183
|
+
client.close();
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1159
1186
|
/**
|
|
1160
1187
|
* Verify that graph-discovered routes align with model endpoints
|
|
1161
1188
|
*
|
|
@@ -1163,12 +1190,12 @@ class CbmAnalyzer {
|
|
|
1163
1190
|
* and delegates comparison to VerifyEngine. Entirely read-only.
|
|
1164
1191
|
*
|
|
1165
1192
|
* @param projectRoot Absolute path to the project root
|
|
1166
|
-
* @param options Verification options
|
|
1193
|
+
* @param options Verification options including codebase root
|
|
1167
1194
|
* @returns Comprehensive verification report
|
|
1168
1195
|
* @throws CLIError if project not indexed or analyzer not installed
|
|
1169
1196
|
*/
|
|
1170
1197
|
async verify(projectRoot, options) {
|
|
1171
|
-
const status = await this.status(projectRoot);
|
|
1198
|
+
const effectiveCodebaseRoot = options?.codebaseRoot ?? projectRoot, status = await this.status(projectRoot, { codebaseRoot: effectiveCodebaseRoot });
|
|
1172
1199
|
if (!status.indexed)
|
|
1173
1200
|
throw new CLIError(`Project not indexed: ${projectRoot}`, ErrorCategory.NOT_FOUND, [
|
|
1174
1201
|
"Run `dr analyzer index` to index the project",
|
|
@@ -1188,10 +1215,7 @@ class CbmAnalyzer {
|
|
|
1188
1215
|
name: "dr-cli",
|
|
1189
1216
|
version
|
|
1190
1217
|
});
|
|
1191
|
-
const projectName = await this.resolveProjectName(
|
|
1192
|
-
label: routeMapping.cbm_label,
|
|
1193
|
-
project: projectName
|
|
1194
|
-
}), routes = this.validateSearchResponse(searchResponse).filter((n) => /^__route__[A-Z]+__\//.test(String(n.qualified_name ?? ""))).filter((n) => isLikelyHttpRoute(String(n.qualified_name ?? ""))).map((node) => this.shapeRoute(node)).filter((r) => r.source_file), engine = new VerifyEngine(), indexMeta = status.index_meta, analyzerName = this.name;
|
|
1218
|
+
const tools = new CbmTools(client), projectName = await this.resolveProjectName(tools, effectiveCodebaseRoot), routes = (await this.fetchRoutes(tools, projectName, routeMapping.cbm_label)).filter((n) => /^__route__[A-Z]+__\//.test(String(n.qualified_name ?? ""))).filter((n) => isLikelyHttpRoute(String(n.qualified_name ?? ""))).map((node) => this.shapeRoute(node)).filter((r) => r.source_file), engine = new VerifyEngine(), indexMeta = status.index_meta, analyzerName = this.name;
|
|
1195
1219
|
return await engine.computeReport(projectRoot, routes, options, analyzerName, indexMeta);
|
|
1196
1220
|
} finally {
|
|
1197
1221
|
client.close();
|