@bugsbunnycodes1998/cartographer-core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/pipeline.test.d.ts +2 -0
- package/dist/__tests__/pipeline.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline.test.js +58 -0
- package/dist/__tests__/pipeline.test.js.map +1 -0
- package/dist/analysis/call-graph.d.ts +13 -0
- package/dist/analysis/call-graph.d.ts.map +1 -0
- package/dist/analysis/call-graph.js +133 -0
- package/dist/analysis/call-graph.js.map +1 -0
- package/dist/analysis/dependency-graph.d.ts +8 -0
- package/dist/analysis/dependency-graph.d.ts.map +1 -0
- package/dist/analysis/dependency-graph.js +101 -0
- package/dist/analysis/dependency-graph.js.map +1 -0
- package/dist/analysis/git/archaeology.d.ts +20 -0
- package/dist/analysis/git/archaeology.d.ts.map +1 -0
- package/dist/analysis/git/archaeology.js +61 -0
- package/dist/analysis/git/archaeology.js.map +1 -0
- package/dist/analysis/git/bus-factor.d.ts +17 -0
- package/dist/analysis/git/bus-factor.d.ts.map +1 -0
- package/dist/analysis/git/bus-factor.js +90 -0
- package/dist/analysis/git/bus-factor.js.map +1 -0
- package/dist/analysis/git/churn.d.ts +26 -0
- package/dist/analysis/git/churn.d.ts.map +1 -0
- package/dist/analysis/git/churn.js +127 -0
- package/dist/analysis/git/churn.js.map +1 -0
- package/dist/analysis/git/contributors.d.ts +14 -0
- package/dist/analysis/git/contributors.d.ts.map +1 -0
- package/dist/analysis/git/contributors.js +60 -0
- package/dist/analysis/git/contributors.js.map +1 -0
- package/dist/analysis/git/evolution.d.ts +10 -0
- package/dist/analysis/git/evolution.d.ts.map +1 -0
- package/dist/analysis/git/evolution.js +127 -0
- package/dist/analysis/git/evolution.js.map +1 -0
- package/dist/analysis/git/index.d.ts +6 -0
- package/dist/analysis/git/index.d.ts.map +1 -0
- package/dist/analysis/git/index.js +6 -0
- package/dist/analysis/git/index.js.map +1 -0
- package/dist/analysis/go-visitor.d.ts +4 -0
- package/dist/analysis/go-visitor.d.ts.map +1 -0
- package/dist/analysis/go-visitor.js +295 -0
- package/dist/analysis/go-visitor.js.map +1 -0
- package/dist/analysis/health/indicators.d.ts +25 -0
- package/dist/analysis/health/indicators.d.ts.map +1 -0
- package/dist/analysis/health/indicators.js +53 -0
- package/dist/analysis/health/indicators.js.map +1 -0
- package/dist/analysis/health/scorer.d.ts +26 -0
- package/dist/analysis/health/scorer.d.ts.map +1 -0
- package/dist/analysis/health/scorer.js +97 -0
- package/dist/analysis/health/scorer.js.map +1 -0
- package/dist/analysis/health/test-coverage.d.ts +19 -0
- package/dist/analysis/health/test-coverage.d.ts.map +1 -0
- package/dist/analysis/health/test-coverage.js +67 -0
- package/dist/analysis/health/test-coverage.js.map +1 -0
- package/dist/analysis/import-resolver.d.ts +10 -0
- package/dist/analysis/import-resolver.d.ts.map +1 -0
- package/dist/analysis/import-resolver.js +353 -0
- package/dist/analysis/import-resolver.js.map +1 -0
- package/dist/analysis/index.d.ts +22 -0
- package/dist/analysis/index.d.ts.map +1 -0
- package/dist/analysis/index.js +24 -0
- package/dist/analysis/index.js.map +1 -0
- package/dist/analysis/java-visitor.d.ts +4 -0
- package/dist/analysis/java-visitor.d.ts.map +1 -0
- package/dist/analysis/java-visitor.js +257 -0
- package/dist/analysis/java-visitor.js.map +1 -0
- package/dist/analysis/metrics.d.ts +19 -0
- package/dist/analysis/metrics.d.ts.map +1 -0
- package/dist/analysis/metrics.js +70 -0
- package/dist/analysis/metrics.js.map +1 -0
- package/dist/analysis/module-detector.d.ts +3 -0
- package/dist/analysis/module-detector.d.ts.map +1 -0
- package/dist/analysis/module-detector.js +257 -0
- package/dist/analysis/module-detector.js.map +1 -0
- package/dist/analysis/parser.d.ts +13 -0
- package/dist/analysis/parser.d.ts.map +1 -0
- package/dist/analysis/parser.js +92 -0
- package/dist/analysis/parser.js.map +1 -0
- package/dist/analysis/python-visitor.d.ts +4 -0
- package/dist/analysis/python-visitor.d.ts.map +1 -0
- package/dist/analysis/python-visitor.js +306 -0
- package/dist/analysis/python-visitor.js.map +1 -0
- package/dist/analysis/rust-visitor.d.ts +4 -0
- package/dist/analysis/rust-visitor.d.ts.map +1 -0
- package/dist/analysis/rust-visitor.js +318 -0
- package/dist/analysis/rust-visitor.js.map +1 -0
- package/dist/analysis/semantic/cache.d.ts +16 -0
- package/dist/analysis/semantic/cache.d.ts.map +1 -0
- package/dist/analysis/semantic/cache.js +26 -0
- package/dist/analysis/semantic/cache.js.map +1 -0
- package/dist/analysis/semantic/openai-client.d.ts +21 -0
- package/dist/analysis/semantic/openai-client.d.ts.map +1 -0
- package/dist/analysis/semantic/openai-client.js +73 -0
- package/dist/analysis/semantic/openai-client.js.map +1 -0
- package/dist/analysis/semantic/prompts.d.ts +32 -0
- package/dist/analysis/semantic/prompts.d.ts.map +1 -0
- package/dist/analysis/semantic/prompts.js +134 -0
- package/dist/analysis/semantic/prompts.js.map +1 -0
- package/dist/analysis/semantic/summarizer.d.ts +36 -0
- package/dist/analysis/semantic/summarizer.d.ts.map +1 -0
- package/dist/analysis/semantic/summarizer.js +229 -0
- package/dist/analysis/semantic/summarizer.js.map +1 -0
- package/dist/analysis/ts-js-visitor.d.ts +4 -0
- package/dist/analysis/ts-js-visitor.d.ts.map +1 -0
- package/dist/analysis/ts-js-visitor.js +390 -0
- package/dist/analysis/ts-js-visitor.js.map +1 -0
- package/dist/analysis/visitor-registry.d.ts +5 -0
- package/dist/analysis/visitor-registry.d.ts.map +1 -0
- package/dist/analysis/visitor-registry.js +17 -0
- package/dist/analysis/visitor-registry.js.map +1 -0
- package/dist/analysis/visitor-utils.d.ts +38 -0
- package/dist/analysis/visitor-utils.d.ts.map +1 -0
- package/dist/analysis/visitor-utils.js +110 -0
- package/dist/analysis/visitor-utils.js.map +1 -0
- package/dist/errors.d.ts +20 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +39 -0
- package/dist/errors.js.map +1 -0
- package/dist/expeditions/custom.d.ts +11 -0
- package/dist/expeditions/custom.d.ts.map +1 -0
- package/dist/expeditions/custom.js +61 -0
- package/dist/expeditions/custom.js.map +1 -0
- package/dist/expeditions/danger-zones.d.ts +9 -0
- package/dist/expeditions/danger-zones.d.ts.map +1 -0
- package/dist/expeditions/danger-zones.js +42 -0
- package/dist/expeditions/danger-zones.js.map +1 -0
- package/dist/expeditions/generator.d.ts +21 -0
- package/dist/expeditions/generator.d.ts.map +1 -0
- package/dist/expeditions/generator.js +78 -0
- package/dist/expeditions/generator.js.map +1 -0
- package/dist/expeditions/grand-tour.d.ts +10 -0
- package/dist/expeditions/grand-tour.d.ts.map +1 -0
- package/dist/expeditions/grand-tour.js +96 -0
- package/dist/expeditions/grand-tour.js.map +1 -0
- package/dist/expeditions/request-flow.d.ts +11 -0
- package/dist/expeditions/request-flow.d.ts.map +1 -0
- package/dist/expeditions/request-flow.js +138 -0
- package/dist/expeditions/request-flow.js.map +1 -0
- package/dist/grammars/tree-sitter-go.wasm +0 -0
- package/dist/grammars/tree-sitter-java.wasm +0 -0
- package/dist/grammars/tree-sitter-javascript.wasm +0 -0
- package/dist/grammars/tree-sitter-python.wasm +0 -0
- package/dist/grammars/tree-sitter-rust.wasm +0 -0
- package/dist/grammars/tree-sitter-tsx.wasm +0 -0
- package/dist/grammars/tree-sitter-typescript.wasm +0 -0
- package/dist/graph/builder.d.ts +23 -0
- package/dist/graph/builder.d.ts.map +1 -0
- package/dist/graph/builder.js +131 -0
- package/dist/graph/builder.js.map +1 -0
- package/dist/graph/exporter.d.ts +5 -0
- package/dist/graph/exporter.d.ts.map +1 -0
- package/dist/graph/exporter.js +20 -0
- package/dist/graph/exporter.js.map +1 -0
- package/dist/graph/layout.d.ts +3 -0
- package/dist/graph/layout.d.ts.map +1 -0
- package/dist/graph/layout.js +257 -0
- package/dist/graph/layout.js.map +1 -0
- package/dist/graph/store.d.ts +13 -0
- package/dist/graph/store.d.ts.map +1 -0
- package/dist/graph/store.js +145 -0
- package/dist/graph/store.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/ingestion/cloner.d.ts +18 -0
- package/dist/ingestion/cloner.d.ts.map +1 -0
- package/dist/ingestion/cloner.js +62 -0
- package/dist/ingestion/cloner.js.map +1 -0
- package/dist/ingestion/file-tree.d.ts +3 -0
- package/dist/ingestion/file-tree.d.ts.map +1 -0
- package/dist/ingestion/file-tree.js +85 -0
- package/dist/ingestion/file-tree.js.map +1 -0
- package/dist/ingestion/index.d.ts +5 -0
- package/dist/ingestion/index.d.ts.map +1 -0
- package/dist/ingestion/index.js +5 -0
- package/dist/ingestion/index.js.map +1 -0
- package/dist/ingestion/language-detector.d.ts +8 -0
- package/dist/ingestion/language-detector.d.ts.map +1 -0
- package/dist/ingestion/language-detector.js +37 -0
- package/dist/ingestion/language-detector.js.map +1 -0
- package/dist/ingestion/path-resolver.d.ts +7 -0
- package/dist/ingestion/path-resolver.d.ts.map +1 -0
- package/dist/ingestion/path-resolver.js +30 -0
- package/dist/ingestion/path-resolver.js.map +1 -0
- package/dist/logger.d.ts +3 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +11 -0
- package/dist/logger.js.map +1 -0
- package/dist/pipeline.d.ts +3 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +223 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/types/analysis.d.ts +51 -0
- package/dist/types/analysis.d.ts.map +1 -0
- package/dist/types/analysis.js +2 -0
- package/dist/types/analysis.js.map +1 -0
- package/dist/types/config.d.ts +19 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +2 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/edges.d.ts +8 -0
- package/dist/types/edges.d.ts.map +1 -0
- package/dist/types/edges.js +2 -0
- package/dist/types/edges.js.map +1 -0
- package/dist/types/expeditions.d.ts +19 -0
- package/dist/types/expeditions.d.ts.map +1 -0
- package/dist/types/expeditions.js +2 -0
- package/dist/types/expeditions.js.map +1 -0
- package/dist/types/graph.d.ts +29 -0
- package/dist/types/graph.d.ts.map +1 -0
- package/dist/types/graph.js +2 -0
- package/dist/types/graph.js.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/nodes.d.ts +35 -0
- package/dist/types/nodes.d.ts.map +1 -0
- package/dist/types/nodes.js +2 -0
- package/dist/types/nodes.js.map +1 -0
- package/package.json +36 -0
package/dist/errors.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export class CartographerError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
constructor(message, code, options) {
|
|
4
|
+
super(message, options);
|
|
5
|
+
this.code = code;
|
|
6
|
+
this.name = "CartographerError";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export class IngestionError extends CartographerError {
|
|
10
|
+
constructor(message, code = "INGESTION_ERROR", options) {
|
|
11
|
+
super(message, code, options);
|
|
12
|
+
this.name = "IngestionError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export class AnalysisError extends CartographerError {
|
|
16
|
+
constructor(message, code = "ANALYSIS_ERROR", options) {
|
|
17
|
+
super(message, code, options);
|
|
18
|
+
this.name = "AnalysisError";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export class GraphError extends CartographerError {
|
|
22
|
+
constructor(message, code = "GRAPH_ERROR", options) {
|
|
23
|
+
super(message, code, options);
|
|
24
|
+
this.name = "GraphError";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export class GitError extends CartographerError {
|
|
28
|
+
constructor(message, code = "GIT_ERROR", options) {
|
|
29
|
+
super(message, code, options);
|
|
30
|
+
this.name = "GitError";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export class LlmError extends CartographerError {
|
|
34
|
+
constructor(message, code = "LLM_ERROR", options) {
|
|
35
|
+
super(message, code, options);
|
|
36
|
+
this.name = "LlmError";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAGxB;IAFlB,YACE,OAAe,EACC,IAAY,EAC5B,OAAsB;QAEtB,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAHR,SAAI,GAAJ,IAAI,CAAQ;QAI5B,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED,MAAM,OAAO,cAAe,SAAQ,iBAAiB;IACnD,YAAY,OAAe,EAAE,OAAe,iBAAiB,EAAE,OAAsB;QACnF,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,OAAO,aAAc,SAAQ,iBAAiB;IAClD,YAAY,OAAe,EAAE,OAAe,gBAAgB,EAAE,OAAsB;QAClF,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AAED,MAAM,OAAO,UAAW,SAAQ,iBAAiB;IAC/C,YAAY,OAAe,EAAE,OAAe,aAAa,EAAE,OAAsB;QAC/E,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC3B,CAAC;CACF;AAED,MAAM,OAAO,QAAS,SAAQ,iBAAiB;IAC7C,YAAY,OAAe,EAAE,OAAe,WAAW,EAAE,OAAsB;QAC7E,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED,MAAM,OAAO,QAAS,SAAQ,iBAAiB;IAC7C,YAAY,OAAe,EAAE,OAAe,WAAW,EAAE,OAAsB;QAC7E,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type Database from "better-sqlite3";
|
|
2
|
+
import type { GraphNode, GraphEdge, Expedition } from "../types/index.js";
|
|
3
|
+
import type { OpenAIClient } from "../analysis/semantic/openai-client.js";
|
|
4
|
+
/**
|
|
5
|
+
* Generate a custom expedition from a user's natural-language question.
|
|
6
|
+
*
|
|
7
|
+
* Sends the question along with a summary of available nodes and edges
|
|
8
|
+
* to the LLM, which returns a structured Expedition JSON.
|
|
9
|
+
*/
|
|
10
|
+
export declare function generateCustomExpedition(question: string, nodes: GraphNode[], edges: GraphEdge[], client: OpenAIClient, db: Database.Database): Promise<Expedition>;
|
|
11
|
+
//# sourceMappingURL=custom.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../src/expeditions/custom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAkB,MAAM,mBAAmB,CAAC;AAC1F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAmB1E;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,SAAS,EAAE,EAClB,KAAK,EAAE,SAAS,EAAE,EAClB,MAAM,EAAE,YAAY,EACpB,EAAE,EAAE,QAAQ,CAAC,QAAQ,GACpB,OAAO,CAAC,UAAU,CAAC,CAiErB"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { expeditionPrompt } from "../analysis/semantic/prompts.js";
|
|
2
|
+
import { createCacheKey, getCachedResult, setCachedResult } from "../analysis/semantic/cache.js";
|
|
3
|
+
import { logger } from "../logger.js";
|
|
4
|
+
/**
|
|
5
|
+
* Generate a custom expedition from a user's natural-language question.
|
|
6
|
+
*
|
|
7
|
+
* Sends the question along with a summary of available nodes and edges
|
|
8
|
+
* to the LLM, which returns a structured Expedition JSON.
|
|
9
|
+
*/
|
|
10
|
+
export async function generateCustomExpedition(question, nodes, edges, client, db) {
|
|
11
|
+
// Build compact summaries for the LLM
|
|
12
|
+
const moduleSummaries = nodes
|
|
13
|
+
.filter((n) => n.kind === "module")
|
|
14
|
+
.map((n) => ({ name: n.name, id: n.id, summary: n.summary ?? "no summary" }));
|
|
15
|
+
const callGraphSummary = edges
|
|
16
|
+
.filter((e) => e.kind === "calls")
|
|
17
|
+
.slice(0, 50) // Limit to keep prompt size reasonable
|
|
18
|
+
.map((e) => `${e.sourceId} -> ${e.targetId}`);
|
|
19
|
+
const nodeIds = new Set(nodes.map((n) => n.id));
|
|
20
|
+
// Check cache
|
|
21
|
+
const cacheInput = `${question}|${moduleSummaries.map((m) => m.id).join(",")}`;
|
|
22
|
+
const cacheKey = createCacheKey(cacheInput, "expedition");
|
|
23
|
+
const cached = getCachedResult(db, cacheKey, "expedition");
|
|
24
|
+
if (cached) {
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(cached);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
logger.debug("Cached expedition parse failed, regenerating");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const { system, user } = expeditionPrompt(question, callGraphSummary.join("\n"), moduleSummaries.map((m) => `- ${m.name} (${m.id}): ${m.summary}`));
|
|
33
|
+
const { result, tokensUsed } = await client.completeJSON([
|
|
34
|
+
{ role: "system", content: system },
|
|
35
|
+
{ role: "user", content: user },
|
|
36
|
+
], "gpt-4o");
|
|
37
|
+
// Validate and sanitize node IDs — only keep steps with valid nodeIds
|
|
38
|
+
const validSteps = result.steps
|
|
39
|
+
.filter((step) => nodeIds.has(step.nodeId))
|
|
40
|
+
.map((step) => ({
|
|
41
|
+
nodeId: step.nodeId,
|
|
42
|
+
zoomLevel: (Math.min(Math.max(step.zoomLevel, 0), 3)),
|
|
43
|
+
narration: step.narration,
|
|
44
|
+
highlightEdges: step.highlightEdges ?? [],
|
|
45
|
+
highlightNodes: (step.highlightNodes ?? []).filter((id) => nodeIds.has(id)),
|
|
46
|
+
duration: step.duration ?? 6,
|
|
47
|
+
action: step.action,
|
|
48
|
+
}));
|
|
49
|
+
const expedition = {
|
|
50
|
+
id: `expedition:custom-${Date.now()}`,
|
|
51
|
+
title: result.title || `Custom: ${question.slice(0, 40)}`,
|
|
52
|
+
description: result.description || question,
|
|
53
|
+
kind: "custom",
|
|
54
|
+
estimatedMinutes: Math.max(1, Math.round(validSteps.length * 6 / 60)),
|
|
55
|
+
steps: validSteps,
|
|
56
|
+
};
|
|
57
|
+
// Cache the result
|
|
58
|
+
setCachedResult(db, cacheKey, "gpt-4o", "expedition", JSON.stringify(expedition), tokensUsed);
|
|
59
|
+
return expedition;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=custom.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom.js","sourceRoot":"","sources":["../../src/expeditions/custom.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { GraphNode, Expedition } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Generate a "Danger Zones" expedition that visits the most problematic
|
|
4
|
+
* files in the codebase — low health, high complexity, high churn.
|
|
5
|
+
*
|
|
6
|
+
* No LLM required.
|
|
7
|
+
*/
|
|
8
|
+
export declare function generateDangerZones(fileNodes: GraphNode[]): Expedition;
|
|
9
|
+
//# sourceMappingURL=danger-zones.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"danger-zones.d.ts","sourceRoot":"","sources":["../../src/expeditions/danger-zones.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAkB,MAAM,mBAAmB,CAAC;AAc/E;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,SAAS,EAAE,GACrB,UAAU,CA6BZ"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Score a file node for "danger" based on health, complexity, and churn.
|
|
3
|
+
* Higher score = more dangerous.
|
|
4
|
+
*/
|
|
5
|
+
function dangerScore(node) {
|
|
6
|
+
return ((100 - node.healthScore) * 0.4 +
|
|
7
|
+
node.complexity * 0.3 +
|
|
8
|
+
node.churnScore * 100 * 0.3);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Generate a "Danger Zones" expedition that visits the most problematic
|
|
12
|
+
* files in the codebase — low health, high complexity, high churn.
|
|
13
|
+
*
|
|
14
|
+
* No LLM required.
|
|
15
|
+
*/
|
|
16
|
+
export function generateDangerZones(fileNodes) {
|
|
17
|
+
// Score and sort descending
|
|
18
|
+
const scored = fileNodes
|
|
19
|
+
.filter((n) => n.kind === "file")
|
|
20
|
+
.map((n) => ({ node: n, score: dangerScore(n) }))
|
|
21
|
+
.sort((a, b) => b.score - a.score);
|
|
22
|
+
// Take top 7
|
|
23
|
+
const topDanger = scored.slice(0, 7);
|
|
24
|
+
const steps = topDanger.map(({ node }) => ({
|
|
25
|
+
nodeId: node.id,
|
|
26
|
+
zoomLevel: 1,
|
|
27
|
+
narration: `Warning: ${node.name} — Health: ${node.healthScore}/100, Complexity: ${node.complexity}. ${node.summary ?? ""}`.trim(),
|
|
28
|
+
highlightEdges: [],
|
|
29
|
+
highlightNodes: [node.id],
|
|
30
|
+
duration: 8,
|
|
31
|
+
}));
|
|
32
|
+
const estimatedMinutes = Math.max(1, Math.round(steps.length * 8 / 60));
|
|
33
|
+
return {
|
|
34
|
+
id: "expedition:danger-zones",
|
|
35
|
+
title: "Danger Zones",
|
|
36
|
+
description: "Tour the most problematic files — high complexity, low health, and frequent changes.",
|
|
37
|
+
kind: "danger_zones",
|
|
38
|
+
estimatedMinutes,
|
|
39
|
+
steps,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=danger-zones.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"danger-zones.js","sourceRoot":"","sources":["../../src/expeditions/danger-zones.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,SAAS,WAAW,CAAC,IAAe;IAClC,OAAO,CACL,CAAC,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,GAAG;QAC9B,IAAI,CAAC,UAAU,GAAG,GAAG;QACrB,IAAI,CAAC,UAAU,GAAG,GAAG,GAAG,GAAG,CAC5B,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CACjC,SAAsB;IAEtB,4BAA4B;IAC5B,MAAM,MAAM,GAAG,SAAS;SACrB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;SAChC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SAChD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAErC,aAAa;IACb,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAErC,MAAM,KAAK,GAAqB,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QAC3D,MAAM,EAAE,IAAI,CAAC,EAAE;QACf,SAAS,EAAE,CAAU;QACrB,SAAS,EAAE,YAAY,IAAI,CAAC,IAAI,cAAc,IAAI,CAAC,WAAW,qBAAqB,IAAI,CAAC,UAAU,KAAK,IAAI,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE;QAClI,cAAc,EAAE,EAAE;QAClB,cAAc,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,QAAQ,EAAE,CAAC;KACZ,CAAC,CAAC,CAAC;IAEJ,MAAM,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAExE,OAAO;QACL,EAAE,EAAE,yBAAyB;QAC7B,KAAK,EAAE,cAAc;QACrB,WAAW,EAAE,sFAAsF;QACnG,IAAI,EAAE,cAAc;QACpB,gBAAgB;QAChB,KAAK;KACN,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type Database from "better-sqlite3";
|
|
2
|
+
import type { GraphNode, GraphEdge, Expedition, ModuleInfo, ProgressEvent } from "../types/index.js";
|
|
3
|
+
import type { OpenAIClient } from "../analysis/semantic/openai-client.js";
|
|
4
|
+
export interface GenerateExpeditionsOptions {
|
|
5
|
+
nodes: GraphNode[];
|
|
6
|
+
edges: GraphEdge[];
|
|
7
|
+
callEdges: GraphEdge[];
|
|
8
|
+
modules: ModuleInfo[];
|
|
9
|
+
client?: OpenAIClient;
|
|
10
|
+
db?: Database.Database;
|
|
11
|
+
onProgress?: (event: ProgressEvent) => void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Generate all available expeditions for the analyzed codebase.
|
|
15
|
+
*
|
|
16
|
+
* - Grand Tour is always generated (no LLM needed).
|
|
17
|
+
* - Danger Zones is always generated (no LLM needed).
|
|
18
|
+
* - Request Flow is generated when call edges are available.
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateExpeditions(options: GenerateExpeditionsOptions): Promise<Expedition[]>;
|
|
21
|
+
//# sourceMappingURL=generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/expeditions/generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACrG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAM1E,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,EAAE,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC;IACvB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;CAC7C;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,UAAU,EAAE,CAAC,CA4EvB"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { generateGrandTour } from "./grand-tour.js";
|
|
2
|
+
import { generateDangerZones } from "./danger-zones.js";
|
|
3
|
+
import { generateRequestFlow } from "./request-flow.js";
|
|
4
|
+
import { logger } from "../logger.js";
|
|
5
|
+
/**
|
|
6
|
+
* Generate all available expeditions for the analyzed codebase.
|
|
7
|
+
*
|
|
8
|
+
* - Grand Tour is always generated (no LLM needed).
|
|
9
|
+
* - Danger Zones is always generated (no LLM needed).
|
|
10
|
+
* - Request Flow is generated when call edges are available.
|
|
11
|
+
*/
|
|
12
|
+
export async function generateExpeditions(options) {
|
|
13
|
+
const { nodes, edges, callEdges, onProgress } = options;
|
|
14
|
+
const expeditions = [];
|
|
15
|
+
const emit = (message) => {
|
|
16
|
+
onProgress?.({ stage: "expeditions", message });
|
|
17
|
+
};
|
|
18
|
+
// Module-level nodes and edges for grand tour
|
|
19
|
+
const moduleNodes = nodes.filter((n) => n.kind === "module");
|
|
20
|
+
const moduleEdges = edges.filter((e) => e.kind === "imports" && e.sourceId.startsWith("mod:") && e.targetId.startsWith("mod:"));
|
|
21
|
+
// 1. Grand Tour (always)
|
|
22
|
+
if (moduleNodes.length > 0) {
|
|
23
|
+
emit("Generating Grand Tour...");
|
|
24
|
+
try {
|
|
25
|
+
const grandTour = generateGrandTour(moduleNodes, moduleEdges);
|
|
26
|
+
expeditions.push(grandTour);
|
|
27
|
+
logger.debug(`Grand Tour: ${grandTour.steps.length} steps`);
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
logger.warn(`Grand Tour generation failed: ${err instanceof Error ? err.message : err}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// 2. Danger Zones (always)
|
|
34
|
+
const fileNodes = nodes.filter((n) => n.kind === "file");
|
|
35
|
+
if (fileNodes.length > 0) {
|
|
36
|
+
emit("Generating Danger Zones...");
|
|
37
|
+
try {
|
|
38
|
+
const dangerZones = generateDangerZones(fileNodes);
|
|
39
|
+
if (dangerZones.steps.length > 0) {
|
|
40
|
+
expeditions.push(dangerZones);
|
|
41
|
+
logger.debug(`Danger Zones: ${dangerZones.steps.length} steps`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
logger.warn(`Danger Zones generation failed: ${err instanceof Error ? err.message : err}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// 3. Request Flow (when call edges available)
|
|
49
|
+
if (callEdges.length > 0 || edges.some((e) => e.kind === "calls")) {
|
|
50
|
+
emit("Generating Request Flow...");
|
|
51
|
+
try {
|
|
52
|
+
const allCallEdges = [
|
|
53
|
+
...callEdges,
|
|
54
|
+
...edges.filter((e) => e.kind === "calls"),
|
|
55
|
+
];
|
|
56
|
+
// Deduplicate
|
|
57
|
+
const seen = new Set();
|
|
58
|
+
const uniqueCallEdges = allCallEdges.filter((e) => {
|
|
59
|
+
const key = `${e.sourceId}|${e.targetId}`;
|
|
60
|
+
if (seen.has(key))
|
|
61
|
+
return false;
|
|
62
|
+
seen.add(key);
|
|
63
|
+
return true;
|
|
64
|
+
});
|
|
65
|
+
const requestFlow = await generateRequestFlow(nodes, uniqueCallEdges, moduleEdges, options.client, options.db);
|
|
66
|
+
if (requestFlow) {
|
|
67
|
+
expeditions.push(requestFlow);
|
|
68
|
+
logger.debug(`Request Flow: ${requestFlow.steps.length} steps`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
logger.warn(`Request Flow generation failed: ${err instanceof Error ? err.message : err}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
emit(`Generated ${expeditions.length} expedition(s)`);
|
|
76
|
+
return expeditions;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../src/expeditions/generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { GraphNode, GraphEdge, Expedition } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Generate a "Grand Tour" expedition that visits every module in
|
|
4
|
+
* topological dependency order (leaf deps first, entry points last).
|
|
5
|
+
*
|
|
6
|
+
* No LLM required — uses module summaries if available, otherwise
|
|
7
|
+
* template narration.
|
|
8
|
+
*/
|
|
9
|
+
export declare function generateGrandTour(modules: GraphNode[], moduleEdges: GraphEdge[]): Expedition;
|
|
10
|
+
//# sourceMappingURL=grand-tour.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grand-tour.d.ts","sourceRoot":"","sources":["../../src/expeditions/grand-tour.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAkB,MAAM,mBAAmB,CAAC;AAwD1F;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,SAAS,EAAE,EACpB,WAAW,EAAE,SAAS,EAAE,GACvB,UAAU,CA8CZ"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Topologically sort module IDs by their dependency edges.
|
|
3
|
+
* Leaf dependencies come first, entry points last.
|
|
4
|
+
* Falls back to original order for any cycle participants.
|
|
5
|
+
*/
|
|
6
|
+
function topologicalSort(moduleIds, edges) {
|
|
7
|
+
const adj = new Map();
|
|
8
|
+
const inDegree = new Map();
|
|
9
|
+
const idSet = new Set(moduleIds);
|
|
10
|
+
for (const id of moduleIds) {
|
|
11
|
+
adj.set(id, []);
|
|
12
|
+
inDegree.set(id, 0);
|
|
13
|
+
}
|
|
14
|
+
for (const edge of edges) {
|
|
15
|
+
if (!idSet.has(edge.sourceId) || !idSet.has(edge.targetId))
|
|
16
|
+
continue;
|
|
17
|
+
// sourceId imports from targetId, so target is a dependency
|
|
18
|
+
// We want dependencies first, so edge direction: targetId -> sourceId in topo order
|
|
19
|
+
adj.get(edge.targetId).push(edge.sourceId);
|
|
20
|
+
inDegree.set(edge.sourceId, (inDegree.get(edge.sourceId) ?? 0) + 1);
|
|
21
|
+
}
|
|
22
|
+
// Kahn's algorithm
|
|
23
|
+
const queue = [];
|
|
24
|
+
for (const [id, deg] of inDegree) {
|
|
25
|
+
if (deg === 0) {
|
|
26
|
+
queue.push(id);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const sorted = [];
|
|
30
|
+
while (queue.length > 0) {
|
|
31
|
+
const node = queue.shift();
|
|
32
|
+
sorted.push(node);
|
|
33
|
+
for (const neighbor of adj.get(node) ?? []) {
|
|
34
|
+
const newDeg = (inDegree.get(neighbor) ?? 1) - 1;
|
|
35
|
+
inDegree.set(neighbor, newDeg);
|
|
36
|
+
if (newDeg === 0) {
|
|
37
|
+
queue.push(neighbor);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Append any modules not reached (cycle participants) at the end
|
|
42
|
+
for (const id of moduleIds) {
|
|
43
|
+
if (!sorted.includes(id)) {
|
|
44
|
+
sorted.push(id);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return sorted;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Generate a "Grand Tour" expedition that visits every module in
|
|
51
|
+
* topological dependency order (leaf deps first, entry points last).
|
|
52
|
+
*
|
|
53
|
+
* No LLM required — uses module summaries if available, otherwise
|
|
54
|
+
* template narration.
|
|
55
|
+
*/
|
|
56
|
+
export function generateGrandTour(modules, moduleEdges) {
|
|
57
|
+
const moduleIds = modules.map((m) => m.id);
|
|
58
|
+
const sortedIds = topologicalSort(moduleIds, moduleEdges);
|
|
59
|
+
// Map for quick lookup
|
|
60
|
+
const moduleMap = new Map(modules.map((m) => [m.id, m]));
|
|
61
|
+
const steps = [];
|
|
62
|
+
for (const modId of sortedIds) {
|
|
63
|
+
const mod = moduleMap.get(modId);
|
|
64
|
+
if (!mod)
|
|
65
|
+
continue;
|
|
66
|
+
const narration = mod.summary ?? `Module: ${mod.name}`;
|
|
67
|
+
// Step 1: Satellite view — highlight the module
|
|
68
|
+
steps.push({
|
|
69
|
+
nodeId: modId,
|
|
70
|
+
zoomLevel: 0,
|
|
71
|
+
narration: `Overview of ${mod.name}: ${narration}`,
|
|
72
|
+
highlightEdges: [],
|
|
73
|
+
highlightNodes: [modId],
|
|
74
|
+
duration: 5,
|
|
75
|
+
});
|
|
76
|
+
// Step 2: Fly into the neighborhood
|
|
77
|
+
steps.push({
|
|
78
|
+
nodeId: modId,
|
|
79
|
+
zoomLevel: 1,
|
|
80
|
+
narration: `Exploring ${mod.name} — ${mod.loc} lines of code, health score ${mod.healthScore}/100.`,
|
|
81
|
+
highlightEdges: [],
|
|
82
|
+
highlightNodes: [modId],
|
|
83
|
+
duration: 5,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
const estimatedMinutes = Math.max(1, Math.round(modules.length * 0.3));
|
|
87
|
+
return {
|
|
88
|
+
id: "expedition:grand-tour",
|
|
89
|
+
title: "Grand Tour",
|
|
90
|
+
description: "A guided tour through every module, following the dependency chain from foundations to entry points.",
|
|
91
|
+
kind: "grand_tour",
|
|
92
|
+
estimatedMinutes,
|
|
93
|
+
steps,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=grand-tour.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grand-tour.js","sourceRoot":"","sources":["../../src/expeditions/grand-tour.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type Database from "better-sqlite3";
|
|
2
|
+
import type { GraphNode, GraphEdge, Expedition } from "../types/index.js";
|
|
3
|
+
import type { OpenAIClient } from "../analysis/semantic/openai-client.js";
|
|
4
|
+
/**
|
|
5
|
+
* Generate a "Request Flow" expedition that traces a request from an
|
|
6
|
+
* entry point through the call graph.
|
|
7
|
+
*
|
|
8
|
+
* Returns null if no entry points are found.
|
|
9
|
+
*/
|
|
10
|
+
export declare function generateRequestFlow(nodes: GraphNode[], callEdges: GraphEdge[], moduleEdges: GraphEdge[], client?: OpenAIClient, db?: Database.Database): Promise<Expedition | null>;
|
|
11
|
+
//# sourceMappingURL=request-flow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-flow.d.ts","sourceRoot":"","sources":["../../src/expeditions/request-flow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAkB,MAAM,mBAAmB,CAAC;AAC1F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAwG1E;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,SAAS,EAAE,EAClB,SAAS,EAAE,SAAS,EAAE,EACtB,WAAW,EAAE,SAAS,EAAE,EACxB,MAAM,CAAC,EAAE,YAAY,EACrB,EAAE,CAAC,EAAE,QAAQ,CAAC,QAAQ,GACrB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAyD5B"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { logger } from "../logger.js";
|
|
2
|
+
const ENTRY_POINT_PATTERN = /route|handler|controller|main|app|index/i;
|
|
3
|
+
const API_LAYERS = new Set(["api", "presentation"]);
|
|
4
|
+
/**
|
|
5
|
+
* Find likely entry-point nodes (API handlers, controllers, etc.).
|
|
6
|
+
*/
|
|
7
|
+
function findEntryPoints(nodes) {
|
|
8
|
+
const candidates = [];
|
|
9
|
+
for (const node of nodes) {
|
|
10
|
+
if (node.kind !== "file")
|
|
11
|
+
continue;
|
|
12
|
+
// Match by architectural layer
|
|
13
|
+
if (node.layer && API_LAYERS.has(node.layer)) {
|
|
14
|
+
candidates.push(node);
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
// Match by name pattern
|
|
18
|
+
if (node.name && ENTRY_POINT_PATTERN.test(node.name)) {
|
|
19
|
+
candidates.push(node);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// Sort by relevance: layer-matched first, then by name pattern
|
|
23
|
+
candidates.sort((a, b) => {
|
|
24
|
+
const aLayer = a.layer && API_LAYERS.has(a.layer) ? 0 : 1;
|
|
25
|
+
const bLayer = b.layer && API_LAYERS.has(b.layer) ? 0 : 1;
|
|
26
|
+
return aLayer - bLayer;
|
|
27
|
+
});
|
|
28
|
+
return candidates;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* BFS from entry point through call edges, collecting visited nodes
|
|
32
|
+
* in order (max `limit` steps).
|
|
33
|
+
*/
|
|
34
|
+
function traceCallPath(entryNodeId, callEdges, nodeMap, limit) {
|
|
35
|
+
// Build adjacency: source -> target[] (caller calls callee)
|
|
36
|
+
const adj = new Map();
|
|
37
|
+
for (const edge of callEdges) {
|
|
38
|
+
const list = adj.get(edge.sourceId) ?? [];
|
|
39
|
+
list.push(edge.targetId);
|
|
40
|
+
adj.set(edge.sourceId, list);
|
|
41
|
+
}
|
|
42
|
+
// For entry at file level, find function nodes that are children of this file
|
|
43
|
+
const entryNode = nodeMap.get(entryNodeId);
|
|
44
|
+
const startIds = [];
|
|
45
|
+
if (entryNode?.kind === "file") {
|
|
46
|
+
// Find function nodes that belong to this file
|
|
47
|
+
for (const [id, node] of nodeMap) {
|
|
48
|
+
if (node.kind === "function" && node.parentId === entryNodeId) {
|
|
49
|
+
startIds.push(id);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// If no function children found, start from the file node itself
|
|
53
|
+
if (startIds.length === 0) {
|
|
54
|
+
startIds.push(entryNodeId);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
startIds.push(entryNodeId);
|
|
59
|
+
}
|
|
60
|
+
const visited = new Set();
|
|
61
|
+
const path = [];
|
|
62
|
+
const queue = [...startIds];
|
|
63
|
+
// Always include the entry file node first
|
|
64
|
+
if (entryNode) {
|
|
65
|
+
path.push(entryNode);
|
|
66
|
+
visited.add(entryNodeId);
|
|
67
|
+
}
|
|
68
|
+
while (queue.length > 0 && path.length < limit) {
|
|
69
|
+
const currentId = queue.shift();
|
|
70
|
+
visited.add(currentId);
|
|
71
|
+
const current = nodeMap.get(currentId);
|
|
72
|
+
if (current && !path.includes(current)) {
|
|
73
|
+
path.push(current);
|
|
74
|
+
}
|
|
75
|
+
for (const targetId of adj.get(currentId) ?? []) {
|
|
76
|
+
if (!visited.has(targetId)) {
|
|
77
|
+
queue.push(targetId);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return path;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Generate a "Request Flow" expedition that traces a request from an
|
|
85
|
+
* entry point through the call graph.
|
|
86
|
+
*
|
|
87
|
+
* Returns null if no entry points are found.
|
|
88
|
+
*/
|
|
89
|
+
export async function generateRequestFlow(nodes, callEdges, moduleEdges, client, db) {
|
|
90
|
+
const entryPoints = findEntryPoints(nodes);
|
|
91
|
+
if (entryPoints.length === 0) {
|
|
92
|
+
logger.debug("No entry points found for request flow expedition");
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
const nodeMap = new Map(nodes.map((n) => [n.id, n]));
|
|
96
|
+
// Use the first (most relevant) entry point
|
|
97
|
+
const entry = entryPoints[0];
|
|
98
|
+
const tracedPath = traceCallPath(entry.id, callEdges, nodeMap, 15);
|
|
99
|
+
if (tracedPath.length < 2) {
|
|
100
|
+
logger.debug("Request flow trace too short (< 2 nodes), skipping");
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
const steps = tracedPath.map((node, idx) => {
|
|
104
|
+
// Progress from zoom level 1 to 2 as we go deeper
|
|
105
|
+
const zoomLevel = idx < 2 ? 1 : 2;
|
|
106
|
+
// Find edges from previous node to this node for highlighting
|
|
107
|
+
const highlightEdges = [];
|
|
108
|
+
if (idx > 0) {
|
|
109
|
+
const prevNode = tracedPath[idx - 1];
|
|
110
|
+
for (const edge of callEdges) {
|
|
111
|
+
if (edge.sourceId === prevNode.id && edge.targetId === node.id) {
|
|
112
|
+
highlightEdges.push(`${edge.sourceId}|${edge.targetId}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const narration = node.kind === "function"
|
|
117
|
+
? `Step ${idx + 1}: Function ${node.name} — ${node.summary ?? `${node.loc} lines, complexity ${node.complexity}`}`
|
|
118
|
+
: `Step ${idx + 1}: ${node.name} — ${node.summary ?? `${node.loc} lines of code`}`;
|
|
119
|
+
return {
|
|
120
|
+
nodeId: node.id,
|
|
121
|
+
zoomLevel,
|
|
122
|
+
narration,
|
|
123
|
+
highlightEdges,
|
|
124
|
+
highlightNodes: [node.id],
|
|
125
|
+
duration: 6,
|
|
126
|
+
};
|
|
127
|
+
});
|
|
128
|
+
const estimatedMinutes = Math.max(1, Math.round(steps.length * 6 / 60));
|
|
129
|
+
return {
|
|
130
|
+
id: "expedition:request-flow",
|
|
131
|
+
title: "Request Lifecycle",
|
|
132
|
+
description: `Trace a request from ${entry.name} through the call graph to see how data flows through the system.`,
|
|
133
|
+
kind: "request_flow",
|
|
134
|
+
estimatedMinutes,
|
|
135
|
+
steps,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=request-flow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-flow.js","sourceRoot":"","sources":["../../src/expeditions/request-flow.ts"],"names":[],"mappings":"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"}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { GraphNode, GraphEdge, ModuleInfo, FileAnalysis } from "../types/index.js";
|
|
2
|
+
import type { FileMetrics, ModuleMetrics } from "../analysis/metrics.js";
|
|
3
|
+
import type { GitArchaeologyResult } from "../analysis/git/archaeology.js";
|
|
4
|
+
import type { SummarizationResult } from "../analysis/semantic/summarizer.js";
|
|
5
|
+
import type { CallGraphResult } from "../analysis/call-graph.js";
|
|
6
|
+
export interface BuildGraphOptions {
|
|
7
|
+
modules: ModuleInfo[];
|
|
8
|
+
analyses: FileAnalysis[];
|
|
9
|
+
moduleEdges: GraphEdge[];
|
|
10
|
+
fileMetrics: Map<string, FileMetrics>;
|
|
11
|
+
moduleMetrics: Map<string, ModuleMetrics>;
|
|
12
|
+
rootDir: string;
|
|
13
|
+
gitResult?: GitArchaeologyResult;
|
|
14
|
+
healthScores?: Map<string, number>;
|
|
15
|
+
summarization?: SummarizationResult;
|
|
16
|
+
callGraphResult?: CallGraphResult;
|
|
17
|
+
}
|
|
18
|
+
export interface BuildGraphResult {
|
|
19
|
+
nodes: GraphNode[];
|
|
20
|
+
edges: GraphEdge[];
|
|
21
|
+
}
|
|
22
|
+
export declare function buildGraph(opts: BuildGraphOptions): BuildGraphResult;
|
|
23
|
+
//# sourceMappingURL=builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../src/graph/builder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACxF,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAMjE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,WAAW,EAAE,SAAS,EAAE,CAAC;IACzB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACtC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,oBAAoB,CAAC;IACjC,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AA2BD,wBAAgB,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,gBAAgB,CA0HpE"}
|