package-versioner 0.7.0 → 0.7.2

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/dist/index.cjs CHANGED
@@ -138,7 +138,23 @@ function extractChangelogEntriesFromCommits(projectDir, revisionRange) {
138
138
  const commits = output.split("---COMMIT_DELIMITER---").filter((commit) => commit.trim() !== "");
139
139
  return commits.map((commit) => parseCommitMessage(commit)).filter((entry) => entry !== null);
140
140
  } catch (error) {
141
- log(`Error extracting commits: ${error}`, "error");
141
+ const errorMessage = error instanceof Error ? error.message : String(error);
142
+ if (errorMessage.includes("ambiguous argument") && errorMessage.includes("unknown revision")) {
143
+ const tagName = revisionRange.split("..")[0] || revisionRange;
144
+ if (tagName.startsWith("v") && !tagName.includes("@")) {
145
+ log(
146
+ `Error: Tag "${tagName}" not found. If you're using package-specific tags (like "package-name@v1.0.0"), you may need to configure "tagTemplate" in your version.config.json to use: \${packageName}@\${prefix}\${version}`,
147
+ "error"
148
+ );
149
+ } else {
150
+ log(
151
+ `Error: Tag or revision "${tagName}" not found in the repository. Please check if this tag exists or if you need to fetch it from the remote.`,
152
+ "error"
153
+ );
154
+ }
155
+ } else {
156
+ log(`Error extracting commits: ${errorMessage}`, "error");
157
+ }
142
158
  return [];
143
159
  }
144
160
  }
@@ -732,6 +748,11 @@ async function gitProcess(options) {
732
748
  }
733
749
  } catch (err) {
734
750
  const errorMessage = err instanceof Error ? err.message : String(err);
751
+ log(`Git process error: ${errorMessage}`, "error");
752
+ if (err instanceof Error && err.stack) {
753
+ console.error("Git process stack trace:");
754
+ console.error(err.stack);
755
+ }
735
756
  throw createGitError("GIT_PROCESS_ERROR" /* GIT_PROCESS_ERROR */, errorMessage);
736
757
  }
737
758
  }
@@ -761,9 +782,16 @@ async function createGitCommitAndTag(files, nextTag, commitMessage, skipHooks, d
761
782
  const errorMessage = error instanceof Error ? error.message : String(error);
762
783
  log(`Failed to create git commit and tag: ${errorMessage}`, "error");
763
784
  if (error instanceof Error) {
785
+ console.error("Git operation error details:");
764
786
  console.error(error.stack || error.message);
787
+ if (errorMessage.includes("Command failed:")) {
788
+ const cmdOutput = errorMessage.split("Command failed:")[1];
789
+ if (cmdOutput) {
790
+ console.error("Git command output:", cmdOutput.trim());
791
+ }
792
+ }
765
793
  } else {
766
- console.error(error);
794
+ console.error("Unknown git error:", error);
767
795
  }
768
796
  throw new GitError(`Git operation failed: ${errorMessage}`, "GIT_ERROR" /* GIT_ERROR */);
769
797
  }
@@ -776,38 +804,42 @@ var import_git_semver_tags = require("git-semver-tags");
776
804
  function escapeRegExp(string) {
777
805
  return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
778
806
  }
779
- function formatTag(version, versionPrefix, packageName, tagTemplate = "${prefix}${version}", packageTagTemplate = "${packageName}@${prefix}${version}") {
780
- const variables = {
781
- version,
782
- prefix: versionPrefix || "",
783
- packageName: packageName || ""
784
- };
785
- const template = packageName ? packageTagTemplate : tagTemplate;
786
- return createTemplateString(template, variables);
787
- }
788
- function formatVersionPrefix(versionPrefix, scope) {
789
- if (!versionPrefix) return "";
790
- const cleanPrefix = versionPrefix.replace(/\/$/, "");
791
- if (scope) {
792
- return `${cleanPrefix}/${scope}`;
793
- }
794
- return cleanPrefix;
795
- }
796
- function formatCommitMessage(template, version, packageName, scope) {
797
- return createTemplateString(template, {
798
- version,
799
- scope,
800
- packageName: packageName || ""
801
- });
807
+ function formatVersionPrefix(prefix) {
808
+ return prefix.endsWith("/") ? prefix.slice(0, -1) : prefix;
802
809
  }
803
- function createTemplateString(template, variables) {
804
- return Object.entries(variables).reduce((result, [key, value]) => {
805
- if (value === void 0) {
806
- return result;
810
+ function formatTag(version, prefix, packageName, template, packageSpecificTags) {
811
+ if ((template == null ? void 0 : template.includes("${packageName}")) && !packageName) {
812
+ log(
813
+ 'Warning: Your tagTemplate contains ${packageName} but no package name is available.\nThis will result in an empty package name in the tag (e.g., "@v1.0.0" instead of "my-package@v1.0.0").\n\nTo fix this:\n\u2022 If using synced mode: Set "packageSpecificTags": true in your config to enable package names in tags\n\u2022 If you want global tags: Remove ${packageName} from your tagTemplate (e.g., use "${prefix}${version}")\n\u2022 If using single/async mode: Ensure your package.json has a valid "name" field',
814
+ "warning"
815
+ );
816
+ }
817
+ if (template) {
818
+ return template.replace(/\$\{version\}/g, version).replace(/\$\{prefix\}/g, prefix).replace(/\$\{packageName\}/g, packageName || "");
819
+ }
820
+ if (packageSpecificTags && packageName) {
821
+ return `${packageName}@${prefix}${version}`;
822
+ }
823
+ return `${prefix}${version}`;
824
+ }
825
+ function formatCommitMessage(template, version, packageName, additionalContext) {
826
+ if (template.includes("${packageName}") && !packageName) {
827
+ log(
828
+ 'Warning: Your commitMessage template contains ${packageName} but no package name is available.\nThis will result in an empty package name in the commit message (e.g., "Release @v1.0.0").\n\nTo fix this:\n\u2022 If using synced mode: Set "packageSpecificTags": true to enable package names in commits\n\u2022 If you want generic commit messages: Remove ${packageName} from your commitMessage template\n\u2022 If using single/async mode: Ensure your package.json has a valid "name" field',
829
+ "warning"
830
+ );
831
+ }
832
+ let result = template.replace(/\$\{version\}/g, version).replace(/\$\{packageName\}/g, packageName || "");
833
+ if (additionalContext) {
834
+ for (const [key, value] of Object.entries(additionalContext)) {
835
+ const placeholder = `\${${key}}`;
836
+ result = result.replace(
837
+ new RegExp(placeholder.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"),
838
+ value
839
+ );
807
840
  }
808
- const regex = new RegExp(`\\$\\{${key}\\}`, "g");
809
- return result.replace(regex, value);
810
- }, template);
841
+ }
842
+ return result;
811
843
  }
812
844
 
813
845
  // src/git/tagsAndBranches.ts
@@ -850,56 +882,71 @@ async function lastMergeBranchName(branches, baseBranch) {
850
882
  return null;
851
883
  }
852
884
  }
853
- async function getLatestTagForPackage(packageName, versionPrefix) {
885
+ async function getLatestTagForPackage(packageName, versionPrefix, options) {
854
886
  try {
887
+ const tagTemplate = (options == null ? void 0 : options.tagTemplate) || "${prefix}${version}";
888
+ const packageSpecificTags = (options == null ? void 0 : options.packageSpecificTags) ?? false;
855
889
  const escapedPackageName = escapeRegExp(packageName);
890
+ const escapedPrefix = versionPrefix ? escapeRegExp(versionPrefix) : "";
856
891
  log(
857
- `Looking for tags for package ${packageName} with prefix ${versionPrefix || "none"}`,
892
+ `Looking for tags for package ${packageName} with prefix ${versionPrefix || "none"}, packageSpecificTags: ${packageSpecificTags}`,
858
893
  "debug"
859
894
  );
860
895
  const allTags = await (0, import_git_semver_tags.getSemverTags)({
861
896
  tagPrefix: versionPrefix
862
897
  });
863
898
  log(`Retrieved ${allTags.length} tags: ${allTags.join(", ")}`, "debug");
864
- let packageTags = [];
865
- if (versionPrefix) {
866
- const pattern1 = new RegExp(`^${escapedPackageName}@${escapeRegExp(versionPrefix)}`);
867
- packageTags = allTags.filter((tag) => pattern1.test(tag));
899
+ if (packageSpecificTags) {
900
+ const packageTagPattern = escapeRegExp(tagTemplate).replace(/\\\$\\\{packageName\\\}/g, `(?:${escapedPackageName})`).replace(/\\\$\\\{prefix\\\}/g, `(?:${escapedPrefix})`).replace(/\\\$\\\{version\\\}/g, "(?:[0-9]+\\.[0-9]+\\.[0-9]+(?:-[a-zA-Z0-9.-]+)?)");
901
+ log(`Using package tag pattern: ${packageTagPattern}`, "debug");
902
+ const packageTagRegex = new RegExp(`^${packageTagPattern}$`);
903
+ let packageTags = allTags.filter((tag) => packageTagRegex.test(tag));
868
904
  if (packageTags.length > 0) {
869
- log(
870
- `Found ${packageTags.length} package tags using pattern: packageName@${versionPrefix}...`,
871
- "debug"
872
- );
905
+ log(`Found ${packageTags.length} package tags using configured pattern`, "debug");
873
906
  log(`Using tag: ${packageTags[0]}`, "debug");
874
907
  return packageTags[0];
875
908
  }
876
- }
877
- if (versionPrefix) {
878
- const pattern2 = new RegExp(`^${escapeRegExp(versionPrefix)}${escapedPackageName}@`);
879
- packageTags = allTags.filter((tag) => pattern2.test(tag));
880
- if (packageTags.length > 0) {
881
- log(
882
- `Found ${packageTags.length} package tags using pattern: ${versionPrefix}packageName@...`,
883
- "debug"
884
- );
885
- log(`Using tag: ${packageTags[0]}`, "debug");
886
- return packageTags[0];
909
+ if (versionPrefix) {
910
+ const pattern1 = new RegExp(`^${escapedPackageName}@${escapeRegExp(versionPrefix)}`);
911
+ packageTags = allTags.filter((tag) => pattern1.test(tag));
912
+ if (packageTags.length > 0) {
913
+ log(
914
+ `Found ${packageTags.length} package tags using pattern: packageName@${versionPrefix}...`,
915
+ "debug"
916
+ );
917
+ log(`Using tag: ${packageTags[0]}`, "debug");
918
+ return packageTags[0];
919
+ }
887
920
  }
888
- }
889
- const pattern3 = new RegExp(`^${escapedPackageName}@`);
890
- packageTags = allTags.filter((tag) => pattern3.test(tag));
891
- log(`Found ${packageTags.length} package tags for ${packageName}`, "debug");
892
- if (packageTags.length === 0) {
893
- log("No matching tags found for pattern: packageName@version", "debug");
894
- if (allTags.length > 0) {
895
- log(`Available tags: ${allTags.join(", ")}`, "debug");
921
+ if (versionPrefix) {
922
+ const pattern2 = new RegExp(`^${escapeRegExp(versionPrefix)}${escapedPackageName}@`);
923
+ packageTags = allTags.filter((tag) => pattern2.test(tag));
924
+ if (packageTags.length > 0) {
925
+ log(
926
+ `Found ${packageTags.length} package tags using pattern: ${versionPrefix}packageName@...`,
927
+ "debug"
928
+ );
929
+ log(`Using tag: ${packageTags[0]}`, "debug");
930
+ return packageTags[0];
931
+ }
932
+ }
933
+ const pattern3 = new RegExp(`^${escapedPackageName}@`);
934
+ packageTags = allTags.filter((tag) => pattern3.test(tag));
935
+ log(`Found ${packageTags.length} package tags for ${packageName}`, "debug");
936
+ if (packageTags.length === 0) {
937
+ log("No matching tags found for pattern: packageName@version", "debug");
938
+ if (allTags.length > 0) {
939
+ log(`Available tags: ${allTags.join(", ")}`, "debug");
940
+ } else {
941
+ log("No tags available in the repository", "debug");
942
+ }
896
943
  } else {
897
- log("No tags available in the repository", "debug");
944
+ log(`Using tag: ${packageTags[0]}`, "debug");
898
945
  }
899
- } else {
900
- log(`Using tag: ${packageTags[0]}`, "debug");
946
+ return packageTags[0] || "";
901
947
  }
902
- return packageTags[0] || "";
948
+ log(`Package-specific tags disabled for ${packageName}, falling back to global tags`, "debug");
949
+ return "";
903
950
  } catch (error) {
904
951
  const errorMessage = error instanceof Error ? error.message : String(error);
905
952
  log(`Failed to get latest tag for package ${packageName}: ${errorMessage}`, "error");
@@ -1434,32 +1481,90 @@ function bumpVersion(currentVersion, bumpType, prereleaseIdentifier) {
1434
1481
  // src/core/versionCalculator.ts
1435
1482
  async function calculateVersion(config, options) {
1436
1483
  const {
1437
- latestTag = "",
1438
- type,
1439
- versionPrefix = "",
1484
+ type: configType,
1485
+ preset = "angular",
1486
+ versionPrefix,
1487
+ prereleaseIdentifier: configPrereleaseIdentifier,
1440
1488
  branchPattern,
1441
- baseBranch,
1442
- prereleaseIdentifier,
1489
+ baseBranch
1490
+ } = config;
1491
+ const {
1492
+ latestTag,
1493
+ name,
1443
1494
  path: pkgPath,
1444
- name
1495
+ type: optionsType,
1496
+ prereleaseIdentifier: optionsPrereleaseIdentifier
1445
1497
  } = options;
1446
- const preset = config.preset || "conventional-commits";
1498
+ const type = optionsType || configType;
1499
+ const prereleaseIdentifier = optionsPrereleaseIdentifier || configPrereleaseIdentifier;
1447
1500
  const initialVersion = "0.1.0";
1501
+ const hasNoTags = !latestTag || latestTag.trim() === "";
1448
1502
  const normalizedPrereleaseId = normalizePrereleaseIdentifier(prereleaseIdentifier, config);
1449
1503
  try {
1450
1504
  let determineTagSearchPattern2 = function(packageName, prefix) {
1451
- if (packageName) {
1452
- const escapedPackageName = escapeRegExp(packageName);
1453
- const escapedPrefix = escapeRegExp(prefix);
1454
- return `${escapedPackageName}[@]?${escapedPrefix}`;
1505
+ if (!packageName) {
1506
+ return prefix;
1455
1507
  }
1456
- return escapeRegExp(prefix);
1508
+ return `${packageName}@${prefix}`;
1509
+ }, escapeRegExp3 = function(string) {
1510
+ return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1457
1511
  };
1458
- var determineTagSearchPattern = determineTagSearchPattern2;
1459
- const hasNoTags = !latestTag;
1460
- const originalPrefix = versionPrefix;
1512
+ var determineTagSearchPattern = determineTagSearchPattern2, escapeRegExp2 = escapeRegExp3;
1513
+ const originalPrefix = versionPrefix || "";
1461
1514
  const tagSearchPattern = determineTagSearchPattern2(name, originalPrefix);
1462
- const escapedTagPattern = escapeRegExp(tagSearchPattern);
1515
+ const escapedTagPattern = escapeRegExp3(tagSearchPattern);
1516
+ if (!hasNoTags && pkgPath) {
1517
+ const packageDir = pkgPath || (0, import_node_process3.cwd)();
1518
+ const manifestResult = getVersionFromManifests(packageDir);
1519
+ if (manifestResult.manifestFound && manifestResult.version) {
1520
+ const cleanedTag = import_semver2.default.clean(latestTag) || latestTag;
1521
+ const tagVersion = import_semver2.default.clean(cleanedTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
1522
+ const packageVersion = manifestResult.version;
1523
+ if (import_semver2.default.gt(packageVersion, tagVersion)) {
1524
+ log(
1525
+ `Warning: Version mismatch detected!
1526
+ \u2022 ${manifestResult.manifestType} version: ${packageVersion}
1527
+ \u2022 Latest Git tag version: ${tagVersion} (from ${latestTag})
1528
+ \u2022 Package version is AHEAD of Git tags
1529
+
1530
+ This usually happens when:
1531
+ \u2022 A version was released but the tag wasn't pushed to the remote repository
1532
+ \u2022 The ${manifestResult.manifestType} was manually updated without creating a corresponding tag
1533
+ \u2022 You're running in CI and the latest tag isn't available yet
1534
+
1535
+ The tool will use the Git tag version (${tagVersion}) as the base for calculation.
1536
+ Expected next version will be based on ${tagVersion}, not ${packageVersion}.
1537
+
1538
+ To fix this mismatch:
1539
+ \u2022 Push missing tags: git push origin --tags
1540
+ \u2022 Or use package version as base by ensuring tags are up to date`,
1541
+ "warning"
1542
+ );
1543
+ } else if (import_semver2.default.gt(tagVersion, packageVersion)) {
1544
+ log(
1545
+ `Warning: Version mismatch detected!
1546
+ \u2022 ${manifestResult.manifestType} version: ${packageVersion}
1547
+ \u2022 Latest Git tag version: ${tagVersion} (from ${latestTag})
1548
+ \u2022 Git tag version is AHEAD of package version
1549
+
1550
+ This usually happens when:
1551
+ \u2022 A release was tagged but the ${manifestResult.manifestType} wasn't updated
1552
+ \u2022 You're on an older branch that hasn't been updated with the latest version
1553
+ \u2022 Automated release process created tags but didn't update manifest files
1554
+ \u2022 You pulled tags but not the corresponding commits that update the package version
1555
+
1556
+ The tool will use the Git tag version (${tagVersion}) as the base for calculation.
1557
+ This will likely result in a version that's already been released.
1558
+
1559
+ To fix this mismatch:
1560
+ \u2022 Update ${manifestResult.manifestType}: Set version to ${tagVersion} or higher
1561
+ \u2022 Or checkout the branch/commit that corresponds to the tag
1562
+ \u2022 Or ensure your branch is up to date with the latest changes`,
1563
+ "warning"
1564
+ );
1565
+ }
1566
+ }
1567
+ }
1463
1568
  const specifiedType = type;
1464
1569
  if (specifiedType) {
1465
1570
  if (hasNoTags) {
@@ -1606,13 +1711,39 @@ function calculateNextVersion(version, manifestType, name, releaseType, prerelea
1606
1711
  return result || initialVersion;
1607
1712
  }
1608
1713
 
1714
+ // src/utils/packageMatching.ts
1715
+ function matchesPackageTarget(packageName, target) {
1716
+ if (packageName === target) {
1717
+ return true;
1718
+ }
1719
+ if (target.endsWith("/*")) {
1720
+ const scope = target.slice(0, -2);
1721
+ if (scope.startsWith("@")) {
1722
+ return packageName.startsWith(`${scope}/`);
1723
+ }
1724
+ return packageName.startsWith(`${scope}/`);
1725
+ }
1726
+ if (target === "*") {
1727
+ return true;
1728
+ }
1729
+ return false;
1730
+ }
1731
+ function shouldProcessPackage(packageName, targets = [], skip = []) {
1732
+ if (skip.includes(packageName)) {
1733
+ return false;
1734
+ }
1735
+ if (targets.length === 0) {
1736
+ return true;
1737
+ }
1738
+ return targets.some((target) => matchesPackageTarget(packageName, target));
1739
+ }
1740
+
1609
1741
  // src/package/packageProcessor.ts
1610
1742
  var PackageProcessor = class {
1611
1743
  skip;
1612
1744
  targets;
1613
1745
  versionPrefix;
1614
1746
  tagTemplate;
1615
- packageTagTemplate;
1616
1747
  commitMessageTemplate;
1617
1748
  dryRun;
1618
1749
  skipHooks;
@@ -1625,7 +1756,6 @@ var PackageProcessor = class {
1625
1756
  this.targets = options.targets || [];
1626
1757
  this.versionPrefix = options.versionPrefix || "v";
1627
1758
  this.tagTemplate = options.tagTemplate;
1628
- this.packageTagTemplate = options.packageTagTemplate;
1629
1759
  this.commitMessageTemplate = options.commitMessageTemplate || "";
1630
1760
  this.dryRun = options.dryRun || false;
1631
1761
  this.skipHooks = options.skipHooks || false;
@@ -1653,18 +1783,15 @@ var PackageProcessor = class {
1653
1783
  const pkgsToConsider = packages.filter((pkg) => {
1654
1784
  var _a2;
1655
1785
  const pkgName = pkg.packageJson.name;
1656
- if ((_a2 = this.skip) == null ? void 0 : _a2.includes(pkgName)) {
1657
- log(`Skipping package ${pkgName} as it's in the skip list.`, "info");
1658
- return false;
1659
- }
1660
- if (!this.targets || this.targets.length === 0) {
1661
- return true;
1662
- }
1663
- const isTargeted = this.targets.includes(pkgName);
1664
- if (!isTargeted) {
1665
- log(`Package ${pkgName} not in target list, skipping.`, "info");
1786
+ const shouldProcess = shouldProcessPackage(pkgName, this.targets, this.skip);
1787
+ if (!shouldProcess) {
1788
+ if ((_a2 = this.skip) == null ? void 0 : _a2.includes(pkgName)) {
1789
+ log(`Skipping package ${pkgName} as it's in the skip list.`, "info");
1790
+ } else {
1791
+ log(`Package ${pkgName} not in target list, skipping.`, "info");
1792
+ }
1666
1793
  }
1667
- return isTargeted;
1794
+ return shouldProcess;
1668
1795
  });
1669
1796
  log(`Found ${pkgsToConsider.length} targeted package(s) to process after filtering.`, "info");
1670
1797
  if (pkgsToConsider.length === 0) {
@@ -1677,7 +1804,10 @@ var PackageProcessor = class {
1677
1804
  const formattedPrefix = formatVersionPrefix(this.versionPrefix);
1678
1805
  let latestTagResult = "";
1679
1806
  try {
1680
- latestTagResult = await getLatestTagForPackage(name, this.versionPrefix);
1807
+ latestTagResult = await getLatestTagForPackage(name, this.versionPrefix, {
1808
+ tagTemplate: this.tagTemplate,
1809
+ packageSpecificTags: this.fullConfig.packageSpecificTags
1810
+ });
1681
1811
  } catch (error) {
1682
1812
  const errorMessage = error instanceof Error ? error.message : String(error);
1683
1813
  log(
@@ -1809,7 +1939,7 @@ var PackageProcessor = class {
1809
1939
  this.versionPrefix,
1810
1940
  name,
1811
1941
  this.tagTemplate,
1812
- this.packageTagTemplate
1942
+ this.fullConfig.packageSpecificTags
1813
1943
  );
1814
1944
  const tagMessage = `chore(release): ${name} ${nextVersion}`;
1815
1945
  addTag(packageTag);
@@ -1895,16 +2025,9 @@ var PackageProcessor = class {
1895
2025
  };
1896
2026
 
1897
2027
  // src/core/versionStrategies.ts
1898
- function shouldProcessPackage(pkg, config, targets = []) {
1899
- var _a;
2028
+ function shouldProcessPackage2(pkg, config, targets = []) {
1900
2029
  const pkgName = pkg.packageJson.name;
1901
- if ((_a = config.skip) == null ? void 0 : _a.includes(pkgName)) {
1902
- return false;
1903
- }
1904
- if (!targets || targets.length === 0) {
1905
- return true;
1906
- }
1907
- return targets.includes(pkgName);
2030
+ return shouldProcessPackage(pkgName, targets, config.skip);
1908
2031
  }
1909
2032
  function createSyncedStrategy(config) {
1910
2033
  return async (packages) => {
@@ -1917,16 +2040,41 @@ function createSyncedStrategy(config) {
1917
2040
  commitMessage = "chore(release): v${version}",
1918
2041
  prereleaseIdentifier,
1919
2042
  dryRun,
1920
- skipHooks
2043
+ skipHooks,
2044
+ mainPackage
1921
2045
  } = config;
1922
2046
  const formattedPrefix = formatVersionPrefix(versionPrefix || "v");
1923
2047
  const latestTag = await getLatestTag();
2048
+ let mainPkgPath = packages.root;
2049
+ let mainPkgName;
2050
+ if (mainPackage) {
2051
+ const mainPkg = packages.packages.find((p) => p.packageJson.name === mainPackage);
2052
+ if (mainPkg) {
2053
+ mainPkgPath = mainPkg.dir;
2054
+ mainPkgName = mainPkg.packageJson.name;
2055
+ log(`Using ${mainPkgName} as primary package for version determination`, "info");
2056
+ } else {
2057
+ log(
2058
+ `Main package '${mainPackage}' not found. Using root package for version determination.`,
2059
+ "warning"
2060
+ );
2061
+ }
2062
+ }
2063
+ if (!mainPkgPath) {
2064
+ mainPkgPath = process.cwd();
2065
+ log(
2066
+ `No valid package path found, using current working directory: ${mainPkgPath}`,
2067
+ "warning"
2068
+ );
2069
+ }
1924
2070
  const nextVersion = await calculateVersion(config, {
1925
2071
  latestTag,
1926
2072
  versionPrefix: formattedPrefix,
1927
2073
  branchPattern,
1928
2074
  baseBranch,
1929
2075
  prereleaseIdentifier,
2076
+ path: mainPkgPath,
2077
+ name: mainPkgName,
1930
2078
  type: config.type
1931
2079
  });
1932
2080
  if (!nextVersion) {
@@ -1935,25 +2083,35 @@ function createSyncedStrategy(config) {
1935
2083
  }
1936
2084
  const files = [];
1937
2085
  const updatedPackages = [];
2086
+ const processedPaths = /* @__PURE__ */ new Set();
1938
2087
  try {
1939
- const rootPkgPath = path7.join(packages.root, "package.json");
1940
- if (import_node_fs7.default.existsSync(rootPkgPath)) {
1941
- updatePackageVersion(rootPkgPath, nextVersion);
1942
- files.push(rootPkgPath);
1943
- updatedPackages.push("root");
2088
+ if (packages.root) {
2089
+ const rootPkgPath = path7.join(packages.root, "package.json");
2090
+ if (import_node_fs7.default.existsSync(rootPkgPath)) {
2091
+ updatePackageVersion(rootPkgPath, nextVersion);
2092
+ files.push(rootPkgPath);
2093
+ updatedPackages.push("root");
2094
+ processedPaths.add(rootPkgPath);
2095
+ }
2096
+ } else {
2097
+ log("Root package path is undefined, skipping root package.json update", "warning");
1944
2098
  }
1945
2099
  } catch (error) {
1946
2100
  const errMessage = error instanceof Error ? error.message : String(error);
1947
2101
  log(`Failed to update root package.json: ${errMessage}`, "error");
1948
2102
  }
1949
2103
  for (const pkg of packages.packages) {
1950
- if (!shouldProcessPackage(pkg, config)) {
2104
+ if (!shouldProcessPackage2(pkg, config)) {
1951
2105
  continue;
1952
2106
  }
1953
2107
  const packageJsonPath = path7.join(pkg.dir, "package.json");
2108
+ if (processedPaths.has(packageJsonPath)) {
2109
+ continue;
2110
+ }
1954
2111
  updatePackageVersion(packageJsonPath, nextVersion);
1955
2112
  files.push(packageJsonPath);
1956
2113
  updatedPackages.push(pkg.packageJson.name);
2114
+ processedPaths.add(packageJsonPath);
1957
2115
  }
1958
2116
  if (updatedPackages.length > 0) {
1959
2117
  log(`Updated ${updatedPackages.length} package(s) to version ${nextVersion}`, "success");
@@ -1961,8 +2119,25 @@ function createSyncedStrategy(config) {
1961
2119
  log("No packages were updated", "warning");
1962
2120
  return;
1963
2121
  }
1964
- const nextTag = formatTag(nextVersion, formattedPrefix, null, tagTemplate);
1965
- const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
2122
+ let tagPackageName = null;
2123
+ let commitPackageName = void 0;
2124
+ if (config.packageSpecificTags && packages.packages.length === 1) {
2125
+ tagPackageName = packages.packages[0].packageJson.name;
2126
+ commitPackageName = packages.packages[0].packageJson.name;
2127
+ }
2128
+ const nextTag = formatTag(
2129
+ nextVersion,
2130
+ formattedPrefix,
2131
+ tagPackageName,
2132
+ tagTemplate,
2133
+ config.packageSpecificTags || false
2134
+ );
2135
+ const formattedCommitMessage = formatCommitMessage(
2136
+ commitMessage,
2137
+ nextVersion,
2138
+ commitPackageName,
2139
+ void 0
2140
+ );
1966
2141
  await createGitCommitAndTag(files, nextTag, formattedCommitMessage, skipHooks, dryRun);
1967
2142
  } catch (error) {
1968
2143
  if (error instanceof VersionError || error instanceof GitError) {
@@ -1980,27 +2155,34 @@ function createSingleStrategy(config) {
1980
2155
  try {
1981
2156
  const {
1982
2157
  packages: configPackages,
2158
+ mainPackage,
1983
2159
  versionPrefix,
1984
2160
  tagTemplate,
1985
- packageTagTemplate,
1986
2161
  commitMessage = "chore(release): ${version}",
1987
2162
  dryRun,
1988
2163
  skipHooks
1989
2164
  } = config;
1990
- if (!configPackages || configPackages.length !== 1) {
2165
+ let packageName;
2166
+ if (mainPackage) {
2167
+ packageName = mainPackage;
2168
+ } else if (configPackages && configPackages.length === 1) {
2169
+ packageName = configPackages[0];
2170
+ } else {
1991
2171
  throw createVersionError(
1992
2172
  "INVALID_CONFIG" /* INVALID_CONFIG */,
1993
- "Single mode requires exactly one package name"
2173
+ "Single mode requires either mainPackage or exactly one package in the packages array"
1994
2174
  );
1995
2175
  }
1996
- const packageName = configPackages[0];
1997
2176
  const pkg = packages.packages.find((p) => p.packageJson.name === packageName);
1998
2177
  if (!pkg) {
1999
2178
  throw createVersionError("PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */, packageName);
2000
2179
  }
2001
2180
  const pkgPath = pkg.dir;
2002
2181
  const formattedPrefix = formatVersionPrefix(versionPrefix || "v");
2003
- let latestTagResult = await getLatestTagForPackage(packageName, formattedPrefix);
2182
+ let latestTagResult = await getLatestTagForPackage(packageName, formattedPrefix, {
2183
+ tagTemplate,
2184
+ packageSpecificTags: config.packageSpecificTags
2185
+ });
2004
2186
  if (!latestTagResult) {
2005
2187
  const globalTagResult = await getLatestTag();
2006
2188
  latestTagResult = globalTagResult || "";
@@ -2031,7 +2213,7 @@ function createSingleStrategy(config) {
2031
2213
  formattedPrefix,
2032
2214
  packageName,
2033
2215
  tagTemplate,
2034
- packageTagTemplate
2216
+ config.packageSpecificTags
2035
2217
  );
2036
2218
  const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion, packageName);
2037
2219
  await createGitCommitAndTag(
@@ -2064,7 +2246,6 @@ function createAsyncStrategy(config) {
2064
2246
  targets: config.packages || [],
2065
2247
  versionPrefix: config.versionPrefix || "v",
2066
2248
  tagTemplate: config.tagTemplate,
2067
- packageTagTemplate: config.packageTagTemplate,
2068
2249
  commitMessageTemplate: config.commitMessage || "",
2069
2250
  dryRun: config.dryRun || false,
2070
2251
  skipHooks: config.skipHooks || false,
@@ -2117,7 +2298,7 @@ function createStrategy(config) {
2117
2298
  if (config.synced) {
2118
2299
  return createSyncedStrategy(config);
2119
2300
  }
2120
- if (((_a = config.packages) == null ? void 0 : _a.length) === 1) {
2301
+ if (config.mainPackage || ((_a = config.packages) == null ? void 0 : _a.length) === 1) {
2121
2302
  return createSingleStrategy(config);
2122
2303
  }
2123
2304
  return createAsyncStrategy(config);
@@ -2162,6 +2343,13 @@ var VersionEngine = class {
2162
2343
  if (!pkgsResult || !pkgsResult.packages) {
2163
2344
  throw createVersionError("PACKAGES_NOT_FOUND" /* PACKAGES_NOT_FOUND */);
2164
2345
  }
2346
+ if (!pkgsResult.root) {
2347
+ log(
2348
+ "Root path is undefined in packages result, setting to current working directory",
2349
+ "warning"
2350
+ );
2351
+ pkgsResult.root = (0, import_node_process5.cwd)();
2352
+ }
2165
2353
  this.workspaceCache = pkgsResult;
2166
2354
  return pkgsResult;
2167
2355
  } catch (error) {
@@ -2182,9 +2370,22 @@ var VersionEngine = class {
2182
2370
  } catch (error) {
2183
2371
  if (error instanceof VersionError || error instanceof GitError) {
2184
2372
  log(`Version engine failed: ${error.message} (${error.code || "UNKNOWN"})`, "error");
2373
+ if (error instanceof GitError) {
2374
+ console.error("Git error details:");
2375
+ if (error.message.includes("Command failed:")) {
2376
+ const cmdOutput = error.message.split("Command failed:")[1];
2377
+ if (cmdOutput) {
2378
+ console.error("Command output:", cmdOutput.trim());
2379
+ }
2380
+ }
2381
+ }
2185
2382
  } else {
2186
2383
  const errorMessage = error instanceof Error ? error.message : String(error);
2187
2384
  log(`Version engine failed: ${errorMessage}`, "error");
2385
+ if (error instanceof Error && error.stack) {
2386
+ console.error("Error stack trace:");
2387
+ console.error(error.stack);
2388
+ }
2188
2389
  }
2189
2390
  throw error;
2190
2391
  }
@@ -2263,6 +2464,16 @@ async function run() {
2263
2464
  printJsonOutput();
2264
2465
  } catch (error) {
2265
2466
  log(error instanceof Error ? error.message : String(error), "error");
2467
+ if (error instanceof Error) {
2468
+ console.error("Error details:");
2469
+ console.error(error.stack || error.message);
2470
+ if (error.message.includes("Command failed:")) {
2471
+ const cmdOutput = error.message.split("Command failed:")[1];
2472
+ if (cmdOutput) {
2473
+ console.error("Command output:", cmdOutput.trim());
2474
+ }
2475
+ }
2476
+ }
2266
2477
  process.exit(1);
2267
2478
  }
2268
2479
  });