ai-first-cli 1.1.0 → 1.1.2

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 (192) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.es.md +137 -1
  3. package/README.md +136 -4
  4. package/ai/ai_context.md +2 -2
  5. package/ai/architecture.md +3 -3
  6. package/ai/cache.json +85 -57
  7. package/ai/ccp/jira-123/context.json +7 -0
  8. package/ai/context/repo.json +56 -0
  9. package/ai/context/utils.json +7 -0
  10. package/ai/dependencies.json +51 -1026
  11. package/ai/files.json +195 -3
  12. package/ai/git/commit-activity.json +8646 -0
  13. package/ai/git/recent-features.json +1 -0
  14. package/ai/git/recent-files.json +52 -0
  15. package/ai/git/recent-flows.json +1 -0
  16. package/ai/graph/knowledge-graph.json +43643 -0
  17. package/ai/graph/module-graph.json +4 -0
  18. package/ai/graph/symbol-graph.json +3307 -879
  19. package/ai/graph/symbol-references.json +119 -32
  20. package/ai/index-state.json +843 -188
  21. package/ai/index.db +0 -0
  22. package/ai/modules.json +4 -0
  23. package/ai/repo-map.json +81 -17
  24. package/ai/repo_map.json +81 -17
  25. package/ai/repo_map.md +21 -7
  26. package/ai/summary.md +5 -5
  27. package/ai/symbols.json +1 -20287
  28. package/dist/analyzers/androidResources.d.ts +23 -0
  29. package/dist/analyzers/androidResources.d.ts.map +1 -0
  30. package/dist/analyzers/androidResources.js +93 -0
  31. package/dist/analyzers/androidResources.js.map +1 -0
  32. package/dist/analyzers/dependencies.d.ts.map +1 -1
  33. package/dist/analyzers/dependencies.js +37 -0
  34. package/dist/analyzers/dependencies.js.map +1 -1
  35. package/dist/analyzers/entrypoints.d.ts.map +1 -1
  36. package/dist/analyzers/entrypoints.js +71 -1
  37. package/dist/analyzers/entrypoints.js.map +1 -1
  38. package/dist/analyzers/gradleModules.d.ts +22 -0
  39. package/dist/analyzers/gradleModules.d.ts.map +1 -0
  40. package/dist/analyzers/gradleModules.js +75 -0
  41. package/dist/analyzers/gradleModules.js.map +1 -0
  42. package/dist/analyzers/techStack.d.ts +7 -0
  43. package/dist/analyzers/techStack.d.ts.map +1 -1
  44. package/dist/analyzers/techStack.js +44 -1
  45. package/dist/analyzers/techStack.js.map +1 -1
  46. package/dist/commands/ai-first.d.ts.map +1 -1
  47. package/dist/commands/ai-first.js +311 -1
  48. package/dist/commands/ai-first.js.map +1 -1
  49. package/dist/core/adapters/adapterRegistry.d.ts +39 -0
  50. package/dist/core/adapters/adapterRegistry.d.ts.map +1 -0
  51. package/dist/core/adapters/adapterRegistry.js +155 -0
  52. package/dist/core/adapters/adapterRegistry.js.map +1 -0
  53. package/dist/core/adapters/baseAdapter.d.ts +49 -0
  54. package/dist/core/adapters/baseAdapter.d.ts.map +1 -0
  55. package/dist/core/adapters/baseAdapter.js +28 -0
  56. package/dist/core/adapters/baseAdapter.js.map +1 -0
  57. package/dist/core/adapters/community/fastapiAdapter.d.ts +7 -0
  58. package/dist/core/adapters/community/fastapiAdapter.d.ts.map +1 -0
  59. package/dist/core/adapters/community/fastapiAdapter.js +40 -0
  60. package/dist/core/adapters/community/fastapiAdapter.js.map +1 -0
  61. package/dist/core/adapters/community/index.d.ts +11 -0
  62. package/dist/core/adapters/community/index.d.ts.map +1 -0
  63. package/dist/core/adapters/community/index.js +11 -0
  64. package/dist/core/adapters/community/index.js.map +1 -0
  65. package/dist/core/adapters/community/laravelAdapter.d.ts +7 -0
  66. package/dist/core/adapters/community/laravelAdapter.d.ts.map +1 -0
  67. package/dist/core/adapters/community/laravelAdapter.js +47 -0
  68. package/dist/core/adapters/community/laravelAdapter.js.map +1 -0
  69. package/dist/core/adapters/community/nestjsAdapter.d.ts +7 -0
  70. package/dist/core/adapters/community/nestjsAdapter.d.ts.map +1 -0
  71. package/dist/core/adapters/community/nestjsAdapter.js +48 -0
  72. package/dist/core/adapters/community/nestjsAdapter.js.map +1 -0
  73. package/dist/core/adapters/community/phoenixAdapter.d.ts +7 -0
  74. package/dist/core/adapters/community/phoenixAdapter.d.ts.map +1 -0
  75. package/dist/core/adapters/community/phoenixAdapter.js +45 -0
  76. package/dist/core/adapters/community/phoenixAdapter.js.map +1 -0
  77. package/dist/core/adapters/community/springBootAdapter.d.ts +7 -0
  78. package/dist/core/adapters/community/springBootAdapter.d.ts.map +1 -0
  79. package/dist/core/adapters/community/springBootAdapter.js +44 -0
  80. package/dist/core/adapters/community/springBootAdapter.js.map +1 -0
  81. package/dist/core/adapters/dotnetAdapter.d.ts +20 -0
  82. package/dist/core/adapters/dotnetAdapter.d.ts.map +1 -0
  83. package/dist/core/adapters/dotnetAdapter.js +86 -0
  84. package/dist/core/adapters/dotnetAdapter.js.map +1 -0
  85. package/dist/core/adapters/index.d.ts +18 -0
  86. package/dist/core/adapters/index.d.ts.map +1 -0
  87. package/dist/core/adapters/index.js +19 -0
  88. package/dist/core/adapters/index.js.map +1 -0
  89. package/dist/core/adapters/javascriptAdapter.d.ts +11 -0
  90. package/dist/core/adapters/javascriptAdapter.d.ts.map +1 -0
  91. package/dist/core/adapters/javascriptAdapter.js +47 -0
  92. package/dist/core/adapters/javascriptAdapter.js.map +1 -0
  93. package/dist/core/adapters/pythonAdapter.d.ts +20 -0
  94. package/dist/core/adapters/pythonAdapter.d.ts.map +1 -0
  95. package/dist/core/adapters/pythonAdapter.js +99 -0
  96. package/dist/core/adapters/pythonAdapter.js.map +1 -0
  97. package/dist/core/adapters/railsAdapter.d.ts +10 -0
  98. package/dist/core/adapters/railsAdapter.d.ts.map +1 -0
  99. package/dist/core/adapters/railsAdapter.js +52 -0
  100. package/dist/core/adapters/railsAdapter.js.map +1 -0
  101. package/dist/core/adapters/salesforceAdapter.d.ts +16 -0
  102. package/dist/core/adapters/salesforceAdapter.d.ts.map +1 -0
  103. package/dist/core/adapters/salesforceAdapter.js +64 -0
  104. package/dist/core/adapters/salesforceAdapter.js.map +1 -0
  105. package/dist/core/adapters/sdk.d.ts +83 -0
  106. package/dist/core/adapters/sdk.d.ts.map +1 -0
  107. package/dist/core/adapters/sdk.js +114 -0
  108. package/dist/core/adapters/sdk.js.map +1 -0
  109. package/dist/core/ccp.d.ts +37 -0
  110. package/dist/core/ccp.d.ts.map +1 -0
  111. package/dist/core/ccp.js +184 -0
  112. package/dist/core/ccp.js.map +1 -0
  113. package/dist/core/gitAnalyzer.d.ts +74 -0
  114. package/dist/core/gitAnalyzer.d.ts.map +1 -0
  115. package/dist/core/gitAnalyzer.js +298 -0
  116. package/dist/core/gitAnalyzer.js.map +1 -0
  117. package/dist/core/incrementalAnalyzer.d.ts +28 -0
  118. package/dist/core/incrementalAnalyzer.d.ts.map +1 -0
  119. package/dist/core/incrementalAnalyzer.js +343 -0
  120. package/dist/core/incrementalAnalyzer.js.map +1 -0
  121. package/dist/core/knowledgeGraphBuilder.d.ts +31 -0
  122. package/dist/core/knowledgeGraphBuilder.d.ts.map +1 -0
  123. package/dist/core/knowledgeGraphBuilder.js +197 -0
  124. package/dist/core/knowledgeGraphBuilder.js.map +1 -0
  125. package/dist/core/lazyAnalyzer.d.ts +57 -0
  126. package/dist/core/lazyAnalyzer.d.ts.map +1 -0
  127. package/dist/core/lazyAnalyzer.js +204 -0
  128. package/dist/core/lazyAnalyzer.js.map +1 -0
  129. package/dist/core/schema.d.ts +57 -0
  130. package/dist/core/schema.d.ts.map +1 -0
  131. package/dist/core/schema.js +131 -0
  132. package/dist/core/schema.js.map +1 -0
  133. package/dist/core/semanticContexts.d.ts +40 -0
  134. package/dist/core/semanticContexts.d.ts.map +1 -0
  135. package/dist/core/semanticContexts.js +454 -0
  136. package/dist/core/semanticContexts.js.map +1 -0
  137. package/docs/es/guide/adapters.md +143 -0
  138. package/docs/es/guide/ai-repository-schema.md +119 -0
  139. package/docs/es/guide/features.md +67 -0
  140. package/docs/es/guide/flows.md +134 -0
  141. package/docs/es/guide/git-intelligence.md +170 -0
  142. package/docs/es/guide/incremental-analysis.md +131 -0
  143. package/docs/es/guide/knowledge-graph.md +135 -0
  144. package/docs/es/guide/lazy-indexing.md +144 -0
  145. package/docs/es/guide/performance.md +125 -0
  146. package/docs/guide/adapters.md +225 -0
  147. package/docs/guide/ai-repository-schema.md +119 -0
  148. package/docs/guide/architecture.md +69 -1
  149. package/docs/guide/flows.md +134 -0
  150. package/docs/guide/git-intelligence.md +170 -0
  151. package/docs/guide/incremental-analysis.md +131 -0
  152. package/docs/guide/knowledge-graph.md +135 -0
  153. package/docs/guide/lazy-indexing.md +144 -0
  154. package/docs/guide/performance.md +125 -0
  155. package/package.json +6 -3
  156. package/src/analyzers/androidResources.ts +113 -0
  157. package/src/analyzers/dependencies.ts +41 -0
  158. package/src/analyzers/entrypoints.ts +80 -1
  159. package/src/analyzers/gradleModules.ts +100 -0
  160. package/src/analyzers/techStack.ts +56 -0
  161. package/src/commands/ai-first.ts +342 -1
  162. package/src/core/adapters/adapterRegistry.ts +187 -0
  163. package/src/core/adapters/baseAdapter.ts +82 -0
  164. package/src/core/adapters/community/fastapiAdapter.ts +50 -0
  165. package/src/core/adapters/community/index.ts +11 -0
  166. package/src/core/adapters/community/laravelAdapter.ts +56 -0
  167. package/src/core/adapters/community/nestjsAdapter.ts +57 -0
  168. package/src/core/adapters/community/phoenixAdapter.ts +54 -0
  169. package/src/core/adapters/community/springBootAdapter.ts +53 -0
  170. package/src/core/adapters/dotnetAdapter.ts +104 -0
  171. package/src/core/adapters/index.ts +24 -0
  172. package/src/core/adapters/javascriptAdapter.ts +56 -0
  173. package/src/core/adapters/pythonAdapter.ts +118 -0
  174. package/src/core/adapters/railsAdapter.ts +65 -0
  175. package/src/core/adapters/salesforceAdapter.ts +76 -0
  176. package/src/core/adapters/sdk.ts +172 -0
  177. package/src/core/ccp.ts +240 -0
  178. package/src/core/gitAnalyzer.ts +391 -0
  179. package/src/core/incrementalAnalyzer.ts +382 -0
  180. package/src/core/knowledgeGraphBuilder.ts +181 -0
  181. package/src/core/lazyAnalyzer.ts +261 -0
  182. package/src/core/schema.ts +157 -0
  183. package/src/core/semanticContexts.ts +575 -0
  184. package/tests/adapters.test.ts +159 -0
  185. package/tests/gitAnalyzer.test.ts +133 -0
  186. package/tests/incrementalAnalyzer.test.ts +83 -0
  187. package/tests/knowledgeGraph.test.ts +146 -0
  188. package/tests/lazyAnalyzer.test.ts +230 -0
  189. package/tests/schema.test.ts +203 -0
  190. package/tests/semanticContexts.test.ts +435 -0
  191. package/ai/context/analyzers.Symbol.json +0 -19
  192. package/ai/context/analyzers.extractSymbols.json +0 -19
@@ -0,0 +1,298 @@
1
+ /**
2
+ * Git Intelligence Analyzer
3
+ *
4
+ * Analyzes recent git activity to provide AI agents with context about
5
+ * recently changed files, features, and flows.
6
+ */
7
+ import fs from "fs";
8
+ import path from "path";
9
+ import { execSync } from "child_process";
10
+ import { ensureDir, writeFile, readJsonFile } from "../utils/fileUtils.js";
11
+ const DEFAULT_OPTIONS = {
12
+ commitLimit: 50,
13
+ maxAgeDays: 30,
14
+ maxFiles: 50
15
+ };
16
+ /**
17
+ * Check if a directory is a git repository
18
+ */
19
+ export function detectGitRepository(rootDir) {
20
+ const gitDir = path.join(rootDir, ".git");
21
+ return fs.existsSync(gitDir);
22
+ }
23
+ /**
24
+ * Execute git command and return output
25
+ */
26
+ function gitExec(rootDir, command) {
27
+ try {
28
+ return execSync(command, {
29
+ cwd: rootDir,
30
+ encoding: "utf-8",
31
+ stdio: ["pipe", "pipe", "ignore"]
32
+ }).trim();
33
+ }
34
+ catch {
35
+ return "";
36
+ }
37
+ }
38
+ /**
39
+ * Get recent commits from git repository
40
+ */
41
+ export function getRecentCommits(rootDir, limit = 50) {
42
+ if (!detectGitRepository(rootDir)) {
43
+ return [];
44
+ }
45
+ const commits = [];
46
+ // Get commit hashes
47
+ const logFormat = "%H|%ai|%s|%an";
48
+ const logOutput = gitExec(rootDir, `git log --format="${logFormat}" -n ${limit}`);
49
+ if (!logOutput) {
50
+ return [];
51
+ }
52
+ const lines = logOutput.split("\n");
53
+ const maxAgeDate = new Date();
54
+ maxAgeDate.setDate(maxAgeDate.getDate() - DEFAULT_OPTIONS.maxAgeDays);
55
+ for (const line of lines) {
56
+ if (!line.trim())
57
+ continue;
58
+ const [hash, dateStr, message, author] = line.split("|");
59
+ const commitDate = new Date(dateStr);
60
+ // Skip commits older than maxAgeDays
61
+ if (commitDate < maxAgeDate) {
62
+ break;
63
+ }
64
+ // Get files changed in this commit
65
+ const filesOutput = gitExec(rootDir, `git diff-tree --no-commit-id --name-only -r ${hash}`);
66
+ const files = filesOutput ? filesOutput.split("\n").filter(f => f.trim()) : [];
67
+ commits.push({
68
+ hash,
69
+ date: dateStr,
70
+ message,
71
+ author,
72
+ files
73
+ });
74
+ }
75
+ return commits;
76
+ }
77
+ /**
78
+ * Extract changed files from commits
79
+ */
80
+ export function extractChangedFiles(commits) {
81
+ const fileStats = new Map();
82
+ for (const commit of commits) {
83
+ for (const file of commit.files) {
84
+ const existing = fileStats.get(file);
85
+ if (existing) {
86
+ existing.count++;
87
+ if (commit.date > existing.lastChanged) {
88
+ existing.lastChanged = commit.date;
89
+ }
90
+ }
91
+ else {
92
+ fileStats.set(file, {
93
+ count: 1,
94
+ lastChanged: commit.date
95
+ });
96
+ }
97
+ }
98
+ }
99
+ // Convert to array and sort by commit count
100
+ const result = Array.from(fileStats.entries())
101
+ .map(([path, stats]) => ({
102
+ path,
103
+ commitCount: stats.count,
104
+ lastChanged: stats.lastChanged
105
+ }))
106
+ .sort((a, b) => b.commitCount - a.commitCount);
107
+ return result.slice(0, DEFAULT_OPTIONS.maxFiles);
108
+ }
109
+ /**
110
+ * Get list of changed files
111
+ */
112
+ export function getRecentFiles(rootDir) {
113
+ const commits = getRecentCommits(rootDir);
114
+ const recentFiles = extractChangedFiles(commits);
115
+ return recentFiles.map(f => f.path);
116
+ }
117
+ /**
118
+ * Load features from ai/context/features/
119
+ */
120
+ function loadFeatures(aiDir) {
121
+ const featuresMap = new Map();
122
+ const featuresDir = path.join(aiDir, "context", "features");
123
+ if (!fs.existsSync(featuresDir)) {
124
+ return featuresMap;
125
+ }
126
+ try {
127
+ const files = fs.readdirSync(featuresDir);
128
+ for (const file of files) {
129
+ if (!file.endsWith(".json"))
130
+ continue;
131
+ const featurePath = path.join(featuresDir, file);
132
+ const featureData = readJsonFile(featurePath);
133
+ if (featureData && featureData.name && featureData.files) {
134
+ // Map each file in the feature to the feature name
135
+ for (const filePath of featureData.files) {
136
+ const existing = featuresMap.get(filePath) || [];
137
+ existing.push(featureData.name);
138
+ featuresMap.set(filePath, existing);
139
+ }
140
+ }
141
+ }
142
+ }
143
+ catch {
144
+ // Ignore errors reading features
145
+ }
146
+ return featuresMap;
147
+ }
148
+ /**
149
+ * Load flows from ai/context/flows/
150
+ */
151
+ function loadFlows(aiDir) {
152
+ const flowsMap = new Map();
153
+ const flowsDir = path.join(aiDir, "context", "flows");
154
+ if (!fs.existsSync(flowsDir)) {
155
+ return flowsMap;
156
+ }
157
+ try {
158
+ const files = fs.readdirSync(flowsDir);
159
+ for (const file of files) {
160
+ if (!file.endsWith(".json"))
161
+ continue;
162
+ const flowPath = path.join(flowsDir, file);
163
+ const flowData = readJsonFile(flowPath);
164
+ if (flowData && flowData.name && flowData.files) {
165
+ // Map each file in the flow to the flow name
166
+ for (const filePath of flowData.files) {
167
+ const existing = flowsMap.get(filePath) || [];
168
+ existing.push(flowData.name);
169
+ flowsMap.set(filePath, existing);
170
+ }
171
+ }
172
+ }
173
+ }
174
+ catch {
175
+ // Ignore errors reading flows
176
+ }
177
+ return flowsMap;
178
+ }
179
+ /**
180
+ * Map changed files to features
181
+ */
182
+ export function mapFilesToFeatures(rootDir, files) {
183
+ const aiDir = path.join(rootDir, "ai");
184
+ const featuresMap = loadFeatures(aiDir);
185
+ const featureSet = new Set();
186
+ for (const file of files) {
187
+ // Try exact match first
188
+ const directMatch = featuresMap.get(file);
189
+ if (directMatch) {
190
+ directMatch.forEach(f => featureSet.add(f));
191
+ }
192
+ // Try partial match (file is inside feature directory)
193
+ for (const [featureFile, featureNames] of featuresMap) {
194
+ if (file.startsWith(featureFile) || featureFile.startsWith(file)) {
195
+ featureNames.forEach(f => featureSet.add(f));
196
+ }
197
+ }
198
+ }
199
+ return Array.from(featureSet);
200
+ }
201
+ /**
202
+ * Map changed files to flows
203
+ */
204
+ export function mapFilesToFlows(rootDir, files) {
205
+ const aiDir = path.join(rootDir, "ai");
206
+ const flowsMap = loadFlows(aiDir);
207
+ const flowSet = new Set();
208
+ for (const file of files) {
209
+ // Try exact match first
210
+ const directMatch = flowsMap.get(file);
211
+ if (directMatch) {
212
+ directMatch.forEach(f => flowSet.add(f));
213
+ }
214
+ // Try partial match (file is inside flow)
215
+ for (const [flowFile, flowNames] of flowsMap) {
216
+ if (file.startsWith(flowFile) || flowFile.startsWith(file)) {
217
+ flowNames.forEach(f => flowSet.add(f));
218
+ }
219
+ }
220
+ }
221
+ return Array.from(flowSet);
222
+ }
223
+ /**
224
+ * Analyze git activity
225
+ */
226
+ export function analyzeGitActivity(rootDir, options = {}) {
227
+ const opts = { ...DEFAULT_OPTIONS, ...options };
228
+ if (!detectGitRepository(rootDir)) {
229
+ return null;
230
+ }
231
+ const commits = getRecentCommits(rootDir, opts.commitLimit);
232
+ if (commits.length === 0) {
233
+ return null;
234
+ }
235
+ const recentFiles = extractChangedFiles(commits);
236
+ const recentFilePaths = recentFiles.map(f => f.path);
237
+ const features = mapFilesToFeatures(rootDir, recentFilePaths);
238
+ const flows = mapFilesToFlows(rootDir, recentFilePaths);
239
+ // Calculate feature/flow commit counts
240
+ const featureCounts = {};
241
+ const flowCounts = {};
242
+ const fileCounts = {};
243
+ for (const commit of commits) {
244
+ const commitFeatures = mapFilesToFeatures(rootDir, commit.files);
245
+ for (const feature of commitFeatures) {
246
+ featureCounts[feature] = (featureCounts[feature] || 0) + 1;
247
+ }
248
+ const commitFlows = mapFilesToFlows(rootDir, commit.files);
249
+ for (const flow of commitFlows) {
250
+ flowCounts[flow] = (flowCounts[flow] || 0) + 1;
251
+ }
252
+ for (const file of commit.files) {
253
+ fileCounts[file] = (fileCounts[file] || 0) + 1;
254
+ }
255
+ }
256
+ return {
257
+ totalCommits: commits.length,
258
+ dateRange: {
259
+ start: commits[commits.length - 1]?.date || "",
260
+ end: commits[0]?.date || ""
261
+ },
262
+ files: fileCounts,
263
+ features: featureCounts,
264
+ flows: flowCounts
265
+ };
266
+ }
267
+ /**
268
+ * Generate git context files
269
+ */
270
+ export function generateGitContext(rootDir, aiDir) {
271
+ const targetAiDir = aiDir || path.join(rootDir, "ai");
272
+ const gitDir = path.join(targetAiDir, "git");
273
+ ensureDir(gitDir);
274
+ const commits = getRecentCommits(rootDir);
275
+ const recentFiles = extractChangedFiles(commits);
276
+ const recentFilePaths = recentFiles.map(f => f.path);
277
+ const recentFeatures = mapFilesToFeatures(rootDir, recentFilePaths);
278
+ const recentFlows = mapFilesToFlows(rootDir, recentFilePaths);
279
+ const activity = analyzeGitActivity(rootDir);
280
+ // Write output files
281
+ const recentFilesJson = JSON.stringify(recentFilePaths, null, 2);
282
+ writeFile(path.join(gitDir, "recent-files.json"), recentFilesJson);
283
+ const recentFeaturesJson = JSON.stringify(recentFeatures, null, 2);
284
+ writeFile(path.join(gitDir, "recent-features.json"), recentFeaturesJson);
285
+ const recentFlowsJson = JSON.stringify(recentFlows, null, 2);
286
+ writeFile(path.join(gitDir, "recent-flows.json"), recentFlowsJson);
287
+ if (activity) {
288
+ const activityJson = JSON.stringify(activity, null, 2);
289
+ writeFile(path.join(gitDir, "commit-activity.json"), activityJson);
290
+ }
291
+ return {
292
+ recentFiles: recentFilePaths,
293
+ recentFeatures,
294
+ recentFlows,
295
+ activity
296
+ };
297
+ }
298
+ //# sourceMappingURL=gitAnalyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitAnalyzer.js","sourceRoot":"","sources":["../../src/core/gitAnalyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Incremental Analyzer
3
+ *
4
+ * Performs incremental updates to repository intelligence when files change,
5
+ * without requiring a full re-analysis.
6
+ */
7
+ export interface ChangedFile {
8
+ path: string;
9
+ status: "added" | "modified" | "deleted";
10
+ hash?: string;
11
+ }
12
+ export interface IncrementalUpdateResult {
13
+ changedFiles: ChangedFile[];
14
+ updatedSymbols: number;
15
+ updatedDependencies: number;
16
+ updatedFeatures: string[];
17
+ updatedFlows: string[];
18
+ graphUpdated: boolean;
19
+ errors: string[];
20
+ }
21
+ export declare function detectChangedFiles(rootDir: string, useGit?: boolean): ChangedFile[];
22
+ export declare function updateSymbols(rootDir: string, changedFiles: ChangedFile[], aiDir: string): number;
23
+ export declare function updateDependencies(rootDir: string, changedFiles: ChangedFile[], aiDir: string): number;
24
+ export declare function updateFeatures(rootDir: string, changedFiles: ChangedFile[], aiDir: string): string[];
25
+ export declare function updateFlows(rootDir: string, changedFiles: ChangedFile[], aiDir: string): string[];
26
+ export declare function updateKnowledgeGraph(rootDir: string, aiDir: string): boolean;
27
+ export declare function runIncrementalUpdate(rootDir: string, aiDir?: string): IncrementalUpdateResult;
28
+ //# sourceMappingURL=incrementalAnalyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"incrementalAnalyzer.d.ts","sourceRoot":"","sources":["../../src/core/incrementalAnalyzer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,uBAAuB;IACtC,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAMD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,OAAc,GAAG,WAAW,EAAE,CAKzF;AAyED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAmCjG;AAMD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CA2BtG;AAMD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAmCpG;AAMD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAmCjG;AAMD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAO5E;AAMD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,uBAAuB,CA8D7F"}
@@ -0,0 +1,343 @@
1
+ /**
2
+ * Incremental Analyzer
3
+ *
4
+ * Performs incremental updates to repository intelligence when files change,
5
+ * without requiring a full re-analysis.
6
+ */
7
+ import fs from "fs";
8
+ import path from "path";
9
+ import { execSync } from "child_process";
10
+ import { writeFile, readJsonFile } from "../utils/fileUtils.js";
11
+ import { computeFileHash, loadIndexState, saveIndexState } from "./indexState.js";
12
+ import { extractSymbols } from "../analyzers/symbols.js";
13
+ import { buildKnowledgeGraph } from "./knowledgeGraphBuilder.js";
14
+ // ============================================================
15
+ // File Change Detection
16
+ // ============================================================
17
+ export function detectChangedFiles(rootDir, useGit = true) {
18
+ if (useGit && isGitRepository(rootDir)) {
19
+ return detectChangesWithGit(rootDir);
20
+ }
21
+ return detectChangesWithTimestamps(rootDir);
22
+ }
23
+ function isGitRepository(rootDir) {
24
+ return fs.existsSync(path.join(rootDir, ".git"));
25
+ }
26
+ function detectChangesWithGit(rootDir) {
27
+ const changes = [];
28
+ try {
29
+ const output = execSync("git diff --name-status HEAD", {
30
+ cwd: rootDir,
31
+ encoding: "utf-8"
32
+ });
33
+ for (const line of output.split("\n")) {
34
+ if (!line.trim())
35
+ continue;
36
+ const [status, filePath] = line.split("\t").map(s => s.trim());
37
+ if (!filePath)
38
+ continue;
39
+ let changeStatus = "modified";
40
+ if (status.startsWith("A") || status === "??")
41
+ changeStatus = "added";
42
+ else if (status.startsWith("D"))
43
+ changeStatus = "deleted";
44
+ changes.push({ path: filePath, status: changeStatus });
45
+ }
46
+ const stagedOutput = execSync("git diff --name-status --cached", {
47
+ cwd: rootDir,
48
+ encoding: "utf-8"
49
+ });
50
+ for (const line of stagedOutput.split("\n")) {
51
+ if (!line.trim())
52
+ continue;
53
+ const [status, filePath] = line.split("\t").map(s => s.trim());
54
+ if (!filePath || changes.find(c => c.path === filePath))
55
+ continue;
56
+ changes.push({ path: filePath, status: "modified" });
57
+ }
58
+ }
59
+ catch {
60
+ return detectChangesWithTimestamps(rootDir);
61
+ }
62
+ return changes;
63
+ }
64
+ function detectChangesWithTimestamps(rootDir) {
65
+ const changes = [];
66
+ const aiDir = path.join(rootDir, "ai");
67
+ const state = loadIndexState(aiDir);
68
+ if (!state)
69
+ return [];
70
+ for (const [filePath, fileState] of Object.entries(state.files)) {
71
+ const fullPath = path.join(rootDir, filePath);
72
+ if (!fs.existsSync(fullPath)) {
73
+ changes.push({ path: filePath, status: "deleted" });
74
+ continue;
75
+ }
76
+ const currentHash = computeFileHash(fullPath);
77
+ if (currentHash && currentHash.hash !== fileState.hash) {
78
+ changes.push({ path: filePath, status: "modified", hash: currentHash.hash });
79
+ }
80
+ }
81
+ return changes;
82
+ }
83
+ // ============================================================
84
+ // Symbol Update
85
+ // ============================================================
86
+ export function updateSymbols(rootDir, changedFiles, aiDir) {
87
+ const symbolsPath = path.join(aiDir, "symbols.json");
88
+ let existingSymbols = [];
89
+ if (fs.existsSync(symbolsPath)) {
90
+ try {
91
+ const raw = readJsonFile(symbolsPath);
92
+ if (Array.isArray(raw))
93
+ existingSymbols = raw;
94
+ }
95
+ catch {
96
+ existingSymbols = [];
97
+ }
98
+ }
99
+ const changedPaths = new Set(changedFiles.map(f => f.path));
100
+ existingSymbols = existingSymbols.filter(s => !changedPaths.has(s.file));
101
+ for (const changed of changedFiles) {
102
+ if (changed.status === "deleted")
103
+ continue;
104
+ const fullPath = path.join(rootDir, changed.path);
105
+ if (!fs.existsSync(fullPath))
106
+ continue;
107
+ try {
108
+ const fileInfo = {
109
+ path: changed.path,
110
+ relativePath: changed.path,
111
+ extension: path.extname(changed.path),
112
+ name: path.basename(changed.path, path.extname(changed.path))
113
+ };
114
+ const symbols = extractSymbols([fileInfo]);
115
+ for (const symbol of symbols.symbols || []) {
116
+ existingSymbols.push({ name: symbol.name, file: changed.path, type: symbol.type });
117
+ }
118
+ }
119
+ catch { /* skip */ }
120
+ }
121
+ writeFile(symbolsPath, JSON.stringify(existingSymbols, null, 2));
122
+ return existingSymbols.length;
123
+ }
124
+ // ============================================================
125
+ // Dependency Update
126
+ // ============================================================
127
+ export function updateDependencies(rootDir, changedFiles, aiDir) {
128
+ const depsPath = path.join(aiDir, "dependencies.json");
129
+ let existingDeps = {};
130
+ if (fs.existsSync(depsPath)) {
131
+ try {
132
+ existingDeps = readJsonFile(depsPath);
133
+ }
134
+ catch { /* ignore */ }
135
+ }
136
+ const packageFiles = changedFiles.filter(f => f.path.endsWith("package.json") || f.path.endsWith("requirements.txt"));
137
+ for (const pkgFile of packageFiles) {
138
+ const fullPath = path.join(rootDir, pkgFile.path);
139
+ if (!fs.existsSync(fullPath))
140
+ continue;
141
+ try {
142
+ if (pkgFile.path.endsWith("package.json")) {
143
+ const pkg = JSON.parse(fs.readFileSync(fullPath, "utf-8"));
144
+ existingDeps.dependencies = pkg.dependencies || {};
145
+ existingDeps.devDependencies = pkg.devDependencies || {};
146
+ }
147
+ }
148
+ catch { /* skip */ }
149
+ }
150
+ writeFile(depsPath, JSON.stringify(existingDeps, null, 2));
151
+ return Object.keys(existingDeps.dependencies || {}).length;
152
+ }
153
+ // ============================================================
154
+ // Feature Update
155
+ // ============================================================
156
+ export function updateFeatures(rootDir, changedFiles, aiDir) {
157
+ const changedPaths = new Set(changedFiles.map(f => f.path));
158
+ const featuresDir = path.join(aiDir, "context", "features");
159
+ const updatedFeatures = [];
160
+ if (!fs.existsSync(featuresDir))
161
+ return updatedFeatures;
162
+ try {
163
+ for (const featureFile of fs.readdirSync(featuresDir)) {
164
+ if (!featureFile.endsWith(".json"))
165
+ continue;
166
+ const featurePath = path.join(featuresDir, featureFile);
167
+ const featureData = readJsonFile(featurePath);
168
+ if (!featureData?.files)
169
+ continue;
170
+ const featureFileSet = new Set(featureData.files);
171
+ const affected = [...changedPaths].some(f => featureFileSet.has(f));
172
+ if (affected || changedFiles.some(c => c.status === "deleted")) {
173
+ const featureFilesList = featureData.files.filter(f => !changedFiles.some(c => c.path === f && c.status === "deleted"));
174
+ if (featureFilesList.length > 0) {
175
+ featureData.files = featureFilesList;
176
+ writeFile(featurePath, JSON.stringify(featureData, null, 2));
177
+ }
178
+ else {
179
+ fs.unlinkSync(featurePath);
180
+ }
181
+ updatedFeatures.push(featureData.name);
182
+ }
183
+ }
184
+ }
185
+ catch { /* ignore */ }
186
+ return updatedFeatures;
187
+ }
188
+ // ============================================================
189
+ // Flow Update
190
+ // ============================================================
191
+ export function updateFlows(rootDir, changedFiles, aiDir) {
192
+ const changedPaths = new Set(changedFiles.map(f => f.path));
193
+ const flowsDir = path.join(aiDir, "context", "flows");
194
+ const updatedFlows = [];
195
+ if (!fs.existsSync(flowsDir))
196
+ return updatedFlows;
197
+ try {
198
+ for (const flowFile of fs.readdirSync(flowsDir)) {
199
+ if (!flowFile.endsWith(".json"))
200
+ continue;
201
+ const flowPath = path.join(flowsDir, flowFile);
202
+ const flowData = readJsonFile(flowPath);
203
+ if (!flowData?.files)
204
+ continue;
205
+ const flowFileSet = new Set(flowData.files);
206
+ const affected = [...changedPaths].some(f => flowFileSet.has(f));
207
+ if (affected || changedFiles.some(c => c.status === "deleted")) {
208
+ const flowFilesList = flowData.files.filter(f => !changedFiles.some(c => c.path === f && c.status === "deleted"));
209
+ if (flowFilesList.length > 0) {
210
+ flowData.files = flowFilesList;
211
+ writeFile(flowPath, JSON.stringify(flowData, null, 2));
212
+ }
213
+ else {
214
+ fs.unlinkSync(flowPath);
215
+ }
216
+ updatedFlows.push(flowData.name);
217
+ }
218
+ }
219
+ }
220
+ catch { /* ignore */ }
221
+ return updatedFlows;
222
+ }
223
+ // ============================================================
224
+ // Knowledge Graph Update
225
+ // ============================================================
226
+ export function updateKnowledgeGraph(rootDir, aiDir) {
227
+ try {
228
+ buildKnowledgeGraph(rootDir, aiDir);
229
+ return true;
230
+ }
231
+ catch {
232
+ return false;
233
+ }
234
+ }
235
+ // ============================================================
236
+ // Main Incremental Update
237
+ // ============================================================
238
+ export function runIncrementalUpdate(rootDir, aiDir) {
239
+ const targetAiDir = aiDir || path.join(rootDir, "ai");
240
+ const errors = [];
241
+ if (!fs.existsSync(targetAiDir)) {
242
+ return {
243
+ changedFiles: [],
244
+ updatedSymbols: 0,
245
+ updatedDependencies: 0,
246
+ updatedFeatures: [],
247
+ updatedFlows: [],
248
+ graphUpdated: false,
249
+ errors: ["AI context directory does not exist. Run 'ai-first init' first."]
250
+ };
251
+ }
252
+ const changedFiles = detectChangedFiles(rootDir);
253
+ if (changedFiles.length === 0) {
254
+ return {
255
+ changedFiles: [],
256
+ updatedSymbols: 0,
257
+ updatedDependencies: 0,
258
+ updatedFeatures: [],
259
+ updatedFlows: [],
260
+ graphUpdated: false,
261
+ errors: []
262
+ };
263
+ }
264
+ let updatedSymbols = 0;
265
+ try {
266
+ updatedSymbols = updateSymbols(rootDir, changedFiles, targetAiDir);
267
+ }
268
+ catch (e) {
269
+ errors.push(`Failed to update symbols: ${e}`);
270
+ }
271
+ let updatedDependencies = 0;
272
+ try {
273
+ updatedDependencies = updateDependencies(rootDir, changedFiles, targetAiDir);
274
+ }
275
+ catch (e) {
276
+ errors.push(`Failed to update dependencies: ${e}`);
277
+ }
278
+ let updatedFeatures = [];
279
+ try {
280
+ updatedFeatures = updateFeatures(rootDir, changedFiles, targetAiDir);
281
+ }
282
+ catch (e) {
283
+ errors.push(`Failed to update features: ${e}`);
284
+ }
285
+ let updatedFlows = [];
286
+ try {
287
+ updatedFlows = updateFlows(rootDir, changedFiles, targetAiDir);
288
+ }
289
+ catch (e) {
290
+ errors.push(`Failed to update flows: ${e}`);
291
+ }
292
+ let graphUpdated = false;
293
+ try {
294
+ graphUpdated = updateKnowledgeGraph(rootDir, targetAiDir);
295
+ }
296
+ catch (e) {
297
+ errors.push(`Failed to update knowledge graph: ${e}`);
298
+ }
299
+ try {
300
+ updateIndexState(rootDir, changedFiles);
301
+ }
302
+ catch { /* non-critical */ }
303
+ return {
304
+ changedFiles,
305
+ updatedSymbols,
306
+ updatedDependencies,
307
+ updatedFeatures,
308
+ updatedFlows,
309
+ graphUpdated,
310
+ errors
311
+ };
312
+ }
313
+ function updateIndexState(rootDir, changedFiles) {
314
+ const aiDir = path.join(rootDir, "ai");
315
+ let state = loadIndexState(aiDir);
316
+ if (!state) {
317
+ state = { version: "1.0.0", lastIndexed: new Date().toISOString(), totalFiles: 0, files: {} };
318
+ }
319
+ const filesMap = new Map(Object.entries(state.files));
320
+ for (const changed of changedFiles) {
321
+ const fullPath = path.join(rootDir, changed.path);
322
+ if (changed.status === "deleted") {
323
+ filesMap.delete(changed.path);
324
+ }
325
+ else if (fs.existsSync(fullPath)) {
326
+ const hashData = computeFileHash(fullPath);
327
+ if (hashData) {
328
+ filesMap.set(changed.path, {
329
+ path: changed.path,
330
+ hash: hashData.hash,
331
+ mtime: hashData.mtime,
332
+ size: hashData.size,
333
+ indexedAt: new Date().toISOString()
334
+ });
335
+ }
336
+ }
337
+ }
338
+ state.files = Object.fromEntries(filesMap);
339
+ state.totalFiles = filesMap.size;
340
+ state.lastIndexed = new Date().toISOString();
341
+ saveIndexState(aiDir, filesMap);
342
+ }
343
+ //# sourceMappingURL=incrementalAnalyzer.js.map