@eldrforge/kodrdriv 1.2.21 → 1.2.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/WORKFLOW-PRECHECK-IMPLEMENTATION.md +239 -0
  2. package/WORKFLOW-SKIP-SUMMARY.md +121 -0
  3. package/dist/arguments.js +2 -2
  4. package/dist/arguments.js.map +1 -1
  5. package/dist/commands/audio-commit.js +15 -6
  6. package/dist/commands/audio-commit.js.map +1 -1
  7. package/dist/commands/audio-review.js +31 -15
  8. package/dist/commands/audio-review.js.map +1 -1
  9. package/dist/commands/commit.js +30 -19
  10. package/dist/commands/commit.js.map +1 -1
  11. package/dist/commands/link.js +27 -27
  12. package/dist/commands/link.js.map +1 -1
  13. package/dist/commands/publish.js +74 -21
  14. package/dist/commands/publish.js.map +1 -1
  15. package/dist/commands/release.js +30 -17
  16. package/dist/commands/release.js.map +1 -1
  17. package/dist/commands/review.js +33 -26
  18. package/dist/commands/review.js.map +1 -1
  19. package/dist/commands/select-audio.js +4 -4
  20. package/dist/commands/select-audio.js.map +1 -1
  21. package/dist/commands/tree.js +122 -35
  22. package/dist/commands/tree.js.map +1 -1
  23. package/dist/commands/unlink.js +13 -13
  24. package/dist/commands/unlink.js.map +1 -1
  25. package/dist/commands/updates.js +21 -0
  26. package/dist/commands/updates.js.map +1 -1
  27. package/dist/commands/versions.js +5 -5
  28. package/dist/commands/versions.js.map +1 -1
  29. package/dist/constants.js +4 -4
  30. package/dist/constants.js.map +1 -1
  31. package/dist/content/files.js +4 -4
  32. package/dist/content/files.js.map +1 -1
  33. package/dist/logging.js +3 -3
  34. package/dist/logging.js.map +1 -1
  35. package/dist/util/aiAdapter.js +28 -0
  36. package/dist/util/aiAdapter.js.map +1 -0
  37. package/dist/util/general.js +5 -5
  38. package/dist/util/general.js.map +1 -1
  39. package/dist/util/interactive.js +6 -437
  40. package/dist/util/interactive.js.map +1 -1
  41. package/dist/util/loggerAdapter.js +24 -0
  42. package/dist/util/loggerAdapter.js.map +1 -0
  43. package/dist/util/performance.js +4 -4
  44. package/dist/util/performance.js.map +1 -1
  45. package/dist/util/safety.js +4 -4
  46. package/dist/util/safety.js.map +1 -1
  47. package/dist/util/storage.js +2 -2
  48. package/dist/util/storage.js.map +1 -1
  49. package/dist/util/storageAdapter.js +25 -0
  50. package/dist/util/storageAdapter.js.map +1 -0
  51. package/package.json +7 -6
  52. package/GITHUB-TOOLS-INTEGRATION.md +0 -323
  53. package/INTEGRATION-SUMMARY.md +0 -232
  54. package/TEST-STATUS.md +0 -168
  55. package/dist/prompt/commit.js +0 -76
  56. package/dist/prompt/commit.js.map +0 -1
  57. package/dist/prompt/instructions/commit.md +0 -133
  58. package/dist/prompt/instructions/release.md +0 -188
  59. package/dist/prompt/instructions/review.md +0 -169
  60. package/dist/prompt/personas/releaser.md +0 -24
  61. package/dist/prompt/personas/you.md +0 -55
  62. package/dist/prompt/release.js +0 -100
  63. package/dist/prompt/release.js.map +0 -1
  64. package/dist/prompt/review.js +0 -64
  65. package/dist/prompt/review.js.map +0 -1
  66. package/dist/util/openai.js +0 -365
  67. package/dist/util/openai.js.map +0 -1
@@ -1,365 +0,0 @@
1
- import { OpenAI } from 'openai';
2
- import { create } from './storage.js';
3
- import { getLogger } from '../logging.js';
4
- import { archiveAudio } from './general.js';
5
- import { safeJsonParse } from '@eldrforge/git-tools';
6
-
7
- function _define_property(obj, key, value) {
8
- if (key in obj) {
9
- Object.defineProperty(obj, key, {
10
- value: value,
11
- enumerable: true,
12
- configurable: true,
13
- writable: true
14
- });
15
- } else {
16
- obj[key] = value;
17
- }
18
- return obj;
19
- }
20
- /**
21
- * Get the appropriate model to use based on command-specific configuration
22
- * Command-specific model overrides the global model setting
23
- */ function getModelForCommand(config, commandName) {
24
- let commandModel;
25
- switch(commandName){
26
- case 'commit':
27
- case 'audio-commit':
28
- var _config_commit;
29
- commandModel = (_config_commit = config.commit) === null || _config_commit === void 0 ? void 0 : _config_commit.model;
30
- break;
31
- case 'release':
32
- var _config_release;
33
- commandModel = (_config_release = config.release) === null || _config_release === void 0 ? void 0 : _config_release.model;
34
- break;
35
- case 'review':
36
- case 'audio-review':
37
- var _config_review;
38
- commandModel = (_config_review = config.review) === null || _config_review === void 0 ? void 0 : _config_review.model;
39
- break;
40
- }
41
- // Return command-specific model if available, otherwise global model
42
- return commandModel || config.model || 'gpt-4o-mini';
43
- }
44
- /**
45
- * Get the appropriate OpenAI reasoning level based on command-specific configuration
46
- * Command-specific reasoning overrides the global reasoning setting
47
- */ function getOpenAIReasoningForCommand(config, commandName) {
48
- let commandReasoning;
49
- switch(commandName){
50
- case 'commit':
51
- case 'audio-commit':
52
- var _config_commit;
53
- commandReasoning = (_config_commit = config.commit) === null || _config_commit === void 0 ? void 0 : _config_commit.openaiReasoning;
54
- break;
55
- case 'release':
56
- var _config_release;
57
- commandReasoning = (_config_release = config.release) === null || _config_release === void 0 ? void 0 : _config_release.openaiReasoning;
58
- break;
59
- case 'review':
60
- case 'audio-review':
61
- var _config_review;
62
- commandReasoning = (_config_review = config.review) === null || _config_review === void 0 ? void 0 : _config_review.openaiReasoning;
63
- break;
64
- }
65
- // Return command-specific reasoning if available, otherwise global reasoning
66
- return commandReasoning || config.openaiReasoning || 'low';
67
- }
68
- /**
69
- * Get the appropriate OpenAI max output tokens based on command-specific configuration
70
- * Command-specific max output tokens overrides the global setting
71
- */ function getOpenAIMaxOutputTokensForCommand(config, commandName) {
72
- let commandMaxOutputTokens;
73
- switch(commandName){
74
- case 'commit':
75
- case 'audio-commit':
76
- var _config_commit;
77
- commandMaxOutputTokens = (_config_commit = config.commit) === null || _config_commit === void 0 ? void 0 : _config_commit.openaiMaxOutputTokens;
78
- break;
79
- case 'release':
80
- var _config_release;
81
- commandMaxOutputTokens = (_config_release = config.release) === null || _config_release === void 0 ? void 0 : _config_release.openaiMaxOutputTokens;
82
- break;
83
- case 'review':
84
- case 'audio-review':
85
- var _config_review;
86
- commandMaxOutputTokens = (_config_review = config.review) === null || _config_review === void 0 ? void 0 : _config_review.openaiMaxOutputTokens;
87
- break;
88
- }
89
- // Return command-specific max output tokens if available, otherwise global setting
90
- return commandMaxOutputTokens || config.openaiMaxOutputTokens || 10000;
91
- }
92
- class OpenAIError extends Error {
93
- constructor(message, isTokenLimitError = false){
94
- super(message), _define_property(this, "isTokenLimitError", void 0), this.isTokenLimitError = isTokenLimitError;
95
- this.name = 'OpenAIError';
96
- }
97
- }
98
- // Check if an error is a token limit exceeded error
99
- function isTokenLimitError(error) {
100
- if (!(error === null || error === void 0 ? void 0 : error.message)) return false;
101
- const message = error.message.toLowerCase();
102
- return message.includes('maximum context length') || message.includes('context_length_exceeded') || message.includes('token limit') || message.includes('too many tokens') || message.includes('reduce the length');
103
- }
104
- // Check if an error is a rate limit error
105
- function isRateLimitError(error) {
106
- if (!(error === null || error === void 0 ? void 0 : error.message) && !(error === null || error === void 0 ? void 0 : error.code) && !(error === null || error === void 0 ? void 0 : error.status)) return false;
107
- // Check for OpenAI specific rate limit indicators
108
- if (error.status === 429 || error.code === 'rate_limit_exceeded') {
109
- return true;
110
- }
111
- // Only check message if it exists
112
- if (error.message) {
113
- const message = error.message.toLowerCase();
114
- return message.includes('rate limit exceeded') || message.includes('too many requests') || message.includes('quota exceeded') || message.includes('rate') && message.includes('limit');
115
- }
116
- return false;
117
- }
118
- async function createCompletion(messages, options = {
119
- model: "gpt-4o-mini"
120
- }) {
121
- const logger = getLogger();
122
- const storage = create({
123
- log: logger.debug
124
- });
125
- let openai = null;
126
- try {
127
- var _completion_choices__message_content, _completion_choices__message, _completion_choices_;
128
- const apiKey = process.env.OPENAI_API_KEY;
129
- if (!apiKey) {
130
- throw new OpenAIError('OPENAI_API_KEY environment variable is not set');
131
- }
132
- // Create the client which we'll close in the finally block.
133
- const timeoutMs = parseInt(process.env.OPENAI_TIMEOUT_MS || '300000'); // Default to 5 minutes
134
- openai = new OpenAI({
135
- apiKey: apiKey,
136
- timeout: timeoutMs
137
- });
138
- const modelToUse = options.model || "gpt-4o-mini";
139
- // Calculate request size
140
- const requestSize = JSON.stringify(messages).length;
141
- const requestSizeKB = (requestSize / 1024).toFixed(2);
142
- // Log model, reasoning level, and request size
143
- const reasoningInfo = options.openaiReasoning ? ` | Reasoning: ${options.openaiReasoning}` : '';
144
- logger.info('🤖 Making request to OpenAI');
145
- logger.info(' Model: %s%s', modelToUse, reasoningInfo);
146
- logger.info(' Request size: %s KB (%s bytes)', requestSizeKB, requestSize.toLocaleString());
147
- logger.debug('Sending prompt to OpenAI: %j', messages);
148
- var _options_openaiMaxOutputTokens, _ref;
149
- // Use openaiMaxOutputTokens if specified (highest priority), otherwise fall back to maxTokens, or default to 10000
150
- const maxCompletionTokens = (_ref = (_options_openaiMaxOutputTokens = options.openaiMaxOutputTokens) !== null && _options_openaiMaxOutputTokens !== void 0 ? _options_openaiMaxOutputTokens : options.maxTokens) !== null && _ref !== void 0 ? _ref : 10000;
151
- // Save request debug file if enabled
152
- if (options.debug && (options.debugRequestFile || options.debugFile)) {
153
- const requestData = {
154
- model: modelToUse,
155
- messages,
156
- max_completion_tokens: maxCompletionTokens,
157
- response_format: options.responseFormat,
158
- reasoning_effort: options.openaiReasoning
159
- };
160
- const debugFile = options.debugRequestFile || options.debugFile;
161
- await storage.writeFile(debugFile, JSON.stringify(requestData, null, 2), 'utf8');
162
- logger.debug('Wrote request debug file to %s', debugFile);
163
- }
164
- // Prepare the API call options
165
- const apiOptions = {
166
- model: modelToUse,
167
- messages,
168
- max_completion_tokens: maxCompletionTokens,
169
- response_format: options.responseFormat
170
- };
171
- // Add reasoning parameter if specified and model supports it
172
- if (options.openaiReasoning && (modelToUse.includes('gpt-5') || modelToUse.includes('o3'))) {
173
- apiOptions.reasoning_effort = options.openaiReasoning;
174
- }
175
- // Add timeout wrapper to the OpenAI API call
176
- const startTime = Date.now();
177
- const completionPromise = openai.chat.completions.create(apiOptions);
178
- // Create timeout promise with proper cleanup to prevent memory leaks
179
- let timeoutId = null;
180
- const timeoutPromise = new Promise((_, reject)=>{
181
- const timeoutMs = parseInt(process.env.OPENAI_TIMEOUT_MS || '300000'); // Default to 5 minutes
182
- timeoutId = setTimeout(()=>reject(new OpenAIError(`OpenAI API call timed out after ${timeoutMs / 1000} seconds`)), timeoutMs);
183
- });
184
- let completion;
185
- try {
186
- completion = await Promise.race([
187
- completionPromise,
188
- timeoutPromise
189
- ]);
190
- } finally{
191
- // Clear the timeout to prevent memory leaks
192
- if (timeoutId !== null) {
193
- clearTimeout(timeoutId);
194
- }
195
- }
196
- const elapsedTime = Date.now() - startTime;
197
- // Save response debug file if enabled
198
- if (options.debug && (options.debugResponseFile || options.debugFile)) {
199
- const debugFile = options.debugResponseFile || options.debugFile;
200
- await storage.writeFile(debugFile, JSON.stringify(completion, null, 2), 'utf8');
201
- logger.debug('Wrote response debug file to %s', debugFile);
202
- }
203
- const response = (_completion_choices_ = completion.choices[0]) === null || _completion_choices_ === void 0 ? void 0 : (_completion_choices__message = _completion_choices_.message) === null || _completion_choices__message === void 0 ? void 0 : (_completion_choices__message_content = _completion_choices__message.content) === null || _completion_choices__message_content === void 0 ? void 0 : _completion_choices__message_content.trim();
204
- if (!response) {
205
- throw new OpenAIError('No response received from OpenAI');
206
- }
207
- // Calculate and log response size
208
- const responseSize = response.length;
209
- const responseSizeKB = (responseSize / 1024).toFixed(2);
210
- logger.info(' Response size: %s KB (%s bytes)', responseSizeKB, responseSize.toLocaleString());
211
- // Log elapsed time
212
- const elapsedTimeFormatted = elapsedTime >= 1000 ? `${(elapsedTime / 1000).toFixed(1)}s` : `${elapsedTime}ms`;
213
- logger.info(' Time: %s', elapsedTimeFormatted);
214
- // Log token usage if available
215
- if (completion.usage) {
216
- var _completion_usage_prompt_tokens, _completion_usage_completion_tokens, _completion_usage_total_tokens;
217
- logger.info(' Token usage: %s prompt + %s completion = %s total', ((_completion_usage_prompt_tokens = completion.usage.prompt_tokens) === null || _completion_usage_prompt_tokens === void 0 ? void 0 : _completion_usage_prompt_tokens.toLocaleString()) || '?', ((_completion_usage_completion_tokens = completion.usage.completion_tokens) === null || _completion_usage_completion_tokens === void 0 ? void 0 : _completion_usage_completion_tokens.toLocaleString()) || '?', ((_completion_usage_total_tokens = completion.usage.total_tokens) === null || _completion_usage_total_tokens === void 0 ? void 0 : _completion_usage_total_tokens.toLocaleString()) || '?');
218
- }
219
- logger.debug('Received response from OpenAI: %s...', response.substring(0, 30));
220
- if (options.responseFormat) {
221
- return safeJsonParse(response, 'OpenAI API response');
222
- } else {
223
- return response;
224
- }
225
- } catch (error) {
226
- logger.error('Error calling OpenAI API: %s %s', error.message, error.stack);
227
- const isTokenError = isTokenLimitError(error);
228
- throw new OpenAIError(`Failed to create completion: ${error.message}`, isTokenError);
229
- } finally{
230
- // OpenAI client cleanup is handled automatically by the library
231
- // No manual cleanup needed for newer versions
232
- }
233
- }
234
- // Create completion with automatic retry on token limit errors
235
- async function createCompletionWithRetry(messages, options = {
236
- model: "gpt-4o-mini"
237
- }, retryCallback) {
238
- const logger = getLogger();
239
- const maxRetries = 3;
240
- for(let attempt = 1; attempt <= maxRetries; attempt++){
241
- try {
242
- const messagesToSend = attempt === 1 ? messages : retryCallback ? await retryCallback(attempt) : messages;
243
- return await createCompletion(messagesToSend, options);
244
- } catch (error) {
245
- if (error instanceof OpenAIError && error.isTokenLimitError && attempt < maxRetries && retryCallback) {
246
- logger.warn('Token limit exceeded on attempt %d/%d, retrying with reduced content...', attempt, maxRetries);
247
- // Add exponential backoff for token limit errors
248
- const backoffMs = Math.min(1000 * Math.pow(2, attempt - 1), 10000);
249
- await new Promise((resolve)=>setTimeout(resolve, backoffMs));
250
- continue;
251
- } else if (isRateLimitError(error) && attempt < maxRetries) {
252
- // Handle rate limiting with exponential backoff
253
- const backoffMs = Math.min(2000 * Math.pow(2, attempt - 1), 15000); // More reasonable backoff: 2s, 4s, 8s, max 15s
254
- logger.warn(`Rate limit hit on attempt ${attempt}/${maxRetries}, waiting ${backoffMs}ms before retry...`);
255
- await new Promise((resolve)=>setTimeout(resolve, backoffMs));
256
- continue;
257
- }
258
- throw error;
259
- }
260
- }
261
- // This should never be reached, but TypeScript requires it
262
- throw new OpenAIError('Max retries exceeded');
263
- }
264
- async function transcribeAudio(filePath, options = {
265
- model: "whisper-1"
266
- }) {
267
- const logger = getLogger();
268
- const storage = create({
269
- log: logger.debug
270
- });
271
- let openai = null;
272
- let audioStream = null;
273
- let streamClosed = false;
274
- // Helper function to safely close the stream
275
- const closeAudioStream = ()=>{
276
- if (audioStream && !streamClosed) {
277
- try {
278
- // Only call destroy if it exists and the stream isn't already destroyed
279
- if (typeof audioStream.destroy === 'function' && !audioStream.destroyed) {
280
- audioStream.destroy();
281
- }
282
- streamClosed = true;
283
- logger.debug('Audio stream closed successfully');
284
- } catch (streamErr) {
285
- logger.debug('Failed to destroy audio read stream: %s', streamErr.message);
286
- streamClosed = true; // Mark as closed even if destroy failed
287
- }
288
- }
289
- };
290
- try {
291
- const apiKey = process.env.OPENAI_API_KEY;
292
- if (!apiKey) {
293
- throw new OpenAIError('OPENAI_API_KEY environment variable is not set');
294
- }
295
- openai = new OpenAI({
296
- apiKey: apiKey
297
- });
298
- logger.debug('Transcribing audio file: %s', filePath);
299
- // Save request debug file if enabled
300
- if (options.debug && (options.debugRequestFile || options.debugFile)) {
301
- const requestData = {
302
- model: options.model || "whisper-1",
303
- file: filePath,
304
- response_format: "json"
305
- };
306
- const debugFile = options.debugRequestFile || options.debugFile;
307
- await storage.writeFile(debugFile, JSON.stringify(requestData, null, 2), 'utf8');
308
- logger.debug('Wrote request debug file to %s', debugFile);
309
- }
310
- audioStream = await storage.readStream(filePath);
311
- // Set up error handler for the stream to ensure cleanup on stream errors
312
- // Only add handler if the stream has the 'on' method (real streams)
313
- if (audioStream && typeof audioStream.on === 'function') {
314
- audioStream.on('error', (streamError)=>{
315
- logger.error('Audio stream error: %s', streamError.message);
316
- closeAudioStream();
317
- });
318
- }
319
- let transcription;
320
- try {
321
- transcription = await openai.audio.transcriptions.create({
322
- model: options.model || "whisper-1",
323
- file: audioStream,
324
- response_format: "json"
325
- });
326
- // Close the stream immediately after successful API call to prevent race conditions
327
- closeAudioStream();
328
- } catch (apiError) {
329
- // Close the stream immediately if the API call fails
330
- closeAudioStream();
331
- throw apiError;
332
- }
333
- // Save response debug file if enabled
334
- if (options.debug && (options.debugResponseFile || options.debugFile)) {
335
- const debugFile = options.debugResponseFile || options.debugFile;
336
- await storage.writeFile(debugFile, JSON.stringify(transcription, null, 2), 'utf8');
337
- logger.debug('Wrote response debug file to %s', debugFile);
338
- }
339
- const response = transcription;
340
- if (!response) {
341
- throw new OpenAIError('No transcription received from OpenAI');
342
- }
343
- logger.debug('Received transcription from OpenAI: %s', response);
344
- // Archive the audio file and transcription
345
- try {
346
- const outputDir = options.outputDirectory || 'output';
347
- await archiveAudio(filePath, response.text, outputDir);
348
- } catch (archiveError) {
349
- // Don't fail the transcription if archiving fails, just log the error
350
- logger.warn('Failed to archive audio file: %s', archiveError.message);
351
- }
352
- return response;
353
- } catch (error) {
354
- logger.error('Error transcribing audio file: %s %s', error.message, error.stack);
355
- throw new OpenAIError(`Failed to transcribe audio: ${error.message}`);
356
- } finally{
357
- // Ensure the audio stream is properly closed to release file handles
358
- closeAudioStream();
359
- // OpenAI client cleanup is handled automatically by the library
360
- // No manual cleanup needed for newer versions
361
- }
362
- }
363
-
364
- export { OpenAIError, createCompletion, createCompletionWithRetry, getModelForCommand, getOpenAIMaxOutputTokensForCommand, getOpenAIReasoningForCommand, isRateLimitError, isTokenLimitError, transcribeAudio };
365
- //# sourceMappingURL=openai.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"openai.js","sources":["../../src/util/openai.ts"],"sourcesContent":["import { OpenAI } from 'openai';\nimport { ChatCompletionMessageParam } from 'openai/resources';\nimport * as Storage from './storage';\nimport { getLogger } from '../logging';\nimport { archiveAudio } from './general';\nimport { Config } from '../types';\nimport { safeJsonParse } from '@eldrforge/git-tools';\n// eslint-disable-next-line no-restricted-imports\nimport fs from 'fs';\n\nexport interface Transcription {\n text: string;\n}\n\n/**\n * Get the appropriate model to use based on command-specific configuration\n * Command-specific model overrides the global model setting\n */\nexport function getModelForCommand(config: Config, commandName: string): string {\n let commandModel: string | undefined;\n\n switch (commandName) {\n case 'commit':\n case 'audio-commit':\n commandModel = config.commit?.model;\n break;\n case 'release':\n commandModel = config.release?.model;\n break;\n case 'review':\n case 'audio-review':\n commandModel = config.review?.model;\n break;\n default:\n // For other commands, just use global model\n break;\n }\n\n // Return command-specific model if available, otherwise global model\n return commandModel || config.model || 'gpt-4o-mini';\n}\n\n/**\n * Get the appropriate OpenAI reasoning level based on command-specific configuration\n * Command-specific reasoning overrides the global reasoning setting\n */\nexport function getOpenAIReasoningForCommand(config: Config, commandName: string): 'low' | 'medium' | 'high' {\n let commandReasoning: 'low' | 'medium' | 'high' | undefined;\n\n switch (commandName) {\n case 'commit':\n case 'audio-commit':\n commandReasoning = config.commit?.openaiReasoning;\n break;\n case 'release':\n commandReasoning = config.release?.openaiReasoning;\n break;\n case 'review':\n case 'audio-review':\n commandReasoning = config.review?.openaiReasoning;\n break;\n default:\n // For other commands, just use global reasoning\n break;\n }\n\n // Return command-specific reasoning if available, otherwise global reasoning\n return commandReasoning || config.openaiReasoning || 'low';\n}\n\n/**\n * Get the appropriate OpenAI max output tokens based on command-specific configuration\n * Command-specific max output tokens overrides the global setting\n */\nexport function getOpenAIMaxOutputTokensForCommand(config: Config, commandName: string): number {\n let commandMaxOutputTokens: number | undefined;\n\n switch (commandName) {\n case 'commit':\n case 'audio-commit':\n commandMaxOutputTokens = config.commit?.openaiMaxOutputTokens;\n break;\n case 'release':\n commandMaxOutputTokens = config.release?.openaiMaxOutputTokens;\n break;\n case 'review':\n case 'audio-review':\n commandMaxOutputTokens = config.review?.openaiMaxOutputTokens;\n break;\n default:\n // For other commands, just use global max output tokens\n break;\n }\n\n // Return command-specific max output tokens if available, otherwise global setting\n return commandMaxOutputTokens || config.openaiMaxOutputTokens || 10000;\n}\n\nexport class OpenAIError extends Error {\n constructor(message: string, public readonly isTokenLimitError: boolean = false) {\n super(message);\n this.name = 'OpenAIError';\n }\n}\n\n// Check if an error is a token limit exceeded error\nexport function isTokenLimitError(error: any): boolean {\n if (!error?.message) return false;\n\n const message = error.message.toLowerCase();\n return message.includes('maximum context length') ||\n message.includes('context_length_exceeded') ||\n message.includes('token limit') ||\n message.includes('too many tokens') ||\n message.includes('reduce the length');\n}\n\n// Check if an error is a rate limit error\nexport function isRateLimitError(error: any): boolean {\n if (!error?.message && !error?.code && !error?.status) return false;\n\n // Check for OpenAI specific rate limit indicators\n if (error.status === 429 || error.code === 'rate_limit_exceeded') {\n return true;\n }\n\n // Only check message if it exists\n if (error.message) {\n const message = error.message.toLowerCase();\n return message.includes('rate limit exceeded') ||\n message.includes('too many requests') ||\n message.includes('quota exceeded') ||\n (message.includes('rate') && message.includes('limit'));\n }\n\n return false;\n}\n\nexport async function createCompletion(messages: ChatCompletionMessageParam[], options: { responseFormat?: any, model?: string, debug?: boolean, debugFile?: string, debugRequestFile?: string, debugResponseFile?: string, maxTokens?: number, openaiReasoning?: 'low' | 'medium' | 'high', openaiMaxOutputTokens?: number } = { model: \"gpt-4o-mini\" }): Promise<string | any> {\n const logger = getLogger();\n const storage = Storage.create({ log: logger.debug });\n let openai: OpenAI | null = null;\n try {\n const apiKey = process.env.OPENAI_API_KEY;\n if (!apiKey) {\n throw new OpenAIError('OPENAI_API_KEY environment variable is not set');\n }\n\n // Create the client which we'll close in the finally block.\n const timeoutMs = parseInt(process.env.OPENAI_TIMEOUT_MS || '300000'); // Default to 5 minutes\n openai = new OpenAI({\n apiKey: apiKey,\n timeout: timeoutMs,\n });\n\n const modelToUse = options.model || \"gpt-4o-mini\";\n\n // Calculate request size\n const requestSize = JSON.stringify(messages).length;\n const requestSizeKB = (requestSize / 1024).toFixed(2);\n\n // Log model, reasoning level, and request size\n const reasoningInfo = options.openaiReasoning ? ` | Reasoning: ${options.openaiReasoning}` : '';\n logger.info('🤖 Making request to OpenAI');\n logger.info(' Model: %s%s', modelToUse, reasoningInfo);\n logger.info(' Request size: %s KB (%s bytes)', requestSizeKB, requestSize.toLocaleString());\n\n logger.debug('Sending prompt to OpenAI: %j', messages);\n\n // Use openaiMaxOutputTokens if specified (highest priority), otherwise fall back to maxTokens, or default to 10000\n const maxCompletionTokens = options.openaiMaxOutputTokens ?? options.maxTokens ?? 10000;\n\n // Save request debug file if enabled\n if (options.debug && (options.debugRequestFile || options.debugFile)) {\n const requestData = {\n model: modelToUse,\n messages,\n max_completion_tokens: maxCompletionTokens,\n response_format: options.responseFormat,\n reasoning_effort: options.openaiReasoning,\n };\n const debugFile = options.debugRequestFile || options.debugFile;\n await storage.writeFile(debugFile!, JSON.stringify(requestData, null, 2), 'utf8');\n logger.debug('Wrote request debug file to %s', debugFile);\n }\n\n // Prepare the API call options\n const apiOptions: any = {\n model: modelToUse,\n messages,\n max_completion_tokens: maxCompletionTokens,\n response_format: options.responseFormat,\n };\n\n // Add reasoning parameter if specified and model supports it\n if (options.openaiReasoning && (modelToUse.includes('gpt-5') || modelToUse.includes('o3'))) {\n apiOptions.reasoning_effort = options.openaiReasoning;\n }\n\n // Add timeout wrapper to the OpenAI API call\n const startTime = Date.now();\n const completionPromise = openai.chat.completions.create(apiOptions);\n\n // Create timeout promise with proper cleanup to prevent memory leaks\n let timeoutId: NodeJS.Timeout | null = null;\n const timeoutPromise = new Promise<never>((_, reject) => {\n const timeoutMs = parseInt(process.env.OPENAI_TIMEOUT_MS || '300000'); // Default to 5 minutes\n timeoutId = setTimeout(() => reject(new OpenAIError(`OpenAI API call timed out after ${timeoutMs/1000} seconds`)), timeoutMs);\n });\n\n let completion;\n try {\n completion = await Promise.race([completionPromise, timeoutPromise]);\n } finally {\n // Clear the timeout to prevent memory leaks\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n }\n }\n\n const elapsedTime = Date.now() - startTime;\n\n // Save response debug file if enabled\n if (options.debug && (options.debugResponseFile || options.debugFile)) {\n const debugFile = options.debugResponseFile || options.debugFile;\n await storage.writeFile(debugFile!, JSON.stringify(completion, null, 2), 'utf8');\n logger.debug('Wrote response debug file to %s', debugFile);\n }\n\n const response = completion.choices[0]?.message?.content?.trim();\n if (!response) {\n throw new OpenAIError('No response received from OpenAI');\n }\n\n // Calculate and log response size\n const responseSize = response.length;\n const responseSizeKB = (responseSize / 1024).toFixed(2);\n logger.info(' Response size: %s KB (%s bytes)', responseSizeKB, responseSize.toLocaleString());\n\n // Log elapsed time\n const elapsedTimeFormatted = elapsedTime >= 1000\n ? `${(elapsedTime / 1000).toFixed(1)}s`\n : `${elapsedTime}ms`;\n logger.info(' Time: %s', elapsedTimeFormatted);\n\n // Log token usage if available\n if (completion.usage) {\n logger.info(' Token usage: %s prompt + %s completion = %s total',\n completion.usage.prompt_tokens?.toLocaleString() || '?',\n completion.usage.completion_tokens?.toLocaleString() || '?',\n completion.usage.total_tokens?.toLocaleString() || '?'\n );\n }\n\n logger.debug('Received response from OpenAI: %s...', response.substring(0, 30));\n if (options.responseFormat) {\n return safeJsonParse(response, 'OpenAI API response');\n } else {\n return response;\n }\n\n } catch (error: any) {\n logger.error('Error calling OpenAI API: %s %s', error.message, error.stack);\n const isTokenError = isTokenLimitError(error);\n throw new OpenAIError(`Failed to create completion: ${error.message}`, isTokenError);\n } finally {\n // OpenAI client cleanup is handled automatically by the library\n // No manual cleanup needed for newer versions\n }\n}\n\n// Create completion with automatic retry on token limit errors\nexport async function createCompletionWithRetry(\n messages: ChatCompletionMessageParam[],\n options: { responseFormat?: any, model?: string, debug?: boolean, debugFile?: string, debugRequestFile?: string, debugResponseFile?: string, maxTokens?: number, openaiReasoning?: 'low' | 'medium' | 'high', openaiMaxOutputTokens?: number } = { model: \"gpt-4o-mini\" },\n retryCallback?: (attempt: number) => Promise<ChatCompletionMessageParam[]>\n): Promise<string | any> {\n const logger = getLogger();\n const maxRetries = 3;\n\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n try {\n const messagesToSend = attempt === 1 ? messages : (retryCallback ? await retryCallback(attempt) : messages);\n return await createCompletion(messagesToSend, options);\n } catch (error: any) {\n if (error instanceof OpenAIError && error.isTokenLimitError && attempt < maxRetries && retryCallback) {\n logger.warn('Token limit exceeded on attempt %d/%d, retrying with reduced content...', attempt, maxRetries);\n // Add exponential backoff for token limit errors\n const backoffMs = Math.min(1000 * Math.pow(2, attempt - 1), 10000);\n await new Promise(resolve => setTimeout(resolve, backoffMs));\n continue;\n } else if (isRateLimitError(error) && attempt < maxRetries) {\n // Handle rate limiting with exponential backoff\n const backoffMs = Math.min(2000 * Math.pow(2, attempt - 1), 15000); // More reasonable backoff: 2s, 4s, 8s, max 15s\n logger.warn(`Rate limit hit on attempt ${attempt}/${maxRetries}, waiting ${backoffMs}ms before retry...`);\n await new Promise(resolve => setTimeout(resolve, backoffMs));\n continue;\n }\n throw error;\n }\n }\n\n // This should never be reached, but TypeScript requires it\n throw new OpenAIError('Max retries exceeded');\n}\n\nexport async function transcribeAudio(filePath: string, options: { model?: string, debug?: boolean, debugFile?: string, debugRequestFile?: string, debugResponseFile?: string, outputDirectory?: string } = { model: \"whisper-1\" }): Promise<Transcription> {\n const logger = getLogger();\n const storage = Storage.create({ log: logger.debug });\n let openai: OpenAI | null = null;\n let audioStream: fs.ReadStream | null = null;\n let streamClosed = false;\n\n // Helper function to safely close the stream\n const closeAudioStream = () => {\n if (audioStream && !streamClosed) {\n try {\n // Only call destroy if it exists and the stream isn't already destroyed\n if (typeof audioStream.destroy === 'function' && !audioStream.destroyed) {\n audioStream.destroy();\n }\n streamClosed = true;\n logger.debug('Audio stream closed successfully');\n } catch (streamErr) {\n logger.debug('Failed to destroy audio read stream: %s', (streamErr as Error).message);\n streamClosed = true; // Mark as closed even if destroy failed\n }\n }\n };\n\n try {\n const apiKey = process.env.OPENAI_API_KEY;\n if (!apiKey) {\n throw new OpenAIError('OPENAI_API_KEY environment variable is not set');\n }\n\n openai = new OpenAI({\n apiKey: apiKey,\n });\n\n logger.debug('Transcribing audio file: %s', filePath);\n\n // Save request debug file if enabled\n if (options.debug && (options.debugRequestFile || options.debugFile)) {\n const requestData = {\n model: options.model || \"whisper-1\",\n file: filePath, // Can't serialize the stream, so just save the file path\n response_format: \"json\",\n };\n const debugFile = options.debugRequestFile || options.debugFile;\n await storage.writeFile(debugFile!, JSON.stringify(requestData, null, 2), 'utf8');\n logger.debug('Wrote request debug file to %s', debugFile);\n }\n\n audioStream = await storage.readStream(filePath);\n\n // Set up error handler for the stream to ensure cleanup on stream errors\n // Only add handler if the stream has the 'on' method (real streams)\n if (audioStream && typeof audioStream.on === 'function') {\n audioStream.on('error', (streamError) => {\n logger.error('Audio stream error: %s', streamError.message);\n closeAudioStream();\n });\n }\n\n let transcription;\n try {\n transcription = await openai.audio.transcriptions.create({\n model: options.model || \"whisper-1\",\n file: audioStream,\n response_format: \"json\",\n });\n // Close the stream immediately after successful API call to prevent race conditions\n closeAudioStream();\n } catch (apiError) {\n // Close the stream immediately if the API call fails\n closeAudioStream();\n throw apiError;\n }\n\n // Save response debug file if enabled\n if (options.debug && (options.debugResponseFile || options.debugFile)) {\n const debugFile = options.debugResponseFile || options.debugFile;\n await storage.writeFile(debugFile!, JSON.stringify(transcription, null, 2), 'utf8');\n logger.debug('Wrote response debug file to %s', debugFile);\n }\n\n const response = transcription;\n if (!response) {\n throw new OpenAIError('No transcription received from OpenAI');\n }\n\n logger.debug('Received transcription from OpenAI: %s', response);\n\n // Archive the audio file and transcription\n try {\n const outputDir = options.outputDirectory || 'output';\n await archiveAudio(filePath, response.text, outputDir);\n } catch (archiveError: any) {\n // Don't fail the transcription if archiving fails, just log the error\n logger.warn('Failed to archive audio file: %s', archiveError.message);\n }\n\n return response;\n\n } catch (error: any) {\n logger.error('Error transcribing audio file: %s %s', error.message, error.stack);\n throw new OpenAIError(`Failed to transcribe audio: ${error.message}`);\n } finally {\n // Ensure the audio stream is properly closed to release file handles\n closeAudioStream();\n // OpenAI client cleanup is handled automatically by the library\n // No manual cleanup needed for newer versions\n }\n}\n"],"names":["getModelForCommand","config","commandName","commandModel","commit","model","release","review","getOpenAIReasoningForCommand","commandReasoning","openaiReasoning","getOpenAIMaxOutputTokensForCommand","commandMaxOutputTokens","openaiMaxOutputTokens","OpenAIError","Error","message","isTokenLimitError","name","error","toLowerCase","includes","isRateLimitError","code","status","createCompletion","messages","options","logger","getLogger","storage","Storage","log","debug","openai","completion","apiKey","process","env","OPENAI_API_KEY","timeoutMs","parseInt","OPENAI_TIMEOUT_MS","OpenAI","timeout","modelToUse","requestSize","JSON","stringify","length","requestSizeKB","toFixed","reasoningInfo","info","toLocaleString","maxCompletionTokens","maxTokens","debugRequestFile","debugFile","requestData","max_completion_tokens","response_format","responseFormat","reasoning_effort","writeFile","apiOptions","startTime","Date","now","completionPromise","chat","completions","create","timeoutId","timeoutPromise","Promise","_","reject","setTimeout","race","clearTimeout","elapsedTime","debugResponseFile","response","choices","content","trim","responseSize","responseSizeKB","elapsedTimeFormatted","usage","prompt_tokens","completion_tokens","total_tokens","substring","safeJsonParse","stack","isTokenError","createCompletionWithRetry","retryCallback","maxRetries","attempt","messagesToSend","warn","backoffMs","Math","min","pow","resolve","transcribeAudio","filePath","audioStream","streamClosed","closeAudioStream","destroy","destroyed","streamErr","file","readStream","on","streamError","transcription","audio","transcriptions","apiError","outputDir","outputDirectory","archiveAudio","text","archiveError"],"mappings":"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"}