@mnemonik/scanner 2.0.1 → 2.1.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.
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,46 @@ 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
  });
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
+ : [];
183
198
  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);
199
+ console.log(`[scanner] Pushing ${filesToPush.length} changed files + ${commits.length} commits for ${projectId.slice(0, 8)}...`);
200
+ await this.client.pushFiles(projectId, filesToPush, commits);
186
201
  }
187
202
  const duration = ((Date.now() - startTime) / 1000).toFixed(1);
188
203
  console.log(`[scanner] Scan complete for ${projectId.slice(0, 8)}: ` +
189
- `${chunks.length} chunks, ${filesToPush.length} pushed (${duration}s)`);
204
+ `${chunks.length} chunks, ${filesToPush.length} pushed, ${commits.length} commits (${duration}s)`);
205
+ return {
206
+ isGitRepo,
207
+ gitMiningEnabled: status.gitMining.enabled,
208
+ // Cache the newest SHA we just pushed; if no new commits, keep the
209
+ // server's watermark.
210
+ lastMinedCommit: commits[0]?.sha ?? status.gitMining.lastMinedCommit,
211
+ };
212
+ }
213
+ /**
214
+ * Fetch commits since the last mine. Swallows errors — a git failure must
215
+ * not block the file scan push.
216
+ */
217
+ async collectCommits(projectRoot, lastMinedCommit) {
218
+ try {
219
+ const commits = await fetchCommits(projectRoot, lastMinedCommit);
220
+ return commits;
221
+ }
222
+ catch (err) {
223
+ console.warn(`[scanner] git log failed in ${projectRoot}:`, err.message);
224
+ return [];
225
+ }
190
226
  }
191
227
  async handleChanges(projectId, projectRoot, changedFiles) {
192
228
  const project = this.projects.get(projectId);
@@ -198,13 +234,20 @@ export class ScannerDaemon {
198
234
  if (chunks.length === 0)
199
235
  return;
200
236
  const files = await this.groupChunksByFile(chunks, projectRoot);
237
+ // v3.68: attach any new commits since our cached watermark. Only the
238
+ // first batch carries them (idempotent jobId on the server collapses
239
+ // duplicates anyway, but one payload saves bandwidth).
240
+ const commits = project.isGitRepo && project.gitMiningEnabled
241
+ ? await this.collectCommits(projectRoot, project.lastMinedCommit)
242
+ : [];
201
243
  const batchSize = 25;
202
244
  const succeededPaths = new Set();
203
245
  let hadFailure = false;
204
246
  for (let i = 0; i < files.length; i += batchSize) {
205
247
  const batch = files.slice(i, i + batchSize);
206
248
  try {
207
- await this.client.pushFiles(projectId, batch);
249
+ // Only attach commits to the first batch.
250
+ await this.client.pushFiles(projectId, batch, i === 0 ? commits : undefined);
208
251
  for (const f of batch)
209
252
  succeededPaths.add(f.path);
210
253
  }
@@ -214,6 +257,11 @@ export class ScannerDaemon {
214
257
  project.pendingRetries.add(f.path);
215
258
  }
216
259
  }
260
+ // Advance the cached watermark only if the first batch succeeded (so we
261
+ // don't skip commits on a retry).
262
+ if (commits.length > 0 && !hadFailure) {
263
+ project.lastMinedCommit = commits[0]?.sha ?? project.lastMinedCommit;
264
+ }
217
265
  if (succeededPaths.size > 0) {
218
266
  console.log(`[scanner] [${projectId.slice(0, 8)}] Pushed ${succeededPaths.size} file(s): ${[...succeededPaths].join(', ')}`);
219
267
  }
@@ -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":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mnemonik/scanner",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
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,66 @@ 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
 
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
+
226
253
  if (filesToPush.length > 0) {
227
254
  console.log(
228
- `[scanner] Pushing ${filesToPush.length} changed files for ${projectId.slice(0, 8)}...`
255
+ `[scanner] Pushing ${filesToPush.length} changed files + ${commits.length} commits for ${projectId.slice(0, 8)}...`
229
256
  );
230
- await this.client.pushFiles(projectId, filesToPush);
257
+ await this.client.pushFiles(projectId, filesToPush, commits);
231
258
  }
232
259
 
233
260
  const duration = ((Date.now() - startTime) / 1000).toFixed(1);
234
261
  console.log(
235
262
  `[scanner] Scan complete for ${projectId.slice(0, 8)}: ` +
236
- `${chunks.length} chunks, ${filesToPush.length} pushed (${duration}s)`
263
+ `${chunks.length} chunks, ${filesToPush.length} pushed, ${commits.length} commits (${duration}s)`
237
264
  );
265
+
266
+ return {
267
+ isGitRepo,
268
+ gitMiningEnabled: status.gitMining.enabled,
269
+ // Cache the newest SHA we just pushed; if no new commits, keep the
270
+ // server's watermark.
271
+ lastMinedCommit: commits[0]?.sha ?? status.gitMining.lastMinedCommit,
272
+ };
273
+ }
274
+
275
+ /**
276
+ * Fetch commits since the last mine. Swallows errors — a git failure must
277
+ * not block the file scan push.
278
+ */
279
+ private async collectCommits(
280
+ projectRoot: string,
281
+ lastMinedCommit: string | null
282
+ ): Promise<ScanPushCommit[]> {
283
+ try {
284
+ const commits = await fetchCommits(projectRoot, lastMinedCommit);
285
+ return commits;
286
+ } catch (err) {
287
+ console.warn(`[scanner] git log failed in ${projectRoot}:`, (err as Error).message);
288
+ return [];
289
+ }
238
290
  }
239
291
 
240
292
  private async handleChanges(
@@ -253,6 +305,14 @@ export class ScannerDaemon {
253
305
 
254
306
  const files = await this.groupChunksByFile(chunks, projectRoot);
255
307
 
308
+ // v3.68: attach any new commits since our cached watermark. Only the
309
+ // first batch carries them (idempotent jobId on the server collapses
310
+ // duplicates anyway, but one payload saves bandwidth).
311
+ const commits =
312
+ project.isGitRepo && project.gitMiningEnabled
313
+ ? await this.collectCommits(projectRoot, project.lastMinedCommit)
314
+ : [];
315
+
256
316
  const batchSize = 25;
257
317
  const succeededPaths = new Set<string>();
258
318
  let hadFailure = false;
@@ -260,7 +320,8 @@ export class ScannerDaemon {
260
320
  for (let i = 0; i < files.length; i += batchSize) {
261
321
  const batch = files.slice(i, i + batchSize);
262
322
  try {
263
- await this.client.pushFiles(projectId, batch);
323
+ // Only attach commits to the first batch.
324
+ await this.client.pushFiles(projectId, batch, i === 0 ? commits : undefined);
264
325
  for (const f of batch) succeededPaths.add(f.path);
265
326
  } catch {
266
327
  hadFailure = true;
@@ -268,6 +329,12 @@ export class ScannerDaemon {
268
329
  }
269
330
  }
270
331
 
332
+ // Advance the cached watermark only if the first batch succeeded (so we
333
+ // don't skip commits on a retry).
334
+ if (commits.length > 0 && !hadFailure) {
335
+ project.lastMinedCommit = commits[0]?.sha ?? project.lastMinedCommit;
336
+ }
337
+
271
338
  if (succeededPaths.size > 0) {
272
339
  console.log(
273
340
  `[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
+ }