@mcarvin/smart-diff 1.1.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +123 -21
- package/dist/index.cjs +447 -134
- 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 +441 -131
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +450 -138
- package/dist/index.umd.js.map +1 -1
- package/dist/typings/ai/aiTypes.d.ts +5 -3
- package/dist/typings/ai/llmProviders.d.ts +12 -0
- package/dist/typings/git/diffShaping.d.ts +9 -0
- package/dist/typings/git/diffTypes.d.ts +2 -0
- package/dist/typings/git/gitDiff.d.ts +2 -0
- package/dist/typings/index.d.ts +14 -7
- package/package.json +34 -7
- package/dist/typings/ai/openAIConfig.d.ts +0 -21
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var ai = require('ai');
|
|
3
4
|
var node_path = require('node:path');
|
|
4
5
|
var simpleGit = require('simple-git');
|
|
5
6
|
|
|
@@ -35,9 +36,55 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
35
36
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
36
37
|
};
|
|
37
38
|
|
|
39
|
+
const DEFAULT_LLM_MAX_DIFF_CHARS = 120000;
|
|
40
|
+
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.
|
|
41
|
+
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.
|
|
42
|
+
Explain what changed in terms of behavior, APIs, data, configuration, security, and operational risk. Tie claims to the patch when possible.
|
|
43
|
+
Produce a concise, developer-focused summary in Markdown.
|
|
44
|
+
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.
|
|
45
|
+
Group related changes; do not list every individual file. When multiple commits appear in the context, briefly separate notable themes by commit when helpful.
|
|
46
|
+
If the user message includes a Team line, use that exact team name in the summary title (for example: "## <Team> – Change summary" or similar).`;
|
|
47
|
+
const LLM_GATEWAY_REQUIRED_MESSAGE = "No LLM provider configured. Set LLM_PROVIDER (openai | openai-compatible | anthropic | google | bedrock | mistral | cohere | groq | xai | deepseek), " +
|
|
48
|
+
"or a provider API key (OPENAI_API_KEY, LLM_API_KEY, ANTHROPIC_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, MISTRAL_API_KEY, COHERE_API_KEY, GROQ_API_KEY, XAI_API_KEY, DEEPSEEK_API_KEY), " +
|
|
49
|
+
"or LLM_BASE_URL / OPENAI_BASE_URL for an OpenAI-compatible gateway, " +
|
|
50
|
+
"or JSON in OPENAI_DEFAULT_HEADERS / LLM_DEFAULT_HEADERS. " +
|
|
51
|
+
"Alternatively pass llmModelProvider or openAiClientProvider to generateSummary or summarizeGitDiff.";
|
|
52
|
+
|
|
53
|
+
const DEFAULT_MODEL_BY_PROVIDER = {
|
|
54
|
+
openai: "gpt-4o-mini",
|
|
55
|
+
"openai-compatible": "gpt-4o-mini",
|
|
56
|
+
anthropic: "claude-3-5-haiku-latest",
|
|
57
|
+
google: "gemini-2.0-flash",
|
|
58
|
+
bedrock: "anthropic.claude-3-5-haiku-20241022-v1:0",
|
|
59
|
+
mistral: "mistral-small-latest",
|
|
60
|
+
cohere: "command-r-08-2024",
|
|
61
|
+
groq: "llama-3.1-8b-instant",
|
|
62
|
+
xai: "grok-2-latest",
|
|
63
|
+
deepseek: "deepseek-chat",
|
|
64
|
+
};
|
|
65
|
+
const VALID_PROVIDERS = new Set([
|
|
66
|
+
"openai",
|
|
67
|
+
"openai-compatible",
|
|
68
|
+
"anthropic",
|
|
69
|
+
"google",
|
|
70
|
+
"bedrock",
|
|
71
|
+
"mistral",
|
|
72
|
+
"cohere",
|
|
73
|
+
"groq",
|
|
74
|
+
"xai",
|
|
75
|
+
"deepseek",
|
|
76
|
+
]);
|
|
77
|
+
function readEnv(name) {
|
|
78
|
+
var _a;
|
|
79
|
+
const value = (_a = process.env[name]) === null || _a === void 0 ? void 0 : _a.trim();
|
|
80
|
+
return value && value.length > 0 ? value : undefined;
|
|
81
|
+
}
|
|
82
|
+
function isValidProviderId(value) {
|
|
83
|
+
return VALID_PROVIDERS.has(value);
|
|
84
|
+
}
|
|
38
85
|
function resolveLlmBaseUrl() {
|
|
39
|
-
var _a
|
|
40
|
-
return (
|
|
86
|
+
var _a;
|
|
87
|
+
return (_a = readEnv("LLM_BASE_URL")) !== null && _a !== void 0 ? _a : readEnv("OPENAI_BASE_URL");
|
|
41
88
|
}
|
|
42
89
|
function parseHeaderJsonObject(raw) {
|
|
43
90
|
const trimmed = raw === null || raw === void 0 ? void 0 : raw.trim();
|
|
@@ -68,87 +115,187 @@ function parseLlmDefaultHeadersFromEnv() {
|
|
|
68
115
|
const merged = Object.assign(Object.assign({}, base), override);
|
|
69
116
|
return Object.keys(merged).length > 0 ? merged : undefined;
|
|
70
117
|
}
|
|
71
|
-
function
|
|
72
|
-
return Object.keys(headers).find((k) => k.toLowerCase() === "authorization");
|
|
73
|
-
}
|
|
74
|
-
function stripBearerPrefix(value) {
|
|
118
|
+
function resolveOpenAiApiKey() {
|
|
75
119
|
var _a;
|
|
76
|
-
|
|
77
|
-
const match = /^Bearer\s+(\S+)/i.exec(trimmed);
|
|
78
|
-
return (_a = match === null || match === void 0 ? void 0 : match[1]) !== null && _a !== void 0 ? _a : trimmed;
|
|
79
|
-
}
|
|
80
|
-
function splitPromotableAuthorizationFromHeaders(headers) {
|
|
81
|
-
const authName = findAuthorizationHeaderName(headers);
|
|
82
|
-
if (!authName) {
|
|
83
|
-
return { defaultHeaders: headers };
|
|
84
|
-
}
|
|
85
|
-
const raw = headers[authName];
|
|
86
|
-
if (!raw) {
|
|
87
|
-
return { defaultHeaders: headers };
|
|
88
|
-
}
|
|
89
|
-
const token = stripBearerPrefix(raw);
|
|
90
|
-
const looksBearer = /^Bearer\s+\S+/i.test(raw.trim());
|
|
91
|
-
const looksOpenAiKey = /^sk-/i.test(token);
|
|
92
|
-
if (!looksBearer && !looksOpenAiKey) {
|
|
93
|
-
return { defaultHeaders: headers };
|
|
94
|
-
}
|
|
95
|
-
const next = Object.assign({}, headers);
|
|
96
|
-
delete next[authName];
|
|
97
|
-
return { defaultHeaders: next, apiKeyFromAuthHeader: token };
|
|
98
|
-
}
|
|
99
|
-
function shouldUseLlmGateway() {
|
|
100
|
-
var _a, _b, _c;
|
|
101
|
-
const apiKey = (_b = (_a = process.env.LLM_API_KEY) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : (_c = process.env.OPENAI_API_KEY) === null || _c === void 0 ? void 0 : _c.trim();
|
|
102
|
-
if (apiKey)
|
|
103
|
-
return true;
|
|
104
|
-
if (resolveLlmBaseUrl())
|
|
105
|
-
return true;
|
|
106
|
-
const jsonHeaders = parseLlmDefaultHeadersFromEnv();
|
|
107
|
-
if (jsonHeaders && Object.keys(jsonHeaders).length > 0)
|
|
108
|
-
return true;
|
|
109
|
-
return false;
|
|
120
|
+
return (_a = readEnv("LLM_API_KEY")) !== null && _a !== void 0 ? _a : readEnv("OPENAI_API_KEY");
|
|
110
121
|
}
|
|
111
|
-
function
|
|
112
|
-
var _a, _b
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
let defaultHeaders;
|
|
117
|
-
let apiKey = envApiKey;
|
|
118
|
-
if (apiKey.length === 0) {
|
|
119
|
-
const split = splitPromotableAuthorizationFromHeaders(mergedHeaders);
|
|
120
|
-
if (split.apiKeyFromAuthHeader) {
|
|
121
|
-
apiKey = split.apiKeyFromAuthHeader;
|
|
122
|
-
}
|
|
123
|
-
defaultHeaders =
|
|
124
|
-
Object.keys(split.defaultHeaders).length > 0
|
|
125
|
-
? split.defaultHeaders
|
|
126
|
-
: undefined;
|
|
122
|
+
function detectLlmProvider() {
|
|
123
|
+
var _a, _b;
|
|
124
|
+
const explicit = (_a = readEnv("LLM_PROVIDER")) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
125
|
+
if (explicit && isValidProviderId(explicit)) {
|
|
126
|
+
return explicit;
|
|
127
127
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
Object.keys(mergedHeaders).length > 0 ? mergedHeaders : undefined;
|
|
128
|
+
if (resolveLlmBaseUrl()) {
|
|
129
|
+
return "openai-compatible";
|
|
131
130
|
}
|
|
132
|
-
|
|
131
|
+
if (resolveOpenAiApiKey()) {
|
|
132
|
+
return "openai";
|
|
133
|
+
}
|
|
134
|
+
if (readEnv("ANTHROPIC_API_KEY"))
|
|
135
|
+
return "anthropic";
|
|
136
|
+
if ((_b = readEnv("GOOGLE_GENERATIVE_AI_API_KEY")) !== null && _b !== void 0 ? _b : readEnv("GOOGLE_API_KEY"))
|
|
137
|
+
return "google";
|
|
138
|
+
if (readEnv("MISTRAL_API_KEY"))
|
|
139
|
+
return "mistral";
|
|
140
|
+
if (readEnv("COHERE_API_KEY"))
|
|
141
|
+
return "cohere";
|
|
142
|
+
if (readEnv("GROQ_API_KEY"))
|
|
143
|
+
return "groq";
|
|
144
|
+
if (readEnv("XAI_API_KEY"))
|
|
145
|
+
return "xai";
|
|
146
|
+
if (readEnv("DEEPSEEK_API_KEY"))
|
|
147
|
+
return "deepseek";
|
|
148
|
+
if (parseLlmDefaultHeadersFromEnv())
|
|
149
|
+
return "openai";
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
function isLlmProviderConfigured() {
|
|
153
|
+
return detectLlmProvider() !== undefined;
|
|
133
154
|
}
|
|
134
|
-
function
|
|
155
|
+
function defaultModelForProvider(provider) {
|
|
156
|
+
return DEFAULT_MODEL_BY_PROVIDER[provider];
|
|
157
|
+
}
|
|
158
|
+
function createOpenAiModel(modelId) {
|
|
135
159
|
return __awaiter(this, void 0, void 0, function* () {
|
|
136
|
-
const {
|
|
137
|
-
|
|
160
|
+
const { createOpenAI } = yield import('@ai-sdk/openai');
|
|
161
|
+
const apiKey = resolveOpenAiApiKey();
|
|
162
|
+
const headers = parseLlmDefaultHeadersFromEnv();
|
|
163
|
+
const provider = createOpenAI(Object.assign(Object.assign({}, (apiKey ? { apiKey } : {})), (headers ? { headers } : {})));
|
|
164
|
+
return provider(modelId);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
function createOpenAiCompatibleModel(modelId) {
|
|
168
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
169
|
+
var _a;
|
|
170
|
+
const { createOpenAICompatible } = yield import('@ai-sdk/openai-compatible');
|
|
171
|
+
const baseURL = resolveLlmBaseUrl();
|
|
172
|
+
if (!baseURL) {
|
|
173
|
+
throw new Error("openai-compatible provider requires LLM_BASE_URL or OPENAI_BASE_URL to be set.");
|
|
174
|
+
}
|
|
175
|
+
const apiKey = resolveOpenAiApiKey();
|
|
176
|
+
const headers = parseLlmDefaultHeadersFromEnv();
|
|
177
|
+
const provider = createOpenAICompatible(Object.assign(Object.assign({ name: (_a = readEnv("LLM_PROVIDER_NAME")) !== null && _a !== void 0 ? _a : "openai-compatible", baseURL }, (apiKey ? { apiKey } : {})), (headers ? { headers } : {})));
|
|
178
|
+
return provider(modelId);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
function wrapMissingPeer(failure) {
|
|
182
|
+
const err = new Error(`Failed to load optional provider package "${failure.pkg}" for LLM_PROVIDER="${failure.provider}". ` +
|
|
183
|
+
`Install it with \`npm install ${failure.pkg}\`.`);
|
|
184
|
+
err.cause = failure.cause;
|
|
185
|
+
return err;
|
|
186
|
+
}
|
|
187
|
+
function importOptional(provider, pkg, loader) {
|
|
188
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
189
|
+
try {
|
|
190
|
+
return yield loader();
|
|
191
|
+
}
|
|
192
|
+
catch (cause) {
|
|
193
|
+
throw wrapMissingPeer({ provider, pkg, cause });
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
function createAnthropicModel(modelId) {
|
|
198
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
199
|
+
const mod = yield importOptional("anthropic", "@ai-sdk/anthropic", () => import('@ai-sdk/anthropic'));
|
|
200
|
+
const apiKey = readEnv("ANTHROPIC_API_KEY");
|
|
201
|
+
const provider = mod.createAnthropic(apiKey ? { apiKey } : undefined);
|
|
202
|
+
return provider(modelId);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
function createGoogleModel(modelId) {
|
|
206
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
207
|
+
var _a;
|
|
208
|
+
const mod = yield importOptional("google", "@ai-sdk/google", () => import('@ai-sdk/google'));
|
|
209
|
+
const apiKey = (_a = readEnv("GOOGLE_GENERATIVE_AI_API_KEY")) !== null && _a !== void 0 ? _a : readEnv("GOOGLE_API_KEY");
|
|
210
|
+
const provider = mod.createGoogleGenerativeAI(apiKey ? { apiKey } : undefined);
|
|
211
|
+
return provider(modelId);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
function createBedrockModel(modelId) {
|
|
215
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
216
|
+
const mod = yield importOptional("bedrock", "@ai-sdk/amazon-bedrock", () => import('@ai-sdk/amazon-bedrock'));
|
|
217
|
+
const provider = mod.createAmazonBedrock();
|
|
218
|
+
return provider(modelId);
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
function createMistralModel(modelId) {
|
|
222
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
223
|
+
const mod = yield importOptional("mistral", "@ai-sdk/mistral", () => import('@ai-sdk/mistral'));
|
|
224
|
+
const apiKey = readEnv("MISTRAL_API_KEY");
|
|
225
|
+
const provider = mod.createMistral(apiKey ? { apiKey } : undefined);
|
|
226
|
+
return provider(modelId);
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
function createCohereModel(modelId) {
|
|
230
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
231
|
+
const mod = yield importOptional("cohere", "@ai-sdk/cohere", () => import('@ai-sdk/cohere'));
|
|
232
|
+
const apiKey = readEnv("COHERE_API_KEY");
|
|
233
|
+
const provider = mod.createCohere(apiKey ? { apiKey } : undefined);
|
|
234
|
+
return provider(modelId);
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
function createGroqModel(modelId) {
|
|
238
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
239
|
+
const mod = yield importOptional("groq", "@ai-sdk/groq", () => import('@ai-sdk/groq'));
|
|
240
|
+
const apiKey = readEnv("GROQ_API_KEY");
|
|
241
|
+
const provider = mod.createGroq(apiKey ? { apiKey } : undefined);
|
|
242
|
+
return provider(modelId);
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
function createXaiModel(modelId) {
|
|
246
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
247
|
+
const mod = yield importOptional("xai", "@ai-sdk/xai", () => import('@ai-sdk/xai'));
|
|
248
|
+
const apiKey = readEnv("XAI_API_KEY");
|
|
249
|
+
const provider = mod.createXai(apiKey ? { apiKey } : undefined);
|
|
250
|
+
return provider(modelId);
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
function createDeepseekModel(modelId) {
|
|
254
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
255
|
+
const mod = yield importOptional("deepseek", "@ai-sdk/deepseek", () => import('@ai-sdk/deepseek'));
|
|
256
|
+
const apiKey = readEnv("DEEPSEEK_API_KEY");
|
|
257
|
+
const provider = mod.createDeepSeek(apiKey ? { apiKey } : undefined);
|
|
258
|
+
return provider(modelId);
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
function resolveLanguageModel() {
|
|
262
|
+
return __awaiter(this, arguments, void 0, function* (options = {}) {
|
|
263
|
+
var _a, _b, _c;
|
|
264
|
+
const provider = (_a = options.provider) !== null && _a !== void 0 ? _a : detectLlmProvider();
|
|
265
|
+
if (!provider) {
|
|
266
|
+
throw new Error("No LLM provider could be resolved. Set LLM_PROVIDER or a provider API key " +
|
|
267
|
+
"(OPENAI_API_KEY, ANTHROPIC_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, MISTRAL_API_KEY, " +
|
|
268
|
+
"COHERE_API_KEY, GROQ_API_KEY, XAI_API_KEY, DEEPSEEK_API_KEY), or LLM_BASE_URL for an OpenAI-compatible gateway.");
|
|
269
|
+
}
|
|
270
|
+
const modelId = (_c = (_b = options.model) !== null && _b !== void 0 ? _b : readEnv("LLM_MODEL")) !== null && _c !== void 0 ? _c : defaultModelForProvider(provider);
|
|
271
|
+
switch (provider) {
|
|
272
|
+
case "openai":
|
|
273
|
+
return createOpenAiModel(modelId);
|
|
274
|
+
case "openai-compatible":
|
|
275
|
+
return createOpenAiCompatibleModel(modelId);
|
|
276
|
+
case "anthropic":
|
|
277
|
+
return createAnthropicModel(modelId);
|
|
278
|
+
case "google":
|
|
279
|
+
return createGoogleModel(modelId);
|
|
280
|
+
case "bedrock":
|
|
281
|
+
return createBedrockModel(modelId);
|
|
282
|
+
case "mistral":
|
|
283
|
+
return createMistralModel(modelId);
|
|
284
|
+
case "cohere":
|
|
285
|
+
return createCohereModel(modelId);
|
|
286
|
+
case "groq":
|
|
287
|
+
return createGroqModel(modelId);
|
|
288
|
+
case "xai":
|
|
289
|
+
return createXaiModel(modelId);
|
|
290
|
+
case "deepseek":
|
|
291
|
+
return createDeepseekModel(modelId);
|
|
292
|
+
default: {
|
|
293
|
+
const _exhaustive = provider;
|
|
294
|
+
throw new Error(`Unhandled LLM provider: ${String(_exhaustive)}`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
138
297
|
});
|
|
139
298
|
}
|
|
140
|
-
|
|
141
|
-
const DEFAULT_LLM_MAX_DIFF_CHARS = 120000;
|
|
142
|
-
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.
|
|
143
|
-
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.
|
|
144
|
-
Explain what changed in terms of behavior, APIs, data, configuration, security, and operational risk. Tie claims to the patch when possible.
|
|
145
|
-
Produce a concise, developer-focused summary in Markdown.
|
|
146
|
-
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.
|
|
147
|
-
Group related changes; do not list every individual file. When multiple commits appear in the context, briefly separate notable themes by commit when helpful.
|
|
148
|
-
If the user message includes a Team line, use that exact team name in the summary title (for example: "## <Team> – Change summary" or similar).`;
|
|
149
|
-
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, " +
|
|
150
|
-
"and/or JSON in OPENAI_DEFAULT_HEADERS or LLM_DEFAULT_HEADERS. " +
|
|
151
|
-
"Alternatively pass openAiClientProvider to generateSummary or summarizeGitDiff.";
|
|
152
299
|
|
|
153
300
|
function resolveLlmMaxDiffChars(cliOverride) {
|
|
154
301
|
var _a;
|
|
@@ -176,18 +323,26 @@ function truncateUnifiedDiffForLlm(diffText, maxChars) {
|
|
|
176
323
|
function markdownDiffTruncationNotice(originalChars, maxChars) {
|
|
177
324
|
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`;
|
|
178
325
|
}
|
|
326
|
+
function resolveMaxOutputTokens() {
|
|
327
|
+
var _a;
|
|
328
|
+
const raw = (_a = process.env.LLM_MAX_TOKENS) !== null && _a !== void 0 ? _a : process.env.OPENAI_MAX_TOKENS;
|
|
329
|
+
const parsed = raw !== undefined ? Number.parseInt(raw, 10) : 4000;
|
|
330
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 4000;
|
|
331
|
+
}
|
|
179
332
|
function generateSummary(input) {
|
|
180
333
|
return __awaiter(this, void 0, void 0, function* () {
|
|
181
|
-
var _a
|
|
182
|
-
const { diffText, fileNames, commits, flags,
|
|
183
|
-
if (!
|
|
334
|
+
var _a;
|
|
335
|
+
const { diffText, fileNames, commits, flags, llmModelProvider, diffSummary, } = input;
|
|
336
|
+
if (!llmModelProvider && !isLlmProviderConfigured()) {
|
|
184
337
|
throw new Error(LLM_GATEWAY_REQUIRED_MESSAGE);
|
|
185
338
|
}
|
|
186
339
|
const maxDiffChars = resolveLlmMaxDiffChars(flags.maxDiffChars);
|
|
187
340
|
const diffTruncated = diffText.length > maxDiffChars;
|
|
188
341
|
const diffForLlm = truncateUnifiedDiffForLlm(diffText, maxDiffChars);
|
|
189
|
-
const userContent =
|
|
190
|
-
const
|
|
342
|
+
const userContent = buildUserContent(flags, commits, fileNames, diffForLlm, diffSummary);
|
|
343
|
+
const systemPrompt = (_a = flags.systemPrompt) !== null && _a !== void 0 ? _a : DEFAULT_GIT_DIFF_SYSTEM_PROMPT;
|
|
344
|
+
const maxOutputTokens = resolveMaxOutputTokens();
|
|
345
|
+
const summary = yield callLlm(userContent, systemPrompt, maxOutputTokens, llmModelProvider, flags);
|
|
191
346
|
if (!diffTruncated) {
|
|
192
347
|
return summary;
|
|
193
348
|
}
|
|
@@ -214,7 +369,7 @@ function formatRegexFilterLines(flags) {
|
|
|
214
369
|
return (`${incLine}${excLine}` +
|
|
215
370
|
"Git context shape: concatenated per-commit unified patches for commits that pass the message filters.\n");
|
|
216
371
|
}
|
|
217
|
-
function
|
|
372
|
+
function buildUserContent(flags, commits, fileNames, diffText, diffSummary) {
|
|
218
373
|
var _a, _b;
|
|
219
374
|
const from = flags.from;
|
|
220
375
|
const to = (_a = flags.to) !== null && _a !== void 0 ? _a : "HEAD";
|
|
@@ -244,31 +399,20 @@ function buildOpenAiUserContent(flags, commits, fileNames, diffText, diffSummary
|
|
|
244
399
|
"=== Git context (unified diff(s); patches may be truncated with an explicit marker) ===\n" +
|
|
245
400
|
diffText);
|
|
246
401
|
}
|
|
247
|
-
function
|
|
402
|
+
function callLlm(userContent, systemPrompt, maxOutputTokens, llmModelProvider, flags) {
|
|
248
403
|
return __awaiter(this, void 0, void 0, function* () {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
const
|
|
253
|
-
const maxTokens = Number.isFinite(parsed) && parsed > 0 ? parsed : 4000;
|
|
254
|
-
const response = yield client.chat.completions.create({
|
|
404
|
+
const model = llmModelProvider
|
|
405
|
+
? yield llmModelProvider()
|
|
406
|
+
: yield resolveLanguageModel(Object.assign(Object.assign({}, (flags.provider ? { provider: flags.provider } : {})), (flags.model ? { model: flags.model } : {})));
|
|
407
|
+
const result = yield ai.generateText({
|
|
255
408
|
model,
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
role: "system",
|
|
259
|
-
content: systemPrompt,
|
|
260
|
-
},
|
|
261
|
-
{
|
|
262
|
-
role: "user",
|
|
263
|
-
content: userContent,
|
|
264
|
-
},
|
|
265
|
-
],
|
|
409
|
+
system: systemPrompt,
|
|
410
|
+
prompt: userContent,
|
|
266
411
|
temperature: 0.2,
|
|
267
|
-
|
|
412
|
+
maxOutputTokens,
|
|
268
413
|
});
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
return text.length > 0 ? text : "No summary generated by OpenAI.";
|
|
414
|
+
const text = result.text.trim();
|
|
415
|
+
return text.length > 0 ? text : "No summary generated by the model.";
|
|
272
416
|
});
|
|
273
417
|
}
|
|
274
418
|
|
|
@@ -350,6 +494,130 @@ function filterCommitsByMessageRegexes(commits, includePatterns, excludePatterns
|
|
|
350
494
|
return commits.filter((c) => commitMessagePassesFilters(c.message, includeRes, excludeRes));
|
|
351
495
|
}
|
|
352
496
|
|
|
497
|
+
const DEFAULT_NOISE_EXCLUDES = [
|
|
498
|
+
"package-lock.json",
|
|
499
|
+
"yarn.lock",
|
|
500
|
+
"pnpm-lock.yaml",
|
|
501
|
+
"npm-shrinkwrap.json",
|
|
502
|
+
"bun.lockb",
|
|
503
|
+
"go.sum",
|
|
504
|
+
"Cargo.lock",
|
|
505
|
+
"Gemfile.lock",
|
|
506
|
+
"composer.lock",
|
|
507
|
+
"Pipfile.lock",
|
|
508
|
+
"poetry.lock",
|
|
509
|
+
"uv.lock",
|
|
510
|
+
"Podfile.lock",
|
|
511
|
+
"node_modules",
|
|
512
|
+
"dist",
|
|
513
|
+
"build",
|
|
514
|
+
"out",
|
|
515
|
+
"coverage",
|
|
516
|
+
"__snapshots__",
|
|
517
|
+
];
|
|
518
|
+
function normalizeContextLines(raw) {
|
|
519
|
+
if (!Number.isFinite(raw) || raw < 0)
|
|
520
|
+
return 0;
|
|
521
|
+
return Math.trunc(raw);
|
|
522
|
+
}
|
|
523
|
+
function buildDiffShapingGitArgs(shaping) {
|
|
524
|
+
const args = [];
|
|
525
|
+
if ((shaping === null || shaping === void 0 ? void 0 : shaping.contextLines) !== undefined) {
|
|
526
|
+
args.push(`-U${normalizeContextLines(shaping.contextLines)}`);
|
|
527
|
+
}
|
|
528
|
+
if (shaping === null || shaping === void 0 ? void 0 : shaping.ignoreWhitespace) {
|
|
529
|
+
args.push("-w");
|
|
530
|
+
}
|
|
531
|
+
return args;
|
|
532
|
+
}
|
|
533
|
+
const PREAMBLE_NOISE_PREFIXES = [
|
|
534
|
+
"diff --git ",
|
|
535
|
+
"index ",
|
|
536
|
+
"new file mode ",
|
|
537
|
+
"deleted file mode ",
|
|
538
|
+
"old mode ",
|
|
539
|
+
"new mode ",
|
|
540
|
+
"similarity index ",
|
|
541
|
+
"dissimilarity index ",
|
|
542
|
+
"rename from ",
|
|
543
|
+
"rename to ",
|
|
544
|
+
"copy from ",
|
|
545
|
+
"copy to ",
|
|
546
|
+
];
|
|
547
|
+
function isPreambleNoiseLine(line) {
|
|
548
|
+
for (const prefix of PREAMBLE_NOISE_PREFIXES) {
|
|
549
|
+
if (line.startsWith(prefix))
|
|
550
|
+
return true;
|
|
551
|
+
}
|
|
552
|
+
return false;
|
|
553
|
+
}
|
|
554
|
+
function stripPreambleLines(text) {
|
|
555
|
+
return text
|
|
556
|
+
.split(/\r?\n/)
|
|
557
|
+
.filter((line) => !isPreambleNoiseLine(line))
|
|
558
|
+
.join("\n");
|
|
559
|
+
}
|
|
560
|
+
function isFileHeaderLine(line) {
|
|
561
|
+
return (/^--- (a\/|b\/|"a\/|"b\/|\/dev\/null)/.test(line) ||
|
|
562
|
+
/^\+\+\+ (a\/|b\/|"a\/|"b\/|\/dev\/null)/.test(line));
|
|
563
|
+
}
|
|
564
|
+
function elideLargeHunks(text, maxHunkLines) {
|
|
565
|
+
const limit = normalizeContextLines(maxHunkLines);
|
|
566
|
+
const lines = text.split(/\r?\n/);
|
|
567
|
+
const out = [];
|
|
568
|
+
let inHunk = false;
|
|
569
|
+
let hunkBuf = [];
|
|
570
|
+
const flushHunk = () => {
|
|
571
|
+
if (hunkBuf.length > limit) {
|
|
572
|
+
const elided = hunkBuf.length - limit;
|
|
573
|
+
out.push(...hunkBuf.slice(0, limit));
|
|
574
|
+
out.push(`[... ${elided} diff line${elided === 1 ? "" : "s"} elided ...]`);
|
|
575
|
+
}
|
|
576
|
+
else {
|
|
577
|
+
out.push(...hunkBuf);
|
|
578
|
+
}
|
|
579
|
+
hunkBuf = [];
|
|
580
|
+
inHunk = false;
|
|
581
|
+
};
|
|
582
|
+
for (const line of lines) {
|
|
583
|
+
if (line.startsWith("@@")) {
|
|
584
|
+
if (inHunk)
|
|
585
|
+
flushHunk();
|
|
586
|
+
out.push(line);
|
|
587
|
+
inHunk = true;
|
|
588
|
+
continue;
|
|
589
|
+
}
|
|
590
|
+
if (line.startsWith("diff --git ") || isFileHeaderLine(line)) {
|
|
591
|
+
if (inHunk)
|
|
592
|
+
flushHunk();
|
|
593
|
+
out.push(line);
|
|
594
|
+
continue;
|
|
595
|
+
}
|
|
596
|
+
if (inHunk) {
|
|
597
|
+
hunkBuf.push(line);
|
|
598
|
+
}
|
|
599
|
+
else {
|
|
600
|
+
out.push(line);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
if (inHunk)
|
|
604
|
+
flushHunk();
|
|
605
|
+
return out.join("\n");
|
|
606
|
+
}
|
|
607
|
+
function shapeUnifiedDiff(text, shaping) {
|
|
608
|
+
if (!(shaping === null || shaping === void 0 ? void 0 : shaping.stripDiffPreamble) && (shaping === null || shaping === void 0 ? void 0 : shaping.maxHunkLines) === undefined) {
|
|
609
|
+
return text;
|
|
610
|
+
}
|
|
611
|
+
let out = text;
|
|
612
|
+
if (shaping.stripDiffPreamble) {
|
|
613
|
+
out = stripPreambleLines(out);
|
|
614
|
+
}
|
|
615
|
+
if (shaping.maxHunkLines !== undefined) {
|
|
616
|
+
out = elideLargeHunks(out, shaping.maxHunkLines);
|
|
617
|
+
}
|
|
618
|
+
return out;
|
|
619
|
+
}
|
|
620
|
+
|
|
353
621
|
const GIT_STATUS_BY_FIRST_CHAR = {
|
|
354
622
|
A: "added",
|
|
355
623
|
D: "deleted",
|
|
@@ -380,25 +648,17 @@ function mergeStatus(existing, next) {
|
|
|
380
648
|
}
|
|
381
649
|
|
|
382
650
|
function parseNameStatusLine(line) {
|
|
383
|
-
var _a;
|
|
384
651
|
const parts = line.split("\t");
|
|
385
652
|
let entry = null;
|
|
386
653
|
if (parts.length >= 2) {
|
|
387
|
-
const statusToken =
|
|
654
|
+
const statusToken = parts[0];
|
|
388
655
|
const status = mapGitStatus(statusToken);
|
|
389
656
|
const isRenameOrCopy = statusToken.startsWith("R") || statusToken.startsWith("C");
|
|
390
657
|
if (isRenameOrCopy && parts.length >= 3) {
|
|
391
|
-
|
|
392
|
-
const newPath = parts[2];
|
|
393
|
-
if (oldPath !== undefined && newPath !== undefined) {
|
|
394
|
-
entry = { path: newPath, status, oldPath };
|
|
395
|
-
}
|
|
658
|
+
entry = { path: parts[2], status, oldPath: parts[1] };
|
|
396
659
|
}
|
|
397
660
|
else if (!isRenameOrCopy) {
|
|
398
|
-
|
|
399
|
-
if (pathOnly !== undefined) {
|
|
400
|
-
entry = { path: pathOnly, status };
|
|
401
|
-
}
|
|
661
|
+
entry = { path: parts[1], status };
|
|
402
662
|
}
|
|
403
663
|
}
|
|
404
664
|
return entry;
|
|
@@ -443,12 +703,11 @@ function numStatPathToLookupKey(pathField) {
|
|
|
443
703
|
return `${dirRaw}${toSeg}`;
|
|
444
704
|
}
|
|
445
705
|
function parseNumStatLine(line) {
|
|
446
|
-
var _a, _b;
|
|
447
706
|
const parts = line.split("\t");
|
|
448
707
|
if (parts.length < 3)
|
|
449
708
|
return null;
|
|
450
|
-
const addStr =
|
|
451
|
-
const delStr =
|
|
709
|
+
const addStr = parts[0];
|
|
710
|
+
const delStr = parts[1];
|
|
452
711
|
const pathField = parts.slice(2).join("\t");
|
|
453
712
|
const additions = addStr !== "-" ? Number.parseInt(addStr, 10) || 0 : 0;
|
|
454
713
|
const deletions = delStr !== "-" ? Number.parseInt(delStr, 10) || 0 : 0;
|
|
@@ -473,11 +732,10 @@ function accumulateNumStat(numStatOutput, into) {
|
|
|
473
732
|
}
|
|
474
733
|
|
|
475
734
|
function parseTabDiffSummaryLine(line) {
|
|
476
|
-
var _a;
|
|
477
735
|
const parts = line.split("\t");
|
|
478
736
|
if (parts.length < 3)
|
|
479
737
|
return null;
|
|
480
|
-
const statusToken =
|
|
738
|
+
const statusToken = parts.shift();
|
|
481
739
|
const status = mapGitStatus(statusToken);
|
|
482
740
|
const add0 = parts[0];
|
|
483
741
|
const del0 = parts[1];
|
|
@@ -595,31 +853,48 @@ function getDiffPathContext(git, pathFilter, repoRootOverride) {
|
|
|
595
853
|
}
|
|
596
854
|
function getDiff(git, query) {
|
|
597
855
|
return __awaiter(this, void 0, void 0, function* () {
|
|
598
|
-
const { from, to, commits, filterByCommits, pathFilter, repoRootOverride } = query;
|
|
856
|
+
const { from, to, commits, filterByCommits, pathFilter, repoRootOverride, shaping, } = query;
|
|
599
857
|
const { specs } = yield getDiffPathContext(git, pathFilter, repoRootOverride);
|
|
858
|
+
const shapingArgs = buildDiffShapingGitArgs(shaping);
|
|
600
859
|
if (!filterByCommits) {
|
|
601
|
-
|
|
860
|
+
const raw = yield git.diff([
|
|
861
|
+
...shapingArgs,
|
|
862
|
+
`${from}..${to}`,
|
|
863
|
+
"--",
|
|
864
|
+
...specs,
|
|
865
|
+
]);
|
|
866
|
+
return shapeUnifiedDiff(raw, shaping);
|
|
602
867
|
}
|
|
603
|
-
const patches = yield Promise.all(commits.map((c) => git.diff([`${c.hash}^!`, "--", ...specs])));
|
|
604
|
-
return patches
|
|
868
|
+
const patches = yield Promise.all(commits.map((c) => git.diff([...shapingArgs, `${c.hash}^!`, "--", ...specs])));
|
|
869
|
+
return patches
|
|
870
|
+
.map((p) => shapeUnifiedDiff(p, shaping))
|
|
871
|
+
.filter(Boolean)
|
|
872
|
+
.join("\n");
|
|
605
873
|
});
|
|
606
874
|
}
|
|
607
875
|
function getDiffSummary(git, query) {
|
|
608
876
|
return __awaiter(this, void 0, void 0, function* () {
|
|
609
|
-
const { from, to, commits, filterByCommits, pathFilter, repoRootOverride } = query;
|
|
877
|
+
const { from, to, commits, filterByCommits, pathFilter, repoRootOverride, shaping, } = query;
|
|
610
878
|
const { specs } = yield getDiffPathContext(git, pathFilter, repoRootOverride);
|
|
879
|
+
const whitespaceArgs = (shaping === null || shaping === void 0 ? void 0 : shaping.ignoreWhitespace) ? ["-w"] : [];
|
|
611
880
|
if (!filterByCommits) {
|
|
612
881
|
const [numOutput, nameOutput] = yield Promise.all([
|
|
613
|
-
git.diff(["--numstat", `${from}..${to}`, "--", ...specs]),
|
|
614
|
-
git.diff([
|
|
882
|
+
git.diff([...whitespaceArgs, "--numstat", `${from}..${to}`, "--", ...specs]),
|
|
883
|
+
git.diff([
|
|
884
|
+
...whitespaceArgs,
|
|
885
|
+
"--name-status",
|
|
886
|
+
`${from}..${to}`,
|
|
887
|
+
"--",
|
|
888
|
+
...specs,
|
|
889
|
+
]),
|
|
615
890
|
]);
|
|
616
891
|
return buildDiffSummaryFromGitOutputs(nameOutput, numOutput);
|
|
617
892
|
}
|
|
618
893
|
const pairs = yield Promise.all(commits.map((c) => __awaiter(this, void 0, void 0, function* () {
|
|
619
894
|
const range = `${c.hash}^!`;
|
|
620
895
|
const [numOutput, nameOutput] = yield Promise.all([
|
|
621
|
-
git.diff(["--numstat", range, "--", ...specs]),
|
|
622
|
-
git.diff(["--name-status", range, "--", ...specs]),
|
|
896
|
+
git.diff([...whitespaceArgs, "--numstat", range, "--", ...specs]),
|
|
897
|
+
git.diff([...whitespaceArgs, "--name-status", range, "--", ...specs]),
|
|
623
898
|
]);
|
|
624
899
|
return { numOutput, nameOutput };
|
|
625
900
|
})));
|
|
@@ -669,6 +944,37 @@ function getChangedFiles(git, query) {
|
|
|
669
944
|
});
|
|
670
945
|
}
|
|
671
946
|
|
|
947
|
+
function buildShapingFromOptions(options) {
|
|
948
|
+
const shaping = {};
|
|
949
|
+
if (options.contextLines !== undefined) {
|
|
950
|
+
shaping.contextLines = options.contextLines;
|
|
951
|
+
}
|
|
952
|
+
if (options.ignoreWhitespace)
|
|
953
|
+
shaping.ignoreWhitespace = true;
|
|
954
|
+
if (options.stripDiffPreamble)
|
|
955
|
+
shaping.stripDiffPreamble = true;
|
|
956
|
+
if (options.maxHunkLines !== undefined) {
|
|
957
|
+
shaping.maxHunkLines = options.maxHunkLines;
|
|
958
|
+
}
|
|
959
|
+
return Object.keys(shaping).length > 0 ? shaping : undefined;
|
|
960
|
+
}
|
|
961
|
+
function buildEffectiveExcludeFolders(options) {
|
|
962
|
+
var _a;
|
|
963
|
+
const userExcludes = (_a = options.excludeFolders) !== null && _a !== void 0 ? _a : [];
|
|
964
|
+
if (!options.excludeDefaultNoise) {
|
|
965
|
+
return userExcludes.length > 0 ? userExcludes : undefined;
|
|
966
|
+
}
|
|
967
|
+
const seen = new Set();
|
|
968
|
+
const merged = [];
|
|
969
|
+
for (const p of [...DEFAULT_NOISE_EXCLUDES, ...userExcludes]) {
|
|
970
|
+
const key = p.trim();
|
|
971
|
+
if (!key || seen.has(key))
|
|
972
|
+
continue;
|
|
973
|
+
seen.add(key);
|
|
974
|
+
merged.push(p);
|
|
975
|
+
}
|
|
976
|
+
return merged;
|
|
977
|
+
}
|
|
672
978
|
function hasNonEmptyTrimmed(arr) {
|
|
673
979
|
return (arr !== null && arr !== void 0 ? arr : []).some((s) => s.trim().length > 0);
|
|
674
980
|
}
|
|
@@ -685,22 +991,25 @@ function summarizeGitDiff(options) {
|
|
|
685
991
|
const git = (_a = options.git) !== null && _a !== void 0 ? _a : createGitClient(options.cwd);
|
|
686
992
|
const from = options.from;
|
|
687
993
|
const to = (_b = options.to) !== null && _b !== void 0 ? _b : "HEAD";
|
|
994
|
+
const effectiveExcludeFolders = buildEffectiveExcludeFolders(options);
|
|
688
995
|
const pathFilter = hasNonEmptyTrimmed(options.includeFolders) ||
|
|
689
|
-
hasNonEmptyTrimmed(
|
|
996
|
+
hasNonEmptyTrimmed(effectiveExcludeFolders)
|
|
690
997
|
? {
|
|
691
998
|
includeFolders: options.includeFolders,
|
|
692
|
-
excludeFolders:
|
|
999
|
+
excludeFolders: effectiveExcludeFolders,
|
|
693
1000
|
}
|
|
694
1001
|
: undefined;
|
|
695
1002
|
const allCommits = yield getCommits(git, from, to);
|
|
696
1003
|
const filteredCommits = filterCommitsByMessageRegexes(allCommits, options.commitMessageIncludeRegexes, options.commitMessageExcludeRegexes);
|
|
697
1004
|
const filterByCommits = shouldFilterByCommits(allCommits, filteredCommits, options);
|
|
1005
|
+
const shaping = buildShapingFromOptions(options);
|
|
698
1006
|
const rangeQuery = {
|
|
699
1007
|
from,
|
|
700
1008
|
to,
|
|
701
1009
|
commits: filteredCommits,
|
|
702
1010
|
filterByCommits,
|
|
703
1011
|
pathFilter,
|
|
1012
|
+
shaping,
|
|
704
1013
|
};
|
|
705
1014
|
const [diffText, fileNames, diffSummary] = yield Promise.all([
|
|
706
1015
|
getDiff(git, rangeQuery),
|
|
@@ -712,6 +1021,7 @@ function summarizeGitDiff(options) {
|
|
|
712
1021
|
to,
|
|
713
1022
|
team: options.teamName,
|
|
714
1023
|
model: options.model,
|
|
1024
|
+
provider: options.provider,
|
|
715
1025
|
maxDiffChars: options.maxDiffChars,
|
|
716
1026
|
systemPrompt: options.systemPrompt,
|
|
717
1027
|
commitMessageIncludeRegexes: options.commitMessageIncludeRegexes,
|
|
@@ -722,17 +1032,20 @@ function summarizeGitDiff(options) {
|
|
|
722
1032
|
fileNames,
|
|
723
1033
|
commits: filteredCommits,
|
|
724
1034
|
flags: summarizeFlags,
|
|
725
|
-
|
|
1035
|
+
llmModelProvider: options.llmModelProvider,
|
|
726
1036
|
diffSummary,
|
|
727
1037
|
});
|
|
728
1038
|
});
|
|
729
1039
|
}
|
|
730
1040
|
|
|
731
1041
|
exports.DEFAULT_GIT_DIFF_SYSTEM_PROMPT = DEFAULT_GIT_DIFF_SYSTEM_PROMPT;
|
|
1042
|
+
exports.DEFAULT_NOISE_EXCLUDES = DEFAULT_NOISE_EXCLUDES;
|
|
732
1043
|
exports.LLM_GATEWAY_REQUIRED_MESSAGE = LLM_GATEWAY_REQUIRED_MESSAGE;
|
|
733
1044
|
exports.buildDiffPathspecs = buildDiffPathspecs;
|
|
1045
|
+
exports.buildDiffShapingGitArgs = buildDiffShapingGitArgs;
|
|
734
1046
|
exports.createGitClient = createGitClient;
|
|
735
|
-
exports.
|
|
1047
|
+
exports.defaultModelForProvider = defaultModelForProvider;
|
|
1048
|
+
exports.detectLlmProvider = detectLlmProvider;
|
|
736
1049
|
exports.filterCommitsByMessageRegexes = filterCommitsByMessageRegexes;
|
|
737
1050
|
exports.generateSummary = generateSummary;
|
|
738
1051
|
exports.getChangedFiles = getChangedFiles;
|
|
@@ -740,12 +1053,12 @@ exports.getCommits = getCommits;
|
|
|
740
1053
|
exports.getDiff = getDiff;
|
|
741
1054
|
exports.getDiffSummary = getDiffSummary;
|
|
742
1055
|
exports.getRepoRoot = getRepoRoot;
|
|
1056
|
+
exports.isLlmProviderConfigured = isLlmProviderConfigured;
|
|
743
1057
|
exports.parseLlmDefaultHeadersFromEnv = parseLlmDefaultHeadersFromEnv;
|
|
1058
|
+
exports.resolveLanguageModel = resolveLanguageModel;
|
|
744
1059
|
exports.resolveLlmBaseUrl = resolveLlmBaseUrl;
|
|
745
1060
|
exports.resolveLlmMaxDiffChars = resolveLlmMaxDiffChars;
|
|
746
|
-
exports.
|
|
747
|
-
exports.shouldUseLlmGateway = shouldUseLlmGateway;
|
|
748
|
-
exports.splitPromotableAuthorizationFromHeaders = splitPromotableAuthorizationFromHeaders;
|
|
1061
|
+
exports.shapeUnifiedDiff = shapeUnifiedDiff;
|
|
749
1062
|
exports.summarizeGitDiff = summarizeGitDiff;
|
|
750
1063
|
exports.truncateUnifiedDiffForLlm = truncateUnifiedDiffForLlm;
|
|
751
1064
|
//# sourceMappingURL=index.cjs.map
|