@eldrforge/kodrdriv 1.2.6 → 1.2.7

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.
@@ -2,6 +2,7 @@
2
2
  import path__default from 'path';
3
3
  import fs__default from 'fs/promises';
4
4
  import { exec } from 'child_process';
5
+ import { runSecure } from '../util/child.js';
5
6
  import util from 'util';
6
7
  import { getLogger } from '../logging.js';
7
8
  import { create } from '../util/storage.js';
@@ -654,16 +655,44 @@ const executePackage = async (packageName, packageInfo, commandToRun, runConfig,
654
655
  if (hasUpdates) {
655
656
  // Commit the dependency updates using kodrdriv commit
656
657
  packageLogger.info('Committing inter-project dependency updates...');
658
+ packageLogger.info('⏱️ This step may take a few minutes as it generates a commit message using AI...');
659
+ // Add timeout wrapper around commit execution
660
+ const commitTimeoutMs = 300000; // 5 minutes
661
+ const commitPromise = execute$3({
662
+ ...runConfig,
663
+ dryRun: false
664
+ });
665
+ const timeoutPromise = new Promise((_, reject)=>{
666
+ setTimeout(()=>reject(new Error(`Commit operation timed out after ${commitTimeoutMs / 1000} seconds`)), commitTimeoutMs);
667
+ });
668
+ // Add progress indicator
669
+ let progressInterval = null;
657
670
  try {
658
- await execute$3({
659
- ...runConfig,
660
- dryRun: false
661
- });
662
- packageLogger.info('Inter-project dependency updates committed successfully');
671
+ // Start progress indicator
672
+ progressInterval = setInterval(()=>{
673
+ packageLogger.info('⏳ Still generating commit message... (this can take 1-3 minutes)');
674
+ }, 30000); // Every 30 seconds
675
+ await Promise.race([
676
+ commitPromise,
677
+ timeoutPromise
678
+ ]);
679
+ packageLogger.info('✅ Inter-project dependency updates committed successfully');
663
680
  } catch (commitError) {
664
- packageLogger.warn(`Failed to commit inter-project dependency updates: ${commitError.message}`);
681
+ if (commitError.message.includes('timed out')) {
682
+ packageLogger.error(`❌ Commit operation timed out after ${commitTimeoutMs / 1000} seconds`);
683
+ packageLogger.error('This usually indicates an issue with the AI service or very large changes');
684
+ packageLogger.error('You may need to manually commit the dependency updates');
685
+ } else {
686
+ packageLogger.warn(`Failed to commit inter-project dependency updates: ${commitError.message}`);
687
+ }
665
688
  // Continue with publish anyway - the updates are still in place
689
+ } finally{
690
+ if (progressInterval) {
691
+ clearInterval(progressInterval);
692
+ }
666
693
  }
694
+ } else {
695
+ packageLogger.info('No inter-project dependency updates needed');
667
696
  }
668
697
  }
669
698
  if (runConfig.debug || runConfig.verbose) {
@@ -682,14 +711,39 @@ const executePackage = async (packageName, packageInfo, commandToRun, runConfig,
682
711
  if (runConfig.debug) {
683
712
  packageLogger.debug(`Shelling out to separate kodrdriv process for ${builtInCommandName} command`);
684
713
  }
714
+ // Add progress indication for publish commands
715
+ if (builtInCommandName === 'publish') {
716
+ packageLogger.info('🚀 Starting publish process...');
717
+ packageLogger.info('⏱️ This may take several minutes (AI processing, PR creation, etc.)');
718
+ }
685
719
  // Ensure dry-run propagates to subprocess even during overall dry-run mode
686
720
  const effectiveCommand = runConfig.dryRun && !commandToRun.includes('--dry-run') ? `${commandToRun} --dry-run` : commandToRun;
687
- // Use runWithLogging for built-in commands to capture all output
688
- const { stdout } = await runWithLogging(effectiveCommand, packageLogger, {}, showOutput);
689
- // Detect explicit skip marker from publish to avoid propagating versions
690
- if (builtInCommandName === 'publish' && stdout && stdout.includes('KODRDRIV_PUBLISH_SKIPPED')) {
691
- packageLogger.info('Publish skipped for this package; will not record or propagate a version.');
692
- publishWasSkipped = true;
721
+ // Add timeout wrapper for publish commands
722
+ const commandTimeoutMs = 1800000; // 30 minutes for publish commands
723
+ if (builtInCommandName === 'publish') {
724
+ packageLogger.info(`⏰ Setting timeout of ${commandTimeoutMs / 60000} minutes for publish command`);
725
+ }
726
+ const commandPromise = runWithLogging(effectiveCommand, packageLogger, {}, showOutput);
727
+ const commandTimeoutPromise = new Promise((_, reject)=>{
728
+ setTimeout(()=>reject(new Error(`Command timed out after ${commandTimeoutMs / 60000} minutes`)), commandTimeoutMs);
729
+ });
730
+ try {
731
+ const { stdout } = await Promise.race([
732
+ commandPromise,
733
+ commandTimeoutPromise
734
+ ]);
735
+ // Detect explicit skip marker from publish to avoid propagating versions
736
+ if (builtInCommandName === 'publish' && stdout && stdout.includes('KODRDRIV_PUBLISH_SKIPPED')) {
737
+ packageLogger.info('Publish skipped for this package; will not record or propagate a version.');
738
+ publishWasSkipped = true;
739
+ }
740
+ } catch (error) {
741
+ if (error.message.includes('timed out')) {
742
+ packageLogger.error(`❌ ${builtInCommandName} command timed out after ${commandTimeoutMs / 60000} minutes`);
743
+ packageLogger.error('This usually indicates the command is stuck waiting for user input or an external service');
744
+ throw error;
745
+ }
746
+ throw error;
693
747
  }
694
748
  } else {
695
749
  // For custom commands, use the existing logic
@@ -765,12 +819,47 @@ const executePackage = async (packageName, packageInfo, commandToRun, runConfig,
765
819
  };
766
820
  }
767
821
  };
822
+ // Add a simple status check function
823
+ const checkTreePublishStatus = async ()=>{
824
+ const logger = getLogger();
825
+ try {
826
+ // Check for running kodrdriv processes
827
+ const { stdout } = await runSecure('ps', [
828
+ 'aux'
829
+ ], {});
830
+ const kodrdrivProcesses = stdout.split('\n').filter((line)=>line.includes('kodrdriv') && !line.includes('grep') && !line.includes('ps aux') && !line.includes('tree --status') // Exclude the current status command
831
+ );
832
+ if (kodrdrivProcesses.length > 0) {
833
+ logger.info('🔍 Found running kodrdriv processes:');
834
+ kodrdrivProcesses.forEach((process1)=>{
835
+ const parts = process1.trim().split(/\s+/);
836
+ const pid = parts[1];
837
+ const command = parts.slice(10).join(' ');
838
+ logger.info(` PID ${pid}: ${command}`);
839
+ });
840
+ } else {
841
+ logger.info('No kodrdriv processes currently running');
842
+ }
843
+ } catch (error) {
844
+ logger.warn('Could not check process status:', error);
845
+ }
846
+ };
768
847
  const execute = async (runConfig)=>{
769
- var _runConfig_tree, _runConfig_tree1, _runConfig_tree2, _runConfig_tree3, _runConfig_tree4, _runConfig_tree5;
848
+ var _runConfig_tree, _runConfig_tree1, _runConfig_tree2, _runConfig_tree3, _runConfig_tree4, _runConfig_tree5, _runConfig_tree6, _runConfig_tree7;
770
849
  const logger = getLogger();
771
850
  const isDryRun = runConfig.dryRun || false;
772
851
  const isContinue = ((_runConfig_tree = runConfig.tree) === null || _runConfig_tree === void 0 ? void 0 : _runConfig_tree.continue) || false;
773
852
  const promotePackage = (_runConfig_tree1 = runConfig.tree) === null || _runConfig_tree1 === void 0 ? void 0 : _runConfig_tree1.promote;
853
+ // Debug logging
854
+ logger.debug('Tree config:', JSON.stringify(runConfig.tree, null, 2));
855
+ logger.debug('Status flag:', (_runConfig_tree2 = runConfig.tree) === null || _runConfig_tree2 === void 0 ? void 0 : _runConfig_tree2.status);
856
+ logger.debug('Full runConfig:', JSON.stringify(runConfig, null, 2));
857
+ // Handle status check
858
+ if ((_runConfig_tree3 = runConfig.tree) === null || _runConfig_tree3 === void 0 ? void 0 : _runConfig_tree3.status) {
859
+ logger.info('🔍 Checking for running kodrdriv processes...');
860
+ await checkTreePublishStatus();
861
+ return 'Status check completed';
862
+ }
774
863
  // Handle promote mode
775
864
  if (promotePackage) {
776
865
  logger.info(`Promoting package '${promotePackage}' to completed status...`);
@@ -817,7 +906,7 @@ const execute = async (runConfig)=>{
817
906
  executionContext = null;
818
907
  }
819
908
  // Check if we're in built-in command mode (tree command with second argument)
820
- const builtInCommand = (_runConfig_tree2 = runConfig.tree) === null || _runConfig_tree2 === void 0 ? void 0 : _runConfig_tree2.builtInCommand;
909
+ const builtInCommand = (_runConfig_tree4 = runConfig.tree) === null || _runConfig_tree4 === void 0 ? void 0 : _runConfig_tree4.builtInCommand;
821
910
  const supportedBuiltInCommands = [
822
911
  'commit',
823
912
  'publish',
@@ -832,8 +921,8 @@ const execute = async (runConfig)=>{
832
921
  }
833
922
  // Handle run subcommand - convert space-separated scripts to npm run commands
834
923
  if (builtInCommand === 'run') {
835
- var _runConfig_tree6;
836
- const packageArgument = (_runConfig_tree6 = runConfig.tree) === null || _runConfig_tree6 === void 0 ? void 0 : _runConfig_tree6.packageArgument;
924
+ var _runConfig_tree8;
925
+ const packageArgument = (_runConfig_tree8 = runConfig.tree) === null || _runConfig_tree8 === void 0 ? void 0 : _runConfig_tree8.packageArgument;
837
926
  if (!packageArgument) {
838
927
  throw new Error('run subcommand requires script names. Usage: kodrdriv tree run "clean build test"');
839
928
  }
@@ -856,11 +945,11 @@ const execute = async (runConfig)=>{
856
945
  runConfig.__scriptsToValidate = scripts;
857
946
  }
858
947
  // Determine the target directories - either specified or current working directory
859
- const directories = ((_runConfig_tree3 = runConfig.tree) === null || _runConfig_tree3 === void 0 ? void 0 : _runConfig_tree3.directories) || [
948
+ const directories = ((_runConfig_tree5 = runConfig.tree) === null || _runConfig_tree5 === void 0 ? void 0 : _runConfig_tree5.directories) || [
860
949
  process.cwd()
861
950
  ];
862
951
  // Handle link status subcommand
863
- if (builtInCommand === 'link' && ((_runConfig_tree4 = runConfig.tree) === null || _runConfig_tree4 === void 0 ? void 0 : _runConfig_tree4.packageArgument) === 'status') {
952
+ if (builtInCommand === 'link' && ((_runConfig_tree6 = runConfig.tree) === null || _runConfig_tree6 === void 0 ? void 0 : _runConfig_tree6.packageArgument) === 'status') {
864
953
  // For tree link status, we want to show status across all packages
865
954
  logger.info(`${isDryRun ? 'DRY RUN: ' : ''}Running link status across workspace...`);
866
955
  // Create a config that will be passed to the link command
@@ -880,7 +969,7 @@ const execute = async (runConfig)=>{
880
969
  }
881
970
  }
882
971
  // Handle unlink status subcommand
883
- if (builtInCommand === 'unlink' && ((_runConfig_tree5 = runConfig.tree) === null || _runConfig_tree5 === void 0 ? void 0 : _runConfig_tree5.packageArgument) === 'status') {
972
+ if (builtInCommand === 'unlink' && ((_runConfig_tree7 = runConfig.tree) === null || _runConfig_tree7 === void 0 ? void 0 : _runConfig_tree7.packageArgument) === 'status') {
884
973
  // For tree unlink status, we want to show status across all packages
885
974
  logger.info(`${isDryRun ? 'DRY RUN: ' : ''}Running unlink status across workspace...`);
886
975
  // Create a config that will be passed to the unlink command
@@ -905,9 +994,9 @@ const execute = async (runConfig)=>{
905
994
  logger.info(`${isDryRun ? 'DRY RUN: ' : ''}Analyzing workspaces at: ${directories.join(', ')}`);
906
995
  }
907
996
  try {
908
- var _runConfig_tree7, _runConfig_tree8, _runConfig_tree9, _runConfig_tree10;
997
+ var _runConfig_tree9, _runConfig_tree10, _runConfig_tree11, _runConfig_tree12;
909
998
  // Get exclusion patterns from config, fallback to empty array
910
- const excludedPatterns = ((_runConfig_tree7 = runConfig.tree) === null || _runConfig_tree7 === void 0 ? void 0 : _runConfig_tree7.exclude) || [];
999
+ const excludedPatterns = ((_runConfig_tree9 = runConfig.tree) === null || _runConfig_tree9 === void 0 ? void 0 : _runConfig_tree9.exclude) || [];
911
1000
  if (excludedPatterns.length > 0) {
912
1001
  logger.verbose(`${isDryRun ? 'DRY RUN: ' : ''}Using exclusion patterns: ${excludedPatterns.join(', ')}`);
913
1002
  }
@@ -934,7 +1023,7 @@ const execute = async (runConfig)=>{
934
1023
  logger.verbose(`${isDryRun ? 'DRY RUN: ' : ''}Determining build order...`);
935
1024
  let buildOrder = topologicalSort(dependencyGraph);
936
1025
  // Handle start-from functionality if specified
937
- const startFrom = (_runConfig_tree8 = runConfig.tree) === null || _runConfig_tree8 === void 0 ? void 0 : _runConfig_tree8.startFrom;
1026
+ const startFrom = (_runConfig_tree10 = runConfig.tree) === null || _runConfig_tree10 === void 0 ? void 0 : _runConfig_tree10.startFrom;
938
1027
  if (startFrom) {
939
1028
  logger.verbose(`${isDryRun ? 'DRY RUN: ' : ''}Looking for start package: ${startFrom}`);
940
1029
  // Resolve the actual package name (can be package name or directory name)
@@ -991,7 +1080,7 @@ const execute = async (runConfig)=>{
991
1080
  logger.info(`${isDryRun ? 'DRY RUN: ' : ''}Starting execution from package '${startFrom}' (${buildOrder.length} of ${originalLength} packages remaining).`);
992
1081
  }
993
1082
  // Handle stop-at functionality if specified
994
- const stopAt = (_runConfig_tree9 = runConfig.tree) === null || _runConfig_tree9 === void 0 ? void 0 : _runConfig_tree9.stopAt;
1083
+ const stopAt = (_runConfig_tree11 = runConfig.tree) === null || _runConfig_tree11 === void 0 ? void 0 : _runConfig_tree11.stopAt;
995
1084
  if (stopAt) {
996
1085
  logger.verbose(`${isDryRun ? 'DRY RUN: ' : ''}Looking for stop package: ${stopAt}`);
997
1086
  // Find the package that matches the stopAt directory name
@@ -1350,12 +1439,12 @@ const execute = async (runConfig)=>{
1350
1439
  returnOutput = `\nBuild order: ${buildOrder.join(' → ')}\n`;
1351
1440
  }
1352
1441
  // Execute command if provided (custom command or built-in command)
1353
- const cmd = (_runConfig_tree10 = runConfig.tree) === null || _runConfig_tree10 === void 0 ? void 0 : _runConfig_tree10.cmd;
1442
+ const cmd = (_runConfig_tree12 = runConfig.tree) === null || _runConfig_tree12 === void 0 ? void 0 : _runConfig_tree12.cmd;
1354
1443
  // Determine command to execute
1355
1444
  let commandToRun;
1356
1445
  let isBuiltInCommand = false;
1357
1446
  if (builtInCommand) {
1358
- var _runConfig_tree11, _runConfig_tree12, _runConfig_tree13;
1447
+ var _runConfig_tree13, _runConfig_tree14, _runConfig_tree15;
1359
1448
  // Built-in command mode: shell out to kodrdriv subprocess
1360
1449
  // Build command with propagated global options
1361
1450
  const globalOptions = [];
@@ -1372,14 +1461,14 @@ const execute = async (runConfig)=>{
1372
1461
  // Build the command with global options
1373
1462
  const optionsString = globalOptions.length > 0 ? ` ${globalOptions.join(' ')}` : '';
1374
1463
  // Add package argument for link/unlink commands
1375
- const packageArg = (_runConfig_tree11 = runConfig.tree) === null || _runConfig_tree11 === void 0 ? void 0 : _runConfig_tree11.packageArgument;
1464
+ const packageArg = (_runConfig_tree13 = runConfig.tree) === null || _runConfig_tree13 === void 0 ? void 0 : _runConfig_tree13.packageArgument;
1376
1465
  const packageArgString = packageArg && (builtInCommand === 'link' || builtInCommand === 'unlink') ? ` "${packageArg}"` : '';
1377
1466
  // Add command-specific options
1378
1467
  let commandSpecificOptions = '';
1379
- if (builtInCommand === 'unlink' && ((_runConfig_tree12 = runConfig.tree) === null || _runConfig_tree12 === void 0 ? void 0 : _runConfig_tree12.cleanNodeModules)) {
1468
+ if (builtInCommand === 'unlink' && ((_runConfig_tree14 = runConfig.tree) === null || _runConfig_tree14 === void 0 ? void 0 : _runConfig_tree14.cleanNodeModules)) {
1380
1469
  commandSpecificOptions += ' --clean-node-modules';
1381
1470
  }
1382
- if ((builtInCommand === 'link' || builtInCommand === 'unlink') && ((_runConfig_tree13 = runConfig.tree) === null || _runConfig_tree13 === void 0 ? void 0 : _runConfig_tree13.externals) && runConfig.tree.externals.length > 0) {
1471
+ if ((builtInCommand === 'link' || builtInCommand === 'unlink') && ((_runConfig_tree15 = runConfig.tree) === null || _runConfig_tree15 === void 0 ? void 0 : _runConfig_tree15.externals) && runConfig.tree.externals.length > 0) {
1383
1472
  commandSpecificOptions += ` --externals ${runConfig.tree.externals.join(' ')}`;
1384
1473
  }
1385
1474
  commandToRun = `kodrdriv ${builtInCommand}${optionsString}${packageArgString}${commandSpecificOptions}`;