@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
@@ -1,18 +1,18 @@
1
- import path__default from 'path';
1
+ import path from 'path';
2
2
  import { execute as execute$1 } from './commit.js';
3
3
  import { hasStagedChanges } from '../content/diff.js';
4
4
  import { execute as execute$2 } from './release.js';
5
5
  import { getDryRunLogger, getLogger } from '../logging.js';
6
6
  import { run, localBranchExists, runSecure, runWithDryRunSupport, safeJsonParse, validatePackageJson, validateGitRef, safeSyncBranchWithRemote, isBranchInSyncWithRemote } from '@eldrforge/git-tools';
7
- import { getCurrentBranchName, findOpenPullRequestByHeadRef, createPullRequest, waitForPullRequestChecks, mergePullRequest, createRelease, closeMilestoneForVersion, getWorkflowsTriggeredByRelease, waitForReleaseWorkflows } from '../util/github.js';
7
+ import * as GitHub from '@eldrforge/github-tools';
8
8
  import { create } from '../util/storage.js';
9
9
  import { calculateBranchDependentVersion, calculateTargetVersion, checkIfTagExists, confirmVersionInteractively, getOutputPath } from '../util/general.js';
10
10
  import { DEFAULT_OUTPUT_DIRECTORY, KODRDRIV_DEFAULTS } from '../constants.js';
11
- import fs__default from 'fs/promises';
11
+ import fs from 'fs/promises';
12
12
 
13
13
  const scanNpmrcForEnvVars = async (storage)=>{
14
14
  const logger = getLogger();
15
- const npmrcPath = path__default.join(process.cwd(), '.npmrc');
15
+ const npmrcPath = path.join(process.cwd(), '.npmrc');
16
16
  const envVars = [];
17
17
  if (await storage.exists(npmrcPath)) {
18
18
  try {
@@ -42,18 +42,18 @@ const scanNpmrcForEnvVars = async (storage)=>{
42
42
  * and cleans them up if found by removing package-lock.json and regenerating it.
43
43
  */ const cleanupNpmLinkReferences = async (isDryRun)=>{
44
44
  const logger = getDryRunLogger(isDryRun);
45
- const packageLockPath = path__default.join(process.cwd(), 'package-lock.json');
45
+ const packageLockPath = path.join(process.cwd(), 'package-lock.json');
46
46
  try {
47
47
  // Check if package-lock.json exists
48
48
  try {
49
- await fs__default.access(packageLockPath);
49
+ await fs.access(packageLockPath);
50
50
  } catch {
51
51
  // No package-lock.json, nothing to clean
52
52
  logger.verbose('No package-lock.json found, skipping npm link cleanup');
53
53
  return;
54
54
  }
55
55
  // Read and parse package-lock.json
56
- const packageLockContent = await fs__default.readFile(packageLockPath, 'utf-8');
56
+ const packageLockContent = await fs.readFile(packageLockPath, 'utf-8');
57
57
  const packageLock = safeJsonParse(packageLockContent, packageLockPath);
58
58
  // Check for file: dependencies in the lockfile
59
59
  let hasFileReferences = false;
@@ -91,7 +91,7 @@ const scanNpmrcForEnvVars = async (storage)=>{
91
91
  logger.info('DRY RUN: Would remove package-lock.json and regenerate it');
92
92
  } else {
93
93
  // Remove package-lock.json
94
- await fs__default.unlink(packageLockPath);
94
+ await fs.unlink(packageLockPath);
95
95
  logger.verbose('Removed package-lock.json with npm link references');
96
96
  // Regenerate clean package-lock.json
97
97
  logger.verbose('Regenerating package-lock.json from package.json...');
@@ -171,7 +171,7 @@ const runPrechecks = async (runConfig, targetBranch)=>{
171
171
  if (isDryRun) {
172
172
  logger.info(`Would verify current branch is not the target branch (${effectiveTargetBranch})`);
173
173
  } else {
174
- const currentBranch = await getCurrentBranchName();
174
+ const currentBranch = await GitHub.getCurrentBranchName();
175
175
  if (currentBranch === effectiveTargetBranch) {
176
176
  throw new Error(`Cannot run publish from the target branch '${effectiveTargetBranch}'. Please switch to a different branch before running publish.`);
177
177
  }
@@ -210,9 +210,35 @@ const runPrechecks = async (runConfig, targetBranch)=>{
210
210
  logger.info(`ℹ️ Target branch '${effectiveTargetBranch}' does not exist locally - will be created when needed.`);
211
211
  }
212
212
  }
213
+ // Check GitHub Actions workflow configuration
214
+ logger.info('Checking GitHub Actions workflow configuration...');
215
+ if (isDryRun) {
216
+ logger.info('Would check if GitHub Actions workflows are configured for pull requests');
217
+ } else {
218
+ try {
219
+ // TODO: Re-enable when checkWorkflowConfiguration is exported from github-tools
220
+ // const workflowConfig = await GitHub.checkWorkflowConfiguration(effectiveTargetBranch);
221
+ const workflowConfig = {
222
+ hasWorkflows: true,
223
+ hasPullRequestTriggers: true,
224
+ workflowCount: 0,
225
+ triggeredWorkflowNames: []
226
+ };
227
+ if (!workflowConfig.hasWorkflows) ; else if (!workflowConfig.hasPullRequestTriggers) ; else {
228
+ logger.info(`✅ Found ${workflowConfig.triggeredWorkflowNames.length} workflow(s) that will run on PRs to ${effectiveTargetBranch}:`);
229
+ for (const workflowName of workflowConfig.triggeredWorkflowNames){
230
+ logger.info(` - ${workflowName}`);
231
+ }
232
+ }
233
+ } catch (error) {
234
+ // Don't fail the precheck if we can't verify workflows
235
+ // The wait logic will handle it later
236
+ logger.debug(`Could not verify workflow configuration: ${error.message}`);
237
+ }
238
+ }
213
239
  // Check if prepublishOnly script exists in package.json
214
240
  logger.info('Checking for prepublishOnly script...');
215
- const packageJsonPath = path__default.join(process.cwd(), 'package.json');
241
+ const packageJsonPath = path.join(process.cwd(), 'package.json');
216
242
  if (!await storage.exists(packageJsonPath)) {
217
243
  if (!isDryRun) {
218
244
  throw new Error('package.json not found in current directory.');
@@ -277,7 +303,7 @@ const sortObjectKeys = (value)=>{
277
303
  const isReleaseNecessaryComparedToTarget = async (targetBranch, isDryRun)=>{
278
304
  const logger = getDryRunLogger(isDryRun);
279
305
  // We compare current HEAD branch to the provided target branch
280
- const currentBranch = await getCurrentBranchName();
306
+ const currentBranch = await GitHub.getCurrentBranchName();
281
307
  // Check if target branch exists before trying to compare
282
308
  try {
283
309
  // Validate target branch exists and is accessible
@@ -393,7 +419,7 @@ const execute = async (runConfig)=>{
393
419
  if (isDryRun) {
394
420
  currentBranch = 'mock-branch';
395
421
  } else {
396
- currentBranch = await getCurrentBranchName();
422
+ currentBranch = await GitHub.getCurrentBranchName();
397
423
  // Fetch latest remote information to avoid conflicts
398
424
  logger.info('📡 Fetching latest remote information to avoid conflicts...');
399
425
  try {
@@ -509,8 +535,8 @@ const execute = async (runConfig)=>{
509
535
  logger.info('Would check for existing pull request');
510
536
  logger.info('Assuming no existing PR found for demo purposes');
511
537
  } else {
512
- const branchName = await getCurrentBranchName();
513
- pr = await findOpenPullRequestByHeadRef(branchName);
538
+ const branchName = await GitHub.getCurrentBranchName();
539
+ pr = await GitHub.findOpenPullRequestByHeadRef(branchName);
514
540
  }
515
541
  if (pr) {
516
542
  logger.info(`Found existing pull request for branch: ${pr.html_url}`);
@@ -536,7 +562,10 @@ const execute = async (runConfig)=>{
536
562
  await runWithDryRunSupport('npm run prepublishOnly', isDryRun, {}, true); // Use inherited stdio
537
563
  // STEP 2: Commit dependency updates if any (still no version bump)
538
564
  logger.verbose('Staging dependency updates for commit');
539
- await runWithDryRunSupport('git add package.json package-lock.json', isDryRun);
565
+ // Check if package-lock.json exists before trying to stage it
566
+ const packageLockExists = await storage.exists('package-lock.json');
567
+ const filesToStage = packageLockExists ? 'package.json package-lock.json' : 'package.json';
568
+ await runWithDryRunSupport(`git add ${filesToStage}`, isDryRun);
540
569
  logger.verbose('Checking for staged dependency updates...');
541
570
  if (isDryRun) {
542
571
  logger.verbose('Would create dependency update commit if changes are staged');
@@ -637,7 +666,10 @@ const execute = async (runConfig)=>{
637
666
  const { stdout: mergeChangesStatus } = await run('git status --porcelain');
638
667
  if (mergeChangesStatus.trim()) {
639
668
  logger.verbose('Staging post-merge changes for commit');
640
- await run('git add package.json package-lock.json');
669
+ // Check if package-lock.json exists before trying to stage it
670
+ const packageLockExistsPostMerge = await storage.exists('package-lock.json');
671
+ const filesToStagePostMerge = packageLockExistsPostMerge ? 'package.json package-lock.json' : 'package.json';
672
+ await run(`git add ${filesToStagePostMerge}`);
641
673
  if (await hasStagedChanges()) {
642
674
  logger.verbose('Committing post-merge changes...');
643
675
  await execute$1(runConfig);
@@ -704,7 +736,10 @@ const execute = async (runConfig)=>{
704
736
  }
705
737
  // STEP 5: Commit version bump as a separate commit
706
738
  logger.verbose('Staging version bump for commit');
707
- await runWithDryRunSupport('git add package.json package-lock.json', isDryRun);
739
+ // Check if package-lock.json exists before trying to stage it
740
+ const packageLockExistsVersionBump = await storage.exists('package-lock.json');
741
+ const filesToStageVersionBump = packageLockExistsVersionBump ? 'package.json package-lock.json' : 'package.json';
742
+ await runWithDryRunSupport(`git add ${filesToStageVersionBump}`, isDryRun);
708
743
  if (isDryRun) {
709
744
  logger.verbose('Would create version bump commit');
710
745
  } else {
@@ -758,7 +793,7 @@ const execute = async (runConfig)=>{
758
793
  }
759
794
  logger.info('Pushing to origin...');
760
795
  // Get current branch name and push explicitly to avoid pushing to wrong remote/branch
761
- const branchName = await getCurrentBranchName();
796
+ const branchName = await GitHub.getCurrentBranchName();
762
797
  await runWithDryRunSupport(`git push origin ${branchName}`, isDryRun);
763
798
  logger.info('Creating pull request...');
764
799
  if (isDryRun) {
@@ -770,7 +805,7 @@ const execute = async (runConfig)=>{
770
805
  };
771
806
  } else {
772
807
  const { stdout: commitTitle } = await run('git log -1 --pretty=%B');
773
- pr = await createPullRequest(commitTitle, 'Automated release PR.', branchName, targetBranch);
808
+ pr = await GitHub.createPullRequest(commitTitle, 'Automated release PR.', branchName, targetBranch);
774
809
  if (!pr) {
775
810
  throw new Error('Failed to create pull request.');
776
811
  }
@@ -779,23 +814,41 @@ const execute = async (runConfig)=>{
779
814
  }
780
815
  logger.info(`Waiting for PR #${pr.number} checks to complete...`);
781
816
  if (!isDryRun) {
782
- var _runConfig_publish15, _runConfig_publish16, _runConfig_publish17;
783
- // Configure timeout and user confirmation behavior
784
- const timeout = ((_runConfig_publish15 = runConfig.publish) === null || _runConfig_publish15 === void 0 ? void 0 : _runConfig_publish15.checksTimeout) || KODRDRIV_DEFAULTS.publish.checksTimeout;
785
- const senditMode = ((_runConfig_publish16 = runConfig.publish) === null || _runConfig_publish16 === void 0 ? void 0 : _runConfig_publish16.sendit) || false;
786
- // sendit flag overrides skipUserConfirmation - if sendit is true, skip confirmation
787
- const skipUserConfirmation = senditMode || ((_runConfig_publish17 = runConfig.publish) === null || _runConfig_publish17 === void 0 ? void 0 : _runConfig_publish17.skipUserConfirmation) || false;
788
- await waitForPullRequestChecks(pr.number, {
789
- timeout,
790
- skipUserConfirmation
791
- });
817
+ // Check if we already know from prechecks that no workflows will trigger
818
+ let shouldSkipWait = false;
819
+ try {
820
+ // TODO: Re-enable when checkWorkflowConfiguration is exported from github-tools
821
+ // const workflowConfig = await GitHub.checkWorkflowConfiguration(targetBranch);
822
+ const workflowConfig = {
823
+ hasWorkflows: true,
824
+ hasPullRequestTriggers: true,
825
+ workflowCount: 0,
826
+ triggeredWorkflowNames: []
827
+ };
828
+ if (!workflowConfig.hasWorkflows || !workflowConfig.hasPullRequestTriggers) ;
829
+ } catch (error) {
830
+ // If we can't verify, proceed with waiting to be safe
831
+ logger.debug(`Could not verify workflow configuration for wait skip: ${error.message}`);
832
+ }
833
+ if (!shouldSkipWait) {
834
+ var _runConfig_publish15, _runConfig_publish16, _runConfig_publish17;
835
+ // Configure timeout and user confirmation behavior
836
+ const timeout = ((_runConfig_publish15 = runConfig.publish) === null || _runConfig_publish15 === void 0 ? void 0 : _runConfig_publish15.checksTimeout) || KODRDRIV_DEFAULTS.publish.checksTimeout;
837
+ const senditMode = ((_runConfig_publish16 = runConfig.publish) === null || _runConfig_publish16 === void 0 ? void 0 : _runConfig_publish16.sendit) || false;
838
+ // sendit flag overrides skipUserConfirmation - if sendit is true, skip confirmation
839
+ const skipUserConfirmation = senditMode || ((_runConfig_publish17 = runConfig.publish) === null || _runConfig_publish17 === void 0 ? void 0 : _runConfig_publish17.skipUserConfirmation) || false;
840
+ await GitHub.waitForPullRequestChecks(pr.number, {
841
+ timeout,
842
+ skipUserConfirmation
843
+ });
844
+ }
792
845
  }
793
846
  const mergeMethod = ((_runConfig_publish2 = runConfig.publish) === null || _runConfig_publish2 === void 0 ? void 0 : _runConfig_publish2.mergeMethod) || 'squash';
794
847
  if (isDryRun) {
795
848
  logger.info(`Would merge PR #${pr.number} using ${mergeMethod} method`);
796
849
  } else {
797
850
  try {
798
- await mergePullRequest(pr.number, mergeMethod, false); // Don't delete branch
851
+ await GitHub.mergePullRequest(pr.number, mergeMethod, false); // Don't delete branch
799
852
  } catch (error) {
800
853
  // Check if this is a merge conflict error
801
854
  if (error.message && (error.message.includes('not mergeable') || error.message.includes('Pull Request is not mergeable') || error.message.includes('merge conflict'))) {
@@ -1004,14 +1057,14 @@ const execute = async (runConfig)=>{
1004
1057
  while(retries > 0){
1005
1058
  try {
1006
1059
  var _runConfig_publish19;
1007
- await createRelease(tagName, releaseTitle, releaseNotesContent);
1060
+ await GitHub.createRelease(tagName, releaseTitle, releaseNotesContent);
1008
1061
  logger.info(`GitHub release created successfully for tag: ${tagName}`);
1009
1062
  // Close milestone for this version if enabled
1010
1063
  const milestonesEnabled = !((_runConfig_publish19 = runConfig.publish) === null || _runConfig_publish19 === void 0 ? void 0 : _runConfig_publish19.noMilestones);
1011
1064
  if (milestonesEnabled) {
1012
1065
  logger.info('🏁 Closing milestone for released version...');
1013
1066
  const version = tagName.replace(/^v/, ''); // Remove 'v' prefix if present
1014
- await closeMilestoneForVersion(version);
1067
+ await GitHub.closeMilestoneForVersion(version);
1015
1068
  } else {
1016
1069
  logger.debug('Milestone integration disabled via --no-milestones');
1017
1070
  }
@@ -1049,7 +1102,7 @@ const execute = async (runConfig)=>{
1049
1102
  if (!workflowNames || workflowNames.length === 0) {
1050
1103
  logger.info('No specific workflow names configured, auto-detecting workflows triggered by release events...');
1051
1104
  try {
1052
- workflowNames = await getWorkflowsTriggeredByRelease();
1105
+ workflowNames = await GitHub.getWorkflowsTriggeredByRelease();
1053
1106
  if (workflowNames.length === 0) {
1054
1107
  logger.info('No workflows found that are triggered by release events.');
1055
1108
  } else {
@@ -1060,7 +1113,7 @@ const execute = async (runConfig)=>{
1060
1113
  workflowNames = undefined; // Fall back to monitoring all workflows
1061
1114
  }
1062
1115
  }
1063
- await waitForReleaseWorkflows(tagName, {
1116
+ await GitHub.waitForReleaseWorkflows(tagName, {
1064
1117
  timeout: workflowTimeout,
1065
1118
  workflowNames,
1066
1119
  skipUserConfirmation