@eldrforge/kodrdriv 1.2.20 → 1.2.22
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/WORKFLOW-PRECHECK-IMPLEMENTATION.md +239 -0
- package/WORKFLOW-SKIP-SUMMARY.md +121 -0
- package/dist/application.js +6 -2
- package/dist/application.js.map +1 -1
- package/dist/arguments.js +2 -2
- package/dist/arguments.js.map +1 -1
- package/dist/commands/audio-commit.js +15 -6
- package/dist/commands/audio-commit.js.map +1 -1
- package/dist/commands/audio-review.js +31 -15
- package/dist/commands/audio-review.js.map +1 -1
- package/dist/commands/commit.js +31 -20
- package/dist/commands/commit.js.map +1 -1
- package/dist/commands/link.js +27 -27
- package/dist/commands/link.js.map +1 -1
- package/dist/commands/publish.js +87 -34
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/release.js +32 -19
- package/dist/commands/release.js.map +1 -1
- package/dist/commands/review.js +36 -30
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/select-audio.js +4 -4
- package/dist/commands/select-audio.js.map +1 -1
- package/dist/commands/tree.js +154 -38
- package/dist/commands/tree.js.map +1 -1
- package/dist/commands/unlink.js +13 -13
- package/dist/commands/unlink.js.map +1 -1
- package/dist/commands/updates.js +21 -0
- package/dist/commands/updates.js.map +1 -1
- package/dist/commands/versions.js +5 -5
- package/dist/commands/versions.js.map +1 -1
- package/dist/constants.js +4 -4
- package/dist/constants.js.map +1 -1
- package/dist/content/files.js +4 -4
- package/dist/content/files.js.map +1 -1
- package/dist/error/CommandErrors.js +1 -65
- package/dist/error/CommandErrors.js.map +1 -1
- package/dist/logging.js +3 -3
- package/dist/logging.js.map +1 -1
- package/dist/util/aiAdapter.js +28 -0
- package/dist/util/aiAdapter.js.map +1 -0
- package/dist/util/general.js +5 -5
- package/dist/util/general.js.map +1 -1
- package/dist/util/interactive.js +6 -437
- package/dist/util/interactive.js.map +1 -1
- package/dist/util/loggerAdapter.js +24 -0
- package/dist/util/loggerAdapter.js.map +1 -0
- package/dist/util/performance.js +4 -4
- package/dist/util/performance.js.map +1 -1
- package/dist/util/safety.js +4 -4
- package/dist/util/safety.js.map +1 -1
- package/dist/util/storage.js +2 -2
- package/dist/util/storage.js.map +1 -1
- package/dist/util/storageAdapter.js +25 -0
- package/dist/util/storageAdapter.js.map +1 -0
- package/package.json +6 -4
- package/test_output.txt +3 -3
- package/INTEGRATION-SUMMARY.md +0 -232
- package/TEST-STATUS.md +0 -168
- package/dist/content/issues.js +0 -331
- package/dist/content/issues.js.map +0 -1
- package/dist/content/releaseNotes.js +0 -90
- package/dist/content/releaseNotes.js.map +0 -1
- package/dist/prompt/commit.js +0 -76
- package/dist/prompt/commit.js.map +0 -1
- package/dist/prompt/instructions/commit.md +0 -133
- package/dist/prompt/instructions/release.md +0 -188
- package/dist/prompt/instructions/review.md +0 -169
- package/dist/prompt/personas/releaser.md +0 -24
- package/dist/prompt/personas/you.md +0 -55
- package/dist/prompt/release.js +0 -100
- package/dist/prompt/release.js.map +0 -1
- package/dist/prompt/review.js +0 -64
- package/dist/prompt/review.js.map +0 -1
- package/dist/util/github.js +0 -1071
- package/dist/util/github.js.map +0 -1
- package/dist/util/openai.js +0 -365
- package/dist/util/openai.js.map +0 -1
package/dist/commands/review.js
CHANGED
|
@@ -2,27 +2,27 @@
|
|
|
2
2
|
import { Formatter } from '@riotprompt/riotprompt';
|
|
3
3
|
import { ValidationError, FileOperationError, CommandError } from '../error/CommandErrors.js';
|
|
4
4
|
import { getLogger } from '../logging.js';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { getUserChoice, createReviewPrompt, createCompletion } from '@eldrforge/ai-service';
|
|
6
|
+
import { toAIConfig } from '../util/aiAdapter.js';
|
|
7
|
+
import { createStorageAdapter } from '../util/storageAdapter.js';
|
|
8
|
+
import { createLoggerAdapter } from '../util/loggerAdapter.js';
|
|
7
9
|
import { create as create$1 } from '../content/log.js';
|
|
8
10
|
import { getReviewExcludedPatterns, getRecentDiffsForReview } from '../content/diff.js';
|
|
9
|
-
import {
|
|
10
|
-
import { handleIssueCreation, get as get$1 } from '../content/issues.js';
|
|
11
|
+
import { handleIssueCreation, getReleaseNotesContent, getIssuesContent } from '@eldrforge/github-tools';
|
|
11
12
|
import { DEFAULT_EXCLUDED_PATTERNS, DEFAULT_OUTPUT_DIRECTORY } from '../constants.js';
|
|
12
13
|
import { getTimestampedReviewNotesFilename, getOutputPath, getTimestampedReviewFilename, getTimestampedResponseFilename, getTimestampedRequestFilename } from '../util/general.js';
|
|
13
14
|
import { create } from '../util/storage.js';
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import os__default from 'os';
|
|
15
|
+
import path from 'path';
|
|
16
|
+
import os from 'os';
|
|
17
17
|
import { spawn } from 'child_process';
|
|
18
|
-
import
|
|
18
|
+
import fs from 'fs/promises';
|
|
19
19
|
|
|
20
20
|
// Utility function to read a review note from a file
|
|
21
21
|
const readReviewNoteFromFile = async (filePath)=>{
|
|
22
22
|
const logger = getLogger();
|
|
23
23
|
try {
|
|
24
24
|
logger.debug(`Reading review note from file: ${filePath}`);
|
|
25
|
-
const content = await
|
|
25
|
+
const content = await fs.readFile(filePath, 'utf8');
|
|
26
26
|
if (!content.trim()) {
|
|
27
27
|
throw new ValidationError(`Review file is empty: ${filePath}`);
|
|
28
28
|
}
|
|
@@ -43,11 +43,11 @@ const getReviewFilesInDirectory = async (directoryPath)=>{
|
|
|
43
43
|
const logger = getLogger();
|
|
44
44
|
try {
|
|
45
45
|
logger.debug(`Scanning directory for review files: ${directoryPath}`);
|
|
46
|
-
const entries = await
|
|
46
|
+
const entries = await fs.readdir(directoryPath, {
|
|
47
47
|
withFileTypes: true
|
|
48
48
|
});
|
|
49
49
|
// Filter for regular files (not directories) and get full paths
|
|
50
|
-
const files = entries.filter((entry)=>entry.isFile()).map((entry)=>
|
|
50
|
+
const files = entries.filter((entry)=>entry.isFile()).map((entry)=>path.join(directoryPath, entry.name)).sort(); // Sort alphabetically
|
|
51
51
|
logger.debug(`Found ${files.length} files in directory: ${directoryPath}`);
|
|
52
52
|
return files;
|
|
53
53
|
} catch (error) {
|
|
@@ -121,20 +121,20 @@ const selectFilesForProcessing = async (reviewFiles, senditMode)=>{
|
|
|
121
121
|
// Safe temp file handling with proper permissions and validation
|
|
122
122
|
const createSecureTempFile = async ()=>{
|
|
123
123
|
const logger = getLogger();
|
|
124
|
-
const tmpDir =
|
|
124
|
+
const tmpDir = os.tmpdir();
|
|
125
125
|
// Ensure temp directory exists and is writable
|
|
126
126
|
try {
|
|
127
127
|
// Use constant value directly to avoid import restrictions
|
|
128
128
|
const W_OK = 2; // fs.constants.W_OK value
|
|
129
|
-
await
|
|
129
|
+
await fs.access(tmpDir, W_OK);
|
|
130
130
|
} catch (error) {
|
|
131
131
|
logger.error(`Temp directory not writable: ${tmpDir}`);
|
|
132
132
|
throw new FileOperationError(`Temp directory not writable: ${error.message}`, tmpDir, error);
|
|
133
133
|
}
|
|
134
|
-
const tmpFilePath =
|
|
134
|
+
const tmpFilePath = path.join(tmpDir, `kodrdriv_review_${Date.now()}_${Math.random().toString(36).substring(7)}.md`);
|
|
135
135
|
// Create file with restrictive permissions (owner read/write only)
|
|
136
136
|
try {
|
|
137
|
-
const fd = await
|
|
137
|
+
const fd = await fs.open(tmpFilePath, 'w', 0o600);
|
|
138
138
|
await fd.close();
|
|
139
139
|
logger.debug(`Created secure temp file: ${tmpFilePath}`);
|
|
140
140
|
return tmpFilePath;
|
|
@@ -147,7 +147,7 @@ const createSecureTempFile = async ()=>{
|
|
|
147
147
|
const cleanupTempFile = async (filePath)=>{
|
|
148
148
|
const logger = getLogger();
|
|
149
149
|
try {
|
|
150
|
-
await
|
|
150
|
+
await fs.unlink(filePath);
|
|
151
151
|
logger.debug(`Cleaned up temp file: ${filePath}`);
|
|
152
152
|
} catch (error) {
|
|
153
153
|
// Only ignore ENOENT (file not found) errors, log others
|
|
@@ -272,14 +272,14 @@ const safeWriteFile = async (filePath, content, encoding = 'utf-8')=>{
|
|
|
272
272
|
const logger = getLogger();
|
|
273
273
|
try {
|
|
274
274
|
// Check if parent directory exists and is writable
|
|
275
|
-
const parentDir =
|
|
275
|
+
const parentDir = path.dirname(filePath);
|
|
276
276
|
const W_OK = 2; // fs.constants.W_OK value
|
|
277
|
-
await
|
|
277
|
+
await fs.access(parentDir, W_OK);
|
|
278
278
|
// Check available disk space (basic check by writing a small test)
|
|
279
279
|
const testFile = `${filePath}.test`;
|
|
280
280
|
try {
|
|
281
|
-
await
|
|
282
|
-
await
|
|
281
|
+
await fs.writeFile(testFile, 'test', encoding);
|
|
282
|
+
await fs.unlink(testFile);
|
|
283
283
|
} catch (error) {
|
|
284
284
|
if (error.code === 'ENOSPC') {
|
|
285
285
|
throw new Error(`Insufficient disk space to write file: ${filePath}`);
|
|
@@ -287,7 +287,7 @@ const safeWriteFile = async (filePath, content, encoding = 'utf-8')=>{
|
|
|
287
287
|
throw error;
|
|
288
288
|
}
|
|
289
289
|
// Write the actual file
|
|
290
|
-
await
|
|
290
|
+
await fs.writeFile(filePath, content, encoding);
|
|
291
291
|
logger.debug(`Successfully wrote file: ${filePath} (${content.length} characters)`);
|
|
292
292
|
} catch (error) {
|
|
293
293
|
logger.error(`Failed to write file ${filePath}: ${error.message}`);
|
|
@@ -296,7 +296,7 @@ const safeWriteFile = async (filePath, content, encoding = 'utf-8')=>{
|
|
|
296
296
|
};
|
|
297
297
|
// Helper function to process a single review note
|
|
298
298
|
const processSingleReview = async (reviewNote, runConfig, outputDirectory)=>{
|
|
299
|
-
var _runConfig_review, _runConfig_review1, _runConfig_review2, _runConfig_review3, _runConfig_review_context, _runConfig_review4, _runConfig_review5, _analysisResult_issues;
|
|
299
|
+
var _runConfig_review, _runConfig_review1, _runConfig_review2, _runConfig_review3, _runConfig_review_context, _runConfig_review4, _runConfig_review5, _aiConfig_commands_review, _aiConfig_commands, _analysisResult_issues;
|
|
300
300
|
const logger = getLogger();
|
|
301
301
|
// Gather additional context based on configuration with improved error handling
|
|
302
302
|
let logContext = '';
|
|
@@ -346,7 +346,7 @@ const processSingleReview = async (reviewNote, runConfig, outputDirectory)=>{
|
|
|
346
346
|
if ((_runConfig_review2 = runConfig.review) === null || _runConfig_review2 === void 0 ? void 0 : _runConfig_review2.includeReleaseNotes) {
|
|
347
347
|
try {
|
|
348
348
|
logger.debug('Fetching recent release notes from GitHub...');
|
|
349
|
-
const releaseNotesContent = await
|
|
349
|
+
const releaseNotesContent = await getReleaseNotesContent({
|
|
350
350
|
limit: runConfig.review.releaseNotesLimit || 3
|
|
351
351
|
});
|
|
352
352
|
if (releaseNotesContent.trim()) {
|
|
@@ -363,7 +363,7 @@ const processSingleReview = async (reviewNote, runConfig, outputDirectory)=>{
|
|
|
363
363
|
if ((_runConfig_review3 = runConfig.review) === null || _runConfig_review3 === void 0 ? void 0 : _runConfig_review3.includeGithubIssues) {
|
|
364
364
|
try {
|
|
365
365
|
logger.debug('Fetching open GitHub issues...');
|
|
366
|
-
issuesContext = await
|
|
366
|
+
issuesContext = await getIssuesContent({
|
|
367
367
|
limit: runConfig.review.githubIssuesLimit || 20
|
|
368
368
|
});
|
|
369
369
|
if (issuesContext.trim()) {
|
|
@@ -399,6 +399,10 @@ const processSingleReview = async (reviewNote, runConfig, outputDirectory)=>{
|
|
|
399
399
|
overridePaths: runConfig.discoveredConfigDirs || [],
|
|
400
400
|
overrides: runConfig.overrides || false
|
|
401
401
|
};
|
|
402
|
+
// Create adapters for ai-service
|
|
403
|
+
const aiConfig = toAIConfig(runConfig);
|
|
404
|
+
const aiStorageAdapter = createStorageAdapter();
|
|
405
|
+
const aiLogger = createLoggerAdapter(runConfig.dryRun || false);
|
|
402
406
|
const promptContent = {
|
|
403
407
|
notes: reviewNote
|
|
404
408
|
};
|
|
@@ -409,23 +413,25 @@ const processSingleReview = async (reviewNote, runConfig, outputDirectory)=>{
|
|
|
409
413
|
releaseNotesContext,
|
|
410
414
|
issuesContext
|
|
411
415
|
};
|
|
412
|
-
const prompt = await
|
|
413
|
-
const modelToUse =
|
|
416
|
+
const prompt = await createReviewPrompt(promptConfig, promptContent, promptContext);
|
|
417
|
+
const modelToUse = ((_aiConfig_commands = aiConfig.commands) === null || _aiConfig_commands === void 0 ? void 0 : (_aiConfig_commands_review = _aiConfig_commands.review) === null || _aiConfig_commands_review === void 0 ? void 0 : _aiConfig_commands_review.model) || aiConfig.model || 'gpt-4o-mini';
|
|
414
418
|
const request = Formatter.create({
|
|
415
419
|
logger
|
|
416
420
|
}).formatPrompt(modelToUse, prompt);
|
|
417
421
|
let analysisResult;
|
|
418
422
|
try {
|
|
423
|
+
var _aiConfig_commands_review1, _aiConfig_commands1;
|
|
419
424
|
const rawResult = await createCompletion(request.messages, {
|
|
420
425
|
model: modelToUse,
|
|
421
|
-
openaiReasoning:
|
|
422
|
-
openaiMaxOutputTokens: getOpenAIMaxOutputTokensForCommand(runConfig, 'review'),
|
|
426
|
+
openaiReasoning: ((_aiConfig_commands1 = aiConfig.commands) === null || _aiConfig_commands1 === void 0 ? void 0 : (_aiConfig_commands_review1 = _aiConfig_commands1.review) === null || _aiConfig_commands_review1 === void 0 ? void 0 : _aiConfig_commands_review1.reasoning) || aiConfig.reasoning,
|
|
423
427
|
responseFormat: {
|
|
424
428
|
type: 'json_object'
|
|
425
429
|
},
|
|
426
430
|
debug: runConfig.debug,
|
|
427
431
|
debugRequestFile: getOutputPath(outputDirectory, getTimestampedRequestFilename('review-analysis')),
|
|
428
|
-
debugResponseFile: getOutputPath(outputDirectory, getTimestampedResponseFilename('review-analysis'))
|
|
432
|
+
debugResponseFile: getOutputPath(outputDirectory, getTimestampedResponseFilename('review-analysis')),
|
|
433
|
+
storage: aiStorageAdapter,
|
|
434
|
+
logger: aiLogger
|
|
429
435
|
});
|
|
430
436
|
// Validate the API response before using it
|
|
431
437
|
analysisResult = validateReviewResult(rawResult);
|
|
@@ -567,7 +573,7 @@ const executeInternal = async (runConfig)=>{
|
|
|
567
573
|
const editorTimeout = (_runConfig_review25 = runConfig.review) === null || _runConfig_review25 === void 0 ? void 0 : _runConfig_review25.editorTimeout; // No default timeout - let user take their time
|
|
568
574
|
await openEditorWithTimeout(editor, tmpFilePath, editorTimeout);
|
|
569
575
|
// Read the file back in, stripping comment lines and whitespace.
|
|
570
|
-
const fileContent = (await
|
|
576
|
+
const fileContent = (await fs.readFile(tmpFilePath, 'utf8')).split('\n').filter((line)=>!line.trim().startsWith('#')).join('\n').trim();
|
|
571
577
|
if (!fileContent) {
|
|
572
578
|
throw new ValidationError('Review note is empty – aborting. Provide a note as an argument, via STDIN, or through the editor.');
|
|
573
579
|
}
|