@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.
Files changed (77) hide show
  1. package/WORKFLOW-PRECHECK-IMPLEMENTATION.md +239 -0
  2. package/WORKFLOW-SKIP-SUMMARY.md +121 -0
  3. package/dist/application.js +6 -2
  4. package/dist/application.js.map +1 -1
  5. package/dist/arguments.js +2 -2
  6. package/dist/arguments.js.map +1 -1
  7. package/dist/commands/audio-commit.js +15 -6
  8. package/dist/commands/audio-commit.js.map +1 -1
  9. package/dist/commands/audio-review.js +31 -15
  10. package/dist/commands/audio-review.js.map +1 -1
  11. package/dist/commands/commit.js +31 -20
  12. package/dist/commands/commit.js.map +1 -1
  13. package/dist/commands/link.js +27 -27
  14. package/dist/commands/link.js.map +1 -1
  15. package/dist/commands/publish.js +87 -34
  16. package/dist/commands/publish.js.map +1 -1
  17. package/dist/commands/release.js +32 -19
  18. package/dist/commands/release.js.map +1 -1
  19. package/dist/commands/review.js +36 -30
  20. package/dist/commands/review.js.map +1 -1
  21. package/dist/commands/select-audio.js +4 -4
  22. package/dist/commands/select-audio.js.map +1 -1
  23. package/dist/commands/tree.js +154 -38
  24. package/dist/commands/tree.js.map +1 -1
  25. package/dist/commands/unlink.js +13 -13
  26. package/dist/commands/unlink.js.map +1 -1
  27. package/dist/commands/updates.js +21 -0
  28. package/dist/commands/updates.js.map +1 -1
  29. package/dist/commands/versions.js +5 -5
  30. package/dist/commands/versions.js.map +1 -1
  31. package/dist/constants.js +4 -4
  32. package/dist/constants.js.map +1 -1
  33. package/dist/content/files.js +4 -4
  34. package/dist/content/files.js.map +1 -1
  35. package/dist/error/CommandErrors.js +1 -65
  36. package/dist/error/CommandErrors.js.map +1 -1
  37. package/dist/logging.js +3 -3
  38. package/dist/logging.js.map +1 -1
  39. package/dist/util/aiAdapter.js +28 -0
  40. package/dist/util/aiAdapter.js.map +1 -0
  41. package/dist/util/general.js +5 -5
  42. package/dist/util/general.js.map +1 -1
  43. package/dist/util/interactive.js +6 -437
  44. package/dist/util/interactive.js.map +1 -1
  45. package/dist/util/loggerAdapter.js +24 -0
  46. package/dist/util/loggerAdapter.js.map +1 -0
  47. package/dist/util/performance.js +4 -4
  48. package/dist/util/performance.js.map +1 -1
  49. package/dist/util/safety.js +4 -4
  50. package/dist/util/safety.js.map +1 -1
  51. package/dist/util/storage.js +2 -2
  52. package/dist/util/storage.js.map +1 -1
  53. package/dist/util/storageAdapter.js +25 -0
  54. package/dist/util/storageAdapter.js.map +1 -0
  55. package/package.json +6 -4
  56. package/test_output.txt +3 -3
  57. package/INTEGRATION-SUMMARY.md +0 -232
  58. package/TEST-STATUS.md +0 -168
  59. package/dist/content/issues.js +0 -331
  60. package/dist/content/issues.js.map +0 -1
  61. package/dist/content/releaseNotes.js +0 -90
  62. package/dist/content/releaseNotes.js.map +0 -1
  63. package/dist/prompt/commit.js +0 -76
  64. package/dist/prompt/commit.js.map +0 -1
  65. package/dist/prompt/instructions/commit.md +0 -133
  66. package/dist/prompt/instructions/release.md +0 -188
  67. package/dist/prompt/instructions/review.md +0 -169
  68. package/dist/prompt/personas/releaser.md +0 -24
  69. package/dist/prompt/personas/you.md +0 -55
  70. package/dist/prompt/release.js +0 -100
  71. package/dist/prompt/release.js.map +0 -1
  72. package/dist/prompt/review.js +0 -64
  73. package/dist/prompt/review.js.map +0 -1
  74. package/dist/util/github.js +0 -1071
  75. package/dist/util/github.js.map +0 -1
  76. package/dist/util/openai.js +0 -365
  77. package/dist/util/openai.js.map +0 -1
@@ -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 { getModelForCommand, createCompletion, getOpenAIMaxOutputTokensForCommand, getOpenAIReasoningForCommand } from '../util/openai.js';
6
- import { createPrompt } from '../prompt/review.js';
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 { get } from '../content/releaseNotes.js';
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 { getUserChoice } from '../util/interactive.js';
15
- import path__default from 'path';
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 fs__default from 'fs/promises';
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 fs__default.readFile(filePath, 'utf8');
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 fs__default.readdir(directoryPath, {
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)=>path__default.join(directoryPath, entry.name)).sort(); // Sort alphabetically
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 = os__default.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 fs__default.access(tmpDir, W_OK);
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 = path__default.join(tmpDir, `kodrdriv_review_${Date.now()}_${Math.random().toString(36).substring(7)}.md`);
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 fs__default.open(tmpFilePath, 'w', 0o600);
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 fs__default.unlink(filePath);
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 = path__default.dirname(filePath);
275
+ const parentDir = path.dirname(filePath);
276
276
  const W_OK = 2; // fs.constants.W_OK value
277
- await fs__default.access(parentDir, W_OK);
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 fs__default.writeFile(testFile, 'test', encoding);
282
- await fs__default.unlink(testFile);
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 fs__default.writeFile(filePath, content, encoding);
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 get({
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 get$1({
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 createPrompt(promptConfig, promptContent, promptContext);
413
- const modelToUse = getModelForCommand(runConfig, 'review');
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: getOpenAIReasoningForCommand(runConfig, 'review'),
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 fs__default.readFile(tmpFilePath, 'utf8')).split('\n').filter((line)=>!line.trim().startsWith('#')).join('\n').trim();
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
  }