@mcarvin/smart-diff 1.0.4 → 1.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/README.md +1 -0
- package/dist/index.cjs +307 -219
- package/dist/index.cjs.map +1 -1
- package/dist/index.min.cjs +1 -1
- package/dist/index.min.cjs.map +1 -1
- package/dist/index.min.mjs +1 -1
- package/dist/index.min.mjs.map +1 -1
- package/dist/index.min.umd.js +1 -1
- package/dist/index.min.umd.js.map +1 -1
- package/dist/index.mjs +307 -219
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +307 -219
- package/dist/index.umd.js.map +1 -1
- package/dist/typings/ai/aiConstants.d.ts +3 -0
- package/dist/typings/ai/aiSummary.d.ts +2 -17
- package/dist/typings/ai/aiTypes.d.ts +21 -0
- package/dist/typings/git/commitMessageFilter.d.ts +2 -0
- package/dist/typings/git/diffGitStatus.d.ts +3 -0
- package/dist/typings/git/diffNameStatusParse.d.ts +8 -0
- package/dist/typings/git/diffNumstatParse.d.ts +4 -0
- package/dist/typings/git/diffPathspecs.d.ts +2 -0
- package/dist/typings/git/diffSummaryBuild.d.ts +2 -0
- package/dist/typings/git/diffSummaryParse.d.ts +2 -0
- package/dist/typings/git/diffTypes.d.ts +31 -0
- package/dist/typings/git/gitDiff.d.ts +5 -33
- package/dist/typings/git/gitDiffOps.d.ts +8 -0
- package/dist/typings/index.d.ts +9 -8
- package/package.json +1 -1
package/dist/index.umd.js
CHANGED
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
|
|
39
39
|
function resolveLlmBaseUrl() {
|
|
40
40
|
var _a, _b, _c;
|
|
41
|
-
return (_b = (_a = process.env.LLM_BASE_URL) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : (_c = process.env.OPENAI_BASE_URL) === null || _c === void 0 ? void 0 : _c.trim();
|
|
41
|
+
return ((_b = (_a = process.env.LLM_BASE_URL) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : (_c = process.env.OPENAI_BASE_URL) === null || _c === void 0 ? void 0 : _c.trim());
|
|
42
42
|
}
|
|
43
43
|
function parseHeaderJsonObject(raw) {
|
|
44
44
|
const trimmed = raw === null || raw === void 0 ? void 0 : raw.trim();
|
|
@@ -46,12 +46,14 @@
|
|
|
46
46
|
return {};
|
|
47
47
|
try {
|
|
48
48
|
const parsed = JSON.parse(trimmed);
|
|
49
|
-
if (typeof parsed !==
|
|
49
|
+
if (typeof parsed !== "object" ||
|
|
50
|
+
parsed === null ||
|
|
51
|
+
Array.isArray(parsed)) {
|
|
50
52
|
return {};
|
|
51
53
|
}
|
|
52
54
|
const out = {};
|
|
53
55
|
for (const [key, value] of Object.entries(parsed)) {
|
|
54
|
-
if (typeof value ===
|
|
56
|
+
if (typeof value === "string" && value.length > 0) {
|
|
55
57
|
out[key] = value;
|
|
56
58
|
}
|
|
57
59
|
}
|
|
@@ -68,7 +70,7 @@
|
|
|
68
70
|
return Object.keys(merged).length > 0 ? merged : undefined;
|
|
69
71
|
}
|
|
70
72
|
function findAuthorizationHeaderName(headers) {
|
|
71
|
-
return Object.keys(headers).find((k) => k.toLowerCase() ===
|
|
73
|
+
return Object.keys(headers).find((k) => k.toLowerCase() === "authorization");
|
|
72
74
|
}
|
|
73
75
|
function stripBearerPrefix(value) {
|
|
74
76
|
var _a;
|
|
@@ -111,7 +113,7 @@
|
|
|
111
113
|
var _a, _b, _c, _d, _e;
|
|
112
114
|
const baseURL = resolveLlmBaseUrl();
|
|
113
115
|
const mergedHeaders = (_a = parseLlmDefaultHeadersFromEnv()) !== null && _a !== void 0 ? _a : {};
|
|
114
|
-
const envApiKey = (_e = (_c = (_b = process.env.LLM_API_KEY) === null || _b === void 0 ? void 0 : _b.trim()) !== null && _c !== void 0 ? _c : (_d = process.env.OPENAI_API_KEY) === null || _d === void 0 ? void 0 : _d.trim()) !== null && _e !== void 0 ? _e :
|
|
116
|
+
const envApiKey = (_e = (_c = (_b = process.env.LLM_API_KEY) === null || _b === void 0 ? void 0 : _b.trim()) !== null && _c !== void 0 ? _c : (_d = process.env.OPENAI_API_KEY) === null || _d === void 0 ? void 0 : _d.trim()) !== null && _e !== void 0 ? _e : "";
|
|
115
117
|
let defaultHeaders;
|
|
116
118
|
let apiKey = envApiKey;
|
|
117
119
|
if (apiKey.length === 0) {
|
|
@@ -119,12 +121,16 @@
|
|
|
119
121
|
if (split.apiKeyFromAuthHeader) {
|
|
120
122
|
apiKey = split.apiKeyFromAuthHeader;
|
|
121
123
|
}
|
|
122
|
-
defaultHeaders =
|
|
124
|
+
defaultHeaders =
|
|
125
|
+
Object.keys(split.defaultHeaders).length > 0
|
|
126
|
+
? split.defaultHeaders
|
|
127
|
+
: undefined;
|
|
123
128
|
}
|
|
124
129
|
else {
|
|
125
|
-
defaultHeaders =
|
|
130
|
+
defaultHeaders =
|
|
131
|
+
Object.keys(mergedHeaders).length > 0 ? mergedHeaders : undefined;
|
|
126
132
|
}
|
|
127
|
-
return Object.assign(Object.assign({ apiKey: apiKey.length > 0 ? apiKey :
|
|
133
|
+
return Object.assign(Object.assign({ apiKey: apiKey.length > 0 ? apiKey : "unused" }, (baseURL ? { baseURL } : {})), (defaultHeaders ? { defaultHeaders } : {}));
|
|
128
134
|
}
|
|
129
135
|
function createOpenAiLikeClient() {
|
|
130
136
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -134,9 +140,22 @@
|
|
|
134
140
|
}
|
|
135
141
|
|
|
136
142
|
const DEFAULT_LLM_MAX_DIFF_CHARS = 120000;
|
|
143
|
+
const DEFAULT_GIT_DIFF_SYSTEM_PROMPT = `You are a senior software engineer helping developers understand code and configuration changes from the git context they supplied.
|
|
144
|
+
You receive: commit subject lines (when available), changed file paths, and unified git patch(es)—either one range diff or concatenated per-commit patches, depending on how the diff was produced. Patches may be truncated mid-section with an explicit marker—do not infer changes beyond visible lines.
|
|
145
|
+
Explain what changed in terms of behavior, APIs, data, configuration, security, and operational risk. Tie claims to the patch when possible.
|
|
146
|
+
Produce a concise, developer-focused summary in Markdown.
|
|
147
|
+
Use sections that fit the change (for example: Highlights, Breaking or risky changes, API / contract changes, Data & schema, Configuration & infra, Security & auth, Tests & quality). Omit empty sections.
|
|
148
|
+
Group related changes; do not list every individual file. When multiple commits appear in the context, briefly separate notable themes by commit when helpful.
|
|
149
|
+
If the user message includes a Team line, use that exact team name in the summary title (for example: "## <Team> – Change summary" or similar).`;
|
|
150
|
+
const LLM_GATEWAY_REQUIRED_MESSAGE = "No LLM gateway configured. Set OPENAI_API_KEY or LLM_API_KEY, and/or LLM_BASE_URL or OPENAI_BASE_URL, " +
|
|
151
|
+
"and/or JSON in OPENAI_DEFAULT_HEADERS or LLM_DEFAULT_HEADERS. " +
|
|
152
|
+
"Alternatively pass openAiClientProvider to generateSummary or summarizeGitDiff.";
|
|
153
|
+
|
|
137
154
|
function resolveLlmMaxDiffChars(cliOverride) {
|
|
138
155
|
var _a;
|
|
139
|
-
if (cliOverride !== undefined &&
|
|
156
|
+
if (cliOverride !== undefined &&
|
|
157
|
+
Number.isFinite(cliOverride) &&
|
|
158
|
+
cliOverride > 0) {
|
|
140
159
|
return Math.trunc(cliOverride);
|
|
141
160
|
}
|
|
142
161
|
const raw = (_a = process.env.LLM_MAX_DIFF_CHARS) === null || _a === void 0 ? void 0 : _a.trim();
|
|
@@ -155,70 +174,75 @@
|
|
|
155
174
|
const marker = `\n\n--- TRUNCATED: unified diff was ${diffText.length} characters; only the first ${maxChars} were sent. Narrow the ref range, adjust commit/path filters, or raise maxDiffChars / LLM_MAX_DIFF_CHARS only if your model context allows. ---\n`;
|
|
156
175
|
return diffText.slice(0, maxChars) + marker;
|
|
157
176
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
Use sections that fit the change (for example: Highlights, Breaking or risky changes, API / contract changes, Data & schema, Configuration & infra, Security & auth, Tests & quality). Omit empty sections.
|
|
163
|
-
Group related changes; do not list every individual file. When multiple commits appear in the context, briefly separate notable themes by commit when helpful.
|
|
164
|
-
If the user message includes a Team line, use that exact team name in the summary title (for example: "## <Team> – Change summary" or similar).`;
|
|
165
|
-
const LLM_GATEWAY_REQUIRED_MESSAGE = 'No LLM gateway configured. Set OPENAI_API_KEY or LLM_API_KEY, and/or LLM_BASE_URL or OPENAI_BASE_URL, ' +
|
|
166
|
-
'and/or JSON in OPENAI_DEFAULT_HEADERS or LLM_DEFAULT_HEADERS. ' +
|
|
167
|
-
'Alternatively pass openAiClientProvider to generateSummary or summarizeGitDiff.';
|
|
168
|
-
function generateSummary(diffText, fileNames, commits, flags, openAiClientProvider, diffSummary) {
|
|
177
|
+
function markdownDiffTruncationNotice(originalChars, maxChars) {
|
|
178
|
+
return `> **Truncated diff:** The unified diff was ${originalChars} characters; only the first ${maxChars} were sent to the model. The summary may not reflect the full change set. Narrow the ref range, adjust path filters, or raise \`maxDiffChars\` / \`LLM_MAX_DIFF_CHARS\`—often together with switching to a model whose context window can fit a larger prompt.\n\n`;
|
|
179
|
+
}
|
|
180
|
+
function generateSummary(input) {
|
|
169
181
|
return __awaiter(this, void 0, void 0, function* () {
|
|
170
182
|
var _a, _b;
|
|
183
|
+
const { diffText, fileNames, commits, flags, openAiClientProvider, diffSummary, } = input;
|
|
171
184
|
if (!shouldUseLlmGateway() && openAiClientProvider === undefined) {
|
|
172
185
|
throw new Error(LLM_GATEWAY_REQUIRED_MESSAGE);
|
|
173
186
|
}
|
|
174
187
|
const maxDiffChars = resolveLlmMaxDiffChars(flags.maxDiffChars);
|
|
188
|
+
const diffTruncated = diffText.length > maxDiffChars;
|
|
175
189
|
const diffForLlm = truncateUnifiedDiffForLlm(diffText, maxDiffChars);
|
|
176
190
|
const userContent = buildOpenAiUserContent(flags, commits, fileNames, diffForLlm, diffSummary);
|
|
177
|
-
|
|
191
|
+
const summary = yield callOpenAi(userContent, (_a = flags.model) !== null && _a !== void 0 ? _a : "gpt-4o-mini", (_b = flags.systemPrompt) !== null && _b !== void 0 ? _b : DEFAULT_GIT_DIFF_SYSTEM_PROMPT, openAiClientProvider !== null && openAiClientProvider !== void 0 ? openAiClientProvider : (() => __awaiter(this, void 0, void 0, function* () { return createOpenAiLikeClient(); })));
|
|
192
|
+
if (!diffTruncated) {
|
|
193
|
+
return summary;
|
|
194
|
+
}
|
|
195
|
+
return markdownDiffTruncationNotice(diffText.length, maxDiffChars) + summary;
|
|
178
196
|
});
|
|
179
197
|
}
|
|
180
198
|
function formatRegexFilterLines(flags) {
|
|
181
199
|
var _a, _b;
|
|
182
|
-
const includes = ((_a = flags.commitMessageIncludeRegexes) !== null && _a !== void 0 ? _a : [])
|
|
183
|
-
|
|
200
|
+
const includes = ((_a = flags.commitMessageIncludeRegexes) !== null && _a !== void 0 ? _a : [])
|
|
201
|
+
.map((s) => s.trim())
|
|
202
|
+
.filter(Boolean);
|
|
203
|
+
const excludes = ((_b = flags.commitMessageExcludeRegexes) !== null && _b !== void 0 ? _b : [])
|
|
204
|
+
.map((s) => s.trim())
|
|
205
|
+
.filter(Boolean);
|
|
184
206
|
const incLine = includes.length > 0
|
|
185
|
-
? `Commit message include regexes (OR): ${includes.map((r) => JSON.stringify(r)).join(
|
|
186
|
-
:
|
|
207
|
+
? `Commit message include regexes (OR): ${includes.map((r) => JSON.stringify(r)).join(", ")}\n`
|
|
208
|
+
: "";
|
|
187
209
|
const excLine = excludes.length > 0
|
|
188
|
-
? `Commit message exclude regexes: ${excludes.map((r) => JSON.stringify(r)).join(
|
|
189
|
-
:
|
|
210
|
+
? `Commit message exclude regexes: ${excludes.map((r) => JSON.stringify(r)).join(", ")}\n`
|
|
211
|
+
: "";
|
|
190
212
|
if (!incLine && !excLine) {
|
|
191
|
-
return
|
|
213
|
+
return "Commit message filters: none.\nGit context shape: single unified diff for the full ref range.\n";
|
|
192
214
|
}
|
|
193
215
|
return (`${incLine}${excLine}` +
|
|
194
|
-
|
|
216
|
+
"Git context shape: concatenated per-commit unified patches for commits that pass the message filters.\n");
|
|
195
217
|
}
|
|
196
218
|
function buildOpenAiUserContent(flags, commits, fileNames, diffText, diffSummary) {
|
|
197
219
|
var _a, _b;
|
|
198
220
|
const from = flags.from;
|
|
199
|
-
const to = (_a = flags.to) !== null && _a !== void 0 ? _a :
|
|
221
|
+
const to = (_a = flags.to) !== null && _a !== void 0 ? _a : "HEAD";
|
|
200
222
|
const team = (_b = flags.team) === null || _b === void 0 ? void 0 : _b.trim();
|
|
201
223
|
const ts = new Date().toISOString();
|
|
202
|
-
const teamLine = team ? `Team: ${team}\n` :
|
|
224
|
+
const teamLine = team ? `Team: ${team}\n` : "";
|
|
203
225
|
const filterBlock = formatRegexFilterLines(flags);
|
|
204
226
|
const commitBlock = commits.length > 0
|
|
205
|
-
? commits
|
|
206
|
-
|
|
207
|
-
|
|
227
|
+
? commits
|
|
228
|
+
.map((c) => `- ${c.hash.slice(0, 7)} ${c.message.replace(/\r?\n/g, " ")}`)
|
|
229
|
+
.join("\n")
|
|
230
|
+
: "- (no commits in range after filtering)";
|
|
231
|
+
const pathsBlock = fileNames.length > 0 ? fileNames.join("\n") : "(no paths in diff scope)";
|
|
208
232
|
const structuredDiffSection = diffSummary
|
|
209
233
|
? `=== Structured git context (JSON summary) ===\n${JSON.stringify(diffSummary, null, 2)}\n\n`
|
|
210
|
-
:
|
|
234
|
+
: "";
|
|
211
235
|
return (`${teamLine}` +
|
|
212
236
|
`Date: ${ts}\n\n` +
|
|
213
237
|
`Git refs: ${from}..${to}\n` +
|
|
214
238
|
filterBlock +
|
|
215
|
-
|
|
216
|
-
|
|
239
|
+
"\n" +
|
|
240
|
+
"=== Included commits (subject lines) ===\n" +
|
|
217
241
|
`${commitBlock}\n\n` +
|
|
218
|
-
|
|
242
|
+
"=== Changed paths ===\n" +
|
|
219
243
|
`${pathsBlock}\n\n` +
|
|
220
244
|
structuredDiffSection +
|
|
221
|
-
|
|
245
|
+
"=== Git context (unified diff(s); patches may be truncated with an explicit marker) ===\n" +
|
|
222
246
|
diffText);
|
|
223
247
|
}
|
|
224
248
|
function callOpenAi(userContent, model, systemPrompt, openAiClientProvider) {
|
|
@@ -232,11 +256,11 @@ If the user message includes a Team line, use that exact team name in the summar
|
|
|
232
256
|
model,
|
|
233
257
|
messages: [
|
|
234
258
|
{
|
|
235
|
-
role:
|
|
259
|
+
role: "system",
|
|
236
260
|
content: systemPrompt,
|
|
237
261
|
},
|
|
238
262
|
{
|
|
239
|
-
role:
|
|
263
|
+
role: "user",
|
|
240
264
|
content: userContent,
|
|
241
265
|
},
|
|
242
266
|
],
|
|
@@ -244,64 +268,25 @@ If the user message includes a Team line, use that exact team name in the summar
|
|
|
244
268
|
max_tokens: maxTokens,
|
|
245
269
|
});
|
|
246
270
|
const typedResponse = response;
|
|
247
|
-
const text = (_f = (_e = (_d = (_c = (_b = typedResponse.choices) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.message) === null || _d === void 0 ? void 0 : _d.content) === null || _e === void 0 ? void 0 : _e.trim()) !== null && _f !== void 0 ? _f :
|
|
248
|
-
return text.length > 0 ? text :
|
|
271
|
+
const text = (_f = (_e = (_d = (_c = (_b = typedResponse.choices) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.message) === null || _d === void 0 ? void 0 : _d.content) === null || _e === void 0 ? void 0 : _e.trim()) !== null && _f !== void 0 ? _f : "";
|
|
272
|
+
return text.length > 0 ? text : "No summary generated by OpenAI.";
|
|
249
273
|
});
|
|
250
274
|
}
|
|
251
275
|
|
|
252
|
-
function createGitClient(cwd = process.cwd()) {
|
|
253
|
-
return simpleGit.simpleGit(cwd);
|
|
254
|
-
}
|
|
255
|
-
function getCommits(git, from, to) {
|
|
256
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
257
|
-
const logResult = yield git.log({ from, to });
|
|
258
|
-
return logResult.all;
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
function compileRegex(pattern, label) {
|
|
262
|
-
try {
|
|
263
|
-
return new RegExp(pattern, 'i');
|
|
264
|
-
}
|
|
265
|
-
catch (_a) {
|
|
266
|
-
throw new Error(`Invalid ${label} regular expression: ${JSON.stringify(pattern)}`);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
function commitMessagePassesFilters(message, includeRes, excludeRes) {
|
|
270
|
-
for (const ex of excludeRes) {
|
|
271
|
-
if (ex.test(message))
|
|
272
|
-
return false;
|
|
273
|
-
}
|
|
274
|
-
if (includeRes.length > 0 && !includeRes.some((r) => r.test(message)))
|
|
275
|
-
return false;
|
|
276
|
-
return true;
|
|
277
|
-
}
|
|
278
|
-
function filterCommitsByMessageRegexes(commits, includePatterns, excludePatterns) {
|
|
279
|
-
const includes = (includePatterns !== null && includePatterns !== void 0 ? includePatterns : []).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
280
|
-
const excludes = (excludePatterns !== null && excludePatterns !== void 0 ? excludePatterns : []).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
281
|
-
const includeRes = includes.map((p, i) => compileRegex(p, `commit message include pattern[${i}]`));
|
|
282
|
-
const excludeRes = excludes.map((p, i) => compileRegex(p, `commit message exclude pattern[${i}]`));
|
|
283
|
-
return commits.filter((c) => commitMessagePassesFilters(c.message, includeRes, excludeRes));
|
|
284
|
-
}
|
|
285
|
-
function getRepoRoot(git) {
|
|
286
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
287
|
-
const root = yield git.revparse(['--show-toplevel']);
|
|
288
|
-
return root.trim();
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
276
|
function normalizeRepoRelativePath(p) {
|
|
292
|
-
const trimmed = p.trim().replace(/\\/g,
|
|
293
|
-
const noLeading = trimmed.replace(/^\/+/,
|
|
294
|
-
const noTrailingSlash = noLeading.replace(/\/+$/,
|
|
295
|
-
return noTrailingSlash.length > 0 ? noTrailingSlash :
|
|
277
|
+
const trimmed = p.trim().replace(/\\/g, "/");
|
|
278
|
+
const noLeading = trimmed.replace(/^\/+/, "");
|
|
279
|
+
const noTrailingSlash = noLeading.replace(/\/+$/, "");
|
|
280
|
+
return noTrailingSlash.length > 0 ? noTrailingSlash : ".";
|
|
296
281
|
}
|
|
297
282
|
function assertPathUnderRepo(repoRoot, userPath) {
|
|
298
283
|
const abs = node_path.resolve(repoRoot, userPath);
|
|
299
284
|
const rel = node_path.relative(repoRoot, abs);
|
|
300
|
-
if (rel ===
|
|
285
|
+
if (rel === "..") {
|
|
301
286
|
throw new Error(`Path escapes repository root: ${JSON.stringify(userPath)}`);
|
|
302
287
|
}
|
|
303
288
|
const segments = rel.split(/[/\\]/);
|
|
304
|
-
if (segments.includes(
|
|
289
|
+
if (segments.includes("..")) {
|
|
305
290
|
throw new Error(`Path escapes repository root: ${JSON.stringify(userPath)}`);
|
|
306
291
|
}
|
|
307
292
|
}
|
|
@@ -309,9 +294,13 @@ If the user message includes a Team line, use that exact team name in the summar
|
|
|
309
294
|
var _a, _b, _c, _d;
|
|
310
295
|
const includeRaw = (_b = (_a = pathFilter === null || pathFilter === void 0 ? void 0 : pathFilter.includeFolders) === null || _a === void 0 ? void 0 : _a.filter((p) => p.trim().length > 0)) !== null && _b !== void 0 ? _b : [];
|
|
311
296
|
const excludeRaw = (_d = (_c = pathFilter === null || pathFilter === void 0 ? void 0 : pathFilter.excludeFolders) === null || _c === void 0 ? void 0 : _c.filter((p) => p.trim().length > 0)) !== null && _d !== void 0 ? _d : [];
|
|
312
|
-
const includes = includeRaw
|
|
313
|
-
|
|
314
|
-
|
|
297
|
+
const includes = includeRaw
|
|
298
|
+
.map(normalizeRepoRelativePath)
|
|
299
|
+
.filter((p) => p !== "." && p !== "");
|
|
300
|
+
const excludes = excludeRaw
|
|
301
|
+
.map(normalizeRepoRelativePath)
|
|
302
|
+
.filter((p) => p !== "." && p !== "");
|
|
303
|
+
const toValidate = includes.length > 0 ? includes : ["."];
|
|
315
304
|
for (const inc of toValidate) {
|
|
316
305
|
assertPathUnderRepo(repoRoot, inc);
|
|
317
306
|
}
|
|
@@ -320,7 +309,7 @@ If the user message includes a Team line, use that exact team name in the summar
|
|
|
320
309
|
}
|
|
321
310
|
const specs = [];
|
|
322
311
|
if (includes.length === 0) {
|
|
323
|
-
specs.push(
|
|
312
|
+
specs.push(".");
|
|
324
313
|
}
|
|
325
314
|
else {
|
|
326
315
|
for (const inc of includes) {
|
|
@@ -332,100 +321,73 @@ If the user message includes a Team line, use that exact team name in the summar
|
|
|
332
321
|
}
|
|
333
322
|
return specs;
|
|
334
323
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
344
|
-
const { specs } = yield getDiffPathContext(git, pathFilter, repoRootOverride);
|
|
345
|
-
if (!filterByCommits) {
|
|
346
|
-
return git.diff([`${from}..${to}`, '--', ...specs]);
|
|
347
|
-
}
|
|
348
|
-
const patches = yield Promise.all(commits.map((c) => git.diff([`${c.hash}^!`, '--', ...specs])));
|
|
349
|
-
return patches.filter(Boolean).join('\n');
|
|
350
|
-
});
|
|
324
|
+
|
|
325
|
+
function compileRegex(pattern, label) {
|
|
326
|
+
try {
|
|
327
|
+
return new RegExp(pattern, "i");
|
|
328
|
+
}
|
|
329
|
+
catch (_a) {
|
|
330
|
+
throw new Error(`Invalid ${label} regular expression: ${JSON.stringify(pattern)}`);
|
|
331
|
+
}
|
|
351
332
|
}
|
|
352
|
-
function
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
return buildDiffSummaryFromGitOutputs(nameOutput, numOutput);
|
|
361
|
-
}
|
|
362
|
-
const pairs = yield Promise.all(commits.map((c) => __awaiter(this, void 0, void 0, function* () {
|
|
363
|
-
const range = `${c.hash}^!`;
|
|
364
|
-
const [numOutput, nameOutput] = yield Promise.all([
|
|
365
|
-
git.diff(['--numstat', range, '--', ...specs]),
|
|
366
|
-
git.diff(['--name-status', range, '--', ...specs]),
|
|
367
|
-
]);
|
|
368
|
-
return { numOutput, nameOutput };
|
|
369
|
-
})));
|
|
370
|
-
const nameJoined = pairs
|
|
371
|
-
.map((p) => p.nameOutput)
|
|
372
|
-
.filter(Boolean)
|
|
373
|
-
.join('\n');
|
|
374
|
-
const numJoined = pairs
|
|
375
|
-
.map((p) => p.numOutput)
|
|
376
|
-
.filter(Boolean)
|
|
377
|
-
.join('\n');
|
|
378
|
-
return buildDiffSummaryFromGitOutputs(nameJoined, numJoined);
|
|
379
|
-
});
|
|
333
|
+
function commitMessagePassesFilters(message, includeRes, excludeRes) {
|
|
334
|
+
for (const ex of excludeRes) {
|
|
335
|
+
if (ex.test(message))
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
if (includeRes.length > 0 && !includeRes.some((r) => r.test(message)))
|
|
339
|
+
return false;
|
|
340
|
+
return true;
|
|
380
341
|
}
|
|
381
|
-
function
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
const fileSet = new Set();
|
|
392
|
-
yield Promise.all(commits.map((c) => __awaiter(this, void 0, void 0, function* () {
|
|
393
|
-
const output = yield git.show(['--name-only', '--pretty=format:', c.hash, '--', ...specs]);
|
|
394
|
-
output
|
|
395
|
-
.split(/\r?\n/)
|
|
396
|
-
.map((f) => f.trim())
|
|
397
|
-
.filter(Boolean)
|
|
398
|
-
.forEach((f) => fileSet.add(f));
|
|
399
|
-
})));
|
|
400
|
-
return Array.from(fileSet);
|
|
401
|
-
});
|
|
342
|
+
function filterCommitsByMessageRegexes(commits, includePatterns, excludePatterns) {
|
|
343
|
+
const includes = (includePatterns !== null && includePatterns !== void 0 ? includePatterns : [])
|
|
344
|
+
.map((p) => p.trim())
|
|
345
|
+
.filter((p) => p.length > 0);
|
|
346
|
+
const excludes = (excludePatterns !== null && excludePatterns !== void 0 ? excludePatterns : [])
|
|
347
|
+
.map((p) => p.trim())
|
|
348
|
+
.filter((p) => p.length > 0);
|
|
349
|
+
const includeRes = includes.map((p, i) => compileRegex(p, `commit message include pattern[${i}]`));
|
|
350
|
+
const excludeRes = excludes.map((p, i) => compileRegex(p, `commit message exclude pattern[${i}]`));
|
|
351
|
+
return commits.filter((c) => commitMessagePassesFilters(c.message, includeRes, excludeRes));
|
|
402
352
|
}
|
|
353
|
+
|
|
403
354
|
const GIT_STATUS_BY_FIRST_CHAR = {
|
|
404
|
-
A:
|
|
405
|
-
D:
|
|
406
|
-
R:
|
|
407
|
-
C:
|
|
408
|
-
T:
|
|
409
|
-
M:
|
|
355
|
+
A: "added",
|
|
356
|
+
D: "deleted",
|
|
357
|
+
R: "renamed",
|
|
358
|
+
C: "copied",
|
|
359
|
+
T: "type-changed",
|
|
360
|
+
M: "modified",
|
|
410
361
|
};
|
|
411
362
|
function mapGitStatus(statusCode) {
|
|
412
363
|
var _a;
|
|
413
|
-
return (_a = GIT_STATUS_BY_FIRST_CHAR[statusCode.charAt(0)]) !== null && _a !== void 0 ? _a :
|
|
364
|
+
return (_a = GIT_STATUS_BY_FIRST_CHAR[statusCode.charAt(0)]) !== null && _a !== void 0 ? _a : "unknown";
|
|
414
365
|
}
|
|
415
366
|
function mergeStatus(existing, next) {
|
|
416
367
|
if (existing === next)
|
|
417
368
|
return existing;
|
|
418
|
-
const precedence = [
|
|
419
|
-
|
|
369
|
+
const precedence = [
|
|
370
|
+
"deleted",
|
|
371
|
+
"added",
|
|
372
|
+
"renamed",
|
|
373
|
+
"copied",
|
|
374
|
+
"type-changed",
|
|
375
|
+
"modified",
|
|
376
|
+
"unknown",
|
|
377
|
+
];
|
|
378
|
+
return precedence.indexOf(existing) <= precedence.indexOf(next)
|
|
379
|
+
? existing
|
|
380
|
+
: next;
|
|
420
381
|
}
|
|
382
|
+
|
|
421
383
|
function parseNameStatusLine(line) {
|
|
422
384
|
var _a;
|
|
423
|
-
const parts = line.split(
|
|
385
|
+
const parts = line.split("\t");
|
|
424
386
|
let entry = null;
|
|
425
387
|
if (parts.length >= 2) {
|
|
426
|
-
const statusToken = (_a = parts[0]) !== null && _a !== void 0 ? _a :
|
|
388
|
+
const statusToken = (_a = parts[0]) !== null && _a !== void 0 ? _a : "";
|
|
427
389
|
const status = mapGitStatus(statusToken);
|
|
428
|
-
const isRenameOrCopy = statusToken.startsWith(
|
|
390
|
+
const isRenameOrCopy = statusToken.startsWith("R") || statusToken.startsWith("C");
|
|
429
391
|
if (isRenameOrCopy && parts.length >= 3) {
|
|
430
392
|
const oldPath = parts[1];
|
|
431
393
|
const newPath = parts[2];
|
|
@@ -471,6 +433,7 @@ If the user message includes a Team line, use that exact team name in the summar
|
|
|
471
433
|
}
|
|
472
434
|
return byPath;
|
|
473
435
|
}
|
|
436
|
+
|
|
474
437
|
function numStatPathToLookupKey(pathField) {
|
|
475
438
|
const brace = /^(.*)\{(.+) => (.+)\}$/.exec(pathField);
|
|
476
439
|
if (!brace) {
|
|
@@ -482,14 +445,14 @@ If the user message includes a Team line, use that exact team name in the summar
|
|
|
482
445
|
}
|
|
483
446
|
function parseNumStatLine(line) {
|
|
484
447
|
var _a, _b;
|
|
485
|
-
const parts = line.split(
|
|
448
|
+
const parts = line.split("\t");
|
|
486
449
|
if (parts.length < 3)
|
|
487
450
|
return null;
|
|
488
|
-
const addStr = (_a = parts[0]) !== null && _a !== void 0 ? _a :
|
|
489
|
-
const delStr = (_b = parts[1]) !== null && _b !== void 0 ? _b :
|
|
490
|
-
const pathField = parts.slice(2).join(
|
|
491
|
-
const additions = addStr !==
|
|
492
|
-
const deletions = delStr !==
|
|
451
|
+
const addStr = (_a = parts[0]) !== null && _a !== void 0 ? _a : "";
|
|
452
|
+
const delStr = (_b = parts[1]) !== null && _b !== void 0 ? _b : "";
|
|
453
|
+
const pathField = parts.slice(2).join("\t");
|
|
454
|
+
const additions = addStr !== "-" ? Number.parseInt(addStr, 10) || 0 : 0;
|
|
455
|
+
const deletions = delStr !== "-" ? Number.parseInt(delStr, 10) || 0 : 0;
|
|
493
456
|
const key = numStatPathToLookupKey(pathField);
|
|
494
457
|
return { key, additions, deletions };
|
|
495
458
|
}
|
|
@@ -503,56 +466,35 @@ If the user message includes a Team line, use that exact team name in the summar
|
|
|
503
466
|
if (!parsed)
|
|
504
467
|
continue;
|
|
505
468
|
const prev = (_a = into.get(parsed.key)) !== null && _a !== void 0 ? _a : { additions: 0, deletions: 0 };
|
|
506
|
-
into.set(parsed.key, {
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
added: 'A',
|
|
511
|
-
deleted: 'D',
|
|
512
|
-
renamed: 'R100',
|
|
513
|
-
copied: 'C100',
|
|
514
|
-
'type-changed': 'T',
|
|
515
|
-
modified: 'M',
|
|
516
|
-
unknown: 'X',
|
|
517
|
-
};
|
|
518
|
-
function diffStatusToSyntheticPrefix(status) {
|
|
519
|
-
return STATUS_TO_SYNTHETIC_PREFIX[status];
|
|
520
|
-
}
|
|
521
|
-
function buildSyntheticDiffLine(meta, counts) {
|
|
522
|
-
const prefix = diffStatusToSyntheticPrefix(meta.status);
|
|
523
|
-
if (meta.oldPath) {
|
|
524
|
-
return `${prefix}\t${counts.additions}\t${counts.deletions}\t${meta.oldPath}\t${meta.path}`;
|
|
525
|
-
}
|
|
526
|
-
return `${prefix}\t${counts.additions}\t${counts.deletions}\t${meta.path}`;
|
|
527
|
-
}
|
|
528
|
-
function buildDiffSummaryFromGitOutputs(nameStatusOutput, numStatOutput) {
|
|
529
|
-
var _a;
|
|
530
|
-
const numMap = new Map();
|
|
531
|
-
accumulateNumStat(numStatOutput, numMap);
|
|
532
|
-
const mergedName = mergeNameEntriesByPath(parseNameStatusLines(nameStatusOutput));
|
|
533
|
-
const syntheticLines = [];
|
|
534
|
-
for (const [path, meta] of mergedName) {
|
|
535
|
-
const counts = (_a = numMap.get(path)) !== null && _a !== void 0 ? _a : { additions: 0, deletions: 0 };
|
|
536
|
-
syntheticLines.push(buildSyntheticDiffLine(meta, counts));
|
|
469
|
+
into.set(parsed.key, {
|
|
470
|
+
additions: prev.additions + parsed.additions,
|
|
471
|
+
deletions: prev.deletions + parsed.deletions,
|
|
472
|
+
});
|
|
537
473
|
}
|
|
538
|
-
return parseDiffSummary(syntheticLines.join('\n'));
|
|
539
474
|
}
|
|
475
|
+
|
|
540
476
|
function parseTabDiffSummaryLine(line) {
|
|
541
477
|
var _a;
|
|
542
|
-
const parts = line.split(
|
|
478
|
+
const parts = line.split("\t");
|
|
543
479
|
if (parts.length < 3)
|
|
544
480
|
return null;
|
|
545
|
-
const statusToken = (_a = parts.shift()) !== null && _a !== void 0 ? _a :
|
|
481
|
+
const statusToken = (_a = parts.shift()) !== null && _a !== void 0 ? _a : "";
|
|
546
482
|
const status = mapGitStatus(statusToken);
|
|
547
483
|
const add0 = parts[0];
|
|
548
484
|
const del0 = parts[1];
|
|
549
|
-
const additions = add0 && add0 !==
|
|
550
|
-
const deletions = del0 && del0 !==
|
|
485
|
+
const additions = add0 && add0 !== "-" ? Number.parseInt(add0, 10) || 0 : 0;
|
|
486
|
+
const deletions = del0 && del0 !== "-" ? Number.parseInt(del0, 10) || 0 : 0;
|
|
551
487
|
if (parts.length === 3) {
|
|
552
488
|
return { status, additions, deletions, newPath: parts[2] };
|
|
553
489
|
}
|
|
554
490
|
if (parts.length === 4) {
|
|
555
|
-
return {
|
|
491
|
+
return {
|
|
492
|
+
status,
|
|
493
|
+
additions,
|
|
494
|
+
deletions,
|
|
495
|
+
oldPath: parts[2],
|
|
496
|
+
newPath: parts[3],
|
|
497
|
+
};
|
|
556
498
|
}
|
|
557
499
|
return null;
|
|
558
500
|
}
|
|
@@ -598,11 +540,142 @@ If the user message includes a Team line, use that exact team name in the summar
|
|
|
598
540
|
};
|
|
599
541
|
}
|
|
600
542
|
|
|
543
|
+
const STATUS_TO_SYNTHETIC_PREFIX = {
|
|
544
|
+
added: "A",
|
|
545
|
+
deleted: "D",
|
|
546
|
+
renamed: "R100",
|
|
547
|
+
copied: "C100",
|
|
548
|
+
"type-changed": "T",
|
|
549
|
+
modified: "M",
|
|
550
|
+
unknown: "X",
|
|
551
|
+
};
|
|
552
|
+
function diffStatusToSyntheticPrefix(status) {
|
|
553
|
+
return STATUS_TO_SYNTHETIC_PREFIX[status];
|
|
554
|
+
}
|
|
555
|
+
function buildSyntheticDiffLine(meta, counts) {
|
|
556
|
+
const prefix = diffStatusToSyntheticPrefix(meta.status);
|
|
557
|
+
if (meta.oldPath) {
|
|
558
|
+
return `${prefix}\t${counts.additions}\t${counts.deletions}\t${meta.oldPath}\t${meta.path}`;
|
|
559
|
+
}
|
|
560
|
+
return `${prefix}\t${counts.additions}\t${counts.deletions}\t${meta.path}`;
|
|
561
|
+
}
|
|
562
|
+
function buildDiffSummaryFromGitOutputs(nameStatusOutput, numStatOutput) {
|
|
563
|
+
var _a;
|
|
564
|
+
const numMap = new Map();
|
|
565
|
+
accumulateNumStat(numStatOutput, numMap);
|
|
566
|
+
const mergedName = mergeNameEntriesByPath(parseNameStatusLines(nameStatusOutput));
|
|
567
|
+
const syntheticLines = [];
|
|
568
|
+
for (const [path, meta] of mergedName) {
|
|
569
|
+
const counts = (_a = numMap.get(path)) !== null && _a !== void 0 ? _a : { additions: 0, deletions: 0 };
|
|
570
|
+
syntheticLines.push(buildSyntheticDiffLine(meta, counts));
|
|
571
|
+
}
|
|
572
|
+
return parseDiffSummary(syntheticLines.join("\n"));
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
function createGitClient(cwd = process.cwd()) {
|
|
576
|
+
return simpleGit.simpleGit(cwd);
|
|
577
|
+
}
|
|
578
|
+
function getCommits(git, from, to) {
|
|
579
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
580
|
+
const logResult = yield git.log({ from, to });
|
|
581
|
+
return logResult.all;
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
function getRepoRoot(git) {
|
|
585
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
586
|
+
const root = yield git.revparse(["--show-toplevel"]);
|
|
587
|
+
return root.trim();
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
function getDiffPathContext(git, pathFilter, repoRootOverride) {
|
|
591
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
592
|
+
const repoRoot = repoRootOverride !== null && repoRootOverride !== void 0 ? repoRootOverride : (yield getRepoRoot(git));
|
|
593
|
+
const specs = buildDiffPathspecs(repoRoot, pathFilter);
|
|
594
|
+
return { repoRoot, specs };
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
function getDiff(git, query) {
|
|
598
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
599
|
+
const { from, to, commits, filterByCommits, pathFilter, repoRootOverride } = query;
|
|
600
|
+
const { specs } = yield getDiffPathContext(git, pathFilter, repoRootOverride);
|
|
601
|
+
if (!filterByCommits) {
|
|
602
|
+
return git.diff([`${from}..${to}`, "--", ...specs]);
|
|
603
|
+
}
|
|
604
|
+
const patches = yield Promise.all(commits.map((c) => git.diff([`${c.hash}^!`, "--", ...specs])));
|
|
605
|
+
return patches.filter(Boolean).join("\n");
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
function getDiffSummary(git, query) {
|
|
609
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
610
|
+
const { from, to, commits, filterByCommits, pathFilter, repoRootOverride } = query;
|
|
611
|
+
const { specs } = yield getDiffPathContext(git, pathFilter, repoRootOverride);
|
|
612
|
+
if (!filterByCommits) {
|
|
613
|
+
const [numOutput, nameOutput] = yield Promise.all([
|
|
614
|
+
git.diff(["--numstat", `${from}..${to}`, "--", ...specs]),
|
|
615
|
+
git.diff(["--name-status", `${from}..${to}`, "--", ...specs]),
|
|
616
|
+
]);
|
|
617
|
+
return buildDiffSummaryFromGitOutputs(nameOutput, numOutput);
|
|
618
|
+
}
|
|
619
|
+
const pairs = yield Promise.all(commits.map((c) => __awaiter(this, void 0, void 0, function* () {
|
|
620
|
+
const range = `${c.hash}^!`;
|
|
621
|
+
const [numOutput, nameOutput] = yield Promise.all([
|
|
622
|
+
git.diff(["--numstat", range, "--", ...specs]),
|
|
623
|
+
git.diff(["--name-status", range, "--", ...specs]),
|
|
624
|
+
]);
|
|
625
|
+
return { numOutput, nameOutput };
|
|
626
|
+
})));
|
|
627
|
+
const nameJoined = pairs
|
|
628
|
+
.map((p) => p.nameOutput)
|
|
629
|
+
.filter(Boolean)
|
|
630
|
+
.join("\n");
|
|
631
|
+
const numJoined = pairs
|
|
632
|
+
.map((p) => p.numOutput)
|
|
633
|
+
.filter(Boolean)
|
|
634
|
+
.join("\n");
|
|
635
|
+
return buildDiffSummaryFromGitOutputs(nameJoined, numJoined);
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
function getChangedFiles(git, query) {
|
|
639
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
640
|
+
const { from, to, commits, filterByCommits, pathFilter, repoRootOverride } = query;
|
|
641
|
+
const { specs } = yield getDiffPathContext(git, pathFilter, repoRootOverride);
|
|
642
|
+
if (!filterByCommits) {
|
|
643
|
+
const output = yield git.diff([
|
|
644
|
+
"--name-only",
|
|
645
|
+
`${from}..${to}`,
|
|
646
|
+
"--",
|
|
647
|
+
...specs,
|
|
648
|
+
]);
|
|
649
|
+
return output
|
|
650
|
+
.split(/\r?\n/)
|
|
651
|
+
.map((f) => f.trim())
|
|
652
|
+
.filter(Boolean);
|
|
653
|
+
}
|
|
654
|
+
const fileSet = new Set();
|
|
655
|
+
yield Promise.all(commits.map((c) => __awaiter(this, void 0, void 0, function* () {
|
|
656
|
+
const output = yield git.show([
|
|
657
|
+
"--name-only",
|
|
658
|
+
"--pretty=format:",
|
|
659
|
+
c.hash,
|
|
660
|
+
"--",
|
|
661
|
+
...specs,
|
|
662
|
+
]);
|
|
663
|
+
output
|
|
664
|
+
.split(/\r?\n/)
|
|
665
|
+
.map((f) => f.trim())
|
|
666
|
+
.filter(Boolean)
|
|
667
|
+
.forEach((f) => fileSet.add(f));
|
|
668
|
+
})));
|
|
669
|
+
return Array.from(fileSet);
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
|
|
601
673
|
function hasNonEmptyTrimmed(arr) {
|
|
602
674
|
return (arr !== null && arr !== void 0 ? arr : []).some((s) => s.trim().length > 0);
|
|
603
675
|
}
|
|
604
676
|
function shouldFilterByCommits(allCommits, filtered, opts) {
|
|
605
|
-
if (hasNonEmptyTrimmed(opts.commitMessageIncludeRegexes) ||
|
|
677
|
+
if (hasNonEmptyTrimmed(opts.commitMessageIncludeRegexes) ||
|
|
678
|
+
hasNonEmptyTrimmed(opts.commitMessageExcludeRegexes)) {
|
|
606
679
|
return true;
|
|
607
680
|
}
|
|
608
681
|
return filtered.length !== allCommits.length;
|
|
@@ -612,8 +685,9 @@ If the user message includes a Team line, use that exact team name in the summar
|
|
|
612
685
|
var _a, _b;
|
|
613
686
|
const git = (_a = options.git) !== null && _a !== void 0 ? _a : createGitClient(options.cwd);
|
|
614
687
|
const from = options.from;
|
|
615
|
-
const to = (_b = options.to) !== null && _b !== void 0 ? _b :
|
|
616
|
-
const pathFilter = hasNonEmptyTrimmed(options.includeFolders) ||
|
|
688
|
+
const to = (_b = options.to) !== null && _b !== void 0 ? _b : "HEAD";
|
|
689
|
+
const pathFilter = hasNonEmptyTrimmed(options.includeFolders) ||
|
|
690
|
+
hasNonEmptyTrimmed(options.excludeFolders)
|
|
617
691
|
? {
|
|
618
692
|
includeFolders: options.includeFolders,
|
|
619
693
|
excludeFolders: options.excludeFolders,
|
|
@@ -622,10 +696,17 @@ If the user message includes a Team line, use that exact team name in the summar
|
|
|
622
696
|
const allCommits = yield getCommits(git, from, to);
|
|
623
697
|
const filteredCommits = filterCommitsByMessageRegexes(allCommits, options.commitMessageIncludeRegexes, options.commitMessageExcludeRegexes);
|
|
624
698
|
const filterByCommits = shouldFilterByCommits(allCommits, filteredCommits, options);
|
|
699
|
+
const rangeQuery = {
|
|
700
|
+
from,
|
|
701
|
+
to,
|
|
702
|
+
commits: filteredCommits,
|
|
703
|
+
filterByCommits,
|
|
704
|
+
pathFilter,
|
|
705
|
+
};
|
|
625
706
|
const [diffText, fileNames, diffSummary] = yield Promise.all([
|
|
626
|
-
getDiff(git,
|
|
627
|
-
getChangedFiles(git,
|
|
628
|
-
getDiffSummary(git,
|
|
707
|
+
getDiff(git, rangeQuery),
|
|
708
|
+
getChangedFiles(git, rangeQuery),
|
|
709
|
+
getDiffSummary(git, rangeQuery),
|
|
629
710
|
]);
|
|
630
711
|
const summarizeFlags = {
|
|
631
712
|
from,
|
|
@@ -637,7 +718,14 @@ If the user message includes a Team line, use that exact team name in the summar
|
|
|
637
718
|
commitMessageIncludeRegexes: options.commitMessageIncludeRegexes,
|
|
638
719
|
commitMessageExcludeRegexes: options.commitMessageExcludeRegexes,
|
|
639
720
|
};
|
|
640
|
-
return generateSummary(
|
|
721
|
+
return generateSummary({
|
|
722
|
+
diffText,
|
|
723
|
+
fileNames,
|
|
724
|
+
commits: filteredCommits,
|
|
725
|
+
flags: summarizeFlags,
|
|
726
|
+
openAiClientProvider: options.openAiClientProvider,
|
|
727
|
+
diffSummary,
|
|
728
|
+
});
|
|
641
729
|
});
|
|
642
730
|
}
|
|
643
731
|
|