@mesadev/agentblame 0.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.
Files changed (58) hide show
  1. package/dist/blame.d.ts +14 -0
  2. package/dist/blame.js +252 -0
  3. package/dist/blame.js.map +1 -0
  4. package/dist/capture.d.ts +16 -0
  5. package/dist/capture.js +284 -0
  6. package/dist/capture.js.map +1 -0
  7. package/dist/cleanup.d.ts +10 -0
  8. package/dist/cleanup.js +136 -0
  9. package/dist/cleanup.js.map +1 -0
  10. package/dist/index.d.ts +10 -0
  11. package/dist/index.js +240 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/lib/db.d.ts +53 -0
  14. package/dist/lib/db.js +290 -0
  15. package/dist/lib/db.js.map +1 -0
  16. package/dist/lib/diff.d.ts +13 -0
  17. package/dist/lib/diff.js +32 -0
  18. package/dist/lib/diff.js.map +1 -0
  19. package/dist/lib/git/gitBlame.d.ts +25 -0
  20. package/dist/lib/git/gitBlame.js +87 -0
  21. package/dist/lib/git/gitBlame.js.map +1 -0
  22. package/dist/lib/git/gitCli.d.ts +17 -0
  23. package/dist/lib/git/gitCli.js +57 -0
  24. package/dist/lib/git/gitCli.js.map +1 -0
  25. package/dist/lib/git/gitConfig.d.ts +20 -0
  26. package/dist/lib/git/gitConfig.js +91 -0
  27. package/dist/lib/git/gitConfig.js.map +1 -0
  28. package/dist/lib/git/gitDiff.d.ts +42 -0
  29. package/dist/lib/git/gitDiff.js +346 -0
  30. package/dist/lib/git/gitDiff.js.map +1 -0
  31. package/dist/lib/git/gitNotes.d.ts +31 -0
  32. package/dist/lib/git/gitNotes.js +93 -0
  33. package/dist/lib/git/gitNotes.js.map +1 -0
  34. package/dist/lib/git/index.d.ts +5 -0
  35. package/dist/lib/git/index.js +22 -0
  36. package/dist/lib/git/index.js.map +1 -0
  37. package/dist/lib/hooks.d.ts +65 -0
  38. package/dist/lib/hooks.js +423 -0
  39. package/dist/lib/hooks.js.map +1 -0
  40. package/dist/lib/index.d.ts +10 -0
  41. package/dist/lib/index.js +33 -0
  42. package/dist/lib/index.js.map +1 -0
  43. package/dist/lib/types.d.ts +190 -0
  44. package/dist/lib/types.js +8 -0
  45. package/dist/lib/types.js.map +1 -0
  46. package/dist/lib/util.d.ts +24 -0
  47. package/dist/lib/util.js +82 -0
  48. package/dist/lib/util.js.map +1 -0
  49. package/dist/process.d.ts +14 -0
  50. package/dist/process.js +224 -0
  51. package/dist/process.js.map +1 -0
  52. package/dist/sync.d.ts +15 -0
  53. package/dist/sync.js +413 -0
  54. package/dist/sync.js.map +1 -0
  55. package/dist/transfer-notes.d.ts +16 -0
  56. package/dist/transfer-notes.js +426 -0
  57. package/dist/transfer-notes.js.map +1 -0
  58. package/package.json +37 -0
package/dist/lib/db.js ADDED
@@ -0,0 +1,290 @@
1
+ "use strict";
2
+ /**
3
+ * Pending Edits Store
4
+ *
5
+ * Reads AI edit logs from ~/.agentblame/logs/ (JSON lines format)
6
+ * Supports line-level matching for precise attribution.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.computeNormalizedHash = exports.computeContentHash = void 0;
43
+ exports.readPendingEdits = readPendingEdits;
44
+ exports.buildLineHashIndex = buildLineHashIndex;
45
+ exports.findLineMatch = findLineMatch;
46
+ exports.markEditsAsMatched = markEditsAsMatched;
47
+ exports.cleanupOldEntries = cleanupOldEntries;
48
+ const fs = __importStar(require("node:fs"));
49
+ const path = __importStar(require("node:path"));
50
+ const util_1 = require("./util");
51
+ Object.defineProperty(exports, "computeContentHash", { enumerable: true, get: function () { return util_1.computeContentHash; } });
52
+ Object.defineProperty(exports, "computeNormalizedHash", { enumerable: true, get: function () { return util_1.computeNormalizedHash; } });
53
+ // =============================================================================
54
+ // Reading Pending Edits
55
+ // =============================================================================
56
+ /**
57
+ * Read all pending edits from log files
58
+ */
59
+ function readPendingEdits() {
60
+ const logsDir = (0, util_1.getLogsDir)();
61
+ const edits = [];
62
+ if (!fs.existsSync(logsDir)) {
63
+ return edits;
64
+ }
65
+ const logFiles = ["cursor-generated.log", "claude-generated.log"];
66
+ for (const file of logFiles) {
67
+ const logPath = path.join(logsDir, file);
68
+ if (!fs.existsSync(logPath)) {
69
+ continue;
70
+ }
71
+ const content = fs.readFileSync(logPath, "utf-8");
72
+ const lines = content.split("\n").filter((line) => line.trim());
73
+ for (let i = 0; i < lines.length; i++) {
74
+ try {
75
+ const entry = JSON.parse(lines[i]);
76
+ // Skip already matched entries
77
+ if (entry.status === "matched") {
78
+ continue;
79
+ }
80
+ // Validate required fields
81
+ if (!entry.content || !entry.file_path || !entry.content_hash) {
82
+ continue;
83
+ }
84
+ edits.push({
85
+ ...entry,
86
+ source_log: file,
87
+ line_number: i,
88
+ });
89
+ }
90
+ catch {
91
+ // Skip malformed lines
92
+ }
93
+ }
94
+ }
95
+ return edits;
96
+ }
97
+ // =============================================================================
98
+ // Line-Level Matching
99
+ // =============================================================================
100
+ /**
101
+ * Build a hash index from pending edits for fast line lookup
102
+ */
103
+ function buildLineHashIndex(edits) {
104
+ const exactHash = new Map();
105
+ const normalizedHash = new Map();
106
+ for (const edit of edits) {
107
+ if (!edit.lines)
108
+ continue;
109
+ for (const line of edit.lines) {
110
+ // Exact hash index
111
+ if (!exactHash.has(line.hash)) {
112
+ exactHash.set(line.hash, []);
113
+ }
114
+ exactHash.get(line.hash).push({ edit, line });
115
+ // Normalized hash index
116
+ if (!normalizedHash.has(line.hash_normalized)) {
117
+ normalizedHash.set(line.hash_normalized, []);
118
+ }
119
+ normalizedHash.get(line.hash_normalized).push({ edit, line });
120
+ }
121
+ }
122
+ return { exactHash, normalizedHash };
123
+ }
124
+ /**
125
+ * Find a line match using the priority strategy:
126
+ * 1. Exact hash match (1.0)
127
+ * 2. Normalized hash match (0.95)
128
+ * 3. Line contained in AI content (0.9)
129
+ * 4. AI content contained in line (0.85)
130
+ */
131
+ function findLineMatch(lineContent, lineHash, lineHashNormalized, filePath, hashIndex, edits) {
132
+ // Strategy 1: Exact hash match
133
+ const exactMatches = hashIndex.exactHash.get(lineHash);
134
+ if (exactMatches && exactMatches.length > 0) {
135
+ // Prefer matches from same file
136
+ const sameFileMatch = exactMatches.find((m) => pathsMatch(m.edit.file_path, filePath));
137
+ const match = sameFileMatch || exactMatches[exactMatches.length - 1];
138
+ return {
139
+ edit: match.edit,
140
+ line: match.line,
141
+ matchType: "exact_hash",
142
+ confidence: 1.0,
143
+ };
144
+ }
145
+ // Strategy 2: Normalized hash match
146
+ const normalizedMatches = hashIndex.normalizedHash.get(lineHashNormalized);
147
+ if (normalizedMatches && normalizedMatches.length > 0) {
148
+ const sameFileMatch = normalizedMatches.find((m) => pathsMatch(m.edit.file_path, filePath));
149
+ const match = sameFileMatch || normalizedMatches[normalizedMatches.length - 1];
150
+ return {
151
+ edit: match.edit,
152
+ line: match.line,
153
+ matchType: "normalized_hash",
154
+ confidence: 0.95,
155
+ };
156
+ }
157
+ // Strategy 3: Line contained in AI edit content
158
+ const normalizedLine = lineContent.trim();
159
+ if (normalizedLine.length > 10) {
160
+ // Only check for non-trivial lines
161
+ for (const edit of edits) {
162
+ if (!pathsMatch(edit.file_path, filePath))
163
+ continue;
164
+ if (edit.content.includes(normalizedLine)) {
165
+ return {
166
+ edit,
167
+ line: { content: normalizedLine, hash: lineHash, hash_normalized: lineHashNormalized },
168
+ matchType: "line_in_ai_content",
169
+ confidence: 0.9,
170
+ };
171
+ }
172
+ }
173
+ }
174
+ // Strategy 4: AI content contained in line (AI wrote part of line)
175
+ for (const edit of edits) {
176
+ if (!pathsMatch(edit.file_path, filePath))
177
+ continue;
178
+ for (const aiLine of edit.lines || []) {
179
+ const trimmedAiLine = aiLine.content.trim();
180
+ if (trimmedAiLine.length > 10 && normalizedLine.includes(trimmedAiLine)) {
181
+ // Check if AI content is >50% of line
182
+ const ratio = trimmedAiLine.length / normalizedLine.length;
183
+ if (ratio > 0.5) {
184
+ return {
185
+ edit,
186
+ line: aiLine,
187
+ matchType: "ai_content_in_line",
188
+ confidence: 0.85,
189
+ };
190
+ }
191
+ }
192
+ }
193
+ }
194
+ return null;
195
+ }
196
+ /**
197
+ * Check if two file paths refer to the same file
198
+ */
199
+ function pathsMatch(path1, path2) {
200
+ const name1 = path1.split("/").pop();
201
+ const name2 = path2.split("/").pop();
202
+ return (name1 === name2 || path1.endsWith(path2) || path2.endsWith(name1 || ""));
203
+ }
204
+ // =============================================================================
205
+ // Marking Edits as Matched
206
+ // =============================================================================
207
+ /**
208
+ * Mark entries as matched in the log file
209
+ */
210
+ function markEditsAsMatched(sourceLog, lineNumbers, commitSha) {
211
+ const logsDir = (0, util_1.getLogsDir)();
212
+ const logPath = path.join(logsDir, sourceLog);
213
+ if (!fs.existsSync(logPath)) {
214
+ return;
215
+ }
216
+ const content = fs.readFileSync(logPath, "utf-8");
217
+ const lines = content.split("\n");
218
+ const lineSet = new Set(lineNumbers);
219
+ const timestamp = new Date().toISOString();
220
+ const updatedLines = lines.map((line, i) => {
221
+ if (!line.trim() || !lineSet.has(i)) {
222
+ return line;
223
+ }
224
+ try {
225
+ const entry = JSON.parse(line);
226
+ entry.status = "matched";
227
+ entry.matched_commit = commitSha;
228
+ entry.matched_at = timestamp;
229
+ return JSON.stringify(entry);
230
+ }
231
+ catch {
232
+ return line;
233
+ }
234
+ });
235
+ fs.writeFileSync(logPath, updatedLines.join("\n"));
236
+ }
237
+ // =============================================================================
238
+ // Cleanup
239
+ // =============================================================================
240
+ /**
241
+ * Clean up old log entries
242
+ * - Removes matched entries older than maxAgeDays
243
+ * - Removes unmatched entries older than expireDays
244
+ */
245
+ function cleanupOldEntries(maxAgeDays = 7, expireDays = 30) {
246
+ const logsDir = (0, util_1.getLogsDir)();
247
+ if (!fs.existsSync(logsDir)) {
248
+ return { removed: 0, kept: 0 };
249
+ }
250
+ const logFiles = ["cursor-generated.log", "claude-generated.log"];
251
+ const now = Date.now();
252
+ const maxAgeMs = maxAgeDays * 24 * 60 * 60 * 1000;
253
+ const expireMs = expireDays * 24 * 60 * 60 * 1000;
254
+ let removed = 0;
255
+ let kept = 0;
256
+ for (const file of logFiles) {
257
+ const logPath = path.join(logsDir, file);
258
+ if (!fs.existsSync(logPath))
259
+ continue;
260
+ const content = fs.readFileSync(logPath, "utf-8");
261
+ const lines = content.split("\n");
262
+ const keptLines = [];
263
+ for (const line of lines) {
264
+ if (!line.trim())
265
+ continue;
266
+ try {
267
+ const entry = JSON.parse(line);
268
+ const timestamp = new Date(entry.timestamp).getTime();
269
+ const age = now - timestamp;
270
+ if (entry.status === "matched" && age > maxAgeMs) {
271
+ removed++;
272
+ }
273
+ else if (!entry.status && age > expireMs) {
274
+ removed++;
275
+ }
276
+ else {
277
+ keptLines.push(line);
278
+ kept++;
279
+ }
280
+ }
281
+ catch {
282
+ keptLines.push(line);
283
+ kept++;
284
+ }
285
+ }
286
+ fs.writeFileSync(logPath, keptLines.join("\n") + (keptLines.length ? "\n" : ""));
287
+ }
288
+ return { removed, kept };
289
+ }
290
+ //# sourceMappingURL=db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/lib/db.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Diff utilities for extracting changes between old and new content
3
+ */
4
+ /**
5
+ * Extract only the added lines from a diff between old and new text.
6
+ * This gives us exactly what the AI wrote, not the entire file.
7
+ */
8
+ export declare function extractAddedContent(oldText: string, newText: string): string;
9
+ /**
10
+ * Check if two pieces of content are substantially the same
11
+ * (ignoring whitespace differences)
12
+ */
13
+ export declare function contentMatches(a: string, b: string): boolean;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ /**
3
+ * Diff utilities for extracting changes between old and new content
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.extractAddedContent = extractAddedContent;
7
+ exports.contentMatches = contentMatches;
8
+ const diff_1 = require("diff");
9
+ /**
10
+ * Extract only the added lines from a diff between old and new text.
11
+ * This gives us exactly what the AI wrote, not the entire file.
12
+ */
13
+ function extractAddedContent(oldText, newText) {
14
+ const parts = (0, diff_1.diffLines)(oldText ?? "", newText ?? "");
15
+ const addedParts = [];
16
+ for (const part of parts) {
17
+ if (part.added) {
18
+ addedParts.push(part.value ?? "");
19
+ }
20
+ }
21
+ return addedParts.join("");
22
+ }
23
+ /**
24
+ * Check if two pieces of content are substantially the same
25
+ * (ignoring whitespace differences)
26
+ */
27
+ function contentMatches(a, b) {
28
+ const normalizeA = a.replace(/\s+/g, " ").trim();
29
+ const normalizeB = b.replace(/\s+/g, " ").trim();
30
+ return normalizeA === normalizeB;
31
+ }
32
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/lib/diff.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAQH,kDAWC;AAMD,wCAIC;AA3BD,+BAAiC;AAEjC;;;GAGG;AACH,SAAgB,mBAAmB,CAAC,OAAe,EAAE,OAAe;IAClE,MAAM,KAAK,GAAG,IAAA,gBAAS,EAAC,OAAO,IAAI,EAAE,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC;IACtD,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,OAAO,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC7B,CAAC;AAED;;;GAGG;AACH,SAAgB,cAAc,CAAC,CAAS,EAAE,CAAS;IACjD,MAAM,UAAU,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACjD,MAAM,UAAU,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACjD,OAAO,UAAU,KAAK,UAAU,CAAC;AACnC,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Git Blame Parser
3
+ *
4
+ * Parses git blame output to get commit information per line
5
+ */
6
+ export interface BlameLine {
7
+ lineNumber: number;
8
+ origLine: number;
9
+ sha: string;
10
+ author: string;
11
+ authorTime: Date;
12
+ content: string;
13
+ }
14
+ export interface BlameResult {
15
+ file: string;
16
+ lines: BlameLine[];
17
+ commits: Map<string, {
18
+ author: string;
19
+ time: Date;
20
+ }>;
21
+ }
22
+ /**
23
+ * Run git blame and parse the output
24
+ */
25
+ export declare function getBlame(repoRoot: string, filePath: string): Promise<BlameResult>;
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ /**
3
+ * Git Blame Parser
4
+ *
5
+ * Parses git blame output to get commit information per line
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.getBlame = getBlame;
9
+ const gitCli_1 = require("./gitCli");
10
+ /**
11
+ * Run git blame and parse the output
12
+ */
13
+ async function getBlame(repoRoot, filePath) {
14
+ // Use --porcelain for machine-readable output
15
+ const result = await (0, gitCli_1.runGit)(repoRoot, ["blame", "--porcelain", filePath], 30000);
16
+ if (result.exitCode !== 0) {
17
+ throw new Error(`git blame failed: ${result.stderr}`);
18
+ }
19
+ return parseBlameOutput(filePath, result.stdout);
20
+ }
21
+ /**
22
+ * Parse git blame --porcelain output
23
+ *
24
+ * Format:
25
+ * <sha> <orig-line> <final-line> <num-lines>
26
+ * author <name>
27
+ * author-mail <email>
28
+ * author-time <timestamp>
29
+ * author-tz <timezone>
30
+ * committer <name>
31
+ * ...
32
+ * filename <path>
33
+ * \t<content>
34
+ */
35
+ function parseBlameOutput(filePath, output) {
36
+ const lines = [];
37
+ const commits = new Map();
38
+ const rawLines = output.split("\n");
39
+ let i = 0;
40
+ let lineNumber = 0;
41
+ while (i < rawLines.length) {
42
+ const headerLine = rawLines[i];
43
+ if (!headerLine || !headerLine.match(/^[0-9a-f]{40}/)) {
44
+ i++;
45
+ continue;
46
+ }
47
+ // Parse header: <sha> <orig-line> <final-line> [<num-lines>]
48
+ const parts = headerLine.split(" ");
49
+ const sha = parts[0];
50
+ const origLine = parseInt(parts[1], 10);
51
+ lineNumber++;
52
+ // Parse metadata until we hit the content line (starts with \t)
53
+ let author = "";
54
+ let authorTime = new Date();
55
+ i++;
56
+ while (i < rawLines.length && !rawLines[i].startsWith("\t")) {
57
+ const line = rawLines[i];
58
+ if (line.startsWith("author ")) {
59
+ author = line.slice(7);
60
+ }
61
+ else if (line.startsWith("author-time ")) {
62
+ authorTime = new Date(parseInt(line.slice(12), 10) * 1000);
63
+ }
64
+ i++;
65
+ }
66
+ // Get content (line starting with \t)
67
+ let content = "";
68
+ if (i < rawLines.length && rawLines[i].startsWith("\t")) {
69
+ content = rawLines[i].slice(1);
70
+ i++;
71
+ }
72
+ // Store commit info
73
+ if (!commits.has(sha)) {
74
+ commits.set(sha, { author, time: authorTime });
75
+ }
76
+ lines.push({
77
+ lineNumber,
78
+ origLine,
79
+ sha,
80
+ author,
81
+ authorTime,
82
+ content,
83
+ });
84
+ }
85
+ return { file: filePath, lines, commits };
86
+ }
87
+ //# sourceMappingURL=gitBlame.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitBlame.js","sourceRoot":"","sources":["../../../src/lib/git/gitBlame.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export interface GitResult {
2
+ exitCode: number;
3
+ stdout: string;
4
+ stderr: string;
5
+ }
6
+ /**
7
+ * Run a git command and return the result
8
+ */
9
+ export declare function runGit(cwd: string, args: string[], timeoutMs?: number): Promise<GitResult>;
10
+ /**
11
+ * Check if a directory is a git repository
12
+ */
13
+ export declare function isGitRepo(dir: string): Promise<boolean>;
14
+ /**
15
+ * Get the root of the git repository
16
+ */
17
+ export declare function getRepoRoot(dir: string): Promise<string | null>;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runGit = runGit;
4
+ exports.isGitRepo = isGitRepo;
5
+ exports.getRepoRoot = getRepoRoot;
6
+ const node_child_process_1 = require("node:child_process");
7
+ /**
8
+ * Run a git command and return the result
9
+ */
10
+ async function runGit(cwd, args, timeoutMs = 30000) {
11
+ return new Promise((resolve) => {
12
+ const proc = (0, node_child_process_1.spawn)("git", args, {
13
+ cwd,
14
+ timeout: timeoutMs,
15
+ stdio: ["ignore", "pipe", "pipe"],
16
+ });
17
+ let stdout = "";
18
+ let stderr = "";
19
+ proc.stdout.on("data", (data) => {
20
+ stdout += data.toString();
21
+ });
22
+ proc.stderr.on("data", (data) => {
23
+ stderr += data.toString();
24
+ });
25
+ proc.on("close", (code) => {
26
+ resolve({
27
+ exitCode: code ?? 1,
28
+ stdout,
29
+ stderr,
30
+ });
31
+ });
32
+ proc.on("error", (err) => {
33
+ resolve({
34
+ exitCode: 1,
35
+ stdout,
36
+ stderr: err.message,
37
+ });
38
+ });
39
+ });
40
+ }
41
+ /**
42
+ * Check if a directory is a git repository
43
+ */
44
+ async function isGitRepo(dir) {
45
+ const result = await runGit(dir, ["rev-parse", "--git-dir"], 5000);
46
+ return result.exitCode === 0;
47
+ }
48
+ /**
49
+ * Get the root of the git repository
50
+ */
51
+ async function getRepoRoot(dir) {
52
+ const result = await runGit(dir, ["rev-parse", "--show-toplevel"], 5000);
53
+ if (result.exitCode !== 0)
54
+ return null;
55
+ return result.stdout.trim() || null;
56
+ }
57
+ //# sourceMappingURL=gitCli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitCli.js","sourceRoot":"","sources":["../../../src/lib/git/gitCli.ts"],"names":[],"mappings":";;AAWA,wBAuCC;AAKD,8BAGC;AAKD,kCAIC;AAnED,2DAA2C;AAQ3C;;GAEG;AACI,KAAK,UAAU,MAAM,CAC1B,GAAW,EACX,IAAc,EACd,SAAS,GAAG,KAAK;IAEjB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,IAAI,GAAG,IAAA,0BAAK,EAAC,KAAK,EAAE,IAAI,EAAE;YAC9B,GAAG;YACH,OAAO,EAAE,SAAS;YAClB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;SAClC,CAAC,CAAC;QAEH,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,MAAM,GAAG,EAAE,CAAC;QAEhB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YAC9B,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YAC9B,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACxB,OAAO,CAAC;gBACN,QAAQ,EAAE,IAAI,IAAI,CAAC;gBACnB,MAAM;gBACN,MAAM;aACP,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACvB,OAAO,CAAC;gBACN,QAAQ,EAAE,CAAC;gBACX,MAAM;gBACN,MAAM,EAAE,GAAG,CAAC,OAAO;aACpB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,SAAS,CAAC,GAAW;IACzC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,WAAW,CAAC,EAAE,IAAI,CAAC,CAAC;IACnE,OAAO,MAAM,CAAC,QAAQ,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,WAAW,CAAC,GAAW;IAC3C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAAE,IAAI,CAAC,CAAC;IACzE,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC;AACtC,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Git configuration for Agent Blame notes
3
+ *
4
+ * Configures auto-push of refs/notes/agentblame.
5
+ * Note: We don't auto-fetch because it fails if notes don't exist on remote.
6
+ * Use fetchNotes() to manually fetch when needed.
7
+ */
8
+ /**
9
+ * Configure a repository to automatically push agentblame notes.
10
+ * Only configures push (not fetch) to avoid errors when notes don't exist on remote.
11
+ */
12
+ export declare function configureNotesSync(repoRoot: string): Promise<boolean>;
13
+ /**
14
+ * Check if notes sync is already configured
15
+ */
16
+ export declare function isNotesSyncConfigured(repoRoot: string): Promise<boolean>;
17
+ /**
18
+ * Remove notes sync configuration
19
+ */
20
+ export declare function removeNotesSync(repoRoot: string): Promise<boolean>;
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ /**
3
+ * Git configuration for Agent Blame notes
4
+ *
5
+ * Configures auto-push of refs/notes/agentblame.
6
+ * Note: We don't auto-fetch because it fails if notes don't exist on remote.
7
+ * Use fetchNotes() to manually fetch when needed.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.configureNotesSync = configureNotesSync;
11
+ exports.isNotesSyncConfigured = isNotesSyncConfigured;
12
+ exports.removeNotesSync = removeNotesSync;
13
+ const gitCli_1 = require("./gitCli");
14
+ /**
15
+ * Configure a repository to automatically push agentblame notes.
16
+ * Only configures push (not fetch) to avoid errors when notes don't exist on remote.
17
+ */
18
+ async function configureNotesSync(repoRoot) {
19
+ try {
20
+ // Check if any push refspec already exists
21
+ const existingPush = await (0, gitCli_1.runGit)(repoRoot, [
22
+ "config",
23
+ "--get-all",
24
+ "remote.origin.push",
25
+ ]).catch(() => ({ stdout: "", exitCode: 1 }));
26
+ // If no push refspec exists, add the default branch push first
27
+ // Otherwise git push would ONLY push notes
28
+ if (!existingPush.stdout.trim()) {
29
+ await (0, gitCli_1.runGit)(repoRoot, [
30
+ "config",
31
+ "--local",
32
+ "--add",
33
+ "remote.origin.push",
34
+ "refs/heads/*",
35
+ ]);
36
+ }
37
+ // Add push refspec for notes (if not already present)
38
+ if (!existingPush.stdout.includes("refs/notes/agentblame")) {
39
+ await (0, gitCli_1.runGit)(repoRoot, [
40
+ "config",
41
+ "--local",
42
+ "--add",
43
+ "remote.origin.push",
44
+ "refs/notes/agentblame",
45
+ ]);
46
+ }
47
+ return true;
48
+ }
49
+ catch {
50
+ return false;
51
+ }
52
+ }
53
+ /**
54
+ * Check if notes sync is already configured
55
+ */
56
+ async function isNotesSyncConfigured(repoRoot) {
57
+ const pushResult = await (0, gitCli_1.runGit)(repoRoot, [
58
+ "config",
59
+ "--get-all",
60
+ "remote.origin.push",
61
+ ]);
62
+ return pushResult.stdout.includes("refs/notes/agentblame");
63
+ }
64
+ /**
65
+ * Remove notes sync configuration
66
+ */
67
+ async function removeNotesSync(repoRoot) {
68
+ try {
69
+ // Remove push refspec
70
+ await (0, gitCli_1.runGit)(repoRoot, [
71
+ "config",
72
+ "--local",
73
+ "--unset-all",
74
+ "remote.origin.push",
75
+ "refs/notes/agentblame",
76
+ ]);
77
+ // Also remove fetch refspec if it exists (from older versions)
78
+ await (0, gitCli_1.runGit)(repoRoot, [
79
+ "config",
80
+ "--local",
81
+ "--unset-all",
82
+ "remote.origin.fetch",
83
+ "refs/notes/agentblame",
84
+ ]).catch(() => { }); // Ignore if not present
85
+ return true;
86
+ }
87
+ catch {
88
+ return false;
89
+ }
90
+ }
91
+ //# sourceMappingURL=gitConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitConfig.js","sourceRoot":"","sources":["../../../src/lib/git/gitConfig.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAQH,gDAoCC;AAKD,sDAUC;AAKD,0CAwBC;AAtFD,qCAAkC;AAElC;;;GAGG;AACI,KAAK,UAAU,kBAAkB,CAAC,QAAgB;IACvD,IAAI,CAAC;QACH,2CAA2C;QAC3C,MAAM,YAAY,GAAG,MAAM,IAAA,eAAM,EAAC,QAAQ,EAAE;YAC1C,QAAQ;YACR,WAAW;YACX,oBAAoB;SACrB,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAE9C,+DAA+D;QAC/D,2CAA2C;QAC3C,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;YAChC,MAAM,IAAA,eAAM,EAAC,QAAQ,EAAE;gBACrB,QAAQ;gBACR,SAAS;gBACT,OAAO;gBACP,oBAAoB;gBACpB,cAAc;aACf,CAAC,CAAC;QACL,CAAC;QAED,sDAAsD;QACtD,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,CAAC;YAC3D,MAAM,IAAA,eAAM,EAAC,QAAQ,EAAE;gBACrB,QAAQ;gBACR,SAAS;gBACT,OAAO;gBACP,oBAAoB;gBACpB,uBAAuB;aACxB,CAAC,CAAC;QACL,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,qBAAqB,CACzC,QAAgB;IAEhB,MAAM,UAAU,GAAG,MAAM,IAAA,eAAM,EAAC,QAAQ,EAAE;QACxC,QAAQ;QACR,WAAW;QACX,oBAAoB;KACrB,CAAC,CAAC;IAEH,OAAO,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC;AAC7D,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,eAAe,CAAC,QAAgB;IACpD,IAAI,CAAC;QACH,sBAAsB;QACtB,MAAM,IAAA,eAAM,EAAC,QAAQ,EAAE;YACrB,QAAQ;YACR,SAAS;YACT,aAAa;YACb,oBAAoB;YACpB,uBAAuB;SACxB,CAAC,CAAC;QAEH,+DAA+D;QAC/D,MAAM,IAAA,eAAM,EAAC,QAAQ,EAAE;YACrB,QAAQ;YACR,SAAS;YACT,aAAa;YACb,qBAAqB;YACrB,uBAAuB;SACxB,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,CAAC,wBAAwB;QAE5C,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}