@mhalder/qdrant-mcp-server 2.2.0 → 3.0.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 (87) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +76 -1
  3. package/build/code/indexer.d.ts +2 -1
  4. package/build/code/indexer.d.ts.map +1 -1
  5. package/build/code/indexer.js +37 -7
  6. package/build/code/indexer.js.map +1 -1
  7. package/build/git/chunker.d.ts +39 -0
  8. package/build/git/chunker.d.ts.map +1 -0
  9. package/build/git/chunker.js +210 -0
  10. package/build/git/chunker.js.map +1 -0
  11. package/build/git/chunker.test.d.ts +2 -0
  12. package/build/git/chunker.test.d.ts.map +1 -0
  13. package/build/git/chunker.test.js +230 -0
  14. package/build/git/chunker.test.js.map +1 -0
  15. package/build/git/config.d.ts +34 -0
  16. package/build/git/config.d.ts.map +1 -0
  17. package/build/git/config.js +163 -0
  18. package/build/git/config.js.map +1 -0
  19. package/build/git/extractor.d.ts +57 -0
  20. package/build/git/extractor.d.ts.map +1 -0
  21. package/build/git/extractor.integration.test.d.ts +6 -0
  22. package/build/git/extractor.integration.test.d.ts.map +1 -0
  23. package/build/git/extractor.integration.test.js +166 -0
  24. package/build/git/extractor.integration.test.js.map +1 -0
  25. package/build/git/extractor.js +231 -0
  26. package/build/git/extractor.js.map +1 -0
  27. package/build/git/extractor.test.d.ts +2 -0
  28. package/build/git/extractor.test.d.ts.map +1 -0
  29. package/build/git/extractor.test.js +267 -0
  30. package/build/git/extractor.test.js.map +1 -0
  31. package/build/git/index.d.ts +10 -0
  32. package/build/git/index.d.ts.map +1 -0
  33. package/build/git/index.js +11 -0
  34. package/build/git/index.js.map +1 -0
  35. package/build/git/indexer.d.ts +50 -0
  36. package/build/git/indexer.d.ts.map +1 -0
  37. package/build/git/indexer.js +588 -0
  38. package/build/git/indexer.js.map +1 -0
  39. package/build/git/indexer.test.d.ts +2 -0
  40. package/build/git/indexer.test.d.ts.map +1 -0
  41. package/build/git/indexer.test.js +867 -0
  42. package/build/git/indexer.test.js.map +1 -0
  43. package/build/git/sync/synchronizer.d.ts +43 -0
  44. package/build/git/sync/synchronizer.d.ts.map +1 -0
  45. package/build/git/sync/synchronizer.js +108 -0
  46. package/build/git/sync/synchronizer.js.map +1 -0
  47. package/build/git/sync/synchronizer.test.d.ts +2 -0
  48. package/build/git/sync/synchronizer.test.d.ts.map +1 -0
  49. package/build/git/sync/synchronizer.test.js +188 -0
  50. package/build/git/sync/synchronizer.test.js.map +1 -0
  51. package/build/git/types.d.ts +159 -0
  52. package/build/git/types.d.ts.map +1 -0
  53. package/build/git/types.js +5 -0
  54. package/build/git/types.js.map +1 -0
  55. package/build/index.js +18 -0
  56. package/build/index.js.map +1 -1
  57. package/build/tools/git-history.d.ts +10 -0
  58. package/build/tools/git-history.d.ts.map +1 -0
  59. package/build/tools/git-history.js +144 -0
  60. package/build/tools/git-history.js.map +1 -0
  61. package/build/tools/index.d.ts +2 -0
  62. package/build/tools/index.d.ts.map +1 -1
  63. package/build/tools/index.js +4 -0
  64. package/build/tools/index.js.map +1 -1
  65. package/build/tools/schemas.d.ts +24 -0
  66. package/build/tools/schemas.d.ts.map +1 -1
  67. package/build/tools/schemas.js +64 -0
  68. package/build/tools/schemas.js.map +1 -1
  69. package/package.json +1 -1
  70. package/src/code/indexer.ts +49 -7
  71. package/src/git/chunker.test.ts +284 -0
  72. package/src/git/chunker.ts +256 -0
  73. package/src/git/config.ts +173 -0
  74. package/src/git/extractor.integration.test.ts +221 -0
  75. package/src/git/extractor.test.ts +403 -0
  76. package/src/git/extractor.ts +284 -0
  77. package/src/git/index.ts +31 -0
  78. package/src/git/indexer.test.ts +1089 -0
  79. package/src/git/indexer.ts +745 -0
  80. package/src/git/sync/synchronizer.test.ts +250 -0
  81. package/src/git/sync/synchronizer.ts +122 -0
  82. package/src/git/types.ts +192 -0
  83. package/src/index.ts +42 -0
  84. package/src/tools/git-history.ts +208 -0
  85. package/src/tools/index.ts +7 -0
  86. package/src/tools/schemas.ts +75 -0
  87. package/vitest.config.ts +2 -0
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Integration tests for GitExtractor
3
+ * These tests run against real git repositories (not mocked)
4
+ */
5
+ import { describe, it, expect, beforeAll } from "vitest";
6
+ import { GitExtractor } from "./extractor.js";
7
+ import { DEFAULT_GIT_CONFIG } from "./config.js";
8
+ import { execFile } from "node:child_process";
9
+ import { promisify } from "node:util";
10
+ const execFileAsync = promisify(execFile);
11
+ describe("GitExtractor Integration Tests", () => {
12
+ let extractor;
13
+ const config = { ...DEFAULT_GIT_CONFIG, maxCommits: 100 };
14
+ // Use the current repository for integration tests
15
+ const repoPath = process.cwd();
16
+ beforeAll(async () => {
17
+ extractor = new GitExtractor(repoPath, config);
18
+ // Verify we're in a git repository
19
+ const isRepo = await extractor.validateRepository();
20
+ if (!isRepo) {
21
+ throw new Error("Integration tests must be run from a git repository");
22
+ }
23
+ });
24
+ describe("validateRepository", () => {
25
+ it("should detect valid git repository", async () => {
26
+ const result = await extractor.validateRepository();
27
+ expect(result).toBe(true);
28
+ });
29
+ it("should return false for non-existent path", async () => {
30
+ const badExtractor = new GitExtractor("/nonexistent/path", config);
31
+ const result = await badExtractor.validateRepository();
32
+ expect(result).toBe(false);
33
+ });
34
+ });
35
+ describe("getCommits - data integrity", () => {
36
+ it("should extract commits without data corruption", async () => {
37
+ const commits = await extractor.getCommits({ maxCommits: 50 });
38
+ expect(commits.length).toBeGreaterThan(0);
39
+ expect(commits.length).toBeLessThanOrEqual(50);
40
+ for (const commit of commits) {
41
+ // Verify hash format (40 hex characters)
42
+ expect(commit.hash).toMatch(/^[a-f0-9]{40}$/);
43
+ // Verify short hash format (7+ hex characters)
44
+ expect(commit.shortHash).toMatch(/^[a-f0-9]{7,}$/);
45
+ // Verify author is not empty
46
+ expect(commit.author.length).toBeGreaterThan(0);
47
+ // Verify author email format
48
+ expect(commit.authorEmail).toMatch(/.+@.+/);
49
+ // Verify date is valid
50
+ expect(commit.date).toBeInstanceOf(Date);
51
+ expect(commit.date.getTime()).not.toBeNaN();
52
+ // Verify subject is not empty
53
+ expect(commit.subject.length).toBeGreaterThan(0);
54
+ // CRITICAL: Verify fields don't contain numstat patterns
55
+ // This catches the parsing bug where numstat bleeds into format fields
56
+ const numstatPattern = /^\d+\s+\d+\s+\S+/;
57
+ expect(commit.hash).not.toMatch(numstatPattern);
58
+ expect(commit.author).not.toMatch(numstatPattern);
59
+ expect(commit.subject).not.toMatch(numstatPattern);
60
+ // Verify insertions/deletions are non-negative integers
61
+ expect(commit.insertions).toBeGreaterThanOrEqual(0);
62
+ expect(commit.deletions).toBeGreaterThanOrEqual(0);
63
+ expect(Number.isInteger(commit.insertions)).toBe(true);
64
+ expect(Number.isInteger(commit.deletions)).toBe(true);
65
+ // Verify files array
66
+ expect(Array.isArray(commit.files)).toBe(true);
67
+ for (const file of commit.files) {
68
+ expect(typeof file).toBe("string");
69
+ expect(file.length).toBeGreaterThan(0);
70
+ }
71
+ }
72
+ });
73
+ it("should return correct commit count matching git rev-list", async () => {
74
+ // Get expected count from git directly
75
+ const { stdout } = await execFileAsync("git", ["rev-list", "--count", "-n", "50", "HEAD"], { cwd: repoPath });
76
+ const expectedCount = Math.min(parseInt(stdout.trim(), 10), 50);
77
+ // Get commits via extractor
78
+ const commits = await extractor.getCommits({ maxCommits: 50 });
79
+ // Should match exactly
80
+ expect(commits.length).toBe(expectedCount);
81
+ });
82
+ it("should extract files correctly with stats", async () => {
83
+ // Find a commit with files using git log
84
+ const { stdout: logOutput } = await execFileAsync("git", ["log", "--oneline", "--shortstat", "-n", "10", "HEAD"], { cwd: repoPath });
85
+ // If there are commits with files changed, verify our extractor gets them
86
+ if (logOutput.includes("file")) {
87
+ const commits = await extractor.getCommits({ maxCommits: 10 });
88
+ const commitsWithFiles = commits.filter((c) => c.files.length > 0);
89
+ // At least some commits should have files
90
+ expect(commitsWithFiles.length).toBeGreaterThan(0);
91
+ // Verify files and stats are consistent
92
+ for (const commit of commitsWithFiles) {
93
+ // If there are files, there should typically be insertions or deletions
94
+ // (unless all files are renames with no changes)
95
+ expect(commit.files.length).toBeGreaterThan(0);
96
+ }
97
+ }
98
+ });
99
+ });
100
+ describe("getCommits - range filtering", () => {
101
+ it("should support sinceCommit range filtering", async () => {
102
+ // Get all commits first
103
+ const allCommits = await extractor.getCommits({ maxCommits: 20 });
104
+ if (allCommits.length >= 5) {
105
+ // Use the 5th commit as the "since" point
106
+ const sinceHash = allCommits[4].hash;
107
+ // Get commits since that point
108
+ const recentCommits = await extractor.getCommits({
109
+ sinceCommit: sinceHash,
110
+ maxCommits: 20,
111
+ });
112
+ // Should have fewer commits (the 4 before the since point)
113
+ expect(recentCommits.length).toBeLessThan(allCommits.length);
114
+ expect(recentCommits.length).toBe(4);
115
+ // Verify the commits are the expected ones
116
+ for (let i = 0; i < recentCommits.length; i++) {
117
+ expect(recentCommits[i].hash).toBe(allCommits[i].hash);
118
+ }
119
+ }
120
+ });
121
+ });
122
+ describe("getCommitDiff", () => {
123
+ it("should return diff for a valid commit", async () => {
124
+ const commits = await extractor.getCommits({ maxCommits: 1 });
125
+ if (commits.length > 0) {
126
+ const diff = await extractor.getCommitDiff(commits[0].hash);
127
+ // Diff should contain commit information
128
+ expect(diff).toContain("commit");
129
+ expect(diff).toContain(commits[0].hash);
130
+ }
131
+ });
132
+ it("should return empty string for invalid commit", async () => {
133
+ const diff = await extractor.getCommitDiff("0000000000000000000000000000000000000000");
134
+ expect(diff).toBe("");
135
+ });
136
+ });
137
+ describe("getLatestCommitHash", () => {
138
+ it("should return the HEAD commit hash", async () => {
139
+ const hash = await extractor.getLatestCommitHash();
140
+ // Verify format
141
+ expect(hash).toMatch(/^[a-f0-9]{40}$/);
142
+ // Verify it matches git rev-parse HEAD
143
+ const { stdout } = await execFileAsync("git", ["rev-parse", "HEAD"], {
144
+ cwd: repoPath,
145
+ });
146
+ expect(hash).toBe(stdout.trim());
147
+ });
148
+ });
149
+ describe("getCommitCount", () => {
150
+ it("should return total commit count", async () => {
151
+ const count = await extractor.getCommitCount();
152
+ // Verify against git rev-list
153
+ const { stdout } = await execFileAsync("git", ["rev-list", "--count", "HEAD"], { cwd: repoPath });
154
+ expect(count).toBe(parseInt(stdout.trim(), 10));
155
+ });
156
+ it("should return count since specific commit", async () => {
157
+ const commits = await extractor.getCommits({ maxCommits: 10 });
158
+ if (commits.length >= 5) {
159
+ const sinceHash = commits[4].hash;
160
+ const count = await extractor.getCommitCount(sinceHash);
161
+ expect(count).toBe(4); // 4 commits between sinceHash and HEAD
162
+ }
163
+ });
164
+ });
165
+ });
166
+ //# sourceMappingURL=extractor.integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractor.integration.test.js","sourceRoot":"","sources":["../../src/git/extractor.integration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,231 @@
1
+ /**
2
+ * GitExtractor - Extract commit data from git repositories
3
+ * Uses child_process.execFile for security (no shell injection)
4
+ */
5
+ import { execFile } from "node:child_process";
6
+ import { promisify } from "node:util";
7
+ import { GIT_LOG_COMMIT_DELIMITER, GIT_LOG_FORMAT, GIT_MAX_BUFFER, } from "./config.js";
8
+ const execFileAsync = promisify(execFile);
9
+ /**
10
+ * Normalize git remote URL to consistent format for hashing.
11
+ * Handles both SSH and HTTPS URL formats.
12
+ *
13
+ * @example
14
+ * normalizeRemoteUrl("git@github.com:user/repo.git") // → "user/repo"
15
+ * normalizeRemoteUrl("https://github.com/user/repo.git") // → "user/repo"
16
+ * normalizeRemoteUrl("") // → ""
17
+ */
18
+ export function normalizeRemoteUrl(url) {
19
+ if (!url)
20
+ return "";
21
+ return url
22
+ .replace(/^git@[^:]+:/, "") // git@github.com:user/repo → user/repo
23
+ .replace(/^https?:\/\/[^/]+\//, "") // https://github.com/user/repo → user/repo
24
+ .replace(/\.git$/, ""); // user/repo.git → user/repo
25
+ }
26
+ export class GitExtractor {
27
+ repoPath;
28
+ config;
29
+ constructor(repoPath, config) {
30
+ this.repoPath = repoPath;
31
+ this.config = config;
32
+ }
33
+ /**
34
+ * Validate that the path is a git repository
35
+ */
36
+ async validateRepository() {
37
+ try {
38
+ await execFileAsync("git", ["rev-parse", "--git-dir"], {
39
+ cwd: this.repoPath,
40
+ maxBuffer: GIT_MAX_BUFFER,
41
+ timeout: this.config.gitTimeout,
42
+ });
43
+ return true;
44
+ }
45
+ catch {
46
+ return false;
47
+ }
48
+ }
49
+ /**
50
+ * Get the latest commit hash
51
+ */
52
+ async getLatestCommitHash() {
53
+ const { stdout } = await execFileAsync("git", ["rev-parse", "HEAD"], {
54
+ cwd: this.repoPath,
55
+ maxBuffer: GIT_MAX_BUFFER,
56
+ timeout: this.config.gitTimeout,
57
+ });
58
+ return stdout.trim();
59
+ }
60
+ /**
61
+ * Get the remote origin URL, or empty string if not configured
62
+ */
63
+ async getRemoteUrl() {
64
+ try {
65
+ const { stdout } = await execFileAsync("git", ["remote", "get-url", "origin"], {
66
+ cwd: this.repoPath,
67
+ maxBuffer: GIT_MAX_BUFFER,
68
+ timeout: this.config.gitTimeout,
69
+ });
70
+ return stdout.trim();
71
+ }
72
+ catch {
73
+ return ""; // No remote configured
74
+ }
75
+ }
76
+ /**
77
+ * Get total commit count (optionally after a specific commit)
78
+ */
79
+ async getCommitCount(sinceCommit) {
80
+ const args = ["rev-list", "--count"];
81
+ if (sinceCommit) {
82
+ args.push(`${sinceCommit}..HEAD`);
83
+ }
84
+ else {
85
+ args.push("HEAD");
86
+ }
87
+ const { stdout } = await execFileAsync("git", args, {
88
+ cwd: this.repoPath,
89
+ maxBuffer: GIT_MAX_BUFFER,
90
+ timeout: this.config.gitTimeout,
91
+ });
92
+ return parseInt(stdout.trim(), 10);
93
+ }
94
+ /**
95
+ * Extract commits from the repository
96
+ */
97
+ async getCommits(options) {
98
+ const maxCommits = options?.maxCommits ?? this.config.maxCommits;
99
+ // Build git log arguments
100
+ const args = [
101
+ "log",
102
+ `--pretty=format:${GIT_LOG_COMMIT_DELIMITER}${GIT_LOG_FORMAT}`,
103
+ "--numstat", // Include insertions/deletions per file
104
+ `-n${maxCommits}`,
105
+ ];
106
+ // Add range if sinceCommit is specified
107
+ if (options?.sinceCommit) {
108
+ args.push(`${options.sinceCommit}..HEAD`);
109
+ }
110
+ // Add date filter if sinceDate is specified
111
+ if (options?.sinceDate) {
112
+ args.push(`--since=${options.sinceDate}`);
113
+ }
114
+ const { stdout } = await execFileAsync("git", args, {
115
+ cwd: this.repoPath,
116
+ maxBuffer: GIT_MAX_BUFFER,
117
+ timeout: this.config.gitTimeout,
118
+ });
119
+ return this.parseGitLog(stdout);
120
+ }
121
+ /**
122
+ * Get the diff for a specific commit
123
+ */
124
+ async getCommitDiff(commitHash) {
125
+ try {
126
+ const { stdout } = await execFileAsync("git", ["show", "--no-color", "-p", commitHash], {
127
+ cwd: this.repoPath,
128
+ maxBuffer: GIT_MAX_BUFFER,
129
+ timeout: this.config.gitTimeout,
130
+ });
131
+ // Truncate diff if it exceeds maxDiffSize
132
+ if (stdout.length > this.config.maxDiffSize) {
133
+ return (stdout.substring(0, this.config.maxDiffSize) +
134
+ `\n\n[diff truncated: showing ${this.config.maxDiffSize} of ${stdout.length} bytes]`);
135
+ }
136
+ return stdout;
137
+ }
138
+ catch {
139
+ return "";
140
+ }
141
+ }
142
+ /**
143
+ * Parse git log output into structured commits
144
+ */
145
+ parseGitLog(output) {
146
+ const commits = [];
147
+ // Split by commit delimiter
148
+ const commitBlocks = output.split(GIT_LOG_COMMIT_DELIMITER);
149
+ for (const block of commitBlocks) {
150
+ const trimmed = block.trim();
151
+ if (!trimmed)
152
+ continue;
153
+ const commit = this.parseCommitBlock(trimmed);
154
+ if (commit) {
155
+ commits.push(commit);
156
+ }
157
+ }
158
+ return commits;
159
+ }
160
+ /**
161
+ * Parse a single commit block
162
+ */
163
+ parseCommitBlock(block) {
164
+ // The format line is first, followed by numstat output
165
+ const lines = block.split("\n");
166
+ if (lines.length === 0)
167
+ return null;
168
+ // Parse the format line: hash|shortHash|author|authorEmail|date|subject|body
169
+ const formatLine = lines[0];
170
+ const parts = formatLine.split("|");
171
+ if (parts.length < 6)
172
+ return null;
173
+ const [hash, shortHash, author, authorEmail, dateStr, subject, ...bodyParts] = parts;
174
+ // Parse files and stats from numstat output
175
+ const { files, insertions, deletions } = this.parseNumstat(lines.slice(1));
176
+ return {
177
+ hash,
178
+ shortHash,
179
+ author,
180
+ authorEmail,
181
+ date: new Date(dateStr),
182
+ subject,
183
+ body: bodyParts.join("|").trim(), // Body might contain | characters
184
+ files,
185
+ insertions,
186
+ deletions,
187
+ };
188
+ }
189
+ /**
190
+ * Parse numstat output (lines after the format line)
191
+ */
192
+ parseNumstat(lines) {
193
+ const files = [];
194
+ let insertions = 0;
195
+ let deletions = 0;
196
+ for (const line of lines) {
197
+ const trimmed = line.trim();
198
+ if (!trimmed)
199
+ continue;
200
+ // numstat format: insertions<tab>deletions<tab>filename
201
+ // Binary files show as "-" for insertions/deletions
202
+ const match = trimmed.match(/^(\d+|-)\s+(\d+|-)\s+(.+)$/);
203
+ if (match) {
204
+ const [, ins, del, filename] = match;
205
+ // Handle binary files (marked with -)
206
+ if (ins !== "-") {
207
+ insertions += parseInt(ins, 10);
208
+ }
209
+ if (del !== "-") {
210
+ deletions += parseInt(del, 10);
211
+ }
212
+ // Handle renamed files (old -> new)
213
+ if (filename.includes(" => ")) {
214
+ const renameParts = filename.match(/(.+)\{(.+) => (.+)\}(.+)?/);
215
+ if (renameParts) {
216
+ files.push(`${renameParts[1]}${renameParts[3]}${renameParts[4] || ""}`);
217
+ }
218
+ else {
219
+ const simpleRename = filename.split(" => ");
220
+ files.push(simpleRename[1] || filename);
221
+ }
222
+ }
223
+ else {
224
+ files.push(filename);
225
+ }
226
+ }
227
+ }
228
+ return { files, insertions, deletions };
229
+ }
230
+ }
231
+ //# sourceMappingURL=extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractor.js","sourceRoot":"","sources":["../../src/git/extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=extractor.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractor.test.d.ts","sourceRoot":"","sources":["../../src/git/extractor.test.ts"],"names":[],"mappings":""}