package-versioner 0.7.0 → 0.7.1

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/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  <img src="https://img.shields.io/npm/v/package-versioner" /></a>
6
6
  <a href="https://www.npmjs.com/package/package-versioner" alt="NPM Downloads">
7
7
  <img src="https://img.shields.io/npm/dw/package-versioner" /></a>
8
-
8
+ <br/><br/>
9
9
  A lightweight yet powerful CLI tool for automated semantic versioning based on Git history and conventional commits. Supports both single package projects and monorepos with flexible versioning strategies.
10
10
 
11
11
  ## Features
@@ -103,14 +103,13 @@ Customize behavior by creating a `version.config.json` file in your project root
103
103
  "commitMessage": "chore: release ${packageName}@${version} [skip ci]",
104
104
  "updateChangelog": true,
105
105
  "changelogFormat": "keep-a-changelog",
106
- "monorepo": {
107
- "synced": true,
108
- "skip": [
109
- "docs",
110
- "e2e"
111
- ],
112
- "packagePath": "packages"
113
- },
106
+ "synced": true,
107
+ "skip": [
108
+ "docs",
109
+ "e2e"
110
+ ],
111
+ "packages": ["packages/*"],
112
+ "mainPackage": "primary-package",
114
113
  "cargo": {
115
114
  "enabled": true,
116
115
  "paths": ["src/", "crates/"]
@@ -118,15 +117,28 @@ Customize behavior by creating a `version.config.json` file in your project root
118
117
  }
119
118
  ```
120
119
 
121
- **Notes:**
122
- - Options like `synced`, `packages`, and `updateInternalDependencies` enable monorepo-specific behaviours.
123
- - The `tagTemplate` and `packageTagTemplate` allow you to customize how Git tags are formatted for releases.
124
- - The `commitMessage` template can include CI skip tokens like `[skip ci]` if you want to prevent CI runs after version commits (e.g., `"commitMessage": "chore: release ${packageName}@${version} [skip ci]"`). See [CI/CD Integration](./docs/CI_CD_INTEGRATION.md) for more details.
125
- - The `updateChangelog` option controls whether to automatically generate and update changelogs for each package (default: true).
126
- - The `changelogFormat` option sets the changelog style to either "keep-a-changelog" (default) or "angular".
127
- - The `cargo` options can help when working with Rust projects:
128
- - `enabled` (default: `true`): Set to `false` to disable Cargo.toml version handling
129
- - `paths` (optional): Specify directories to search for Cargo.toml files
120
+ ### Configuration Options
121
+
122
+ #### General Options (All Projects)
123
+ - `preset`: Conventional commits preset to use for version calculation (default: "angular")
124
+ - `versionPrefix`: Prefix for version numbers in tags (default: "v")
125
+ - `tagTemplate`: Template for Git tags (default: "${prefix}${version}")
126
+ - `commitMessage`: Template for commit messages (default: "chore(release): ${version}")
127
+ - `updateChangelog`: Whether to automatically update changelogs (default: true)
128
+ - `changelogFormat`: Format for changelogs - "keep-a-changelog" or "angular" (default: "keep-a-changelog")
129
+ - `cargo`: Options for Rust projects:
130
+ - `enabled`: Whether to handle Cargo.toml files (default: true)
131
+ - `paths`: Directories to search for Cargo.toml files (optional)
132
+
133
+ #### Monorepo-Specific Options
134
+ - `synced`: Whether all packages should be versioned together (default: true)
135
+ - `skip`: Array of package names to exclude from versioning
136
+ - `packages`: Glob patterns for package discovery (e.g., ["packages/*"])
137
+ - `mainPackage`: Package name whose commit history should drive version determination
138
+ - `packageTagTemplate`: Template for package-specific Git tags (default: "${packageName}@${prefix}${version}")
139
+ - `updateInternalDependencies`: How to update internal dependencies ("patch", "minor", "major", or "inherit")
140
+
141
+ For more details on CI/CD integration and advanced usage, see [CI/CD Integration](./docs/CI_CD_INTEGRATION.md).
130
142
 
131
143
  ## How Versioning Works
132
144
 
package/dist/index.cjs CHANGED
@@ -732,6 +732,11 @@ async function gitProcess(options) {
732
732
  }
733
733
  } catch (err) {
734
734
  const errorMessage = err instanceof Error ? err.message : String(err);
735
+ log(`Git process error: ${errorMessage}`, "error");
736
+ if (err instanceof Error && err.stack) {
737
+ console.error("Git process stack trace:");
738
+ console.error(err.stack);
739
+ }
735
740
  throw createGitError("GIT_PROCESS_ERROR" /* GIT_PROCESS_ERROR */, errorMessage);
736
741
  }
737
742
  }
@@ -761,9 +766,16 @@ async function createGitCommitAndTag(files, nextTag, commitMessage, skipHooks, d
761
766
  const errorMessage = error instanceof Error ? error.message : String(error);
762
767
  log(`Failed to create git commit and tag: ${errorMessage}`, "error");
763
768
  if (error instanceof Error) {
769
+ console.error("Git operation error details:");
764
770
  console.error(error.stack || error.message);
771
+ if (errorMessage.includes("Command failed:")) {
772
+ const cmdOutput = errorMessage.split("Command failed:")[1];
773
+ if (cmdOutput) {
774
+ console.error("Git command output:", cmdOutput.trim());
775
+ }
776
+ }
765
777
  } else {
766
- console.error(error);
778
+ console.error("Unknown git error:", error);
767
779
  }
768
780
  throw new GitError(`Git operation failed: ${errorMessage}`, "GIT_ERROR" /* GIT_ERROR */);
769
781
  }
@@ -1917,16 +1929,41 @@ function createSyncedStrategy(config) {
1917
1929
  commitMessage = "chore(release): v${version}",
1918
1930
  prereleaseIdentifier,
1919
1931
  dryRun,
1920
- skipHooks
1932
+ skipHooks,
1933
+ mainPackage
1921
1934
  } = config;
1922
1935
  const formattedPrefix = formatVersionPrefix(versionPrefix || "v");
1923
1936
  const latestTag = await getLatestTag();
1937
+ let mainPkgPath = packages.root;
1938
+ let mainPkgName;
1939
+ if (mainPackage) {
1940
+ const mainPkg = packages.packages.find((p) => p.packageJson.name === mainPackage);
1941
+ if (mainPkg) {
1942
+ mainPkgPath = mainPkg.dir;
1943
+ mainPkgName = mainPkg.packageJson.name;
1944
+ log(`Using ${mainPkgName} as primary package for version determination`, "info");
1945
+ } else {
1946
+ log(
1947
+ `Main package '${mainPackage}' not found. Using root package for version determination.`,
1948
+ "warning"
1949
+ );
1950
+ }
1951
+ }
1952
+ if (!mainPkgPath) {
1953
+ mainPkgPath = process.cwd();
1954
+ log(
1955
+ `No valid package path found, using current working directory: ${mainPkgPath}`,
1956
+ "warning"
1957
+ );
1958
+ }
1924
1959
  const nextVersion = await calculateVersion(config, {
1925
1960
  latestTag,
1926
1961
  versionPrefix: formattedPrefix,
1927
1962
  branchPattern,
1928
1963
  baseBranch,
1929
1964
  prereleaseIdentifier,
1965
+ path: mainPkgPath,
1966
+ name: mainPkgName,
1930
1967
  type: config.type
1931
1968
  });
1932
1969
  if (!nextVersion) {
@@ -1936,11 +1973,15 @@ function createSyncedStrategy(config) {
1936
1973
  const files = [];
1937
1974
  const updatedPackages = [];
1938
1975
  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");
1976
+ if (packages.root) {
1977
+ const rootPkgPath = path7.join(packages.root, "package.json");
1978
+ if (import_node_fs7.default.existsSync(rootPkgPath)) {
1979
+ updatePackageVersion(rootPkgPath, nextVersion);
1980
+ files.push(rootPkgPath);
1981
+ updatedPackages.push("root");
1982
+ }
1983
+ } else {
1984
+ log("Root package path is undefined, skipping root package.json update", "warning");
1944
1985
  }
1945
1986
  } catch (error) {
1946
1987
  const errMessage = error instanceof Error ? error.message : String(error);
@@ -1980,6 +2021,7 @@ function createSingleStrategy(config) {
1980
2021
  try {
1981
2022
  const {
1982
2023
  packages: configPackages,
2024
+ mainPackage,
1983
2025
  versionPrefix,
1984
2026
  tagTemplate,
1985
2027
  packageTagTemplate,
@@ -1987,13 +2029,17 @@ function createSingleStrategy(config) {
1987
2029
  dryRun,
1988
2030
  skipHooks
1989
2031
  } = config;
1990
- if (!configPackages || configPackages.length !== 1) {
2032
+ let packageName;
2033
+ if (mainPackage) {
2034
+ packageName = mainPackage;
2035
+ } else if (configPackages && configPackages.length === 1) {
2036
+ packageName = configPackages[0];
2037
+ } else {
1991
2038
  throw createVersionError(
1992
2039
  "INVALID_CONFIG" /* INVALID_CONFIG */,
1993
- "Single mode requires exactly one package name"
2040
+ "Single mode requires either mainPackage or exactly one package in the packages array"
1994
2041
  );
1995
2042
  }
1996
- const packageName = configPackages[0];
1997
2043
  const pkg = packages.packages.find((p) => p.packageJson.name === packageName);
1998
2044
  if (!pkg) {
1999
2045
  throw createVersionError("PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */, packageName);
@@ -2117,7 +2163,7 @@ function createStrategy(config) {
2117
2163
  if (config.synced) {
2118
2164
  return createSyncedStrategy(config);
2119
2165
  }
2120
- if (((_a = config.packages) == null ? void 0 : _a.length) === 1) {
2166
+ if (config.mainPackage || ((_a = config.packages) == null ? void 0 : _a.length) === 1) {
2121
2167
  return createSingleStrategy(config);
2122
2168
  }
2123
2169
  return createAsyncStrategy(config);
@@ -2162,6 +2208,13 @@ var VersionEngine = class {
2162
2208
  if (!pkgsResult || !pkgsResult.packages) {
2163
2209
  throw createVersionError("PACKAGES_NOT_FOUND" /* PACKAGES_NOT_FOUND */);
2164
2210
  }
2211
+ if (!pkgsResult.root) {
2212
+ log(
2213
+ "Root path is undefined in packages result, setting to current working directory",
2214
+ "warning"
2215
+ );
2216
+ pkgsResult.root = (0, import_node_process5.cwd)();
2217
+ }
2165
2218
  this.workspaceCache = pkgsResult;
2166
2219
  return pkgsResult;
2167
2220
  } catch (error) {
@@ -2182,9 +2235,22 @@ var VersionEngine = class {
2182
2235
  } catch (error) {
2183
2236
  if (error instanceof VersionError || error instanceof GitError) {
2184
2237
  log(`Version engine failed: ${error.message} (${error.code || "UNKNOWN"})`, "error");
2238
+ if (error instanceof GitError) {
2239
+ console.error("Git error details:");
2240
+ if (error.message.includes("Command failed:")) {
2241
+ const cmdOutput = error.message.split("Command failed:")[1];
2242
+ if (cmdOutput) {
2243
+ console.error("Command output:", cmdOutput.trim());
2244
+ }
2245
+ }
2246
+ }
2185
2247
  } else {
2186
2248
  const errorMessage = error instanceof Error ? error.message : String(error);
2187
2249
  log(`Version engine failed: ${errorMessage}`, "error");
2250
+ if (error instanceof Error && error.stack) {
2251
+ console.error("Error stack trace:");
2252
+ console.error(error.stack);
2253
+ }
2188
2254
  }
2189
2255
  throw error;
2190
2256
  }
@@ -2263,6 +2329,16 @@ async function run() {
2263
2329
  printJsonOutput();
2264
2330
  } catch (error) {
2265
2331
  log(error instanceof Error ? error.message : String(error), "error");
2332
+ if (error instanceof Error) {
2333
+ console.error("Error details:");
2334
+ console.error(error.stack || error.message);
2335
+ if (error.message.includes("Command failed:")) {
2336
+ const cmdOutput = error.message.split("Command failed:")[1];
2337
+ if (cmdOutput) {
2338
+ console.error("Command output:", cmdOutput.trim());
2339
+ }
2340
+ }
2341
+ }
2266
2342
  process.exit(1);
2267
2343
  }
2268
2344
  });
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import * as fs9 from "node:fs";
5
- import path7 from "node:path";
4
+ import * as fs10 from "fs";
5
+ import path8 from "path";
6
6
  import { Command } from "commander";
7
7
 
8
8
  // src/changelog/changelogRegenerator.ts
9
- import { execSync as execSync2 } from "node:child_process";
10
- import fs from "node:fs";
11
- import path from "node:path";
9
+ import { execSync as execSync2 } from "child_process";
10
+ import fs from "fs";
11
+ import path from "path";
12
12
 
13
13
  // src/utils/logging.ts
14
14
  import chalk from "chalk";
@@ -92,7 +92,7 @@ function log(message, level = "info") {
92
92
  }
93
93
 
94
94
  // src/changelog/commitParser.ts
95
- import { execSync } from "node:child_process";
95
+ import { execSync } from "child_process";
96
96
  var CONVENTIONAL_COMMIT_REGEX = /^(\w+)(?:\(([^)]+)\))?(!)?: (.+)(?:\n\n([\s\S]*))?/;
97
97
  var BREAKING_CHANGE_REGEX = /BREAKING CHANGE: ([\s\S]+?)(?:\n\n|$)/;
98
98
  function extractChangelogEntriesFromCommits(projectDir, revisionRange) {
@@ -521,8 +521,8 @@ async function writeChangelog(content, outputPath, dryRun) {
521
521
  }
522
522
 
523
523
  // src/config.ts
524
- import * as fs2 from "node:fs";
525
- import { cwd } from "node:process";
524
+ import * as fs2 from "fs";
525
+ import { cwd } from "process";
526
526
  function loadConfig(configPath) {
527
527
  const localProcess = cwd();
528
528
  const filePath = configPath || `${localProcess}/version.config.json`;
@@ -544,7 +544,7 @@ function loadConfig(configPath) {
544
544
  }
545
545
 
546
546
  // src/core/versionEngine.ts
547
- import { cwd as cwd4 } from "node:process";
547
+ import { cwd as cwd4 } from "process";
548
548
  import { getPackagesSync } from "@manypkg/get-packages";
549
549
 
550
550
  // src/errors/gitError.ts
@@ -591,14 +591,14 @@ function createVersionError(code, details) {
591
591
  }
592
592
 
593
593
  // src/core/versionStrategies.ts
594
- import fs8 from "node:fs";
595
- import * as path6 from "node:path";
594
+ import fs9 from "fs";
595
+ import * as path7 from "path";
596
596
 
597
597
  // src/git/commands.ts
598
- import { cwd as cwd2 } from "node:process";
598
+ import { cwd as cwd2 } from "process";
599
599
 
600
600
  // src/git/commandExecutor.ts
601
- import { exec, execSync as nativeExecSync } from "node:child_process";
601
+ import { exec, execSync as nativeExecSync } from "child_process";
602
602
  var execAsync = (command, options) => {
603
603
  const defaultOptions = { maxBuffer: 1024 * 1024 * 10, ...options };
604
604
  return new Promise((resolve, reject) => {
@@ -618,8 +618,8 @@ var execAsync = (command, options) => {
618
618
  var execSync3 = (command, args) => nativeExecSync(command, { maxBuffer: 1024 * 1024 * 10, ...args });
619
619
 
620
620
  // src/git/repository.ts
621
- import { existsSync, statSync } from "node:fs";
622
- import { join } from "node:path";
621
+ import { existsSync, statSync } from "fs";
622
+ import { join } from "path";
623
623
  function isGitRepository(directory) {
624
624
  const gitDir = join(directory, ".git");
625
625
  if (!existsSync(gitDir)) {
@@ -699,6 +699,11 @@ async function gitProcess(options) {
699
699
  }
700
700
  } catch (err) {
701
701
  const errorMessage = err instanceof Error ? err.message : String(err);
702
+ log(`Git process error: ${errorMessage}`, "error");
703
+ if (err instanceof Error && err.stack) {
704
+ console.error("Git process stack trace:");
705
+ console.error(err.stack);
706
+ }
702
707
  throw createGitError("GIT_PROCESS_ERROR" /* GIT_PROCESS_ERROR */, errorMessage);
703
708
  }
704
709
  }
@@ -728,9 +733,16 @@ async function createGitCommitAndTag(files, nextTag, commitMessage, skipHooks, d
728
733
  const errorMessage = error instanceof Error ? error.message : String(error);
729
734
  log(`Failed to create git commit and tag: ${errorMessage}`, "error");
730
735
  if (error instanceof Error) {
736
+ console.error("Git operation error details:");
731
737
  console.error(error.stack || error.message);
738
+ if (errorMessage.includes("Command failed:")) {
739
+ const cmdOutput = errorMessage.split("Command failed:")[1];
740
+ if (cmdOutput) {
741
+ console.error("Git command output:", cmdOutput.trim());
742
+ }
743
+ }
732
744
  } else {
733
- console.error(error);
745
+ console.error("Unknown git error:", error);
734
746
  }
735
747
  throw new GitError(`Git operation failed: ${errorMessage}`, "GIT_ERROR" /* GIT_ERROR */);
736
748
  }
@@ -878,11 +890,12 @@ async function getLatestTagForPackage(packageName, versionPrefix) {
878
890
  }
879
891
 
880
892
  // src/package/packageManagement.ts
881
- import fs4 from "node:fs";
893
+ import fs4 from "fs";
894
+ import path3 from "path";
882
895
 
883
896
  // src/cargo/cargoHandler.ts
884
- import fs3 from "node:fs";
885
- import path2 from "node:path";
897
+ import fs3 from "fs";
898
+ import path2 from "path";
886
899
  import * as TOML from "smol-toml";
887
900
  function getCargoInfo(cargoPath) {
888
901
  var _a;
@@ -968,13 +981,13 @@ function updatePackageVersion(packagePath, version) {
968
981
  }
969
982
 
970
983
  // src/package/packageProcessor.ts
971
- import * as fs7 from "node:fs";
972
- import path5 from "node:path";
973
- import { exit } from "node:process";
984
+ import * as fs8 from "fs";
985
+ import path6 from "path";
986
+ import { exit } from "process";
974
987
 
975
988
  // src/changelog/changelogManager.ts
976
- import * as fs5 from "node:fs";
977
- import * as path3 from "node:path";
989
+ import * as fs5 from "fs";
990
+ import * as path4 from "path";
978
991
  function createChangelog(_packagePath, packageName) {
979
992
  return {
980
993
  projectName: packageName,
@@ -990,7 +1003,7 @@ function parseChangelog(filePath) {
990
1003
  fs5.readFileSync(filePath, "utf8");
991
1004
  log(`Parsed changelog at ${filePath}`, "info");
992
1005
  return {
993
- projectName: path3.basename(path3.dirname(filePath)),
1006
+ projectName: path4.basename(path4.dirname(filePath)),
994
1007
  unreleased: [],
995
1008
  versions: []
996
1009
  };
@@ -1259,7 +1272,7 @@ function generateChangelogContent(changelog, repoUrl, format = "keep-a-changelog
1259
1272
  }
1260
1273
  function updateChangelog(packagePath, packageName, version, entries, repoUrl, format = "keep-a-changelog") {
1261
1274
  try {
1262
- const changelogPath = path3.join(packagePath, "CHANGELOG.md");
1275
+ const changelogPath = path4.join(packagePath, "CHANGELOG.md");
1263
1276
  let changelog;
1264
1277
  if (fs5.existsSync(changelogPath)) {
1265
1278
  const existingChangelog = parseChangelog(changelogPath);
@@ -1298,16 +1311,16 @@ function capitalizeFirstLetter(input) {
1298
1311
  }
1299
1312
 
1300
1313
  // src/core/versionCalculator.ts
1301
- import { cwd as cwd3 } from "node:process";
1314
+ import { cwd as cwd3 } from "process";
1302
1315
  import { Bumper } from "conventional-recommended-bump";
1303
1316
  import semver2 from "semver";
1304
1317
 
1305
1318
  // src/utils/manifestHelpers.ts
1306
- import fs6 from "node:fs";
1307
- import path4 from "node:path";
1319
+ import fs6 from "fs";
1320
+ import path5 from "path";
1308
1321
  function getVersionFromManifests(packageDir) {
1309
- const packageJsonPath = path4.join(packageDir, "package.json");
1310
- const cargoTomlPath = path4.join(packageDir, "Cargo.toml");
1322
+ const packageJsonPath = path5.join(packageDir, "package.json");
1323
+ const cargoTomlPath = path5.join(packageDir, "Cargo.toml");
1311
1324
  if (fs6.existsSync(packageJsonPath)) {
1312
1325
  try {
1313
1326
  const packageJson = JSON.parse(fs6.readFileSync(packageJsonPath, "utf-8"));
@@ -1352,14 +1365,15 @@ function getVersionFromManifests(packageDir) {
1352
1365
  };
1353
1366
  }
1354
1367
  function throwIfNoManifestsFound(packageDir) {
1355
- const packageJsonPath = path4.join(packageDir, "package.json");
1356
- const cargoTomlPath = path4.join(packageDir, "Cargo.toml");
1368
+ const packageJsonPath = path5.join(packageDir, "package.json");
1369
+ const cargoTomlPath = path5.join(packageDir, "Cargo.toml");
1357
1370
  throw new Error(
1358
1371
  `Neither package.json nor Cargo.toml found at ${packageDir}. Checked paths: ${packageJsonPath}, ${cargoTomlPath}. Cannot determine version.`
1359
1372
  );
1360
1373
  }
1361
1374
 
1362
1375
  // src/utils/versionUtils.ts
1376
+ import fs7 from "fs";
1363
1377
  import semver from "semver";
1364
1378
  import * as TOML2 from "smol-toml";
1365
1379
  var STANDARD_BUMP_TYPES = ["major", "minor", "patch"];
@@ -1719,9 +1733,9 @@ var PackageProcessor = class {
1719
1733
  }
1720
1734
  let repoUrl;
1721
1735
  try {
1722
- const packageJsonPath2 = path5.join(pkgPath, "package.json");
1723
- if (fs7.existsSync(packageJsonPath2)) {
1724
- const packageJson = JSON.parse(fs7.readFileSync(packageJsonPath2, "utf8"));
1736
+ const packageJsonPath2 = path6.join(pkgPath, "package.json");
1737
+ if (fs8.existsSync(packageJsonPath2)) {
1738
+ const packageJson = JSON.parse(fs8.readFileSync(packageJsonPath2, "utf8"));
1725
1739
  if (packageJson.repository) {
1726
1740
  if (typeof packageJson.repository === "string") {
1727
1741
  repoUrl = packageJson.repository;
@@ -1748,8 +1762,8 @@ var PackageProcessor = class {
1748
1762
  this.fullConfig.changelogFormat
1749
1763
  );
1750
1764
  }
1751
- const packageJsonPath = path5.join(pkgPath, "package.json");
1752
- if (fs7.existsSync(packageJsonPath)) {
1765
+ const packageJsonPath = path6.join(pkgPath, "package.json");
1766
+ if (fs8.existsSync(packageJsonPath)) {
1753
1767
  updatePackageVersion(packageJsonPath, nextVersion);
1754
1768
  }
1755
1769
  const cargoEnabled = ((_a = this.fullConfig.cargo) == null ? void 0 : _a.enabled) !== false;
@@ -1757,14 +1771,14 @@ var PackageProcessor = class {
1757
1771
  const cargoPaths = (_b = this.fullConfig.cargo) == null ? void 0 : _b.paths;
1758
1772
  if (cargoPaths && cargoPaths.length > 0) {
1759
1773
  for (const cargoPath of cargoPaths) {
1760
- const resolvedCargoPath = path5.resolve(pkgPath, cargoPath, "Cargo.toml");
1761
- if (fs7.existsSync(resolvedCargoPath)) {
1774
+ const resolvedCargoPath = path6.resolve(pkgPath, cargoPath, "Cargo.toml");
1775
+ if (fs8.existsSync(resolvedCargoPath)) {
1762
1776
  updatePackageVersion(resolvedCargoPath, nextVersion);
1763
1777
  }
1764
1778
  }
1765
1779
  } else {
1766
- const cargoTomlPath = path5.join(pkgPath, "Cargo.toml");
1767
- if (fs7.existsSync(cargoTomlPath)) {
1780
+ const cargoTomlPath = path6.join(pkgPath, "Cargo.toml");
1781
+ if (fs8.existsSync(cargoTomlPath)) {
1768
1782
  updatePackageVersion(cargoTomlPath, nextVersion);
1769
1783
  }
1770
1784
  }
@@ -1801,8 +1815,8 @@ var PackageProcessor = class {
1801
1815
  }
1802
1816
  const filesToCommit = [];
1803
1817
  for (const info of updatedPackagesInfo) {
1804
- const packageJsonPath = path5.join(info.path, "package.json");
1805
- if (fs7.existsSync(packageJsonPath)) {
1818
+ const packageJsonPath = path6.join(info.path, "package.json");
1819
+ if (fs8.existsSync(packageJsonPath)) {
1806
1820
  filesToCommit.push(packageJsonPath);
1807
1821
  }
1808
1822
  const cargoEnabled = ((_c = this.fullConfig.cargo) == null ? void 0 : _c.enabled) !== false;
@@ -1810,14 +1824,14 @@ var PackageProcessor = class {
1810
1824
  const cargoPaths = (_d = this.fullConfig.cargo) == null ? void 0 : _d.paths;
1811
1825
  if (cargoPaths && cargoPaths.length > 0) {
1812
1826
  for (const cargoPath of cargoPaths) {
1813
- const resolvedCargoPath = path5.resolve(info.path, cargoPath, "Cargo.toml");
1814
- if (fs7.existsSync(resolvedCargoPath)) {
1827
+ const resolvedCargoPath = path6.resolve(info.path, cargoPath, "Cargo.toml");
1828
+ if (fs8.existsSync(resolvedCargoPath)) {
1815
1829
  filesToCommit.push(resolvedCargoPath);
1816
1830
  }
1817
1831
  }
1818
1832
  } else {
1819
- const cargoTomlPath = path5.join(info.path, "Cargo.toml");
1820
- if (fs7.existsSync(cargoTomlPath)) {
1833
+ const cargoTomlPath = path6.join(info.path, "Cargo.toml");
1834
+ if (fs8.existsSync(cargoTomlPath)) {
1821
1835
  filesToCommit.push(cargoTomlPath);
1822
1836
  }
1823
1837
  }
@@ -1882,16 +1896,41 @@ function createSyncedStrategy(config) {
1882
1896
  commitMessage = "chore(release): v${version}",
1883
1897
  prereleaseIdentifier,
1884
1898
  dryRun,
1885
- skipHooks
1899
+ skipHooks,
1900
+ mainPackage
1886
1901
  } = config;
1887
1902
  const formattedPrefix = formatVersionPrefix(versionPrefix || "v");
1888
1903
  const latestTag = await getLatestTag();
1904
+ let mainPkgPath = packages.root;
1905
+ let mainPkgName;
1906
+ if (mainPackage) {
1907
+ const mainPkg = packages.packages.find((p) => p.packageJson.name === mainPackage);
1908
+ if (mainPkg) {
1909
+ mainPkgPath = mainPkg.dir;
1910
+ mainPkgName = mainPkg.packageJson.name;
1911
+ log(`Using ${mainPkgName} as primary package for version determination`, "info");
1912
+ } else {
1913
+ log(
1914
+ `Main package '${mainPackage}' not found. Using root package for version determination.`,
1915
+ "warning"
1916
+ );
1917
+ }
1918
+ }
1919
+ if (!mainPkgPath) {
1920
+ mainPkgPath = process.cwd();
1921
+ log(
1922
+ `No valid package path found, using current working directory: ${mainPkgPath}`,
1923
+ "warning"
1924
+ );
1925
+ }
1889
1926
  const nextVersion = await calculateVersion(config, {
1890
1927
  latestTag,
1891
1928
  versionPrefix: formattedPrefix,
1892
1929
  branchPattern,
1893
1930
  baseBranch,
1894
1931
  prereleaseIdentifier,
1932
+ path: mainPkgPath,
1933
+ name: mainPkgName,
1895
1934
  type: config.type
1896
1935
  });
1897
1936
  if (!nextVersion) {
@@ -1901,11 +1940,15 @@ function createSyncedStrategy(config) {
1901
1940
  const files = [];
1902
1941
  const updatedPackages = [];
1903
1942
  try {
1904
- const rootPkgPath = path6.join(packages.root, "package.json");
1905
- if (fs8.existsSync(rootPkgPath)) {
1906
- updatePackageVersion(rootPkgPath, nextVersion);
1907
- files.push(rootPkgPath);
1908
- updatedPackages.push("root");
1943
+ if (packages.root) {
1944
+ const rootPkgPath = path7.join(packages.root, "package.json");
1945
+ if (fs9.existsSync(rootPkgPath)) {
1946
+ updatePackageVersion(rootPkgPath, nextVersion);
1947
+ files.push(rootPkgPath);
1948
+ updatedPackages.push("root");
1949
+ }
1950
+ } else {
1951
+ log("Root package path is undefined, skipping root package.json update", "warning");
1909
1952
  }
1910
1953
  } catch (error) {
1911
1954
  const errMessage = error instanceof Error ? error.message : String(error);
@@ -1915,7 +1958,7 @@ function createSyncedStrategy(config) {
1915
1958
  if (!shouldProcessPackage(pkg, config)) {
1916
1959
  continue;
1917
1960
  }
1918
- const packageJsonPath = path6.join(pkg.dir, "package.json");
1961
+ const packageJsonPath = path7.join(pkg.dir, "package.json");
1919
1962
  updatePackageVersion(packageJsonPath, nextVersion);
1920
1963
  files.push(packageJsonPath);
1921
1964
  updatedPackages.push(pkg.packageJson.name);
@@ -1945,6 +1988,7 @@ function createSingleStrategy(config) {
1945
1988
  try {
1946
1989
  const {
1947
1990
  packages: configPackages,
1991
+ mainPackage,
1948
1992
  versionPrefix,
1949
1993
  tagTemplate,
1950
1994
  packageTagTemplate,
@@ -1952,13 +1996,17 @@ function createSingleStrategy(config) {
1952
1996
  dryRun,
1953
1997
  skipHooks
1954
1998
  } = config;
1955
- if (!configPackages || configPackages.length !== 1) {
1999
+ let packageName;
2000
+ if (mainPackage) {
2001
+ packageName = mainPackage;
2002
+ } else if (configPackages && configPackages.length === 1) {
2003
+ packageName = configPackages[0];
2004
+ } else {
1956
2005
  throw createVersionError(
1957
2006
  "INVALID_CONFIG" /* INVALID_CONFIG */,
1958
- "Single mode requires exactly one package name"
2007
+ "Single mode requires either mainPackage or exactly one package in the packages array"
1959
2008
  );
1960
2009
  }
1961
- const packageName = configPackages[0];
1962
2010
  const pkg = packages.packages.find((p) => p.packageJson.name === packageName);
1963
2011
  if (!pkg) {
1964
2012
  throw createVersionError("PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */, packageName);
@@ -1988,7 +2036,7 @@ function createSingleStrategy(config) {
1988
2036
  log(`No version change needed for ${packageName}`, "info");
1989
2037
  return;
1990
2038
  }
1991
- const packageJsonPath = path6.join(pkgPath, "package.json");
2039
+ const packageJsonPath = path7.join(pkgPath, "package.json");
1992
2040
  updatePackageVersion(packageJsonPath, nextVersion);
1993
2041
  log(`Updated package ${packageName} to version ${nextVersion}`, "success");
1994
2042
  const nextTag = formatTag(
@@ -2082,7 +2130,7 @@ function createStrategy(config) {
2082
2130
  if (config.synced) {
2083
2131
  return createSyncedStrategy(config);
2084
2132
  }
2085
- if (((_a = config.packages) == null ? void 0 : _a.length) === 1) {
2133
+ if (config.mainPackage || ((_a = config.packages) == null ? void 0 : _a.length) === 1) {
2086
2134
  return createSingleStrategy(config);
2087
2135
  }
2088
2136
  return createAsyncStrategy(config);
@@ -2127,6 +2175,13 @@ var VersionEngine = class {
2127
2175
  if (!pkgsResult || !pkgsResult.packages) {
2128
2176
  throw createVersionError("PACKAGES_NOT_FOUND" /* PACKAGES_NOT_FOUND */);
2129
2177
  }
2178
+ if (!pkgsResult.root) {
2179
+ log(
2180
+ "Root path is undefined in packages result, setting to current working directory",
2181
+ "warning"
2182
+ );
2183
+ pkgsResult.root = cwd4();
2184
+ }
2130
2185
  this.workspaceCache = pkgsResult;
2131
2186
  return pkgsResult;
2132
2187
  } catch (error) {
@@ -2147,9 +2202,22 @@ var VersionEngine = class {
2147
2202
  } catch (error) {
2148
2203
  if (error instanceof VersionError || error instanceof GitError) {
2149
2204
  log(`Version engine failed: ${error.message} (${error.code || "UNKNOWN"})`, "error");
2205
+ if (error instanceof GitError) {
2206
+ console.error("Git error details:");
2207
+ if (error.message.includes("Command failed:")) {
2208
+ const cmdOutput = error.message.split("Command failed:")[1];
2209
+ if (cmdOutput) {
2210
+ console.error("Command output:", cmdOutput.trim());
2211
+ }
2212
+ }
2213
+ }
2150
2214
  } else {
2151
2215
  const errorMessage = error instanceof Error ? error.message : String(error);
2152
2216
  log(`Version engine failed: ${errorMessage}`, "error");
2217
+ if (error instanceof Error && error.stack) {
2218
+ console.error("Error stack trace:");
2219
+ console.error(error.stack);
2220
+ }
2153
2221
  }
2154
2222
  throw error;
2155
2223
  }
@@ -2166,11 +2234,11 @@ var VersionEngine = class {
2166
2234
  // src/index.ts
2167
2235
  function getPackageVersion() {
2168
2236
  try {
2169
- const packageJsonPath = path7.resolve(
2170
- path7.dirname(import.meta.url.replace("file:", "")),
2237
+ const packageJsonPath = path8.resolve(
2238
+ path8.dirname(import.meta.url.replace("file:", "")),
2171
2239
  "../package.json"
2172
2240
  );
2173
- const packageJsonContent = fs9.readFileSync(packageJsonPath, "utf-8");
2241
+ const packageJsonContent = fs10.readFileSync(packageJsonPath, "utf-8");
2174
2242
  const packageJson = JSON.parse(packageJsonContent);
2175
2243
  return packageJson.version || "0.0.0";
2176
2244
  } catch (error) {
@@ -2227,6 +2295,16 @@ async function run() {
2227
2295
  printJsonOutput();
2228
2296
  } catch (error) {
2229
2297
  log(error instanceof Error ? error.message : String(error), "error");
2298
+ if (error instanceof Error) {
2299
+ console.error("Error details:");
2300
+ console.error(error.stack || error.message);
2301
+ if (error.message.includes("Command failed:")) {
2302
+ const cmdOutput = error.message.split("Command failed:")[1];
2303
+ if (cmdOutput) {
2304
+ console.error("Command output:", cmdOutput.trim());
2305
+ }
2306
+ }
2307
+ }
2230
2308
  process.exit(1);
2231
2309
  }
2232
2310
  });
@@ -2253,7 +2331,7 @@ async function run() {
2253
2331
  const content = await regenerateChangelog(regenerateOptions);
2254
2332
  await writeChangelog(
2255
2333
  content,
2256
- path7.resolve(options.projectDir, options.output),
2334
+ path8.resolve(options.projectDir, options.output),
2257
2335
  options.dryRun
2258
2336
  );
2259
2337
  if (!options.dryRun) {
@@ -56,6 +56,11 @@
56
56
  "default": [],
57
57
  "description": "List of packages to include in versioning"
58
58
  },
59
+ "mainPackage": {
60
+ "type": "string",
61
+ "minLength": 1,
62
+ "description": "The package to use for version determination"
63
+ },
59
64
  "versionStrategy": {
60
65
  "type": "string",
61
66
  "enum": ["branchPattern", "commitMessage"],
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "package-versioner",
3
3
  "description": "A lightweight yet powerful CLI tool for automated semantic versioning based on Git history and conventional commits.",
4
- "version": "0.7.0",
4
+ "version": "0.7.1",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.mjs",
@@ -39,23 +39,23 @@
39
39
  "devDependencies": {
40
40
  "@biomejs/biome": "^1.9.4",
41
41
  "@types/figlet": "^1.5.5",
42
- "@types/node": "^22.15.17",
42
+ "@types/node": "^24.0.3",
43
43
  "@types/semver": "^7.3.13",
44
- "@vitest/coverage-v8": "^3.1.3",
44
+ "@vitest/coverage-v8": "^3.2.3",
45
45
  "husky": "^9.1.7",
46
- "lint-staged": "^16.0.0",
47
- "tsup": "^8.4.0",
48
- "tsx": "^4.19.4",
46
+ "lint-staged": "^16.1.2",
47
+ "tsup": "^8.5.0",
48
+ "tsx": "^4.20.3",
49
49
  "typescript": "^5.8.3",
50
- "vitest": "^3.1.3"
50
+ "vitest": "^3.2.3"
51
51
  },
52
52
  "dependencies": {
53
53
  "@manypkg/get-packages": "^3.0.0",
54
54
  "chalk": "^5.4.1",
55
- "commander": "^13.1.0",
55
+ "commander": "^14.0.0",
56
56
  "conventional-changelog-angular": "^8.0.0",
57
57
  "conventional-commits-filter": "^5.0.0",
58
- "conventional-recommended-bump": "^11.0.0",
58
+ "conventional-recommended-bump": "^11.2.0",
59
59
  "figlet": "^1.8.1",
60
60
  "git-semver-tags": "^8.0.0",
61
61
  "semver": "^7.7.2",