autodocs-engine 0.9.9 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +123 -117
  2. package/dist/anti-pattern-detector.js +22 -0
  3. package/dist/anti-pattern-detector.js.map +1 -1
  4. package/dist/ast-parser.js +31 -3
  5. package/dist/ast-parser.js.map +1 -1
  6. package/dist/benchmark/scorer.js +3 -1
  7. package/dist/benchmark/scorer.js.map +1 -1
  8. package/dist/bin/autodocs-engine.js +7 -0
  9. package/dist/bin/autodocs-engine.js.map +1 -1
  10. package/dist/bin/serve.d.ts +1 -0
  11. package/dist/bin/serve.js +5 -1
  12. package/dist/bin/serve.js.map +1 -1
  13. package/dist/bin/setup-hooks.d.ts +1 -0
  14. package/dist/bin/setup-hooks.js +59 -0
  15. package/dist/bin/setup-hooks.js.map +1 -0
  16. package/dist/config.d.ts +1 -0
  17. package/dist/config.js +4 -0
  18. package/dist/config.js.map +1 -1
  19. package/dist/convention-extractor.js +10 -0
  20. package/dist/convention-extractor.js.map +1 -1
  21. package/dist/detectors/api-patterns.d.ts +2 -0
  22. package/dist/detectors/api-patterns.js +101 -0
  23. package/dist/detectors/api-patterns.js.map +1 -0
  24. package/dist/detectors/async-patterns.d.ts +2 -0
  25. package/dist/detectors/async-patterns.js +79 -0
  26. package/dist/detectors/async-patterns.js.map +1 -0
  27. package/dist/detectors/error-handling.js +82 -30
  28. package/dist/detectors/error-handling.js.map +1 -1
  29. package/dist/detectors/state-management.d.ts +2 -0
  30. package/dist/detectors/state-management.js +75 -0
  31. package/dist/detectors/state-management.js.map +1 -0
  32. package/dist/execution-flow.d.ts +23 -0
  33. package/dist/execution-flow.js +286 -0
  34. package/dist/execution-flow.js.map +1 -0
  35. package/dist/git-history.js +18 -7
  36. package/dist/git-history.js.map +1 -1
  37. package/dist/implicit-coupling.d.ts +7 -0
  38. package/dist/implicit-coupling.js +40 -0
  39. package/dist/implicit-coupling.js.map +1 -0
  40. package/dist/import-chain.js +12 -3
  41. package/dist/import-chain.js.map +1 -1
  42. package/dist/index.js +20 -1
  43. package/dist/index.js.map +1 -1
  44. package/dist/llm/serializer.js +8 -6
  45. package/dist/llm/serializer.js.map +1 -1
  46. package/dist/mcp/cache.d.ts +11 -1
  47. package/dist/mcp/cache.js +49 -7
  48. package/dist/mcp/cache.js.map +1 -1
  49. package/dist/mcp/queries.d.ts +19 -3
  50. package/dist/mcp/queries.js +342 -62
  51. package/dist/mcp/queries.js.map +1 -1
  52. package/dist/mcp/server.d.ts +1 -0
  53. package/dist/mcp/server.js +42 -1
  54. package/dist/mcp/server.js.map +1 -1
  55. package/dist/mcp/tools.d.ts +1 -0
  56. package/dist/mcp/tools.js +162 -20
  57. package/dist/mcp/tools.js.map +1 -1
  58. package/dist/output-validator.js +73 -0
  59. package/dist/output-validator.js.map +1 -1
  60. package/dist/pipeline.js +37 -0
  61. package/dist/pipeline.js.map +1 -1
  62. package/dist/symbol-graph.js +4 -0
  63. package/dist/symbol-graph.js.map +1 -1
  64. package/dist/type-enricher.d.ts +17 -0
  65. package/dist/type-enricher.js +127 -0
  66. package/dist/type-enricher.js.map +1 -0
  67. package/dist/type-resolver.d.ts +13 -0
  68. package/dist/type-resolver.js +75 -0
  69. package/dist/type-resolver.js.map +1 -0
  70. package/dist/types.d.ts +36 -3
  71. package/dist/types.js +5 -1
  72. package/dist/types.js.map +1 -1
  73. package/hooks/autodocs-hook.cjs +227 -0
  74. package/package.json +3 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async-patterns.js","sourceRoot":"","sources":["../../src/detectors/async-patterns.ts"],"names":[],"mappings":"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"}
@@ -1,47 +1,99 @@
1
- import { sourceParsedFiles } from "../convention-extractor.js";
2
- export const errorHandlingDetector = (files, tiers, _warnings) => {
1
+ // src/detectors/error-handling.ts Error handling pattern detector
2
+ // Detects: custom error classes, Result/Either patterns, error class hierarchies.
3
+ // Does NOT use try/catch density — per adversarial review, that's a false signal
4
+ // (mature codebases use middleware/Result types, not widespread try/catch).
5
+ import { buildConfidence, sourceParsedFiles } from "../convention-extractor.js";
6
+ // Libraries that provide typed error/result patterns
7
+ const RESULT_LIBRARIES = {
8
+ neverthrow: "neverthrow (Result<T, E>)",
9
+ "fp-ts": "fp-ts (Either<E, A>)",
10
+ "oxide.ts": "oxide.ts (Result<T, E>)",
11
+ effect: "Effect (typed errors via Effect<A, E, R>)",
12
+ "ts-results": "ts-results (Result<T, E>)",
13
+ "true-myth": "true-myth (Result<T, E>)",
14
+ };
15
+ // Names that suggest a custom Result/Either type
16
+ const RESULT_EXPORT_NAMES = new Set(["Result", "Ok", "Err", "Either", "Left", "Right", "Success", "Failure"]);
17
+ export const errorHandlingDetector = (files, tiers, _warnings, _context) => {
3
18
  const conventions = [];
4
19
  const sourceFiles = sourceParsedFiles(files, tiers);
5
20
  if (sourceFiles.length === 0)
6
21
  return conventions;
7
- let tryCatchTotal = 0;
8
- let filesWithTryCatch = 0;
9
- let errorBoundaryCount = 0;
10
- for (const f of sourceFiles) {
11
- if (f.contentSignals.tryCatchCount > 0) {
12
- tryCatchTotal += f.contentSignals.tryCatchCount;
13
- filesWithTryCatch++;
22
+ // 1. Custom error classes — exports with kind:"class" and name ending in Error/Exception
23
+ const errorClasses = [];
24
+ for (const file of sourceFiles) {
25
+ for (const exp of file.exports) {
26
+ if (exp.kind === "class" && (/Error$/.test(exp.name) || /Exception$/.test(exp.name))) {
27
+ errorClasses.push(exp.name);
28
+ }
14
29
  }
15
- if (f.contentSignals.hasErrorBoundary)
16
- errorBoundaryCount++;
17
30
  }
18
- if (tryCatchTotal > 0) {
31
+ if (errorClasses.length >= 2) {
32
+ // Check for hierarchy pattern: multiple error classes suggest a typed error hierarchy
33
+ const isHierarchy = errorClasses.length >= 3;
34
+ const name = isHierarchy ? "Typed error class hierarchy" : "Custom error classes";
35
+ const description = isHierarchy
36
+ ? `Uses a hierarchy of ${errorClasses.length} typed error classes (${errorClasses.slice(0, 3).join(", ")}${errorClasses.length > 3 ? `, ...${errorClasses.length - 3} more` : ""})`
37
+ : `Defines custom error classes: ${errorClasses.join(", ")}`;
19
38
  conventions.push({
20
39
  category: "error-handling",
21
- name: "Try-catch error handling",
22
- description: `Uses try-catch blocks for error handling`,
23
- confidence: conf(filesWithTryCatch, sourceFiles.length),
24
- examples: [`${tryCatchTotal} try-catch blocks in ${filesWithTryCatch} files`],
40
+ source: "errorHandling",
41
+ name,
42
+ description,
43
+ confidence: buildConfidence(errorClasses.length, errorClasses.length),
44
+ examples: errorClasses.slice(0, 5),
25
45
  });
26
46
  }
27
- if (errorBoundaryCount > 0) {
47
+ // 2. Result/Either pattern — check imports for known result-type libraries (count files, not imports)
48
+ const resultLibraryImports = new Map();
49
+ for (const file of sourceFiles) {
50
+ const fileLibs = new Set(); // dedupe per file
51
+ for (const imp of file.imports) {
52
+ if (imp.isTypeOnly)
53
+ continue;
54
+ for (const [pkg, label] of Object.entries(RESULT_LIBRARIES)) {
55
+ if (imp.moduleSpecifier === pkg || imp.moduleSpecifier.startsWith(`${pkg}/`)) {
56
+ fileLibs.add(label);
57
+ }
58
+ }
59
+ }
60
+ for (const label of fileLibs) {
61
+ resultLibraryImports.set(label, (resultLibraryImports.get(label) ?? 0) + 1);
62
+ }
63
+ }
64
+ if (resultLibraryImports.size > 0) {
65
+ const totalFiles = [...resultLibraryImports.values()].reduce((a, b) => a + b, 0);
66
+ const libs = [...resultLibraryImports.entries()].sort((a, b) => b[1] - a[1]);
28
67
  conventions.push({
29
68
  category: "error-handling",
30
- name: "Error boundaries",
31
- description: `Uses React Error Boundaries for UI error handling`,
32
- confidence: conf(errorBoundaryCount, sourceFiles.length),
33
- examples: [`${errorBoundaryCount} files reference ErrorBoundary`],
69
+ source: "errorHandling",
70
+ name: "Result/Either pattern",
71
+ description: `Uses ${libs[0][0]} for typed error handling (${totalFiles} files)`,
72
+ confidence: buildConfidence(totalFiles, sourceFiles.length),
73
+ examples: libs.map(([lib, count]) => `${lib}: ${count} files`),
34
74
  });
35
75
  }
76
+ // 3. Custom Result types — exports named Result/Ok/Err/Either without a library
77
+ if (resultLibraryImports.size === 0) {
78
+ const resultExports = [];
79
+ for (const file of sourceFiles) {
80
+ for (const exp of file.exports) {
81
+ if (RESULT_EXPORT_NAMES.has(exp.name) && (exp.kind === "type" || exp.kind === "interface")) {
82
+ resultExports.push(exp.name);
83
+ }
84
+ }
85
+ }
86
+ if (resultExports.length >= 2) {
87
+ conventions.push({
88
+ category: "error-handling",
89
+ source: "errorHandling",
90
+ name: "Custom Result type pattern",
91
+ description: `Defines custom Result types: ${[...new Set(resultExports)].join(", ")}`,
92
+ confidence: buildConfidence(resultExports.length, resultExports.length),
93
+ examples: [...new Set(resultExports)].slice(0, 5),
94
+ });
95
+ }
96
+ }
36
97
  return conventions;
37
98
  };
38
- function conf(matched, total) {
39
- const percentage = total > 0 ? Math.round((matched / total) * 100) : 0;
40
- return {
41
- matched,
42
- total,
43
- percentage,
44
- description: `${matched} of ${total} (${percentage}%)`,
45
- };
46
- }
47
99
  //# sourceMappingURL=error-handling.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"error-handling.js","sourceRoot":"","sources":["../../src/detectors/error-handling.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAE/D,MAAM,CAAC,MAAM,qBAAqB,GAAuB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE;IACnF,MAAM,WAAW,GAAiB,EAAE,CAAC;IACrC,MAAM,WAAW,GAAG,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACpD,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,WAAW,CAAC;IAEjD,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,iBAAiB,GAAG,CAAC,CAAC;IAC1B,IAAI,kBAAkB,GAAG,CAAC,CAAC;IAE3B,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;QAC5B,IAAI,CAAC,CAAC,cAAc,CAAC,aAAa,GAAG,CAAC,EAAE,CAAC;YACvC,aAAa,IAAI,CAAC,CAAC,cAAc,CAAC,aAAa,CAAC;YAChD,iBAAiB,EAAE,CAAC;QACtB,CAAC;QACD,IAAI,CAAC,CAAC,cAAc,CAAC,gBAAgB;YAAE,kBAAkB,EAAE,CAAC;IAC9D,CAAC;IAED,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;QACtB,WAAW,CAAC,IAAI,CAAC;YACf,QAAQ,EAAE,gBAAgB;YAC1B,IAAI,EAAE,0BAA0B;YAChC,WAAW,EAAE,0CAA0C;YACvD,UAAU,EAAE,IAAI,CAAC,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAAC;YACvD,QAAQ,EAAE,CAAC,GAAG,aAAa,wBAAwB,iBAAiB,QAAQ,CAAC;SAC9E,CAAC,CAAC;IACL,CAAC;IAED,IAAI,kBAAkB,GAAG,CAAC,EAAE,CAAC;QAC3B,WAAW,CAAC,IAAI,CAAC;YACf,QAAQ,EAAE,gBAAgB;YAC1B,IAAI,EAAE,kBAAkB;YACxB,WAAW,EAAE,mDAAmD;YAChE,UAAU,EAAE,IAAI,CAAC,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAAC;YACxD,QAAQ,EAAE,CAAC,GAAG,kBAAkB,gCAAgC,CAAC;SAClE,CAAC,CAAC;IACL,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC,CAAC;AAEF,SAAS,IAAI,CAAC,OAAe,EAAE,KAAa;IAC1C,MAAM,UAAU,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACvE,OAAO;QACL,OAAO;QACP,KAAK;QACL,UAAU;QACV,WAAW,EAAE,GAAG,OAAO,OAAO,KAAK,KAAK,UAAU,IAAI;KACvD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"error-handling.js","sourceRoot":"","sources":["../../src/detectors/error-handling.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { ConventionDetector } from "../types.js";
2
+ export declare const stateManagementDetector: ConventionDetector;
@@ -0,0 +1,75 @@
1
+ // src/detectors/state-management.ts — State management pattern detector
2
+ // Import-based detection for Redux, Zustand, Jotai, MobX, Recoil, Signals, Context API.
3
+ // Reports ALL detected libraries (dominant + supplementary) per adversarial review.
4
+ import { buildConfidence, sourceParsedFiles } from "../convention-extractor.js";
5
+ const STATE_LIBRARIES = {
6
+ redux: { label: "Redux", packages: ["@reduxjs/toolkit", "react-redux", "redux"] },
7
+ zustand: { label: "Zustand", packages: ["zustand"] },
8
+ jotai: { label: "Jotai", packages: ["jotai"] },
9
+ recoil: { label: "Recoil", packages: ["recoil"] },
10
+ mobx: { label: "MobX", packages: ["mobx", "mobx-react", "mobx-react-lite"] },
11
+ signals: { label: "Signals", packages: ["@preact/signals", "@preact/signals-react", "@angular/core"] },
12
+ valtio: { label: "Valtio", packages: ["valtio"] },
13
+ xstate: { label: "XState", packages: ["xstate", "@xstate/react"] },
14
+ };
15
+ export const stateManagementDetector = (files, tiers, _warnings, _context) => {
16
+ const conventions = [];
17
+ const sourceFiles = sourceParsedFiles(files, tiers);
18
+ if (sourceFiles.length === 0)
19
+ return conventions;
20
+ // Count files importing each state management library
21
+ const libFileCounts = new Map(); // library key → file count
22
+ for (const file of sourceFiles) {
23
+ const fileLibs = new Set(); // dedupe per file
24
+ for (const imp of file.imports) {
25
+ if (imp.isTypeOnly)
26
+ continue;
27
+ for (const [key, { packages }] of Object.entries(STATE_LIBRARIES)) {
28
+ if (packages.some((pkg) => imp.moduleSpecifier === pkg || imp.moduleSpecifier.startsWith(`${pkg}/`))) {
29
+ fileLibs.add(key);
30
+ }
31
+ }
32
+ }
33
+ for (const key of fileLibs) {
34
+ libFileCounts.set(key, (libFileCounts.get(key) ?? 0) + 1);
35
+ }
36
+ }
37
+ // Detect Context API usage: imports of createContext from react
38
+ let contextApiFiles = 0;
39
+ for (const file of sourceFiles) {
40
+ for (const imp of file.imports) {
41
+ if (imp.isTypeOnly)
42
+ continue;
43
+ if (imp.moduleSpecifier === "react" && imp.importedNames.includes("createContext")) {
44
+ contextApiFiles++;
45
+ break;
46
+ }
47
+ }
48
+ }
49
+ if (contextApiFiles > 0) {
50
+ libFileCounts.set("context", contextApiFiles);
51
+ }
52
+ if (libFileCounts.size === 0)
53
+ return conventions;
54
+ // Sort by file count descending
55
+ const sorted = [...libFileCounts.entries()].sort((a, b) => b[1] - a[1]);
56
+ const totalFiles = sorted.reduce((sum, [, count]) => sum + count, 0);
57
+ // Build description showing all detected libraries with roles
58
+ const dominant = sorted[0];
59
+ const dominantLabel = dominant[0] === "context" ? "React Context API" : (STATE_LIBRARIES[dominant[0]]?.label ?? dominant[0]);
60
+ const parts = [];
61
+ for (const [key, count] of sorted) {
62
+ const label = key === "context" ? "React Context API" : (STATE_LIBRARIES[key]?.label ?? key);
63
+ parts.push(`${label} (${count} files)`);
64
+ }
65
+ conventions.push({
66
+ category: "state-management",
67
+ source: "stateManagement",
68
+ name: sorted.length === 1 ? `${dominantLabel} state management` : `${dominantLabel} + ${sorted.length - 1} more`,
69
+ description: sorted.length === 1 ? `Uses ${dominantLabel} for state management` : `State management: ${parts.join(", ")}`,
70
+ confidence: buildConfidence(totalFiles, sourceFiles.length),
71
+ examples: parts,
72
+ });
73
+ return conventions;
74
+ };
75
+ //# sourceMappingURL=state-management.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-management.js","sourceRoot":"","sources":["../../src/detectors/state-management.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { CallGraphEdge, CoChangeEdge, DependencyInsights, ExecutionFlow, PublicAPIEntry } from "./types.js";
2
+ type NodeId = string;
3
+ interface ScoredEntry {
4
+ nodeId: NodeId;
5
+ score: number;
6
+ }
7
+ export declare function scoreEntryPoints(callGraph: CallGraphEdge[], publicAPI: PublicAPIEntry[], dependencyInsights?: DependencyInsights): ScoredEntry[];
8
+ interface RawFlow {
9
+ nodeIds: NodeId[];
10
+ }
11
+ export declare function traceFlows(callGraph: CallGraphEdge[], entries: ScoredEntry[]): RawFlow[];
12
+ export declare function deduplicateFlows(candidates: RawFlow[], maxFlows: number): RawFlow[];
13
+ /**
14
+ * Enrich existing flows with co-change confidence scores.
15
+ * Called after git history is attached to the package analysis.
16
+ */
17
+ export declare function enrichFlowConfidence(flows: ExecutionFlow[], coChangeEdges: CoChangeEdge[]): void;
18
+ /**
19
+ * Detect execution flows via forward BFS from scored entry points.
20
+ * Returns empty array if call graph is too sparse (<10 edges) or package is React-only.
21
+ */
22
+ export declare function computeExecutionFlows(callGraph: CallGraphEdge[], publicAPI: PublicAPIEntry[], dependencyInsights?: DependencyInsights, coChangeEdges?: CoChangeEdge[]): ExecutionFlow[];
23
+ export {};
@@ -0,0 +1,286 @@
1
+ // src/execution-flow.ts — Execution flow tracing via forward BFS from entry points.
2
+ // Detects labeled execution paths: "runPipeline → analyzePackage → buildSymbolGraph (3 steps)"
3
+ // Uses spine-first tracing (full primary chain + fork paths) instead of fixed maxBranching.
4
+ // Co-change Jaccard validates flows — our unique advantage over GitNexus.
5
+ // ─── Constants ───────────────────────────────────────────────────────────────
6
+ const MIN_CALL_GRAPH_EDGES = 10; // Skip flow detection for sparse graphs
7
+ const MAX_TRACE_DEPTH = 10; // Maximum steps in a single flow
8
+ const MIN_STEPS = 3; // Minimum steps for a meaningful flow
9
+ const MAX_FORK_PATHS = 3; // Alternative callees explored at each spine node
10
+ const MAX_TRACES_PER_ENTRY = 15; // Cap traces from a single entry point
11
+ function makeNodeId(file, fn) {
12
+ return `${file}#${fn}`;
13
+ }
14
+ function nodeName(id) {
15
+ return id.split("#")[1];
16
+ }
17
+ function nodeFile(id) {
18
+ return id.split("#")[0];
19
+ }
20
+ // ─── Entry Point Scoring ─────────────────────────────────────────────────────
21
+ // Boost: patterns that indicate genuine entry points in TS/JS
22
+ const ENTRY_PATTERNS = /^(main|run|start|handle|execute|process|serve|init|bootstrap|listen|register|setup|configure|launch)/i;
23
+ const ENTRY_SUFFIX_PATTERNS = /(?:Controller|Middleware|Handler|Router|Command|Plugin)$/;
24
+ // Penalty: utility functions that are rarely true entry points
25
+ const UTILITY_PATTERNS = /^(get|set|is|has|to|from|parse|format|validate|normalize|ensure|assert|check|clone|merge|map|filter|reduce|compose|pipe|wrap|create(?!.*Server))/i;
26
+ // Exclude: test orchestration functions
27
+ const TEST_PATTERNS = /^(describe|it|test|beforeEach|afterEach|beforeAll|afterAll|expect)$/;
28
+ // Framework-specific: high-value entry points detected from dependencies
29
+ const FRAMEWORK_PATTERNS = {
30
+ next: { patterns: [/^(getServerSideProps|getStaticProps|getStaticPaths|loader|action|default)$/], multiplier: 2.5 },
31
+ express: { patterns: [/Middleware$/i, /Router$/i], multiplier: 2.5 },
32
+ fastify: { patterns: [/Middleware$/i, /Router$/i], multiplier: 2.5 },
33
+ hono: { patterns: [/Middleware$/i, /Handler$/i], multiplier: 2.5 },
34
+ "@nestjs/core": { patterns: [/Controller$/i], multiplier: 2.5 },
35
+ "@nestjs/common": { patterns: [/Controller$/i], multiplier: 2.5 },
36
+ };
37
+ export function scoreEntryPoints(callGraph, publicAPI, dependencyInsights) {
38
+ // Build adjacency counts
39
+ const outDegree = new Map();
40
+ const inDegree = new Map();
41
+ const allNodes = new Set();
42
+ for (const edge of callGraph) {
43
+ const from = makeNodeId(edge.fromFile, edge.from);
44
+ const to = makeNodeId(edge.toFile, edge.to);
45
+ allNodes.add(from);
46
+ allNodes.add(to);
47
+ outDegree.set(from, (outDegree.get(from) ?? 0) + 1);
48
+ inDegree.set(to, (inDegree.get(to) ?? 0) + 1);
49
+ }
50
+ // Detect active frameworks for multipliers
51
+ const activeFrameworks = new Set();
52
+ if (dependencyInsights?.frameworks) {
53
+ for (const fw of dependencyInsights.frameworks) {
54
+ if (FRAMEWORK_PATTERNS[fw.name])
55
+ activeFrameworks.add(fw.name);
56
+ }
57
+ }
58
+ const exportedNames = new Set(publicAPI.filter((e) => !e.isTypeOnly).map((e) => e.name));
59
+ const scored = [];
60
+ for (const nodeId of allNodes) {
61
+ const fn = nodeName(nodeId);
62
+ const out = outDegree.get(nodeId) ?? 0;
63
+ const inD = inDegree.get(nodeId) ?? 0;
64
+ // Exclude test orchestration
65
+ if (TEST_PATTERNS.test(fn))
66
+ continue;
67
+ // Base: functions with high out-degree relative to in-degree are entry-like
68
+ const baseScore = (out + 1) / (inD + 1);
69
+ // Export boost: exported functions are more likely externally invoked
70
+ const exportMul = exportedNames.has(fn) ? 1.5 : 1.0;
71
+ // Zero-caller boost: exported with no internal callers = likely framework-invoked
72
+ const externalOnlyMul = inD === 0 && out >= 2 && exportedNames.has(fn) ? 1.8 : 1.0;
73
+ // Framework multiplier (checked first — overrides name penalty for framework entry points)
74
+ let frameworkMul = 1.0;
75
+ for (const fwName of activeFrameworks) {
76
+ const fw = FRAMEWORK_PATTERNS[fwName];
77
+ if (fw.patterns.some((p) => p.test(fn))) {
78
+ frameworkMul = Math.max(frameworkMul, fw.multiplier);
79
+ }
80
+ }
81
+ // Name pattern multiplier (skip penalty if framework multiplier already boosted)
82
+ let nameMul = 1.0;
83
+ if (ENTRY_PATTERNS.test(fn) || ENTRY_SUFFIX_PATTERNS.test(fn))
84
+ nameMul = 2.0;
85
+ else if (UTILITY_PATTERNS.test(fn) && frameworkMul <= 1.0)
86
+ nameMul = 0.3;
87
+ const score = baseScore * exportMul * externalOnlyMul * nameMul * frameworkMul;
88
+ if (score > 0)
89
+ scored.push({ nodeId, score });
90
+ }
91
+ // Dynamic cap: scale with codebase size
92
+ const maxEntries = Math.max(10, Math.min(200, Math.floor(allNodes.size / 10)));
93
+ scored.sort((a, b) => b.score - a.score);
94
+ return scored.slice(0, maxEntries);
95
+ }
96
+ export function traceFlows(callGraph, entries) {
97
+ // Build forward adjacency with out-degree for callee ranking
98
+ const adj = new Map();
99
+ const outDegree = new Map();
100
+ for (const edge of callGraph) {
101
+ const from = makeNodeId(edge.fromFile, edge.from);
102
+ const to = makeNodeId(edge.toFile, edge.to);
103
+ const callees = adj.get(from) ?? [];
104
+ callees.push(to);
105
+ adj.set(from, callees);
106
+ outDegree.set(to, (outDegree.get(to) ?? 0) + (adj.get(to)?.length ?? 0));
107
+ }
108
+ // Recount out-degree properly
109
+ for (const [node, callees] of adj) {
110
+ outDegree.set(node, callees.length);
111
+ }
112
+ const allFlows = [];
113
+ for (const entry of entries) {
114
+ const traces = [];
115
+ // PRIMARY SPINE: follow highest out-degree callee at each step (no branching limit)
116
+ const spine = traceSpine(entry.nodeId, adj, outDegree);
117
+ if (spine.length >= MIN_STEPS) {
118
+ traces.push({ nodeIds: spine });
119
+ }
120
+ // FORK PATHS: at each spine node, explore alternative callees
121
+ for (let i = 0; i < spine.length && traces.length < MAX_TRACES_PER_ENTRY; i++) {
122
+ const node = spine[i];
123
+ const callees = adj.get(node) ?? [];
124
+ if (callees.length <= 1)
125
+ continue; // No forks at this node
126
+ // Sort callees by out-degree descending, skip the spine callee
127
+ const spineNext = i + 1 < spine.length ? spine[i + 1] : null;
128
+ const forks = callees
129
+ .filter((c) => c !== spineNext)
130
+ .sort((a, b) => (outDegree.get(b) ?? 0) - (outDegree.get(a) ?? 0))
131
+ .slice(0, MAX_FORK_PATHS);
132
+ for (const fork of forks) {
133
+ // Trace a sub-spine from this fork point
134
+ const pathPrefix = spine.slice(0, i + 1);
135
+ const visited = new Set(pathPrefix);
136
+ if (visited.has(fork))
137
+ continue;
138
+ const forkSpine = traceSpine(fork, adj, outDegree, visited);
139
+ const fullPath = [...pathPrefix, ...forkSpine];
140
+ if (fullPath.length >= MIN_STEPS) {
141
+ traces.push({ nodeIds: fullPath });
142
+ }
143
+ }
144
+ }
145
+ allFlows.push(...traces);
146
+ }
147
+ return allFlows;
148
+ }
149
+ /** Trace a single spine: follow highest out-degree callee at each step. */
150
+ function traceSpine(start, adj, outDegree, visited) {
151
+ const path = [start];
152
+ const seen = visited ?? new Set([start]);
153
+ if (visited)
154
+ seen.add(start);
155
+ let current = start;
156
+ for (let depth = 1; depth < MAX_TRACE_DEPTH; depth++) {
157
+ const callees = (adj.get(current) ?? []).filter((c) => !seen.has(c));
158
+ if (callees.length === 0)
159
+ break;
160
+ // Pick callee with highest out-degree (leads to deeper paths)
161
+ // Tie-break: alphabetical nodeId for determinism
162
+ callees.sort((a, b) => {
163
+ const diff = (outDegree.get(b) ?? 0) - (outDegree.get(a) ?? 0);
164
+ return diff !== 0 ? diff : a.localeCompare(b);
165
+ });
166
+ const next = callees[0];
167
+ seen.add(next);
168
+ path.push(next);
169
+ current = next;
170
+ }
171
+ return path;
172
+ }
173
+ // ─── Deduplication ───────────────────────────────────────────────────────────
174
+ export function deduplicateFlows(candidates, maxFlows) {
175
+ // Sort by length descending — longer flows are preferred
176
+ const sorted = [...candidates].sort((a, b) => b.nodeIds.length - a.nodeIds.length);
177
+ // Phase 1: Subset removal — discard flows that are contiguous subpaths of a longer flow
178
+ const kept = [];
179
+ for (const flow of sorted) {
180
+ const isSubset = kept.some((existing) => isContiguousSubpath(flow.nodeIds, existing.nodeIds));
181
+ if (!isSubset)
182
+ kept.push(flow);
183
+ }
184
+ // Phase 2: Endpoint dedup — keep longest per (entry, terminal) pair
185
+ const byEndpoints = new Map();
186
+ for (const flow of kept) {
187
+ const key = `${flow.nodeIds[0]}::${flow.nodeIds[flow.nodeIds.length - 1]}`;
188
+ const existing = byEndpoints.get(key);
189
+ if (!existing || flow.nodeIds.length > existing.nodeIds.length) {
190
+ byEndpoints.set(key, flow);
191
+ }
192
+ }
193
+ return [...byEndpoints.values()].sort((a, b) => b.nodeIds.length - a.nodeIds.length).slice(0, maxFlows);
194
+ }
195
+ /** Check if `sub` is a contiguous subpath of `sup` (sliding window). */
196
+ function isContiguousSubpath(sub, sup) {
197
+ if (sub.length >= sup.length)
198
+ return false;
199
+ for (let i = 0; i <= sup.length - sub.length; i++) {
200
+ if (sub.every((step, j) => step === sup[i + j]))
201
+ return true;
202
+ }
203
+ return false;
204
+ }
205
+ // ─── Co-Change Confidence ────────────────────────────────────────────────────
206
+ function computeFlowConfidence(files, coChangeEdges) {
207
+ if (!coChangeEdges || coChangeEdges.length === 0 || files.length < 2)
208
+ return 0;
209
+ // Build fast pairwise Jaccard lookup
210
+ const jaccardMap = new Map();
211
+ for (const e of coChangeEdges) {
212
+ jaccardMap.set(`${e.file1}\0${e.file2}`, e.jaccard);
213
+ jaccardMap.set(`${e.file2}\0${e.file1}`, e.jaccard);
214
+ }
215
+ let total = 0;
216
+ let pairs = 0;
217
+ for (let i = 0; i < files.length - 1; i++) {
218
+ if (files[i] === files[i + 1])
219
+ continue; // Skip same-file adjacent steps
220
+ total += jaccardMap.get(`${files[i]}\0${files[i + 1]}`) ?? 0;
221
+ pairs++;
222
+ }
223
+ return pairs > 0 ? total / pairs : 0;
224
+ }
225
+ // ─── Label Generation ────────────────────────────────────────────────────────
226
+ function generateLabel(steps, files) {
227
+ const uniqueFiles = new Set(files).size;
228
+ if (steps.length <= 4) {
229
+ return `${steps.join(" → ")} (${steps.length} steps, ${uniqueFiles} files)`;
230
+ }
231
+ return `${steps[0]} → ${steps[1]} → ... → ${steps[steps.length - 1]} (${steps.length} steps, ${uniqueFiles} files)`;
232
+ }
233
+ // ─── Public API ──────────────────────────────────────────────────────────────
234
+ /**
235
+ * Enrich existing flows with co-change confidence scores.
236
+ * Called after git history is attached to the package analysis.
237
+ */
238
+ export function enrichFlowConfidence(flows, coChangeEdges) {
239
+ for (const flow of flows) {
240
+ flow.confidence = computeFlowConfidence(flow.files, coChangeEdges);
241
+ }
242
+ // Re-sort by confidence
243
+ flows.sort((a, b) => b.confidence - a.confidence || b.length - a.length);
244
+ }
245
+ /**
246
+ * Detect execution flows via forward BFS from scored entry points.
247
+ * Returns empty array if call graph is too sparse (<10 edges) or package is React-only.
248
+ */
249
+ export function computeExecutionFlows(callGraph, publicAPI, dependencyInsights, coChangeEdges) {
250
+ if (callGraph.length < MIN_CALL_GRAPH_EDGES)
251
+ return [];
252
+ // Score and select entry points
253
+ const entries = scoreEntryPoints(callGraph, publicAPI, dependencyInsights);
254
+ if (entries.length === 0)
255
+ return [];
256
+ // Trace flows via spine-first BFS
257
+ const rawFlows = traceFlows(callGraph, entries);
258
+ if (rawFlows.length === 0)
259
+ return [];
260
+ // Deduplicate
261
+ const functionCount = new Set(callGraph.flatMap((e) => [makeNodeId(e.fromFile, e.from), makeNodeId(e.toFile, e.to)]))
262
+ .size;
263
+ const maxFlows = Math.max(10, Math.min(200, Math.floor(functionCount / 10)));
264
+ const deduped = deduplicateFlows(rawFlows, maxFlows);
265
+ // Convert to ExecutionFlow with co-change confidence
266
+ const flows = deduped.map((raw) => {
267
+ const steps = raw.nodeIds.map(nodeName);
268
+ const files = raw.nodeIds.map(nodeFile);
269
+ const confidence = computeFlowConfidence(files, coChangeEdges);
270
+ return {
271
+ label: generateLabel(steps, files),
272
+ entryPoint: steps[0],
273
+ entryFile: files[0],
274
+ terminal: steps[steps.length - 1],
275
+ terminalFile: files[files.length - 1],
276
+ steps,
277
+ files,
278
+ length: steps.length,
279
+ confidence,
280
+ };
281
+ });
282
+ // Sort by confidence descending, then length descending
283
+ flows.sort((a, b) => b.confidence - a.confidence || b.length - a.length);
284
+ return flows;
285
+ }
286
+ //# sourceMappingURL=execution-flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execution-flow.js","sourceRoot":"","sources":["../src/execution-flow.ts"],"names":[],"mappings":"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"}
@@ -8,8 +8,11 @@ import { relative, resolve } from "node:path";
8
8
  import { SOURCE_EXTENSIONS } from "./types.js";
9
9
  // ─── Constants ───────────────────────────────────────────────────────────────
10
10
  const MIN_COMMITS = 10;
11
- const MAX_COMMITS = 500;
12
- const MAX_DAYS = 90;
11
+ const INITIAL_MAX_COMMITS = 500;
12
+ const EXPANDED_MAX_COMMITS = 1000;
13
+ const FULL_MAX_COMMITS = 2000;
14
+ const MAX_DAYS = 365; // expanded from 90 — recency decay handles old data
15
+ const MIN_USEFUL_EDGES = 5; // minimum co-change edges before expanding
13
16
  const MAX_FILES_PER_COMMIT = 30;
14
17
  const HUB_FILE_THRESHOLD = 0.7;
15
18
  const HUB_FILE_THRESHOLD_YOUNG = 0.9;
@@ -37,15 +40,23 @@ export function mineGitHistory(repoDir, packageDirs, warnings, options = {}) {
37
40
  });
38
41
  return null;
39
42
  }
40
- const maxCommits = options.maxCommits ?? MAX_COMMITS;
41
43
  const maxDays = options.maxDays ?? MAX_DAYS;
42
- const raw = runGitLog(absRepoDir, maxCommits, maxDays);
43
- if (raw === null)
44
- return null;
45
44
  const gitRoot = resolveGitRoot(absRepoDir);
46
45
  if (gitRoot === null)
47
46
  return null;
48
- const allCommits = parseGitLog(raw);
47
+ // Adaptive windowing: start with 500 commits, expand if insufficient signal
48
+ const commitTargets = [options.maxCommits ?? INITIAL_MAX_COMMITS, EXPANDED_MAX_COMMITS, FULL_MAX_COMMITS];
49
+ let allCommits = [];
50
+ for (const target of commitTargets) {
51
+ if (allCommits.length >= target)
52
+ break; // already have enough from prior expansion
53
+ const raw = runGitLog(absRepoDir, target, maxDays);
54
+ if (raw === null)
55
+ return null;
56
+ allCommits = parseGitLog(raw);
57
+ if (allCommits.length >= target * 0.8)
58
+ break; // got most of what we asked for — no point expanding
59
+ }
49
60
  if (allCommits.length < MIN_COMMITS) {
50
61
  warnings.push({
51
62
  level: "info",