@fathippo/fathippo-context-engine 0.1.4 → 0.1.5

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 (39) hide show
  1. package/dist/engine.d.ts +4 -0
  2. package/dist/engine.d.ts.map +1 -1
  3. package/dist/engine.js +60 -2
  4. package/dist/engine.js.map +1 -1
  5. package/dist/profiler/framework-detection.d.ts +6 -0
  6. package/dist/profiler/framework-detection.d.ts.map +1 -0
  7. package/dist/profiler/framework-detection.js +452 -0
  8. package/dist/profiler/framework-detection.js.map +1 -0
  9. package/dist/profiler/git-analysis.d.ts +7 -0
  10. package/dist/profiler/git-analysis.d.ts.map +1 -0
  11. package/dist/profiler/git-analysis.js +125 -0
  12. package/dist/profiler/git-analysis.js.map +1 -0
  13. package/dist/profiler/import-analysis.d.ts +7 -0
  14. package/dist/profiler/import-analysis.d.ts.map +1 -0
  15. package/dist/profiler/import-analysis.js +160 -0
  16. package/dist/profiler/import-analysis.js.map +1 -0
  17. package/dist/profiler/index.d.ts +29 -0
  18. package/dist/profiler/index.d.ts.map +1 -0
  19. package/dist/profiler/index.js +176 -0
  20. package/dist/profiler/index.js.map +1 -0
  21. package/dist/profiler/scanner.d.ts +6 -0
  22. package/dist/profiler/scanner.d.ts.map +1 -0
  23. package/dist/profiler/scanner.js +360 -0
  24. package/dist/profiler/scanner.js.map +1 -0
  25. package/dist/profiler/serializer.d.ts +7 -0
  26. package/dist/profiler/serializer.d.ts.map +1 -0
  27. package/dist/profiler/serializer.js +112 -0
  28. package/dist/profiler/serializer.js.map +1 -0
  29. package/dist/profiler/types.d.ts +104 -0
  30. package/dist/profiler/types.d.ts.map +1 -0
  31. package/dist/profiler/types.js +8 -0
  32. package/dist/profiler/types.js.map +1 -0
  33. package/dist/profiler/workspace-id.d.ts +5 -0
  34. package/dist/profiler/workspace-id.d.ts.map +1 -0
  35. package/dist/profiler/workspace-id.js +65 -0
  36. package/dist/profiler/workspace-id.js.map +1 -0
  37. package/dist/types.d.ts +4 -0
  38. package/dist/types.d.ts.map +1 -1
  39. package/package.json +1 -1
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Import/require statement scanning across multiple languages.
3
+ * Counts import frequency per module to identify actual dependency usage.
4
+ */
5
+ import { readFile } from "node:fs/promises";
6
+ import path from "node:path";
7
+ // Regex patterns for import detection per language family
8
+ const JS_TS_IMPORT = /(?:import\s+(?:[\w{},*\s]+\s+from\s+)?['"]([^'"]+)['"]|require\s*\(\s*['"]([^'"]+)['"]\s*\))/g;
9
+ const PYTHON_IMPORT = /(?:^from\s+([\w.]+)\s+import|^import\s+([\w.]+))/gm;
10
+ const GO_IMPORT = /(?:"([^"]+)")/g;
11
+ const RUST_USE = /^use\s+([\w:]+)/gm;
12
+ const C_INCLUDE = /^#include\s+[<"]([^>"]+)[>"]/gm;
13
+ const JS_TS_EXTENSIONS = new Set(["ts", "tsx", "js", "jsx", "mjs", "cjs"]);
14
+ const PYTHON_EXTENSIONS = new Set(["py"]);
15
+ const GO_EXTENSIONS = new Set(["go"]);
16
+ const RUST_EXTENSIONS = new Set(["rs"]);
17
+ const C_EXTENSIONS = new Set(["c", "cpp", "h", "hpp"]);
18
+ /** Max file size to scan (skip very large files). */
19
+ const MAX_FILE_SIZE = 256 * 1024; // 256 KB
20
+ /** Max files to scan for imports. */
21
+ const MAX_FILES_TO_SCAN = 2000;
22
+ export async function analyzeImports(workspaceRoot, files) {
23
+ const moduleCounts = new Map();
24
+ const fileImportCounts = new Map();
25
+ let scanned = 0;
26
+ for (const file of files) {
27
+ if (scanned >= MAX_FILES_TO_SCAN)
28
+ break;
29
+ const ext = file.split(".").pop()?.toLowerCase() ?? "";
30
+ if (!JS_TS_EXTENSIONS.has(ext) &&
31
+ !PYTHON_EXTENSIONS.has(ext) &&
32
+ !GO_EXTENSIONS.has(ext) &&
33
+ !RUST_EXTENSIONS.has(ext) &&
34
+ !C_EXTENSIONS.has(ext)) {
35
+ continue;
36
+ }
37
+ const fullPath = path.join(workspaceRoot, file);
38
+ let content;
39
+ try {
40
+ content = await readFile(fullPath, "utf-8");
41
+ if (content.length > MAX_FILE_SIZE)
42
+ continue;
43
+ }
44
+ catch {
45
+ continue;
46
+ }
47
+ scanned++;
48
+ const imports = extractImports(content, ext);
49
+ let importCount = 0;
50
+ for (const mod of imports) {
51
+ const normalized = normalizeModule(mod, ext);
52
+ if (!normalized)
53
+ continue;
54
+ moduleCounts.set(normalized, (moduleCounts.get(normalized) ?? 0) + 1);
55
+ importCount++;
56
+ }
57
+ if (importCount > 0) {
58
+ fileImportCounts.set(file, importCount);
59
+ }
60
+ }
61
+ // Top imports by frequency
62
+ const topImports = [...moduleCounts.entries()]
63
+ .sort((a, b) => b[1] - a[1])
64
+ .slice(0, 20)
65
+ .map(([module, count]) => ({ module, count }));
66
+ // Most imported files (files with most import statements referencing them)
67
+ // Count how many times each local file is imported by others
68
+ const localFileImports = new Map();
69
+ for (const [mod, count] of moduleCounts) {
70
+ if (mod.startsWith("./") || mod.startsWith("../") || mod.startsWith("@/")) {
71
+ localFileImports.set(mod, count);
72
+ }
73
+ }
74
+ const mostImportedFiles = [...localFileImports.entries()]
75
+ .sort((a, b) => b[1] - a[1])
76
+ .slice(0, 10)
77
+ .map(([filePath, importCount]) => ({ path: filePath, importCount }));
78
+ return {
79
+ topImports,
80
+ mostImportedFiles,
81
+ };
82
+ }
83
+ function extractImports(content, ext) {
84
+ const imports = [];
85
+ if (JS_TS_EXTENSIONS.has(ext)) {
86
+ for (const match of content.matchAll(JS_TS_IMPORT)) {
87
+ const mod = match[1] ?? match[2];
88
+ if (mod)
89
+ imports.push(mod);
90
+ }
91
+ }
92
+ else if (PYTHON_EXTENSIONS.has(ext)) {
93
+ for (const match of content.matchAll(PYTHON_IMPORT)) {
94
+ const mod = match[1] ?? match[2];
95
+ if (mod)
96
+ imports.push(mod);
97
+ }
98
+ }
99
+ else if (GO_EXTENSIONS.has(ext)) {
100
+ // Find import blocks
101
+ const importBlock = content.match(/import\s*\(([\s\S]*?)\)/);
102
+ if (importBlock) {
103
+ for (const match of importBlock[1].matchAll(GO_IMPORT)) {
104
+ if (match[1])
105
+ imports.push(match[1]);
106
+ }
107
+ }
108
+ // Single imports
109
+ for (const match of content.matchAll(/^import\s+"([^"]+)"/gm)) {
110
+ if (match[1])
111
+ imports.push(match[1]);
112
+ }
113
+ }
114
+ else if (RUST_EXTENSIONS.has(ext)) {
115
+ for (const match of content.matchAll(RUST_USE)) {
116
+ if (match[1])
117
+ imports.push(match[1]);
118
+ }
119
+ }
120
+ else if (C_EXTENSIONS.has(ext)) {
121
+ for (const match of content.matchAll(C_INCLUDE)) {
122
+ if (match[1])
123
+ imports.push(match[1]);
124
+ }
125
+ }
126
+ return imports;
127
+ }
128
+ function normalizeModule(mod, ext) {
129
+ if (!mod || mod.length === 0)
130
+ return null;
131
+ if (JS_TS_EXTENSIONS.has(ext)) {
132
+ // For relative imports, keep as-is
133
+ if (mod.startsWith(".") || mod.startsWith("@/"))
134
+ return mod;
135
+ // For external deps, extract package name (handle scoped packages)
136
+ if (mod.startsWith("@")) {
137
+ const parts = mod.split("/");
138
+ return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : mod;
139
+ }
140
+ // Plain module name
141
+ return mod.split("/")[0] ?? mod;
142
+ }
143
+ if (PYTHON_EXTENSIONS.has(ext)) {
144
+ // Return top-level package
145
+ return mod.split(".")[0] ?? mod;
146
+ }
147
+ if (GO_EXTENSIONS.has(ext)) {
148
+ // Return full module path but trim to meaningful prefix
149
+ return mod;
150
+ }
151
+ if (RUST_EXTENSIONS.has(ext)) {
152
+ // Return crate name (first part before ::)
153
+ return mod.split("::")[0] ?? mod;
154
+ }
155
+ if (C_EXTENSIONS.has(ext)) {
156
+ return mod;
157
+ }
158
+ return mod;
159
+ }
160
+ //# sourceMappingURL=import-analysis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-analysis.js","sourceRoot":"","sources":["../../src/profiler/import-analysis.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Codebase Profiler — Main orchestrator.
3
+ *
4
+ * Profiles a workspace by scanning file tree, detecting frameworks,
5
+ * analyzing git history, and computing import frequency. Stores the
6
+ * result to `.fathippo/codebase-profile.json`.
7
+ */
8
+ import type { CodebaseProfile, ProfileConfig } from "./types.js";
9
+ export type { CodebaseProfile, ProfileConfig, TechStack, ScanResult, GitAnalysis, ImportAnalysis, ScanOptions } from "./types.js";
10
+ export { scanFileTree } from "./scanner.js";
11
+ export { detectTechStack } from "./framework-detection.js";
12
+ export { analyzeGitHistory } from "./git-analysis.js";
13
+ export { analyzeImports } from "./import-analysis.js";
14
+ export { deriveWorkspaceId } from "./workspace-id.js";
15
+ export { formatCodebaseProfileForInjection } from "./serializer.js";
16
+ /**
17
+ * Profile a codebase. If a cached profile exists on disk and `force` is false,
18
+ * returns the cached version.
19
+ */
20
+ export declare function profileCodebase(workspaceRoot: string, options?: ProfileConfig): Promise<CodebaseProfile>;
21
+ /**
22
+ * Load a cached profile from disk.
23
+ */
24
+ export declare function loadCodebaseProfile(workspaceRoot: string): Promise<CodebaseProfile | null>;
25
+ /**
26
+ * Save a profile to disk at `.fathippo/codebase-profile.json`.
27
+ */
28
+ export declare function saveCodebaseProfile(workspaceRoot: string, profile: CodebaseProfile): Promise<void>;
29
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/profiler/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAQjE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAClI,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,iCAAiC,EAAE,MAAM,iBAAiB,CAAC;AAKpE;;;GAGG;AACH,wBAAsB,eAAe,CACnC,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,eAAe,CAAC,CA8H1B;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAYhG;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,IAAI,CAAC,CAWf"}
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Codebase Profiler — Main orchestrator.
3
+ *
4
+ * Profiles a workspace by scanning file tree, detecting frameworks,
5
+ * analyzing git history, and computing import frequency. Stores the
6
+ * result to `.fathippo/codebase-profile.json`.
7
+ */
8
+ import { existsSync } from "node:fs";
9
+ import { readFile, writeFile, mkdir } from "node:fs/promises";
10
+ import path from "node:path";
11
+ import { scanFileTree } from "./scanner.js";
12
+ import { detectTechStack } from "./framework-detection.js";
13
+ import { analyzeGitHistory, getHeadCommit } from "./git-analysis.js";
14
+ import { analyzeImports } from "./import-analysis.js";
15
+ export { scanFileTree } from "./scanner.js";
16
+ export { detectTechStack } from "./framework-detection.js";
17
+ export { analyzeGitHistory } from "./git-analysis.js";
18
+ export { analyzeImports } from "./import-analysis.js";
19
+ export { deriveWorkspaceId } from "./workspace-id.js";
20
+ export { formatCodebaseProfileForInjection } from "./serializer.js";
21
+ const PROFILE_DIR = ".fathippo";
22
+ const PROFILE_FILE = "codebase-profile.json";
23
+ /**
24
+ * Profile a codebase. If a cached profile exists on disk and `force` is false,
25
+ * returns the cached version.
26
+ */
27
+ export async function profileCodebase(workspaceRoot, options) {
28
+ // Check for cached profile unless force
29
+ if (!options?.force) {
30
+ const cached = await loadCodebaseProfile(workspaceRoot);
31
+ if (cached)
32
+ return cached;
33
+ }
34
+ // Run all analyses in parallel
35
+ const [scanResult, techStack, gitResult, headCommit] = await Promise.all([
36
+ scanFileTree(workspaceRoot, {
37
+ maxFiles: options?.maxFiles ?? 5000,
38
+ maxDepth: options?.maxDepth ?? 4,
39
+ extraIgnorePatterns: options?.extraIgnorePatterns,
40
+ }),
41
+ detectTechStack(workspaceRoot),
42
+ analyzeGitHistory(workspaceRoot).catch(() => ({
43
+ totalCommits: 0,
44
+ activeContributors: 0,
45
+ mostActiveDirectories: [],
46
+ branchingModel: "unknown",
47
+ hotspots: [],
48
+ })),
49
+ Promise.resolve(getHeadCommit(workspaceRoot)),
50
+ ]);
51
+ // Import analysis depends on scan result
52
+ const importResult = await analyzeImports(workspaceRoot, scanResult.allFiles).catch(() => ({
53
+ topImports: [],
54
+ mostImportedFiles: [],
55
+ }));
56
+ // Merge language breakdown into tech stack
57
+ techStack.languages = [...scanResult.languageBreakdown.entries()]
58
+ .sort((a, b) => b[1] - a[1])
59
+ .filter(([, pct]) => pct >= 1)
60
+ .map(([name, percentage]) => ({ name, percentage }));
61
+ // Build hotspots
62
+ const hotspots = [];
63
+ // Git hotspots (most changed)
64
+ for (const hs of gitResult.hotspots.slice(0, 8)) {
65
+ hotspots.push({
66
+ path: hs.path,
67
+ reason: "most-changed",
68
+ metric: hs.commits,
69
+ });
70
+ }
71
+ // Size hotspots (largest files not already listed)
72
+ const hotspotPaths = new Set(hotspots.map((h) => h.path));
73
+ for (const file of scanResult.largestFiles.slice(0, 5)) {
74
+ if (!hotspotPaths.has(file.path)) {
75
+ hotspots.push({
76
+ path: file.path,
77
+ reason: "largest",
78
+ metric: file.loc,
79
+ });
80
+ hotspotPaths.add(file.path);
81
+ }
82
+ }
83
+ // Import hotspots (most imported local files)
84
+ for (const file of importResult.mostImportedFiles.slice(0, 3)) {
85
+ if (!hotspotPaths.has(file.path)) {
86
+ hotspots.push({
87
+ path: file.path,
88
+ reason: "most-imported",
89
+ metric: file.importCount,
90
+ });
91
+ hotspotPaths.add(file.path);
92
+ }
93
+ }
94
+ // Top direct dependencies by actual import usage
95
+ const topDirect = importResult.topImports
96
+ .filter((imp) => !imp.module.startsWith(".") && !imp.module.startsWith("@/") && !imp.module.startsWith("node:"))
97
+ .slice(0, 10)
98
+ .map((imp) => imp.module);
99
+ // Peer projects (monorepo cross-package deps)
100
+ const peerProjects = importResult.topImports
101
+ .filter((imp) => imp.module.startsWith("@") && scanResult.workspaces.some((ws) => imp.module.includes(path.basename(ws))))
102
+ .map((imp) => imp.module);
103
+ // Assemble profile
104
+ const profile = {
105
+ version: 1,
106
+ generatedAt: new Date().toISOString(),
107
+ generatedFromCommit: headCommit,
108
+ workspaceRoot,
109
+ techStack,
110
+ structure: {
111
+ type: scanResult.structureType,
112
+ entryPoints: scanResult.entryPoints,
113
+ workspaces: scanResult.workspaces.length > 0 ? scanResult.workspaces : undefined,
114
+ totalFiles: scanResult.totalFiles,
115
+ totalDirectories: scanResult.totalDirectories,
116
+ fileTreeSummary: scanResult.fileTreeSummary,
117
+ },
118
+ hotspots: hotspots.slice(0, 15),
119
+ dependencies: {
120
+ topDirect,
121
+ peerProjects: peerProjects.length > 0 ? peerProjects : undefined,
122
+ },
123
+ git: {
124
+ totalCommits: gitResult.totalCommits,
125
+ activeContributors: gitResult.activeContributors,
126
+ mostActiveDirectories: gitResult.mostActiveDirectories,
127
+ branchingModel: gitResult.branchingModel,
128
+ },
129
+ architecture: {
130
+ summary: "Profile generated with free-data analysis. Run with LLM summarization for architectural insights.",
131
+ patterns: [],
132
+ conventions: [],
133
+ },
134
+ };
135
+ // Save to disk
136
+ await saveCodebaseProfile(workspaceRoot, profile);
137
+ return profile;
138
+ }
139
+ /**
140
+ * Load a cached profile from disk.
141
+ */
142
+ export async function loadCodebaseProfile(workspaceRoot) {
143
+ const profilePath = getProfilePath(workspaceRoot);
144
+ if (!existsSync(profilePath))
145
+ return null;
146
+ try {
147
+ const content = await readFile(profilePath, "utf-8");
148
+ const profile = JSON.parse(content);
149
+ if (profile.version !== 1)
150
+ return null;
151
+ return profile;
152
+ }
153
+ catch {
154
+ return null;
155
+ }
156
+ }
157
+ /**
158
+ * Save a profile to disk at `.fathippo/codebase-profile.json`.
159
+ */
160
+ export async function saveCodebaseProfile(workspaceRoot, profile) {
161
+ const dir = path.join(workspaceRoot, PROFILE_DIR);
162
+ try {
163
+ if (!existsSync(dir)) {
164
+ await mkdir(dir, { recursive: true });
165
+ }
166
+ const profilePath = path.join(dir, PROFILE_FILE);
167
+ await writeFile(profilePath, JSON.stringify(profile, null, 2), "utf-8");
168
+ }
169
+ catch (error) {
170
+ console.error("[FatHippo Profiler] Failed to save profile:", error);
171
+ }
172
+ }
173
+ function getProfilePath(workspaceRoot) {
174
+ return path.join(workspaceRoot, PROFILE_DIR, PROFILE_FILE);
175
+ }
176
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/profiler/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * File tree scanner with ignore patterns, LOC counting, and structure detection.
3
+ */
4
+ import type { ScanOptions, ScanResult } from "./types.js";
5
+ export declare function scanFileTree(workspaceRoot: string, options?: ScanOptions): Promise<ScanResult>;
6
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/profiler/scanner.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAsG1D,wBAAsB,YAAY,CAChC,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,UAAU,CAAC,CAyGrB"}