@mnemonik/scanner 2.0.1 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.d.ts +37 -2
- package/dist/client.js +22 -3
- package/dist/client.js.map +1 -1
- package/dist/daemon.d.ts +5 -0
- package/dist/daemon.js +91 -15
- package/dist/daemon.js.map +1 -1
- package/dist/git.d.ts +31 -0
- package/dist/git.js +111 -0
- package/dist/git.js.map +1 -0
- package/package.json +1 -1
- package/src/client.ts +52 -8
- package/src/daemon.ts +111 -16
- package/src/git.ts +122 -0
package/dist/client.d.ts
CHANGED
|
@@ -15,17 +15,52 @@ export interface ScanPushFile {
|
|
|
15
15
|
};
|
|
16
16
|
}>;
|
|
17
17
|
}
|
|
18
|
+
export interface ScanPushCommit {
|
|
19
|
+
sha: string;
|
|
20
|
+
author: string;
|
|
21
|
+
date: string;
|
|
22
|
+
message: string;
|
|
23
|
+
files: string[];
|
|
24
|
+
}
|
|
18
25
|
export interface ScanPushPayload {
|
|
19
26
|
projectId: string;
|
|
20
27
|
files: ScanPushFile[];
|
|
28
|
+
commits?: ScanPushCommit[];
|
|
29
|
+
}
|
|
30
|
+
export interface ScanStatusResponse {
|
|
31
|
+
files: Array<{
|
|
32
|
+
path: string;
|
|
33
|
+
hash: string;
|
|
34
|
+
}>;
|
|
35
|
+
gitMining?: {
|
|
36
|
+
enabled: boolean;
|
|
37
|
+
lastMinedCommit: string | null;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export interface GitMiningMeta {
|
|
41
|
+
enabled: boolean;
|
|
42
|
+
lastMinedCommit: string | null;
|
|
21
43
|
}
|
|
22
44
|
export declare class MnemonikClient {
|
|
23
45
|
private serverUrl;
|
|
24
46
|
private apiKey;
|
|
25
47
|
constructor(serverUrl: string, apiKey: string);
|
|
26
48
|
private request;
|
|
27
|
-
|
|
28
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Fetch per-file hashes for dedup, plus git-mining metadata (v3.68).
|
|
51
|
+
* The daemon uses `gitMining.enabled` to decide whether to collect commits
|
|
52
|
+
* this cycle, and `lastMinedCommit` as the lower bound of `git log`.
|
|
53
|
+
*/
|
|
54
|
+
getStatus(projectId: string): Promise<{
|
|
55
|
+
fileHashes: Map<string, string>;
|
|
56
|
+
gitMining: GitMiningMeta;
|
|
57
|
+
}>;
|
|
58
|
+
/**
|
|
59
|
+
* Push file chunks in batches. When `commits` is supplied (non-empty) it is
|
|
60
|
+
* attached to the first batch only — BullMQ's idempotent jobId means a
|
|
61
|
+
* duplicate would collapse anyway, but one payload saves bandwidth.
|
|
62
|
+
*/
|
|
63
|
+
pushFiles(projectId: string, files: ScanPushFile[], commits?: ScanPushCommit[]): Promise<{
|
|
29
64
|
success: boolean;
|
|
30
65
|
}>;
|
|
31
66
|
sendHeartbeat(projectId: string): Promise<void>;
|
package/dist/client.js
CHANGED
|
@@ -45,15 +45,34 @@ export class MnemonikClient {
|
|
|
45
45
|
}
|
|
46
46
|
throw new Error(`Request to ${path} failed after ${retries} retries`);
|
|
47
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Fetch per-file hashes for dedup, plus git-mining metadata (v3.68).
|
|
50
|
+
* The daemon uses `gitMining.enabled` to decide whether to collect commits
|
|
51
|
+
* this cycle, and `lastMinedCommit` as the lower bound of `git log`.
|
|
52
|
+
*/
|
|
48
53
|
async getStatus(projectId) {
|
|
49
54
|
const result = await this.request('/api/v1/scan/status', { projectId });
|
|
50
|
-
return
|
|
55
|
+
return {
|
|
56
|
+
fileHashes: new Map(result.files.map((f) => [f.path, f.hash])),
|
|
57
|
+
gitMining: result.gitMining ?? { enabled: false, lastMinedCommit: null },
|
|
58
|
+
};
|
|
51
59
|
}
|
|
52
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Push file chunks in batches. When `commits` is supplied (non-empty) it is
|
|
62
|
+
* attached to the first batch only — BullMQ's idempotent jobId means a
|
|
63
|
+
* duplicate would collapse anyway, but one payload saves bandwidth.
|
|
64
|
+
*/
|
|
65
|
+
async pushFiles(projectId, files, commits) {
|
|
53
66
|
const batchSize = 25;
|
|
67
|
+
let attachedCommits = false;
|
|
54
68
|
for (let i = 0; i < files.length; i += batchSize) {
|
|
55
69
|
const batch = files.slice(i, i + batchSize);
|
|
56
|
-
|
|
70
|
+
const body = { projectId, files: batch };
|
|
71
|
+
if (!attachedCommits && commits && commits.length > 0) {
|
|
72
|
+
body.commits = commits;
|
|
73
|
+
attachedCommits = true;
|
|
74
|
+
}
|
|
75
|
+
await this.request('/api/v1/scan/push', body);
|
|
57
76
|
}
|
|
58
77
|
return { success: true };
|
|
59
78
|
}
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/daemon.d.ts
CHANGED
|
@@ -31,6 +31,11 @@ export declare class ScannerDaemon {
|
|
|
31
31
|
private addProject;
|
|
32
32
|
private waitForServer;
|
|
33
33
|
private initialScan;
|
|
34
|
+
/**
|
|
35
|
+
* Fetch commits since the last mine. Swallows errors — a git failure must
|
|
36
|
+
* not block the file scan push.
|
|
37
|
+
*/
|
|
38
|
+
private collectCommits;
|
|
34
39
|
private handleChanges;
|
|
35
40
|
private startRetryLoop;
|
|
36
41
|
private groupChunksByFile;
|
package/dist/daemon.js
CHANGED
|
@@ -5,6 +5,7 @@ import { CodeScanner } from '@mnemonik/shared';
|
|
|
5
5
|
import { MnemonikClient } from './client.js';
|
|
6
6
|
import { FileWatcher } from './watcher.js';
|
|
7
7
|
import { ProjectDiscovery } from './discovery.js';
|
|
8
|
+
import { probeGit, fetchCommits } from './git.js';
|
|
8
9
|
export class ScannerDaemon {
|
|
9
10
|
config;
|
|
10
11
|
client;
|
|
@@ -116,8 +117,13 @@ export class ScannerDaemon {
|
|
|
116
117
|
async addProject(discovered) {
|
|
117
118
|
const label = discovered.projectName ?? discovered.projectId.slice(0, 8);
|
|
118
119
|
console.log(`[scanner] Adding project: ${label} (${discovered.path})`);
|
|
120
|
+
let gitState = {
|
|
121
|
+
isGitRepo: false,
|
|
122
|
+
gitMiningEnabled: false,
|
|
123
|
+
lastMinedCommit: null,
|
|
124
|
+
};
|
|
119
125
|
try {
|
|
120
|
-
await this.initialScan(discovered.projectId, discovered.path);
|
|
126
|
+
gitState = await this.initialScan(discovered.projectId, discovered.path);
|
|
121
127
|
}
|
|
122
128
|
catch (err) {
|
|
123
129
|
console.warn(`[scanner] Initial scan failed for ${label}:`, err.message);
|
|
@@ -146,6 +152,9 @@ export class ScannerDaemon {
|
|
|
146
152
|
watcher,
|
|
147
153
|
pendingRetries: new Set(),
|
|
148
154
|
retryTimer: null,
|
|
155
|
+
isGitRepo: gitState.isGitRepo,
|
|
156
|
+
gitMiningEnabled: gitState.gitMiningEnabled,
|
|
157
|
+
lastMinedCommit: gitState.lastMinedCommit,
|
|
149
158
|
});
|
|
150
159
|
}
|
|
151
160
|
async waitForServer() {
|
|
@@ -174,19 +183,58 @@ export class ScannerDaemon {
|
|
|
174
183
|
async initialScan(projectId, projectRoot) {
|
|
175
184
|
const startTime = Date.now();
|
|
176
185
|
const chunks = await this.scanner.scanDirectory(projectRoot);
|
|
177
|
-
const
|
|
186
|
+
const status = await this.client.getStatus(projectId);
|
|
178
187
|
const files = await this.groupChunksByFile(chunks, projectRoot);
|
|
179
188
|
const filesToPush = files.filter((f) => {
|
|
180
|
-
const serverHash =
|
|
189
|
+
const serverHash = status.fileHashes.get(f.path);
|
|
181
190
|
return !serverHash || serverHash !== f.hash;
|
|
182
191
|
});
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
192
|
+
// v3.68: collect new commits since last mine when this is a git repo and
|
|
193
|
+
// the server has mining enabled for this project (Pro+ tier + not opted out).
|
|
194
|
+
const isGitRepo = await probeGit(projectRoot);
|
|
195
|
+
const commits = isGitRepo && status.gitMining.enabled
|
|
196
|
+
? await this.collectCommits(projectRoot, status.gitMining.lastMinedCommit)
|
|
197
|
+
: [];
|
|
198
|
+
// v3.68.1: push when there's anything to send — file changes OR new
|
|
199
|
+
// commits. Previously a stable repo with new commits never pushed,
|
|
200
|
+
// silently losing those commits forever.
|
|
201
|
+
let watermark = status.gitMining.lastMinedCommit;
|
|
202
|
+
if (filesToPush.length > 0 || commits.length > 0) {
|
|
203
|
+
console.log(`[scanner] Pushing ${filesToPush.length} changed files + ${commits.length} commits for ${projectId.slice(0, 8)}...`);
|
|
204
|
+
try {
|
|
205
|
+
await this.client.pushFiles(projectId, filesToPush, commits);
|
|
206
|
+
// Only advance the watermark after a successful push that actually
|
|
207
|
+
// carried the commits.
|
|
208
|
+
if (commits.length > 0) {
|
|
209
|
+
watermark = commits[0]?.sha ?? watermark;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
console.warn(`[scanner] Initial push failed for ${projectId.slice(0, 8)}: ${err.message}`);
|
|
214
|
+
}
|
|
186
215
|
}
|
|
187
216
|
const duration = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
188
217
|
console.log(`[scanner] Scan complete for ${projectId.slice(0, 8)}: ` +
|
|
189
|
-
`${chunks.length} chunks, ${filesToPush.length} pushed (${duration}s)`);
|
|
218
|
+
`${chunks.length} chunks, ${filesToPush.length} pushed, ${commits.length} commits (${duration}s)`);
|
|
219
|
+
return {
|
|
220
|
+
isGitRepo,
|
|
221
|
+
gitMiningEnabled: status.gitMining.enabled,
|
|
222
|
+
lastMinedCommit: watermark,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Fetch commits since the last mine. Swallows errors — a git failure must
|
|
227
|
+
* not block the file scan push.
|
|
228
|
+
*/
|
|
229
|
+
async collectCommits(projectRoot, lastMinedCommit) {
|
|
230
|
+
try {
|
|
231
|
+
const commits = await fetchCommits(projectRoot, lastMinedCommit);
|
|
232
|
+
return commits;
|
|
233
|
+
}
|
|
234
|
+
catch (err) {
|
|
235
|
+
console.warn(`[scanner] git log failed in ${projectRoot}:`, err.message);
|
|
236
|
+
return [];
|
|
237
|
+
}
|
|
190
238
|
}
|
|
191
239
|
async handleChanges(projectId, projectRoot, changedFiles) {
|
|
192
240
|
const project = this.projects.get(projectId);
|
|
@@ -198,22 +246,50 @@ export class ScannerDaemon {
|
|
|
198
246
|
if (chunks.length === 0)
|
|
199
247
|
return;
|
|
200
248
|
const files = await this.groupChunksByFile(chunks, projectRoot);
|
|
249
|
+
// v3.68: attach any new commits since our cached watermark. Only the
|
|
250
|
+
// first push carries them (idempotent jobId on the server collapses
|
|
251
|
+
// duplicates anyway, but one payload saves bandwidth).
|
|
252
|
+
const commits = project.isGitRepo && project.gitMiningEnabled
|
|
253
|
+
? await this.collectCommits(projectRoot, project.lastMinedCommit)
|
|
254
|
+
: [];
|
|
201
255
|
const batchSize = 25;
|
|
202
256
|
const succeededPaths = new Set();
|
|
203
257
|
let hadFailure = false;
|
|
204
|
-
|
|
205
|
-
|
|
258
|
+
let firstBatchSucceeded = false;
|
|
259
|
+
if (files.length > 0) {
|
|
260
|
+
for (let i = 0; i < files.length; i += batchSize) {
|
|
261
|
+
const batch = files.slice(i, i + batchSize);
|
|
262
|
+
try {
|
|
263
|
+
// Only attach commits to the first batch.
|
|
264
|
+
await this.client.pushFiles(projectId, batch, i === 0 ? commits : undefined);
|
|
265
|
+
for (const f of batch)
|
|
266
|
+
succeededPaths.add(f.path);
|
|
267
|
+
if (i === 0)
|
|
268
|
+
firstBatchSucceeded = true;
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
hadFailure = true;
|
|
272
|
+
for (const f of batch)
|
|
273
|
+
project.pendingRetries.add(f.path);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
else if (commits.length > 0) {
|
|
278
|
+
// No file changes but new commits exist — fire a commit-only push so
|
|
279
|
+
// they reach the server. v3.68.1 schema allows files=[].
|
|
206
280
|
try {
|
|
207
|
-
await this.client.pushFiles(projectId,
|
|
208
|
-
|
|
209
|
-
succeededPaths.add(f.path);
|
|
281
|
+
await this.client.pushFiles(projectId, [], commits);
|
|
282
|
+
firstBatchSucceeded = true;
|
|
210
283
|
}
|
|
211
|
-
catch {
|
|
284
|
+
catch (err) {
|
|
212
285
|
hadFailure = true;
|
|
213
|
-
|
|
214
|
-
project.pendingRetries.add(f.path);
|
|
286
|
+
console.warn(`[scanner] [${projectId.slice(0, 8)}] Commit-only push failed: ${err.message}`);
|
|
215
287
|
}
|
|
216
288
|
}
|
|
289
|
+
// Advance the watermark only if commits actually made it to the server.
|
|
290
|
+
if (commits.length > 0 && firstBatchSucceeded) {
|
|
291
|
+
project.lastMinedCommit = commits[0]?.sha ?? project.lastMinedCommit;
|
|
292
|
+
}
|
|
217
293
|
if (succeededPaths.size > 0) {
|
|
218
294
|
console.log(`[scanner] [${projectId.slice(0, 8)}] Pushed ${succeededPaths.size} file(s): ${[...succeededPaths].join(', ')}`);
|
|
219
295
|
}
|
package/dist/daemon.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"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"}
|
package/dist/git.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git commit extraction on the scanner daemon side.
|
|
3
|
+
*
|
|
4
|
+
* The production server runs in ECS and cannot `git log` the user's repo —
|
|
5
|
+
* the repo lives on the user's machine, next to the daemon. We run `git log`
|
|
6
|
+
* here and push the parsed commits alongside scan results. Server-side
|
|
7
|
+
* `GitMiner.mineCommits` consumes them without touching the filesystem.
|
|
8
|
+
*/
|
|
9
|
+
export interface ParsedCommit {
|
|
10
|
+
sha: string;
|
|
11
|
+
author: string;
|
|
12
|
+
date: string;
|
|
13
|
+
message: string;
|
|
14
|
+
files: string[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* True when `repoRoot/.git` exists and `git log -1` returns a commit.
|
|
18
|
+
* Non-git projects, `git init` with no commits, and corrupted repos all
|
|
19
|
+
* return false without throwing.
|
|
20
|
+
*/
|
|
21
|
+
export declare function probeGit(repoRoot: string): Promise<boolean>;
|
|
22
|
+
/**
|
|
23
|
+
* Fetch commits between `sinceCommit` and HEAD (or the last MAX_COMMITS on
|
|
24
|
+
* first run). Returns [] on failure — caller omits the field from the push.
|
|
25
|
+
*
|
|
26
|
+
* Uses `-z` NUL-separated output so `--name-only` file entries cannot collide
|
|
27
|
+
* with commit metadata. Parser mirrors the server-side token-walking parser
|
|
28
|
+
* in GitMiner.parseLogOutput.
|
|
29
|
+
*/
|
|
30
|
+
export declare function fetchCommits(repoRoot: string, sinceCommit: string | null): Promise<ParsedCommit[]>;
|
|
31
|
+
export declare function parseLogOutput(raw: string): ParsedCommit[];
|
package/dist/git.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git commit extraction on the scanner daemon side.
|
|
3
|
+
*
|
|
4
|
+
* The production server runs in ECS and cannot `git log` the user's repo —
|
|
5
|
+
* the repo lives on the user's machine, next to the daemon. We run `git log`
|
|
6
|
+
* here and push the parsed commits alongside scan results. Server-side
|
|
7
|
+
* `GitMiner.mineCommits` consumes them without touching the filesystem.
|
|
8
|
+
*/
|
|
9
|
+
import { execFile } from 'child_process';
|
|
10
|
+
import { promisify } from 'util';
|
|
11
|
+
import { access } from 'fs/promises';
|
|
12
|
+
import { join } from 'path';
|
|
13
|
+
const execFileAsync = promisify(execFile);
|
|
14
|
+
// Keep in sync with server-side MAX_COMMITS_PER_RUN in GitMiner.ts and the
|
|
15
|
+
// `commits` array cap in scanPushSchema.
|
|
16
|
+
const MAX_COMMITS = 100;
|
|
17
|
+
const GIT_TIMEOUT_MS = 20_000;
|
|
18
|
+
/**
|
|
19
|
+
* True when `repoRoot/.git` exists and `git log -1` returns a commit.
|
|
20
|
+
* Non-git projects, `git init` with no commits, and corrupted repos all
|
|
21
|
+
* return false without throwing.
|
|
22
|
+
*/
|
|
23
|
+
export async function probeGit(repoRoot) {
|
|
24
|
+
try {
|
|
25
|
+
await access(join(repoRoot, '.git'));
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const { stdout } = await execFileAsync('git', ['log', '-1', '--format=%H'], {
|
|
32
|
+
cwd: repoRoot,
|
|
33
|
+
encoding: 'utf-8',
|
|
34
|
+
timeout: GIT_TIMEOUT_MS,
|
|
35
|
+
});
|
|
36
|
+
return /^[0-9a-f]{40}/m.test(stdout);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Fetch commits between `sinceCommit` and HEAD (or the last MAX_COMMITS on
|
|
44
|
+
* first run). Returns [] on failure — caller omits the field from the push.
|
|
45
|
+
*
|
|
46
|
+
* Uses `-z` NUL-separated output so `--name-only` file entries cannot collide
|
|
47
|
+
* with commit metadata. Parser mirrors the server-side token-walking parser
|
|
48
|
+
* in GitMiner.parseLogOutput.
|
|
49
|
+
*/
|
|
50
|
+
export async function fetchCommits(repoRoot, sinceCommit) {
|
|
51
|
+
const args = [
|
|
52
|
+
'log',
|
|
53
|
+
'-z',
|
|
54
|
+
'--format=%H%n%an%n%aI%n%B',
|
|
55
|
+
'--name-only',
|
|
56
|
+
`--max-count=${MAX_COMMITS}`,
|
|
57
|
+
];
|
|
58
|
+
if (sinceCommit)
|
|
59
|
+
args.push(`${sinceCommit}..HEAD`);
|
|
60
|
+
let raw;
|
|
61
|
+
try {
|
|
62
|
+
const result = await execFileAsync('git', args, {
|
|
63
|
+
cwd: repoRoot,
|
|
64
|
+
encoding: 'utf-8',
|
|
65
|
+
timeout: GIT_TIMEOUT_MS,
|
|
66
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
67
|
+
});
|
|
68
|
+
raw = result.stdout;
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
const msg = err.message;
|
|
72
|
+
// "fatal: Invalid revision range <sha>..HEAD" — the daemon's cached
|
|
73
|
+
// last_mined_commit is stale (e.g. history was rewritten or the server
|
|
74
|
+
// was reseeded). Fall back to a fresh full-history scan.
|
|
75
|
+
if (sinceCommit && /Invalid (?:revision range|symmetric difference expression)/i.test(msg)) {
|
|
76
|
+
return fetchCommits(repoRoot, null);
|
|
77
|
+
}
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
return parseLogOutput(raw);
|
|
81
|
+
}
|
|
82
|
+
export function parseLogOutput(raw) {
|
|
83
|
+
const commits = [];
|
|
84
|
+
const tokens = raw.split('\0').filter((t) => t.length > 0);
|
|
85
|
+
let current = null;
|
|
86
|
+
for (const token of tokens) {
|
|
87
|
+
if (token.includes('\n')) {
|
|
88
|
+
if (current)
|
|
89
|
+
commits.push(current);
|
|
90
|
+
const lines = token.split('\n');
|
|
91
|
+
const sha = lines[0]?.trim() ?? '';
|
|
92
|
+
const author = lines[1]?.trim() ?? '';
|
|
93
|
+
const date = lines[2]?.trim() ?? '';
|
|
94
|
+
const message = lines.slice(3).join('\n').trim();
|
|
95
|
+
if (!sha || !author || !date || !message) {
|
|
96
|
+
current = null;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
current = { sha, author, date, message, files: [] };
|
|
100
|
+
}
|
|
101
|
+
else if (current) {
|
|
102
|
+
const file = token.trim();
|
|
103
|
+
if (file.length > 0)
|
|
104
|
+
current.files.push(file);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (current)
|
|
108
|
+
commits.push(current);
|
|
109
|
+
return commits;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=git.js.map
|
package/dist/git.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -16,9 +16,31 @@ export interface ScanPushFile {
|
|
|
16
16
|
}>;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
export interface ScanPushCommit {
|
|
20
|
+
sha: string;
|
|
21
|
+
author: string;
|
|
22
|
+
date: string;
|
|
23
|
+
message: string;
|
|
24
|
+
files: string[];
|
|
25
|
+
}
|
|
26
|
+
|
|
19
27
|
export interface ScanPushPayload {
|
|
20
28
|
projectId: string;
|
|
21
29
|
files: ScanPushFile[];
|
|
30
|
+
commits?: ScanPushCommit[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface ScanStatusResponse {
|
|
34
|
+
files: Array<{ path: string; hash: string }>;
|
|
35
|
+
gitMining?: {
|
|
36
|
+
enabled: boolean;
|
|
37
|
+
lastMinedCommit: string | null;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface GitMiningMeta {
|
|
42
|
+
enabled: boolean;
|
|
43
|
+
lastMinedCommit: string | null;
|
|
22
44
|
}
|
|
23
45
|
|
|
24
46
|
export class MnemonikClient {
|
|
@@ -69,19 +91,41 @@ export class MnemonikClient {
|
|
|
69
91
|
throw new Error(`Request to ${path} failed after ${retries} retries`);
|
|
70
92
|
}
|
|
71
93
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
94
|
+
/**
|
|
95
|
+
* Fetch per-file hashes for dedup, plus git-mining metadata (v3.68).
|
|
96
|
+
* The daemon uses `gitMining.enabled` to decide whether to collect commits
|
|
97
|
+
* this cycle, and `lastMinedCommit` as the lower bound of `git log`.
|
|
98
|
+
*/
|
|
99
|
+
async getStatus(
|
|
100
|
+
projectId: string
|
|
101
|
+
): Promise<{ fileHashes: Map<string, string>; gitMining: GitMiningMeta }> {
|
|
102
|
+
const result = await this.request<ScanStatusResponse>('/api/v1/scan/status', { projectId });
|
|
103
|
+
return {
|
|
104
|
+
fileHashes: new Map(result.files.map((f) => [f.path, f.hash])),
|
|
105
|
+
gitMining: result.gitMining ?? { enabled: false, lastMinedCommit: null },
|
|
106
|
+
};
|
|
78
107
|
}
|
|
79
108
|
|
|
80
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Push file chunks in batches. When `commits` is supplied (non-empty) it is
|
|
111
|
+
* attached to the first batch only — BullMQ's idempotent jobId means a
|
|
112
|
+
* duplicate would collapse anyway, but one payload saves bandwidth.
|
|
113
|
+
*/
|
|
114
|
+
async pushFiles(
|
|
115
|
+
projectId: string,
|
|
116
|
+
files: ScanPushFile[],
|
|
117
|
+
commits?: ScanPushCommit[]
|
|
118
|
+
): Promise<{ success: boolean }> {
|
|
81
119
|
const batchSize = 25;
|
|
120
|
+
let attachedCommits = false;
|
|
82
121
|
for (let i = 0; i < files.length; i += batchSize) {
|
|
83
122
|
const batch = files.slice(i, i + batchSize);
|
|
84
|
-
|
|
123
|
+
const body: ScanPushPayload = { projectId, files: batch };
|
|
124
|
+
if (!attachedCommits && commits && commits.length > 0) {
|
|
125
|
+
body.commits = commits;
|
|
126
|
+
attachedCommits = true;
|
|
127
|
+
}
|
|
128
|
+
await this.request('/api/v1/scan/push', body);
|
|
85
129
|
}
|
|
86
130
|
return { success: true };
|
|
87
131
|
}
|
package/src/daemon.ts
CHANGED
|
@@ -2,9 +2,10 @@ import { createHash } from 'crypto';
|
|
|
2
2
|
import { readFile } from 'fs/promises';
|
|
3
3
|
import { join } from 'path';
|
|
4
4
|
import { CodeScanner, type CodeChunk } from '@mnemonik/shared';
|
|
5
|
-
import { MnemonikClient, type ScanPushFile } from './client.js';
|
|
5
|
+
import { MnemonikClient, type ScanPushCommit, type ScanPushFile } from './client.js';
|
|
6
6
|
import { FileWatcher } from './watcher.js';
|
|
7
7
|
import { ProjectDiscovery, type DiscoveredProject } from './discovery.js';
|
|
8
|
+
import { probeGit, fetchCommits } from './git.js';
|
|
8
9
|
|
|
9
10
|
export interface DaemonConfig {
|
|
10
11
|
serverUrl: string;
|
|
@@ -21,6 +22,13 @@ interface WatchedProject {
|
|
|
21
22
|
watcher: FileWatcher;
|
|
22
23
|
pendingRetries: Set<string>;
|
|
23
24
|
retryTimer: ReturnType<typeof setInterval> | null;
|
|
25
|
+
// v3.68: git-mining state cached across scans. `isGitRepo` is set once at
|
|
26
|
+
// project add time (false for non-git projects, skips git calls entirely).
|
|
27
|
+
// `gitMiningEnabled` reflects server-side Pro+ tier + feature flag +
|
|
28
|
+
// per-project opt-out. `lastMinedCommit` bounds `git log` from below.
|
|
29
|
+
isGitRepo: boolean;
|
|
30
|
+
gitMiningEnabled: boolean;
|
|
31
|
+
lastMinedCommit: string | null;
|
|
24
32
|
}
|
|
25
33
|
|
|
26
34
|
export class ScannerDaemon {
|
|
@@ -147,8 +155,13 @@ export class ScannerDaemon {
|
|
|
147
155
|
const label = discovered.projectName ?? discovered.projectId.slice(0, 8);
|
|
148
156
|
console.log(`[scanner] Adding project: ${label} (${discovered.path})`);
|
|
149
157
|
|
|
158
|
+
let gitState = {
|
|
159
|
+
isGitRepo: false,
|
|
160
|
+
gitMiningEnabled: false,
|
|
161
|
+
lastMinedCommit: null as string | null,
|
|
162
|
+
};
|
|
150
163
|
try {
|
|
151
|
-
await this.initialScan(discovered.projectId, discovered.path);
|
|
164
|
+
gitState = await this.initialScan(discovered.projectId, discovered.path);
|
|
152
165
|
} catch (err) {
|
|
153
166
|
console.warn(`[scanner] Initial scan failed for ${label}:`, (err as Error).message);
|
|
154
167
|
}
|
|
@@ -184,6 +197,9 @@ export class ScannerDaemon {
|
|
|
184
197
|
watcher,
|
|
185
198
|
pendingRetries: new Set(),
|
|
186
199
|
retryTimer: null,
|
|
200
|
+
isGitRepo: gitState.isGitRepo,
|
|
201
|
+
gitMiningEnabled: gitState.gitMiningEnabled,
|
|
202
|
+
lastMinedCommit: gitState.lastMinedCommit,
|
|
187
203
|
});
|
|
188
204
|
}
|
|
189
205
|
|
|
@@ -211,30 +227,79 @@ export class ScannerDaemon {
|
|
|
211
227
|
throw new Error(`Server unreachable after ${maxRetries} attempts`);
|
|
212
228
|
}
|
|
213
229
|
|
|
214
|
-
private async initialScan(
|
|
230
|
+
private async initialScan(
|
|
231
|
+
projectId: string,
|
|
232
|
+
projectRoot: string
|
|
233
|
+
): Promise<{ isGitRepo: boolean; gitMiningEnabled: boolean; lastMinedCommit: string | null }> {
|
|
215
234
|
const startTime = Date.now();
|
|
216
235
|
|
|
217
236
|
const chunks = await this.scanner.scanDirectory(projectRoot);
|
|
218
|
-
const
|
|
237
|
+
const status = await this.client.getStatus(projectId);
|
|
219
238
|
|
|
220
239
|
const files = await this.groupChunksByFile(chunks, projectRoot);
|
|
221
240
|
const filesToPush = files.filter((f) => {
|
|
222
|
-
const serverHash =
|
|
241
|
+
const serverHash = status.fileHashes.get(f.path);
|
|
223
242
|
return !serverHash || serverHash !== f.hash;
|
|
224
243
|
});
|
|
225
244
|
|
|
226
|
-
|
|
245
|
+
// v3.68: collect new commits since last mine when this is a git repo and
|
|
246
|
+
// the server has mining enabled for this project (Pro+ tier + not opted out).
|
|
247
|
+
const isGitRepo = await probeGit(projectRoot);
|
|
248
|
+
const commits =
|
|
249
|
+
isGitRepo && status.gitMining.enabled
|
|
250
|
+
? await this.collectCommits(projectRoot, status.gitMining.lastMinedCommit)
|
|
251
|
+
: [];
|
|
252
|
+
|
|
253
|
+
// v3.68.1: push when there's anything to send — file changes OR new
|
|
254
|
+
// commits. Previously a stable repo with new commits never pushed,
|
|
255
|
+
// silently losing those commits forever.
|
|
256
|
+
let watermark = status.gitMining.lastMinedCommit;
|
|
257
|
+
if (filesToPush.length > 0 || commits.length > 0) {
|
|
227
258
|
console.log(
|
|
228
|
-
`[scanner] Pushing ${filesToPush.length} changed files for ${projectId.slice(0, 8)}...`
|
|
259
|
+
`[scanner] Pushing ${filesToPush.length} changed files + ${commits.length} commits for ${projectId.slice(0, 8)}...`
|
|
229
260
|
);
|
|
230
|
-
|
|
261
|
+
try {
|
|
262
|
+
await this.client.pushFiles(projectId, filesToPush, commits);
|
|
263
|
+
// Only advance the watermark after a successful push that actually
|
|
264
|
+
// carried the commits.
|
|
265
|
+
if (commits.length > 0) {
|
|
266
|
+
watermark = commits[0]?.sha ?? watermark;
|
|
267
|
+
}
|
|
268
|
+
} catch (err) {
|
|
269
|
+
console.warn(
|
|
270
|
+
`[scanner] Initial push failed for ${projectId.slice(0, 8)}: ${(err as Error).message}`
|
|
271
|
+
);
|
|
272
|
+
}
|
|
231
273
|
}
|
|
232
274
|
|
|
233
275
|
const duration = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
234
276
|
console.log(
|
|
235
277
|
`[scanner] Scan complete for ${projectId.slice(0, 8)}: ` +
|
|
236
|
-
`${chunks.length} chunks, ${filesToPush.length} pushed (${duration}s)`
|
|
278
|
+
`${chunks.length} chunks, ${filesToPush.length} pushed, ${commits.length} commits (${duration}s)`
|
|
237
279
|
);
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
isGitRepo,
|
|
283
|
+
gitMiningEnabled: status.gitMining.enabled,
|
|
284
|
+
lastMinedCommit: watermark,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Fetch commits since the last mine. Swallows errors — a git failure must
|
|
290
|
+
* not block the file scan push.
|
|
291
|
+
*/
|
|
292
|
+
private async collectCommits(
|
|
293
|
+
projectRoot: string,
|
|
294
|
+
lastMinedCommit: string | null
|
|
295
|
+
): Promise<ScanPushCommit[]> {
|
|
296
|
+
try {
|
|
297
|
+
const commits = await fetchCommits(projectRoot, lastMinedCommit);
|
|
298
|
+
return commits;
|
|
299
|
+
} catch (err) {
|
|
300
|
+
console.warn(`[scanner] git log failed in ${projectRoot}:`, (err as Error).message);
|
|
301
|
+
return [];
|
|
302
|
+
}
|
|
238
303
|
}
|
|
239
304
|
|
|
240
305
|
private async handleChanges(
|
|
@@ -253,21 +318,51 @@ export class ScannerDaemon {
|
|
|
253
318
|
|
|
254
319
|
const files = await this.groupChunksByFile(chunks, projectRoot);
|
|
255
320
|
|
|
321
|
+
// v3.68: attach any new commits since our cached watermark. Only the
|
|
322
|
+
// first push carries them (idempotent jobId on the server collapses
|
|
323
|
+
// duplicates anyway, but one payload saves bandwidth).
|
|
324
|
+
const commits =
|
|
325
|
+
project.isGitRepo && project.gitMiningEnabled
|
|
326
|
+
? await this.collectCommits(projectRoot, project.lastMinedCommit)
|
|
327
|
+
: [];
|
|
328
|
+
|
|
256
329
|
const batchSize = 25;
|
|
257
330
|
const succeededPaths = new Set<string>();
|
|
258
331
|
let hadFailure = false;
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
332
|
+
let firstBatchSucceeded = false;
|
|
333
|
+
|
|
334
|
+
if (files.length > 0) {
|
|
335
|
+
for (let i = 0; i < files.length; i += batchSize) {
|
|
336
|
+
const batch = files.slice(i, i + batchSize);
|
|
337
|
+
try {
|
|
338
|
+
// Only attach commits to the first batch.
|
|
339
|
+
await this.client.pushFiles(projectId, batch, i === 0 ? commits : undefined);
|
|
340
|
+
for (const f of batch) succeededPaths.add(f.path);
|
|
341
|
+
if (i === 0) firstBatchSucceeded = true;
|
|
342
|
+
} catch {
|
|
343
|
+
hadFailure = true;
|
|
344
|
+
for (const f of batch) project.pendingRetries.add(f.path);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
} else if (commits.length > 0) {
|
|
348
|
+
// No file changes but new commits exist — fire a commit-only push so
|
|
349
|
+
// they reach the server. v3.68.1 schema allows files=[].
|
|
262
350
|
try {
|
|
263
|
-
await this.client.pushFiles(projectId,
|
|
264
|
-
|
|
265
|
-
} catch {
|
|
351
|
+
await this.client.pushFiles(projectId, [], commits);
|
|
352
|
+
firstBatchSucceeded = true;
|
|
353
|
+
} catch (err) {
|
|
266
354
|
hadFailure = true;
|
|
267
|
-
|
|
355
|
+
console.warn(
|
|
356
|
+
`[scanner] [${projectId.slice(0, 8)}] Commit-only push failed: ${(err as Error).message}`
|
|
357
|
+
);
|
|
268
358
|
}
|
|
269
359
|
}
|
|
270
360
|
|
|
361
|
+
// Advance the watermark only if commits actually made it to the server.
|
|
362
|
+
if (commits.length > 0 && firstBatchSucceeded) {
|
|
363
|
+
project.lastMinedCommit = commits[0]?.sha ?? project.lastMinedCommit;
|
|
364
|
+
}
|
|
365
|
+
|
|
271
366
|
if (succeededPaths.size > 0) {
|
|
272
367
|
console.log(
|
|
273
368
|
`[scanner] [${projectId.slice(0, 8)}] Pushed ${succeededPaths.size} file(s): ${[...succeededPaths].join(', ')}`
|
package/src/git.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git commit extraction on the scanner daemon side.
|
|
3
|
+
*
|
|
4
|
+
* The production server runs in ECS and cannot `git log` the user's repo —
|
|
5
|
+
* the repo lives on the user's machine, next to the daemon. We run `git log`
|
|
6
|
+
* here and push the parsed commits alongside scan results. Server-side
|
|
7
|
+
* `GitMiner.mineCommits` consumes them without touching the filesystem.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { execFile } from 'child_process';
|
|
11
|
+
import { promisify } from 'util';
|
|
12
|
+
import { access } from 'fs/promises';
|
|
13
|
+
import { join } from 'path';
|
|
14
|
+
|
|
15
|
+
const execFileAsync = promisify(execFile);
|
|
16
|
+
|
|
17
|
+
export interface ParsedCommit {
|
|
18
|
+
sha: string;
|
|
19
|
+
author: string;
|
|
20
|
+
date: string;
|
|
21
|
+
message: string;
|
|
22
|
+
files: string[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Keep in sync with server-side MAX_COMMITS_PER_RUN in GitMiner.ts and the
|
|
26
|
+
// `commits` array cap in scanPushSchema.
|
|
27
|
+
const MAX_COMMITS = 100;
|
|
28
|
+
const GIT_TIMEOUT_MS = 20_000;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* True when `repoRoot/.git` exists and `git log -1` returns a commit.
|
|
32
|
+
* Non-git projects, `git init` with no commits, and corrupted repos all
|
|
33
|
+
* return false without throwing.
|
|
34
|
+
*/
|
|
35
|
+
export async function probeGit(repoRoot: string): Promise<boolean> {
|
|
36
|
+
try {
|
|
37
|
+
await access(join(repoRoot, '.git'));
|
|
38
|
+
} catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const { stdout } = await execFileAsync('git', ['log', '-1', '--format=%H'], {
|
|
43
|
+
cwd: repoRoot,
|
|
44
|
+
encoding: 'utf-8',
|
|
45
|
+
timeout: GIT_TIMEOUT_MS,
|
|
46
|
+
});
|
|
47
|
+
return /^[0-9a-f]{40}/m.test(stdout);
|
|
48
|
+
} catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Fetch commits between `sinceCommit` and HEAD (or the last MAX_COMMITS on
|
|
55
|
+
* first run). Returns [] on failure — caller omits the field from the push.
|
|
56
|
+
*
|
|
57
|
+
* Uses `-z` NUL-separated output so `--name-only` file entries cannot collide
|
|
58
|
+
* with commit metadata. Parser mirrors the server-side token-walking parser
|
|
59
|
+
* in GitMiner.parseLogOutput.
|
|
60
|
+
*/
|
|
61
|
+
export async function fetchCommits(
|
|
62
|
+
repoRoot: string,
|
|
63
|
+
sinceCommit: string | null
|
|
64
|
+
): Promise<ParsedCommit[]> {
|
|
65
|
+
const args = [
|
|
66
|
+
'log',
|
|
67
|
+
'-z',
|
|
68
|
+
'--format=%H%n%an%n%aI%n%B',
|
|
69
|
+
'--name-only',
|
|
70
|
+
`--max-count=${MAX_COMMITS}`,
|
|
71
|
+
];
|
|
72
|
+
if (sinceCommit) args.push(`${sinceCommit}..HEAD`);
|
|
73
|
+
|
|
74
|
+
let raw: string;
|
|
75
|
+
try {
|
|
76
|
+
const result = await execFileAsync('git', args, {
|
|
77
|
+
cwd: repoRoot,
|
|
78
|
+
encoding: 'utf-8',
|
|
79
|
+
timeout: GIT_TIMEOUT_MS,
|
|
80
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
81
|
+
});
|
|
82
|
+
raw = result.stdout;
|
|
83
|
+
} catch (err) {
|
|
84
|
+
const msg = (err as Error).message;
|
|
85
|
+
// "fatal: Invalid revision range <sha>..HEAD" — the daemon's cached
|
|
86
|
+
// last_mined_commit is stale (e.g. history was rewritten or the server
|
|
87
|
+
// was reseeded). Fall back to a fresh full-history scan.
|
|
88
|
+
if (sinceCommit && /Invalid (?:revision range|symmetric difference expression)/i.test(msg)) {
|
|
89
|
+
return fetchCommits(repoRoot, null);
|
|
90
|
+
}
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return parseLogOutput(raw);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function parseLogOutput(raw: string): ParsedCommit[] {
|
|
98
|
+
const commits: ParsedCommit[] = [];
|
|
99
|
+
const tokens = raw.split('\0').filter((t) => t.length > 0);
|
|
100
|
+
let current: ParsedCommit | null = null;
|
|
101
|
+
|
|
102
|
+
for (const token of tokens) {
|
|
103
|
+
if (token.includes('\n')) {
|
|
104
|
+
if (current) commits.push(current);
|
|
105
|
+
const lines = token.split('\n');
|
|
106
|
+
const sha = lines[0]?.trim() ?? '';
|
|
107
|
+
const author = lines[1]?.trim() ?? '';
|
|
108
|
+
const date = lines[2]?.trim() ?? '';
|
|
109
|
+
const message = lines.slice(3).join('\n').trim();
|
|
110
|
+
if (!sha || !author || !date || !message) {
|
|
111
|
+
current = null;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
current = { sha, author, date, message, files: [] };
|
|
115
|
+
} else if (current) {
|
|
116
|
+
const file = token.trim();
|
|
117
|
+
if (file.length > 0) current.files.push(file);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (current) commits.push(current);
|
|
121
|
+
return commits;
|
|
122
|
+
}
|