@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.
- package/dist/blame.d.ts +14 -0
- package/dist/blame.js +252 -0
- package/dist/blame.js.map +1 -0
- package/dist/capture.d.ts +16 -0
- package/dist/capture.js +284 -0
- package/dist/capture.js.map +1 -0
- package/dist/cleanup.d.ts +10 -0
- package/dist/cleanup.js +136 -0
- package/dist/cleanup.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +240 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/db.d.ts +53 -0
- package/dist/lib/db.js +290 -0
- package/dist/lib/db.js.map +1 -0
- package/dist/lib/diff.d.ts +13 -0
- package/dist/lib/diff.js +32 -0
- package/dist/lib/diff.js.map +1 -0
- package/dist/lib/git/gitBlame.d.ts +25 -0
- package/dist/lib/git/gitBlame.js +87 -0
- package/dist/lib/git/gitBlame.js.map +1 -0
- package/dist/lib/git/gitCli.d.ts +17 -0
- package/dist/lib/git/gitCli.js +57 -0
- package/dist/lib/git/gitCli.js.map +1 -0
- package/dist/lib/git/gitConfig.d.ts +20 -0
- package/dist/lib/git/gitConfig.js +91 -0
- package/dist/lib/git/gitConfig.js.map +1 -0
- package/dist/lib/git/gitDiff.d.ts +42 -0
- package/dist/lib/git/gitDiff.js +346 -0
- package/dist/lib/git/gitDiff.js.map +1 -0
- package/dist/lib/git/gitNotes.d.ts +31 -0
- package/dist/lib/git/gitNotes.js +93 -0
- package/dist/lib/git/gitNotes.js.map +1 -0
- package/dist/lib/git/index.d.ts +5 -0
- package/dist/lib/git/index.js +22 -0
- package/dist/lib/git/index.js.map +1 -0
- package/dist/lib/hooks.d.ts +65 -0
- package/dist/lib/hooks.js +423 -0
- package/dist/lib/hooks.js.map +1 -0
- package/dist/lib/index.d.ts +10 -0
- package/dist/lib/index.js +33 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/types.d.ts +190 -0
- package/dist/lib/types.js +8 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/util.d.ts +24 -0
- package/dist/lib/util.js +82 -0
- package/dist/lib/util.js.map +1 -0
- package/dist/process.d.ts +14 -0
- package/dist/process.js +224 -0
- package/dist/process.js.map +1 -0
- package/dist/sync.d.ts +15 -0
- package/dist/sync.js +413 -0
- package/dist/sync.js.map +1 -0
- package/dist/transfer-notes.d.ts +16 -0
- package/dist/transfer-notes.js +426 -0
- package/dist/transfer-notes.js.map +1 -0
- 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":";AAAA;;;;;GAKG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoBH,4CA6CC;AASD,gDAgCC;AAgBD,sCA+EC;AAqBD,gDAkCC;AAWD,8CAsDC;AA/TD,4CAA8B;AAC9B,gDAAkC;AAQlC,iCAA+E;AA6TtE,mGA7TY,yBAAkB,OA6TZ;AAAE,sGA7TY,4BAAqB,OA6TZ;AA3TlD,gFAAgF;AAChF,wBAAwB;AACxB,gFAAgF;AAEhF;;GAEG;AACH,SAAgB,gBAAgB;IAC9B,MAAM,OAAO,GAAG,IAAA,iBAAU,GAAE,CAAC;IAC7B,MAAM,KAAK,GAAkB,EAAE,CAAC;IAEhC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,QAAQ,GAAG,CAAC,sBAAsB,EAAE,sBAAsB,CAAC,CAAC;IAElE,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACzC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAEhE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAiB,CAAC;gBAEnD,+BAA+B;gBAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;oBAC/B,SAAS;gBACX,CAAC;gBAED,2BAA2B;gBAC3B,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;oBAC9D,SAAS;gBACX,CAAC;gBAED,KAAK,CAAC,IAAI,CAAC;oBACT,GAAG,KAAK;oBACR,UAAU,EAAE,IAAI;oBAChB,WAAW,EAAE,CAAC;iBACf,CAAC,CAAC;YACL,CAAC;YAAC,MAAM,CAAC;gBACP,uBAAuB;YACzB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,gFAAgF;AAChF,sBAAsB;AACtB,gFAAgF;AAEhF;;GAEG;AACH,SAAgB,kBAAkB,CAAC,KAAoB;IAIrD,MAAM,SAAS,GAAG,IAAI,GAAG,EAGtB,CAAC;IACJ,MAAM,cAAc,GAAG,IAAI,GAAG,EAG3B,CAAC;IAEJ,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,SAAS;QAE1B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,mBAAmB;YACnB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9B,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC/B,CAAC;YACD,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAE,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAE/C,wBAAwB;YACxB,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC;gBAC9C,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;YAC/C,CAAC;YACD,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAE,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC;AACvC,CAAC;AASD;;;;;;GAMG;AACH,SAAgB,aAAa,CAC3B,WAAmB,EACnB,QAAgB,EAChB,kBAA0B,EAC1B,QAAgB,EAChB,SAAgD,EAChD,KAAoB;IAEpB,+BAA+B;IAC/B,MAAM,YAAY,GAAG,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACvD,IAAI,YAAY,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5C,gCAAgC;QAChC,MAAM,aAAa,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAC5C,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CACvC,CAAC;QACF,MAAM,KAAK,GAAG,aAAa,IAAI,YAAY,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACrE,OAAO;YACL,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,SAAS,EAAE,YAAY;YACvB,UAAU,EAAE,GAAG;SAChB,CAAC;IACJ,CAAC;IAED,oCAAoC;IACpC,MAAM,iBAAiB,GAAG,SAAS,CAAC,cAAc,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAC3E,IAAI,iBAAiB,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtD,MAAM,aAAa,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CACjD,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CACvC,CAAC;QACF,MAAM,KAAK,GAAG,aAAa,IAAI,iBAAiB,CAAC,iBAAiB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC/E,OAAO;YACL,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,SAAS,EAAE,iBAAiB;YAC5B,UAAU,EAAE,IAAI;SACjB,CAAC;IACJ,CAAC;IAED,gDAAgD;IAChD,MAAM,cAAc,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;IAC1C,IAAI,cAAc,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QAC/B,mCAAmC;QACnC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC;gBAAE,SAAS;YAEpD,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;gBAC1C,OAAO;oBACL,IAAI;oBACJ,IAAI,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,EAAE,eAAe,EAAE,kBAAkB,EAAE;oBACtF,SAAS,EAAE,oBAAoB;oBAC/B,UAAU,EAAE,GAAG;iBAChB,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,mEAAmE;IACnE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC;YAAE,SAAS;QAEpD,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;YACtC,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,aAAa,CAAC,MAAM,GAAG,EAAE,IAAI,cAAc,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;gBACxE,sCAAsC;gBACtC,MAAM,KAAK,GAAG,aAAa,CAAC,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC;gBAC3D,IAAI,KAAK,GAAG,GAAG,EAAE,CAAC;oBAChB,OAAO;wBACL,IAAI;wBACJ,IAAI,EAAE,MAAM;wBACZ,SAAS,EAAE,oBAAoB;wBAC/B,UAAU,EAAE,IAAI;qBACjB,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAS,UAAU,CAAC,KAAa,EAAE,KAAa;IAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;IACrC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;IAErC,OAAO,CACL,KAAK,KAAK,KAAK,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC,CACxE,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,2BAA2B;AAC3B,gFAAgF;AAEhF;;GAEG;AACH,SAAgB,kBAAkB,CAChC,SAAiB,EACjB,WAAqB,EACrB,SAAiB;IAEjB,MAAM,OAAO,GAAG,IAAA,iBAAU,GAAE,CAAC;IAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAE9C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAClD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAElC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;IACrC,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAE3C,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;QACzC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACpC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC/B,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC;YACzB,KAAK,CAAC,cAAc,GAAG,SAAS,CAAC;YACjC,KAAK,CAAC,UAAU,GAAG,SAAS,CAAC;YAC7B,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,gFAAgF;AAChF,UAAU;AACV,gFAAgF;AAEhF;;;;GAIG;AACH,SAAgB,iBAAiB,CAC/B,UAAU,GAAG,CAAC,EACd,UAAU,GAAG,EAAE;IAEf,MAAM,OAAO,GAAG,IAAA,iBAAU,GAAE,CAAC;IAC7B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IACjC,CAAC;IAED,MAAM,QAAQ,GAAG,CAAC,sBAAsB,EAAE,sBAAsB,CAAC,CAAC;IAClE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,QAAQ,GAAG,UAAU,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAClD,MAAM,QAAQ,GAAG,UAAU,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAElD,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,IAAI,GAAG,CAAC,CAAC;IAEb,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACzC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;YAAE,SAAS;QAEtC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,SAAS,GAAa,EAAE,CAAC;QAE/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;gBAAE,SAAS;YAE3B,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC/B,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;gBACtD,MAAM,GAAG,GAAG,GAAG,GAAG,SAAS,CAAC;gBAE5B,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,GAAG,GAAG,QAAQ,EAAE,CAAC;oBACjD,OAAO,EAAE,CAAC;gBACZ,CAAC;qBAAM,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,GAAG,GAAG,QAAQ,EAAE,CAAC;oBAC3C,OAAO,EAAE,CAAC;gBACZ,CAAC;qBAAM,CAAC;oBACN,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBACrB,IAAI,EAAE,CAAC;gBACT,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACrB,IAAI,EAAE,CAAC;YACT,CAAC;QACH,CAAC;QAED,EAAE,CAAC,aAAa,CACd,OAAO,EACP,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CACtD,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC3B,CAAC"}
|
|
@@ -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;
|
package/dist/lib/diff.js
ADDED
|
@@ -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"}
|