@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 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
- getStatus(projectId: string): Promise<Map<string, string>>;
28
- pushFiles(projectId: string, files: ScanPushFile[]): Promise<{
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 new Map(result.files.map((f) => [f.path, f.hash]));
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
- async pushFiles(projectId, files) {
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
- await this.request('/api/v1/scan/push', { projectId, files: batch });
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
  }
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
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 serverHashes = await this.client.getStatus(projectId);
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 = serverHashes.get(f.path);
189
+ const serverHash = status.fileHashes.get(f.path);
181
190
  return !serverHash || serverHash !== f.hash;
182
191
  });
183
- if (filesToPush.length > 0) {
184
- console.log(`[scanner] Pushing ${filesToPush.length} changed files for ${projectId.slice(0, 8)}...`);
185
- await this.client.pushFiles(projectId, filesToPush);
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
- for (let i = 0; i < files.length; i += batchSize) {
205
- const batch = files.slice(i, i + batchSize);
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, batch);
208
- for (const f of batch)
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
- for (const f of batch)
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
  }
@@ -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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAU1C,2EAA2E;AAC3E,yCAAyC;AACzC,MAAM,WAAW,GAAG,GAAG,CAAC;AACxB,MAAM,cAAc,GAAG,MAAM,CAAC;AAE9B;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,QAAgB;IAC7C,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,aAAa,CAAC,EAAE;YAC1E,GAAG,EAAE,QAAQ;YACb,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,cAAc;SACxB,CAAC,CAAC;QACH,OAAO,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,QAAgB,EAChB,WAA0B;IAE1B,MAAM,IAAI,GAAG;QACX,KAAK;QACL,IAAI;QACJ,2BAA2B;QAC3B,aAAa;QACb,eAAe,WAAW,EAAE;KAC7B,CAAC;IACF,IAAI,WAAW;QAAE,IAAI,CAAC,IAAI,CAAC,GAAG,WAAW,QAAQ,CAAC,CAAC;IAEnD,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE;YAC9C,GAAG,EAAE,QAAQ;YACb,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,cAAc;YACvB,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;SAC5B,CAAC,CAAC;QACH,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC;IACtB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAI,GAAa,CAAC,OAAO,CAAC;QACnC,oEAAoE;QACpE,uEAAuE;QACvE,yDAAyD;QACzD,IAAI,WAAW,IAAI,6DAA6D,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3F,OAAO,YAAY,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACtC,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,MAAM,OAAO,GAAmB,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3D,IAAI,OAAO,GAAwB,IAAI,CAAC;IAExC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,IAAI,OAAO;gBAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACnC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAChC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;YACnC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;YACpC,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YACjD,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACzC,OAAO,GAAG,IAAI,CAAC;gBACf,SAAS;YACX,CAAC;YACD,OAAO,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;QACtD,CAAC;aAAM,IAAI,OAAO,EAAE,CAAC;YACnB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;YAC1B,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IACD,IAAI,OAAO;QAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACnC,OAAO,OAAO,CAAC;AACjB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mnemonik/scanner",
3
- "version": "2.0.1",
3
+ "version": "2.1.1",
4
4
  "description": "Automatic codebase indexing daemon for Mnemonik",
5
5
  "type": "module",
6
6
  "bin": {
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
- async getStatus(projectId: string): Promise<Map<string, string>> {
73
- const result = await this.request<{ files: Array<{ path: string; hash: string }> }>(
74
- '/api/v1/scan/status',
75
- { projectId }
76
- );
77
- return new Map(result.files.map((f) => [f.path, f.hash]));
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
- async pushFiles(projectId: string, files: ScanPushFile[]): Promise<{ success: boolean }> {
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
- await this.request('/api/v1/scan/push', { projectId, files: batch });
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(projectId: string, projectRoot: string): Promise<void> {
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 serverHashes = await this.client.getStatus(projectId);
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 = serverHashes.get(f.path);
241
+ const serverHash = status.fileHashes.get(f.path);
223
242
  return !serverHash || serverHash !== f.hash;
224
243
  });
225
244
 
226
- if (filesToPush.length > 0) {
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
- await this.client.pushFiles(projectId, filesToPush);
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
- for (let i = 0; i < files.length; i += batchSize) {
261
- const batch = files.slice(i, i + batchSize);
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, batch);
264
- for (const f of batch) succeededPaths.add(f.path);
265
- } catch {
351
+ await this.client.pushFiles(projectId, [], commits);
352
+ firstBatchSucceeded = true;
353
+ } catch (err) {
266
354
  hadFailure = true;
267
- for (const f of batch) project.pendingRetries.add(f.path);
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
+ }