package-versioner 0.6.4 → 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/dist/index.js CHANGED
@@ -1,79 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import * as fs7 from "node:fs";
5
- import path5 from "node:path";
4
+ import * as fs10 from "fs";
5
+ import path8 from "path";
6
6
  import { Command } from "commander";
7
7
 
8
- // src/config.ts
9
- import * as fs from "node:fs";
10
- import { cwd } from "node:process";
11
- function loadConfig(configPath) {
12
- const localProcess = cwd();
13
- const filePath = configPath || `${localProcess}/version.config.json`;
14
- return new Promise((resolve, reject) => {
15
- fs.readFile(filePath, "utf-8", (err, data) => {
16
- if (err) {
17
- reject(new Error(`Could not locate the config file at ${filePath}: ${err.message}`));
18
- return;
19
- }
20
- try {
21
- const config = JSON.parse(data);
22
- resolve(config);
23
- } catch (err2) {
24
- const errorMessage = err2 instanceof Error ? err2.message : String(err2);
25
- reject(new Error(`Failed to parse config file ${filePath}: ${errorMessage}`));
26
- }
27
- });
28
- });
29
- }
30
-
31
- // src/core/versionEngine.ts
32
- import { cwd as cwd4 } from "node:process";
33
- import { getPackagesSync } from "@manypkg/get-packages";
34
-
35
- // src/errors/gitError.ts
36
- var GitError = class extends Error {
37
- constructor(message, code) {
38
- super(message);
39
- this.code = code;
40
- this.name = "GitError";
41
- }
42
- };
43
- function createGitError(code, details) {
44
- const messages = {
45
- ["NOT_GIT_REPO" /* NOT_GIT_REPO */]: "Not a git repository",
46
- ["GIT_PROCESS_ERROR" /* GIT_PROCESS_ERROR */]: "Failed to create new version",
47
- ["NO_FILES" /* NO_FILES */]: "No files specified for commit",
48
- ["NO_COMMIT_MESSAGE" /* NO_COMMIT_MESSAGE */]: "Commit message is required",
49
- ["GIT_ERROR" /* GIT_ERROR */]: "Git operation failed"
50
- };
51
- const baseMessage = messages[code];
52
- const fullMessage = details ? `${baseMessage}: ${details}` : baseMessage;
53
- return new GitError(fullMessage, code);
54
- }
55
-
56
- // src/errors/versionError.ts
57
- var VersionError = class extends Error {
58
- constructor(message, code) {
59
- super(message);
60
- this.code = code;
61
- this.name = "VersionError";
62
- }
63
- };
64
- function createVersionError(code, details) {
65
- const messages = {
66
- ["CONFIG_REQUIRED" /* CONFIG_REQUIRED */]: "Configuration is required",
67
- ["PACKAGES_NOT_FOUND" /* PACKAGES_NOT_FOUND */]: "Failed to get packages information",
68
- ["WORKSPACE_ERROR" /* WORKSPACE_ERROR */]: "Failed to get workspace packages",
69
- ["INVALID_CONFIG" /* INVALID_CONFIG */]: "Invalid configuration",
70
- ["PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */]: "Package not found",
71
- ["VERSION_CALCULATION_ERROR" /* VERSION_CALCULATION_ERROR */]: "Failed to calculate version"
72
- };
73
- const baseMessage = messages[code];
74
- const fullMessage = details ? `${baseMessage}: ${details}` : baseMessage;
75
- return new VersionError(fullMessage, code);
76
- }
8
+ // src/changelog/changelogRegenerator.ts
9
+ import { execSync as execSync2 } from "child_process";
10
+ import fs from "fs";
11
+ import path from "path";
77
12
 
78
13
  // src/utils/logging.ts
79
14
  import chalk from "chalk";
@@ -156,15 +91,514 @@ function log(message, level = "info") {
156
91
  }
157
92
  }
158
93
 
94
+ // src/changelog/commitParser.ts
95
+ import { execSync } from "child_process";
96
+ var CONVENTIONAL_COMMIT_REGEX = /^(\w+)(?:\(([^)]+)\))?(!)?: (.+)(?:\n\n([\s\S]*))?/;
97
+ var BREAKING_CHANGE_REGEX = /BREAKING CHANGE: ([\s\S]+?)(?:\n\n|$)/;
98
+ function extractChangelogEntriesFromCommits(projectDir, revisionRange) {
99
+ try {
100
+ const command = `git log ${revisionRange} --pretty=format:"%B---COMMIT_DELIMITER---" --no-merges`;
101
+ const output = execSync(command, {
102
+ cwd: projectDir,
103
+ encoding: "utf8"
104
+ });
105
+ const commits = output.split("---COMMIT_DELIMITER---").filter((commit) => commit.trim() !== "");
106
+ return commits.map((commit) => parseCommitMessage(commit)).filter((entry) => entry !== null);
107
+ } catch (error) {
108
+ log(`Error extracting commits: ${error}`, "error");
109
+ return [];
110
+ }
111
+ }
112
+ function parseCommitMessage(message) {
113
+ const match = message.match(CONVENTIONAL_COMMIT_REGEX);
114
+ if (match) {
115
+ const [, type, scope, breakingMark, subject, body = ""] = match;
116
+ const breakingFromMark = breakingMark === "!";
117
+ const breakingChangeMatch = body.match(BREAKING_CHANGE_REGEX);
118
+ const hasBreakingChange = breakingFromMark || breakingChangeMatch !== null;
119
+ const changelogType = mapCommitTypeToChangelogType(type);
120
+ if (!changelogType) {
121
+ return null;
122
+ }
123
+ const issueIds = extractIssueIds(body);
124
+ let description = subject;
125
+ if (hasBreakingChange) {
126
+ description = `**BREAKING** ${description}`;
127
+ }
128
+ return {
129
+ type: changelogType,
130
+ description,
131
+ scope: scope || void 0,
132
+ issueIds: issueIds.length > 0 ? issueIds : void 0,
133
+ originalType: type
134
+ // Store original type for custom formatting
135
+ };
136
+ }
137
+ if (!message.startsWith("Merge") && !message.match(/^v?\d+\.\d+\.\d+/)) {
138
+ const firstLine = message.split("\n")[0].trim();
139
+ return {
140
+ type: "changed",
141
+ description: firstLine
142
+ };
143
+ }
144
+ return null;
145
+ }
146
+ function mapCommitTypeToChangelogType(type) {
147
+ switch (type) {
148
+ case "feat":
149
+ return "added";
150
+ case "fix":
151
+ return "fixed";
152
+ case "docs":
153
+ case "style":
154
+ case "refactor":
155
+ case "perf":
156
+ case "build":
157
+ case "ci":
158
+ return "changed";
159
+ case "revert":
160
+ return "removed";
161
+ case "chore":
162
+ return "changed";
163
+ case "test":
164
+ return null;
165
+ default:
166
+ return "changed";
167
+ }
168
+ }
169
+ function extractIssueIds(body) {
170
+ const issueRegex = /(?:fix|fixes|close|closes|resolve|resolves)\s+#(\d+)/gi;
171
+ const issueIds = [];
172
+ let match = issueRegex.exec(body);
173
+ while (match !== null) {
174
+ issueIds.push(`#${match[1]}`);
175
+ match = issueRegex.exec(body);
176
+ }
177
+ return issueIds;
178
+ }
179
+
180
+ // src/changelog/formatters.ts
181
+ function formatChangelogEntries(format, version, date, entries, packageName, repoUrl) {
182
+ const formattingEntries = entries.map((entry) => {
183
+ const hasBreaking = entry.description.includes("**BREAKING**");
184
+ return {
185
+ ...entry,
186
+ breaking: hasBreaking
187
+ };
188
+ });
189
+ return format === "keep-a-changelog" ? formatKeepAChangelogEntries(version, date, formattingEntries, repoUrl) : formatAngularEntries(version, date, formattingEntries, packageName);
190
+ }
191
+ function formatKeepAChangelogEntries(version, date, entries, repoUrl) {
192
+ const added = [];
193
+ const changed = [];
194
+ const deprecated = [];
195
+ const removed = [];
196
+ const fixed = [];
197
+ const security = [];
198
+ for (const entry of entries) {
199
+ const entryText = entry.scope ? `- **${entry.scope}**: ${entry.description}` : `- ${entry.description}`;
200
+ const formattedEntry = entry.breaking ? entryText.replace(/^- /, "- **BREAKING** ") : entryText;
201
+ const entryType = entry.originalType || entry.type;
202
+ switch (entryType) {
203
+ case "feat":
204
+ added.push(formattedEntry);
205
+ break;
206
+ case "fix":
207
+ fixed.push(formattedEntry);
208
+ break;
209
+ case "docs":
210
+ case "style":
211
+ case "refactor":
212
+ case "perf":
213
+ case "build":
214
+ case "ci":
215
+ changed.push(formattedEntry);
216
+ break;
217
+ case "test":
218
+ break;
219
+ case "chore":
220
+ if (entry.description.toLowerCase().includes("deprecat")) {
221
+ deprecated.push(formattedEntry);
222
+ } else {
223
+ changed.push(formattedEntry);
224
+ }
225
+ break;
226
+ // Keep-a-changelog standard types
227
+ case "added":
228
+ added.push(formattedEntry);
229
+ break;
230
+ case "changed":
231
+ changed.push(formattedEntry);
232
+ break;
233
+ case "deprecated":
234
+ deprecated.push(formattedEntry);
235
+ break;
236
+ case "removed":
237
+ removed.push(formattedEntry);
238
+ break;
239
+ case "fixed":
240
+ fixed.push(formattedEntry);
241
+ break;
242
+ case "security":
243
+ security.push(formattedEntry);
244
+ break;
245
+ default:
246
+ changed.push(formattedEntry);
247
+ }
248
+ }
249
+ let content = `## [${version}] - ${date}
250
+
251
+ `;
252
+ if (added.length > 0) {
253
+ content += `### Added
254
+
255
+ ${added.join("\n")}
256
+
257
+ `;
258
+ }
259
+ if (changed.length > 0) {
260
+ content += `### Changed
261
+
262
+ ${changed.join("\n")}
263
+
264
+ `;
265
+ }
266
+ if (deprecated.length > 0) {
267
+ content += `### Deprecated
268
+
269
+ ${deprecated.join("\n")}
270
+
271
+ `;
272
+ }
273
+ if (removed.length > 0) {
274
+ content += `### Removed
275
+
276
+ ${removed.join("\n")}
277
+
278
+ `;
279
+ }
280
+ if (fixed.length > 0) {
281
+ content += `### Fixed
282
+
283
+ ${fixed.join("\n")}
284
+
285
+ `;
286
+ }
287
+ if (security.length > 0) {
288
+ content += `### Security
289
+
290
+ ${security.join("\n")}
291
+
292
+ `;
293
+ }
294
+ if (repoUrl) {
295
+ content += `[${version}]: ${repoUrl}/compare/v${version}...HEAD
296
+ `;
297
+ }
298
+ return content.trim();
299
+ }
300
+ function formatAngularEntries(version, date, entries, packageName) {
301
+ const features = [];
302
+ const bugfixes = [];
303
+ const performance = [];
304
+ const breaking = [];
305
+ for (const entry of entries) {
306
+ if (entry.breaking) {
307
+ breaking.push(entry);
308
+ }
309
+ const entryType = entry.originalType || entry.type;
310
+ switch (entryType) {
311
+ case "feat":
312
+ case "added":
313
+ features.push(entry);
314
+ break;
315
+ case "fix":
316
+ case "fixed":
317
+ bugfixes.push(entry);
318
+ break;
319
+ case "perf":
320
+ performance.push(entry);
321
+ break;
322
+ }
323
+ }
324
+ let content = `## [${version}]${packageName ? ` (${packageName})` : ""} (${date})
325
+
326
+ `;
327
+ if (features.length > 0) {
328
+ content += "### Features\n\n";
329
+ content += formatAngularTypeEntries(features);
330
+ content += "\n";
331
+ }
332
+ if (bugfixes.length > 0) {
333
+ content += "### Bug Fixes\n\n";
334
+ content += formatAngularTypeEntries(bugfixes);
335
+ content += "\n";
336
+ }
337
+ if (performance.length > 0) {
338
+ content += "### Performance Improvements\n\n";
339
+ content += formatAngularTypeEntries(performance);
340
+ content += "\n";
341
+ }
342
+ if (breaking.length > 0) {
343
+ content += "### BREAKING CHANGES\n\n";
344
+ content += formatAngularTypeEntries(breaking);
345
+ content += "\n";
346
+ }
347
+ return content.trim();
348
+ }
349
+ function formatAngularTypeEntries(entries) {
350
+ var _a;
351
+ const entriesByScope = /* @__PURE__ */ new Map();
352
+ for (const entry of entries) {
353
+ const scope = entry.scope || "";
354
+ if (!entriesByScope.has(scope)) {
355
+ entriesByScope.set(scope, []);
356
+ }
357
+ (_a = entriesByScope.get(scope)) == null ? void 0 : _a.push(entry);
358
+ }
359
+ const result = [];
360
+ for (const [scope, scopeEntries] of Object.entries(groupEntriesByScope(entries))) {
361
+ if (scope !== "undefined" && scope !== "") {
362
+ result.push(`* **${scope}:**`);
363
+ for (const entry of scopeEntries) {
364
+ const description = entry.description.replace("**BREAKING** ", "");
365
+ result.push(` * ${description}`);
366
+ }
367
+ } else {
368
+ for (const entry of scopeEntries) {
369
+ const description = entry.description.replace("**BREAKING** ", "");
370
+ result.push(`* ${description}`);
371
+ }
372
+ }
373
+ }
374
+ return result.join("\n");
375
+ }
376
+ function groupEntriesByScope(entries) {
377
+ const result = {};
378
+ for (const entry of entries) {
379
+ const scope = entry.scope || "";
380
+ if (!result[scope]) {
381
+ result[scope] = [];
382
+ }
383
+ result[scope].push(entry);
384
+ }
385
+ return result;
386
+ }
387
+
388
+ // src/changelog/templates.ts
389
+ function getDefaultTemplate(format) {
390
+ return format === "keep-a-changelog" ? getKeepAChangelogTemplate() : getAngularTemplate();
391
+ }
392
+ function getKeepAChangelogTemplate() {
393
+ return `# Changelog
394
+
395
+ All notable changes to this project will be documented in this file.
396
+
397
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
398
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
399
+
400
+ `;
401
+ }
402
+ function getAngularTemplate() {
403
+ return `# Changelog
404
+
405
+ `;
406
+ }
407
+
408
+ // src/changelog/changelogRegenerator.ts
409
+ function getAllVersionTags(since, versionPrefix = "v") {
410
+ try {
411
+ const command = since ? `git tag --list "${versionPrefix}*" --sort=creatordate --contains ${since}` : `git tag --list "${versionPrefix}*" --sort=creatordate`;
412
+ const tagOutput = execSync2(command, { encoding: "utf8" }).trim();
413
+ if (!tagOutput) {
414
+ return [];
415
+ }
416
+ const tags = tagOutput.split("\n").filter((tag) => !!tag);
417
+ return tags.map((tag) => {
418
+ try {
419
+ const date = execSync2(`git log -1 --format=%ad --date=short ${tag}`, {
420
+ encoding: "utf8"
421
+ }).trim();
422
+ const version = tag.replace(new RegExp(`^${versionPrefix}`), "");
423
+ return { tag, version, date };
424
+ } catch (error) {
425
+ log(`Failed to get date for tag ${tag}: ${error}`, "warning");
426
+ return { tag, version: tag.replace(new RegExp(`^${versionPrefix}`), ""), date: "Unknown" };
427
+ }
428
+ });
429
+ } catch (error) {
430
+ log(`Failed to get version tags: ${error}`, "error");
431
+ return [];
432
+ }
433
+ }
434
+ async function regenerateChangelog(options) {
435
+ const { format, since, projectDir } = options;
436
+ const packageJsonPath = path.join(projectDir, "package.json");
437
+ let packageName = "";
438
+ let repoUrl = options.repoUrl;
439
+ if (fs.existsSync(packageJsonPath)) {
440
+ try {
441
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
442
+ packageName = packageJson.name || "";
443
+ if (!repoUrl && packageJson.repository) {
444
+ if (typeof packageJson.repository === "string") {
445
+ repoUrl = packageJson.repository;
446
+ } else if (packageJson.repository.url) {
447
+ repoUrl = packageJson.repository.url;
448
+ }
449
+ if ((repoUrl == null ? void 0 : repoUrl.startsWith("git+")) && (repoUrl == null ? void 0 : repoUrl.endsWith(".git"))) {
450
+ repoUrl = repoUrl.substring(4, repoUrl.length - 4);
451
+ }
452
+ }
453
+ } catch (error) {
454
+ log(`Failed to read package.json: ${error}`, "warning");
455
+ }
456
+ }
457
+ let versionPrefix = "v";
458
+ try {
459
+ const allTags = execSync2("git tag --list", { encoding: "utf8" }).trim().split("\n");
460
+ const versionTag = allTags.find((tag) => /^[vV][0-9]/.test(tag));
461
+ if (versionTag) {
462
+ versionPrefix = versionTag.charAt(0);
463
+ }
464
+ } catch {
465
+ }
466
+ const tags = getAllVersionTags(since, versionPrefix);
467
+ if (!tags.length) {
468
+ throw new Error(
469
+ 'No version tags found in git history. Make sure you have tags that start with the version prefix (usually "v").'
470
+ );
471
+ }
472
+ let changelogContent = getDefaultTemplate(format);
473
+ log(`Found ${tags.length} version tags, generating changelog...`, "info");
474
+ const versions = [];
475
+ for (let i = tags.length - 1; i >= 0; i--) {
476
+ const currentTag = tags[i];
477
+ const previousTag = i > 0 ? tags[i - 1].tag : null;
478
+ log(`Processing changes for ${currentTag.tag}...`, "info");
479
+ try {
480
+ const tagRange = previousTag ? `${previousTag}..${currentTag.tag}` : currentTag.tag;
481
+ const entries = extractChangelogEntriesFromCommits(projectDir, tagRange);
482
+ if (!entries.length) {
483
+ log(`No changelog entries found for ${currentTag.tag}, adding placeholder entry`, "info");
484
+ entries.push({
485
+ type: "changed",
486
+ description: `Release version ${currentTag.version}`
487
+ });
488
+ }
489
+ versions.unshift(
490
+ formatChangelogEntries(
491
+ format,
492
+ currentTag.version,
493
+ currentTag.date,
494
+ entries,
495
+ packageName,
496
+ repoUrl
497
+ )
498
+ );
499
+ } catch (error) {
500
+ log(`Failed to process version ${currentTag.tag}: ${error}`, "error");
501
+ }
502
+ }
503
+ changelogContent += versions.join("\n\n");
504
+ return changelogContent;
505
+ }
506
+ async function writeChangelog(content, outputPath, dryRun) {
507
+ if (dryRun) {
508
+ log("--- Changelog Preview ---", "info");
509
+ console.log(content);
510
+ log("--- End Preview ---", "info");
511
+ return;
512
+ }
513
+ try {
514
+ fs.writeFileSync(outputPath, content, "utf8");
515
+ log(`Changelog successfully written to ${outputPath}`, "success");
516
+ } catch (error) {
517
+ throw new Error(
518
+ `Failed to write changelog: ${error instanceof Error ? error.message : String(error)}`
519
+ );
520
+ }
521
+ }
522
+
523
+ // src/config.ts
524
+ import * as fs2 from "fs";
525
+ import { cwd } from "process";
526
+ function loadConfig(configPath) {
527
+ const localProcess = cwd();
528
+ const filePath = configPath || `${localProcess}/version.config.json`;
529
+ return new Promise((resolve, reject) => {
530
+ fs2.readFile(filePath, "utf-8", (err, data) => {
531
+ if (err) {
532
+ reject(new Error(`Could not locate the config file at ${filePath}: ${err.message}`));
533
+ return;
534
+ }
535
+ try {
536
+ const config = JSON.parse(data);
537
+ resolve(config);
538
+ } catch (err2) {
539
+ const errorMessage = err2 instanceof Error ? err2.message : String(err2);
540
+ reject(new Error(`Failed to parse config file ${filePath}: ${errorMessage}`));
541
+ }
542
+ });
543
+ });
544
+ }
545
+
546
+ // src/core/versionEngine.ts
547
+ import { cwd as cwd4 } from "process";
548
+ import { getPackagesSync } from "@manypkg/get-packages";
549
+
550
+ // src/errors/gitError.ts
551
+ var GitError = class extends Error {
552
+ constructor(message, code) {
553
+ super(message);
554
+ this.code = code;
555
+ this.name = "GitError";
556
+ }
557
+ };
558
+ function createGitError(code, details) {
559
+ const messages = {
560
+ ["NOT_GIT_REPO" /* NOT_GIT_REPO */]: "Not a git repository",
561
+ ["GIT_PROCESS_ERROR" /* GIT_PROCESS_ERROR */]: "Failed to create new version",
562
+ ["NO_FILES" /* NO_FILES */]: "No files specified for commit",
563
+ ["NO_COMMIT_MESSAGE" /* NO_COMMIT_MESSAGE */]: "Commit message is required",
564
+ ["GIT_ERROR" /* GIT_ERROR */]: "Git operation failed"
565
+ };
566
+ const baseMessage = messages[code];
567
+ const fullMessage = details ? `${baseMessage}: ${details}` : baseMessage;
568
+ return new GitError(fullMessage, code);
569
+ }
570
+
571
+ // src/errors/versionError.ts
572
+ var VersionError = class extends Error {
573
+ constructor(message, code) {
574
+ super(message);
575
+ this.code = code;
576
+ this.name = "VersionError";
577
+ }
578
+ };
579
+ function createVersionError(code, details) {
580
+ const messages = {
581
+ ["CONFIG_REQUIRED" /* CONFIG_REQUIRED */]: "Configuration is required",
582
+ ["PACKAGES_NOT_FOUND" /* PACKAGES_NOT_FOUND */]: "Failed to get packages information",
583
+ ["WORKSPACE_ERROR" /* WORKSPACE_ERROR */]: "Failed to get workspace packages",
584
+ ["INVALID_CONFIG" /* INVALID_CONFIG */]: "Invalid configuration",
585
+ ["PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */]: "Package not found",
586
+ ["VERSION_CALCULATION_ERROR" /* VERSION_CALCULATION_ERROR */]: "Failed to calculate version"
587
+ };
588
+ const baseMessage = messages[code];
589
+ const fullMessage = details ? `${baseMessage}: ${details}` : baseMessage;
590
+ return new VersionError(fullMessage, code);
591
+ }
592
+
159
593
  // src/core/versionStrategies.ts
160
- import fs6 from "node:fs";
161
- import * as path4 from "node:path";
594
+ import fs9 from "fs";
595
+ import * as path7 from "path";
162
596
 
163
597
  // src/git/commands.ts
164
- import { cwd as cwd2 } from "node:process";
598
+ import { cwd as cwd2 } from "process";
165
599
 
166
600
  // src/git/commandExecutor.ts
167
- import { exec, execSync as nativeExecSync } from "node:child_process";
601
+ import { exec, execSync as nativeExecSync } from "child_process";
168
602
  var execAsync = (command, options) => {
169
603
  const defaultOptions = { maxBuffer: 1024 * 1024 * 10, ...options };
170
604
  return new Promise((resolve, reject) => {
@@ -181,11 +615,11 @@ var execAsync = (command, options) => {
181
615
  );
182
616
  });
183
617
  };
184
- var execSync = (command, args) => nativeExecSync(command, { maxBuffer: 1024 * 1024 * 10, ...args });
618
+ var execSync3 = (command, args) => nativeExecSync(command, { maxBuffer: 1024 * 1024 * 10, ...args });
185
619
 
186
620
  // src/git/repository.ts
187
- import { existsSync, statSync } from "node:fs";
188
- import { join } from "node:path";
621
+ import { existsSync, statSync } from "fs";
622
+ import { join } from "path";
189
623
  function isGitRepository(directory) {
190
624
  const gitDir = join(directory, ".git");
191
625
  if (!existsSync(gitDir)) {
@@ -196,14 +630,14 @@ function isGitRepository(directory) {
196
630
  return false;
197
631
  }
198
632
  try {
199
- execSync("git rev-parse --is-inside-work-tree", { cwd: directory });
633
+ execSync3("git rev-parse --is-inside-work-tree", { cwd: directory });
200
634
  return true;
201
635
  } catch (_error) {
202
636
  return false;
203
637
  }
204
638
  }
205
639
  function getCurrentBranch() {
206
- const result = execSync("git rev-parse --abbrev-ref HEAD");
640
+ const result = execSync3("git rev-parse --abbrev-ref HEAD");
207
641
  return result.toString().trim();
208
642
  }
209
643
 
@@ -265,6 +699,11 @@ async function gitProcess(options) {
265
699
  }
266
700
  } catch (err) {
267
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
+ }
268
707
  throw createGitError("GIT_PROCESS_ERROR" /* GIT_PROCESS_ERROR */, errorMessage);
269
708
  }
270
709
  }
@@ -294,9 +733,16 @@ async function createGitCommitAndTag(files, nextTag, commitMessage, skipHooks, d
294
733
  const errorMessage = error instanceof Error ? error.message : String(error);
295
734
  log(`Failed to create git commit and tag: ${errorMessage}`, "error");
296
735
  if (error instanceof Error) {
736
+ console.error("Git operation error details:");
297
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
+ }
298
744
  } else {
299
- console.error(error);
745
+ console.error("Unknown git error:", error);
300
746
  }
301
747
  throw new GitError(`Git operation failed: ${errorMessage}`, "GIT_ERROR" /* GIT_ERROR */);
302
748
  }
@@ -347,7 +793,7 @@ function createTemplateString(template, variables) {
347
793
  function getCommitsLength(pkgRoot) {
348
794
  try {
349
795
  const gitCommand = `git rev-list --count HEAD ^$(git describe --tags --abbrev=0) ${pkgRoot}`;
350
- const amount = execSync(gitCommand).toString().trim();
796
+ const amount = execSync3(gitCommand).toString().trim();
351
797
  return Number(amount);
352
798
  } catch (error) {
353
799
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -444,20 +890,21 @@ async function getLatestTagForPackage(packageName, versionPrefix) {
444
890
  }
445
891
 
446
892
  // src/package/packageManagement.ts
447
- import fs3 from "node:fs";
893
+ import fs4 from "fs";
894
+ import path3 from "path";
448
895
 
449
896
  // src/cargo/cargoHandler.ts
450
- import fs2 from "node:fs";
451
- import path from "node:path";
897
+ import fs3 from "fs";
898
+ import path2 from "path";
452
899
  import * as TOML from "smol-toml";
453
900
  function getCargoInfo(cargoPath) {
454
901
  var _a;
455
- if (!fs2.existsSync(cargoPath)) {
902
+ if (!fs3.existsSync(cargoPath)) {
456
903
  log(`Cargo.toml file not found at: ${cargoPath}`, "error");
457
904
  throw new Error(`Cargo.toml file not found at: ${cargoPath}`);
458
905
  }
459
906
  try {
460
- const fileContent = fs2.readFileSync(cargoPath, "utf8");
907
+ const fileContent = fs3.readFileSync(cargoPath, "utf8");
461
908
  const cargo = TOML.parse(fileContent);
462
909
  if (!((_a = cargo.package) == null ? void 0 : _a.name)) {
463
910
  log(`Package name not found in: ${cargoPath}`, "error");
@@ -467,7 +914,7 @@ function getCargoInfo(cargoPath) {
467
914
  name: cargo.package.name,
468
915
  version: cargo.package.version || "0.0.0",
469
916
  path: cargoPath,
470
- dir: path.dirname(cargoPath),
917
+ dir: path2.dirname(cargoPath),
471
918
  content: cargo
472
919
  };
473
920
  } catch (error) {
@@ -480,12 +927,12 @@ function getCargoInfo(cargoPath) {
480
927
  }
481
928
  }
482
929
  function isCargoToml(filePath) {
483
- return path.basename(filePath) === "Cargo.toml";
930
+ return path2.basename(filePath) === "Cargo.toml";
484
931
  }
485
932
  function updateCargoVersion(cargoPath, version) {
486
933
  var _a;
487
934
  try {
488
- const originalContent = fs2.readFileSync(cargoPath, "utf8");
935
+ const originalContent = fs3.readFileSync(cargoPath, "utf8");
489
936
  const cargo = TOML.parse(originalContent);
490
937
  const packageName = (_a = cargo.package) == null ? void 0 : _a.name;
491
938
  if (!packageName) {
@@ -497,7 +944,7 @@ function updateCargoVersion(cargoPath, version) {
497
944
  cargo.package.version = version;
498
945
  }
499
946
  const updatedContent = TOML.stringify(cargo);
500
- fs2.writeFileSync(cargoPath, updatedContent);
947
+ fs3.writeFileSync(cargoPath, updatedContent);
501
948
  addPackageUpdate(packageName, version, cargoPath);
502
949
  log(`Updated Cargo.toml at ${cargoPath} to version ${version}`, "success");
503
950
  } catch (error) {
@@ -516,11 +963,11 @@ function updatePackageVersion(packagePath, version) {
516
963
  return;
517
964
  }
518
965
  try {
519
- const packageContent = fs3.readFileSync(packagePath, "utf8");
966
+ const packageContent = fs4.readFileSync(packagePath, "utf8");
520
967
  const packageJson = JSON.parse(packageContent);
521
968
  const packageName = packageJson.name;
522
969
  packageJson.version = version;
523
- fs3.writeFileSync(packagePath, `${JSON.stringify(packageJson, null, 2)}
970
+ fs4.writeFileSync(packagePath, `${JSON.stringify(packageJson, null, 2)}
524
971
  `);
525
972
  addPackageUpdate(packageName, version, packagePath);
526
973
  log(`Updated package.json at ${packagePath} to version ${version}`, "success");
@@ -534,24 +981,349 @@ function updatePackageVersion(packagePath, version) {
534
981
  }
535
982
 
536
983
  // src/package/packageProcessor.ts
537
- import * as fs5 from "node:fs";
538
- import path3 from "node:path";
539
- import { exit } from "node:process";
984
+ import * as fs8 from "fs";
985
+ import path6 from "path";
986
+ import { exit } from "process";
987
+
988
+ // src/changelog/changelogManager.ts
989
+ import * as fs5 from "fs";
990
+ import * as path4 from "path";
991
+ function createChangelog(_packagePath, packageName) {
992
+ return {
993
+ projectName: packageName,
994
+ unreleased: [],
995
+ versions: []
996
+ };
997
+ }
998
+ function parseChangelog(filePath) {
999
+ try {
1000
+ if (!fs5.existsSync(filePath)) {
1001
+ return null;
1002
+ }
1003
+ fs5.readFileSync(filePath, "utf8");
1004
+ log(`Parsed changelog at ${filePath}`, "info");
1005
+ return {
1006
+ projectName: path4.basename(path4.dirname(filePath)),
1007
+ unreleased: [],
1008
+ versions: []
1009
+ };
1010
+ } catch (error) {
1011
+ log(
1012
+ `Error parsing changelog: ${error instanceof Error ? error.message : String(error)}`,
1013
+ "error"
1014
+ );
1015
+ return null;
1016
+ }
1017
+ }
1018
+ function generateLinks(changelog, repoUrl) {
1019
+ var _a, _b;
1020
+ if (!repoUrl || changelog.versions.length === 0) {
1021
+ return "";
1022
+ }
1023
+ let links = "\n";
1024
+ if (changelog.unreleased.length > 0) {
1025
+ const latestVersion = ((_a = changelog.versions[0]) == null ? void 0 : _a.version) || "";
1026
+ links += `[unreleased]: ${repoUrl}/compare/v${latestVersion}...HEAD
1027
+ `;
1028
+ }
1029
+ for (let i = 0; i < changelog.versions.length; i++) {
1030
+ const currentVersion = changelog.versions[i].version;
1031
+ const previousVersion = (_b = changelog.versions[i + 1]) == null ? void 0 : _b.version;
1032
+ if (previousVersion) {
1033
+ links += `[${currentVersion}]: ${repoUrl}/compare/v${previousVersion}...v${currentVersion}
1034
+ `;
1035
+ } else if (i === changelog.versions.length - 1) {
1036
+ links += `[${currentVersion}]: ${repoUrl}/releases/tag/v${currentVersion}
1037
+ `;
1038
+ }
1039
+ }
1040
+ return links;
1041
+ }
1042
+ function generateAngularChangelogContent(changelog, repoUrl) {
1043
+ let content = "# Changelog\n\n";
1044
+ if (changelog.unreleased.length > 0) {
1045
+ content += "## [Unreleased]\n\n";
1046
+ const groupedByType = groupEntriesByAngularType(changelog.unreleased);
1047
+ for (const [type, entries] of Object.entries(groupedByType)) {
1048
+ content += `### ${formatAngularType(type)}
1049
+
1050
+ `;
1051
+ const groupedByScope = groupEntriesByScope2(entries);
1052
+ for (const [scope, scopeEntries] of Object.entries(groupedByScope)) {
1053
+ if (scope !== "undefined" && scope !== "") {
1054
+ content += `* **${scope}:**
1055
+ `;
1056
+ for (const entry of scopeEntries) {
1057
+ content += formatAngularEntry(entry, false);
1058
+ }
1059
+ content += "\n";
1060
+ } else {
1061
+ for (const entry of scopeEntries) {
1062
+ content += formatAngularEntry(entry, true);
1063
+ }
1064
+ }
1065
+ }
1066
+ content += "\n";
1067
+ }
1068
+ const breakingChanges = changelog.unreleased.filter(
1069
+ (entry) => entry.description.includes("**BREAKING**")
1070
+ );
1071
+ if (breakingChanges.length > 0) {
1072
+ content += "### BREAKING CHANGES\n\n";
1073
+ for (const entry of breakingChanges) {
1074
+ const description = entry.description.replace("**BREAKING** ", "");
1075
+ content += `* ${entry.scope ? `**${entry.scope}:** ` : ""}${description}`;
1076
+ if (entry.issueIds && entry.issueIds.length > 0) {
1077
+ content += ` (${entry.issueIds.join(", ")})`;
1078
+ }
1079
+ content += "\n";
1080
+ }
1081
+ content += "\n";
1082
+ }
1083
+ }
1084
+ for (const version of changelog.versions) {
1085
+ content += `## [${version.version}] - ${version.date}
1086
+
1087
+ `;
1088
+ const groupedByType = groupEntriesByAngularType(version.entries);
1089
+ for (const [type, entries] of Object.entries(groupedByType)) {
1090
+ content += `### ${formatAngularType(type)}
1091
+
1092
+ `;
1093
+ const groupedByScope = groupEntriesByScope2(entries);
1094
+ for (const [scope, scopeEntries] of Object.entries(groupedByScope)) {
1095
+ if (scope !== "undefined" && scope !== "") {
1096
+ content += `* **${scope}:**
1097
+ `;
1098
+ for (const entry of scopeEntries) {
1099
+ content += formatAngularEntry(entry, false);
1100
+ }
1101
+ content += "\n";
1102
+ } else {
1103
+ for (const entry of scopeEntries) {
1104
+ content += formatAngularEntry(entry, true);
1105
+ }
1106
+ }
1107
+ }
1108
+ content += "\n";
1109
+ }
1110
+ const breakingChanges = version.entries.filter(
1111
+ (entry) => entry.description.includes("**BREAKING**")
1112
+ );
1113
+ if (breakingChanges.length > 0) {
1114
+ content += "### BREAKING CHANGES\n\n";
1115
+ for (const entry of breakingChanges) {
1116
+ const description = entry.description.replace("**BREAKING** ", "");
1117
+ content += `* ${entry.scope ? `**${entry.scope}:** ` : ""}${description}`;
1118
+ if (entry.issueIds && entry.issueIds.length > 0) {
1119
+ content += ` (${entry.issueIds.join(", ")})`;
1120
+ }
1121
+ content += "\n";
1122
+ }
1123
+ content += "\n";
1124
+ }
1125
+ }
1126
+ content += generateLinks(changelog, repoUrl);
1127
+ return content;
1128
+ }
1129
+ function groupEntriesByAngularType(entries) {
1130
+ const result = {};
1131
+ for (const entry of entries) {
1132
+ const type = entry.originalType || mapToAngularType(entry.type);
1133
+ if (!result[type]) {
1134
+ result[type] = [];
1135
+ }
1136
+ result[type].push(entry);
1137
+ }
1138
+ return result;
1139
+ }
1140
+ function mapToAngularType(type) {
1141
+ switch (type) {
1142
+ case "added":
1143
+ return "feat";
1144
+ case "fixed":
1145
+ return "fix";
1146
+ case "changed":
1147
+ return "perf";
1148
+ case "deprecated":
1149
+ case "removed":
1150
+ case "security":
1151
+ return type;
1152
+ default:
1153
+ return type;
1154
+ }
1155
+ }
1156
+ function formatAngularType(type) {
1157
+ switch (type) {
1158
+ case "feat":
1159
+ return "Features";
1160
+ case "fix":
1161
+ return "Bug Fixes";
1162
+ case "perf":
1163
+ return "Performance Improvements";
1164
+ case "security":
1165
+ return "Security";
1166
+ case "deprecated":
1167
+ return "Deprecated";
1168
+ case "removed":
1169
+ return "Removed";
1170
+ default:
1171
+ return capitalizeFirstLetter(type);
1172
+ }
1173
+ }
1174
+ function groupEntriesByScope2(entries) {
1175
+ const result = {};
1176
+ for (const entry of entries) {
1177
+ const scope = entry.scope || "";
1178
+ if (!result[scope]) {
1179
+ result[scope] = [];
1180
+ }
1181
+ result[scope].push(entry);
1182
+ }
1183
+ return result;
1184
+ }
1185
+ function formatAngularEntry(entry, includeScope) {
1186
+ let result = " * ";
1187
+ if (includeScope && entry.scope) {
1188
+ result += `**${entry.scope}:** `;
1189
+ }
1190
+ let description = entry.description;
1191
+ if (!includeScope && entry.scope && description.startsWith(`**${entry.scope}**: `)) {
1192
+ description = description.substring(`**${entry.scope}**: `.length);
1193
+ }
1194
+ if (description.startsWith("**BREAKING** ")) {
1195
+ description = description.substring("**BREAKING** ".length);
1196
+ }
1197
+ result += description;
1198
+ if (entry.issueIds && entry.issueIds.length > 0) {
1199
+ result += ` (${entry.issueIds.join(", ")})`;
1200
+ }
1201
+ result += "\n";
1202
+ return result;
1203
+ }
1204
+ function generateChangelogContent(changelog, repoUrl, format = "keep-a-changelog") {
1205
+ if (format === "angular") {
1206
+ return generateAngularChangelogContent(changelog, repoUrl);
1207
+ }
1208
+ let content = "# Changelog\n\n";
1209
+ content += `All notable changes to ${changelog.projectName} will be documented in this file.
1210
+
1211
+ `;
1212
+ content += "The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),\n";
1213
+ content += "and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n";
1214
+ if (changelog.unreleased.length > 0) {
1215
+ content += "## [Unreleased]\n\n";
1216
+ const grouped = changelog.unreleased.reduce(
1217
+ (acc, entry) => {
1218
+ if (!acc[entry.type]) {
1219
+ acc[entry.type] = [];
1220
+ }
1221
+ acc[entry.type].push(entry);
1222
+ return acc;
1223
+ },
1224
+ {}
1225
+ );
1226
+ for (const [type, entries] of Object.entries(grouped)) {
1227
+ content += `### ${capitalizeFirstLetter(type)}
1228
+
1229
+ `;
1230
+ for (const entry of entries) {
1231
+ let entryText = `- ${entry.description}`;
1232
+ if (entry.issueIds && entry.issueIds.length > 0) {
1233
+ entryText += ` (${entry.issueIds.join(", ")})`;
1234
+ }
1235
+ content += `${entryText}.
1236
+ `;
1237
+ }
1238
+ content += "\n";
1239
+ }
1240
+ }
1241
+ for (const version of changelog.versions) {
1242
+ content += `## [${version.version}] - ${version.date}
1243
+
1244
+ `;
1245
+ const grouped = version.entries.reduce(
1246
+ (acc, entry) => {
1247
+ if (!acc[entry.type]) {
1248
+ acc[entry.type] = [];
1249
+ }
1250
+ acc[entry.type].push(entry);
1251
+ return acc;
1252
+ },
1253
+ {}
1254
+ );
1255
+ for (const [type, entries] of Object.entries(grouped)) {
1256
+ content += `### ${capitalizeFirstLetter(type)}
1257
+
1258
+ `;
1259
+ for (const entry of entries) {
1260
+ let entryText = `- ${entry.description}`;
1261
+ if (entry.issueIds && entry.issueIds.length > 0) {
1262
+ entryText += ` (${entry.issueIds.join(", ")})`;
1263
+ }
1264
+ content += `${entryText}.
1265
+ `;
1266
+ }
1267
+ content += "\n";
1268
+ }
1269
+ }
1270
+ content += generateLinks(changelog, repoUrl);
1271
+ return content;
1272
+ }
1273
+ function updateChangelog(packagePath, packageName, version, entries, repoUrl, format = "keep-a-changelog") {
1274
+ try {
1275
+ const changelogPath = path4.join(packagePath, "CHANGELOG.md");
1276
+ let changelog;
1277
+ if (fs5.existsSync(changelogPath)) {
1278
+ const existingChangelog = parseChangelog(changelogPath);
1279
+ if (existingChangelog) {
1280
+ changelog = existingChangelog;
1281
+ } else {
1282
+ changelog = createChangelog(packagePath, packageName);
1283
+ }
1284
+ } else {
1285
+ changelog = createChangelog(packagePath, packageName);
1286
+ }
1287
+ if (version) {
1288
+ const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1289
+ const newVersion = {
1290
+ version,
1291
+ date: today,
1292
+ entries: [...changelog.unreleased, ...entries]
1293
+ };
1294
+ changelog.unreleased = [];
1295
+ changelog.versions.unshift(newVersion);
1296
+ } else {
1297
+ changelog.unreleased = [...changelog.unreleased, ...entries];
1298
+ }
1299
+ const content = generateChangelogContent(changelog, repoUrl, format);
1300
+ fs5.writeFileSync(changelogPath, content);
1301
+ log(`Updated changelog at ${changelogPath}`, "success");
1302
+ } catch (error) {
1303
+ log(
1304
+ `Error updating changelog: ${error instanceof Error ? error.message : String(error)}`,
1305
+ "error"
1306
+ );
1307
+ }
1308
+ }
1309
+ function capitalizeFirstLetter(input) {
1310
+ return input.charAt(0).toUpperCase() + input.slice(1);
1311
+ }
540
1312
 
541
1313
  // src/core/versionCalculator.ts
542
- import { cwd as cwd3 } from "node:process";
1314
+ import { cwd as cwd3 } from "process";
543
1315
  import { Bumper } from "conventional-recommended-bump";
544
1316
  import semver2 from "semver";
545
1317
 
546
1318
  // src/utils/manifestHelpers.ts
547
- import fs4 from "node:fs";
548
- import path2 from "node:path";
1319
+ import fs6 from "fs";
1320
+ import path5 from "path";
549
1321
  function getVersionFromManifests(packageDir) {
550
- const packageJsonPath = path2.join(packageDir, "package.json");
551
- const cargoTomlPath = path2.join(packageDir, "Cargo.toml");
552
- if (fs4.existsSync(packageJsonPath)) {
1322
+ const packageJsonPath = path5.join(packageDir, "package.json");
1323
+ const cargoTomlPath = path5.join(packageDir, "Cargo.toml");
1324
+ if (fs6.existsSync(packageJsonPath)) {
553
1325
  try {
554
- const packageJson = JSON.parse(fs4.readFileSync(packageJsonPath, "utf-8"));
1326
+ const packageJson = JSON.parse(fs6.readFileSync(packageJsonPath, "utf-8"));
555
1327
  if (packageJson.version) {
556
1328
  log(`Found version ${packageJson.version} in package.json`, "debug");
557
1329
  return {
@@ -567,7 +1339,7 @@ function getVersionFromManifests(packageDir) {
567
1339
  log(`Error reading package.json: ${errMsg}`, "warning");
568
1340
  }
569
1341
  }
570
- if (fs4.existsSync(cargoTomlPath)) {
1342
+ if (fs6.existsSync(cargoTomlPath)) {
571
1343
  try {
572
1344
  const cargoInfo = getCargoInfo(cargoTomlPath);
573
1345
  if (cargoInfo.version) {
@@ -593,14 +1365,15 @@ function getVersionFromManifests(packageDir) {
593
1365
  };
594
1366
  }
595
1367
  function throwIfNoManifestsFound(packageDir) {
596
- const packageJsonPath = path2.join(packageDir, "package.json");
597
- const cargoTomlPath = path2.join(packageDir, "Cargo.toml");
1368
+ const packageJsonPath = path5.join(packageDir, "package.json");
1369
+ const cargoTomlPath = path5.join(packageDir, "Cargo.toml");
598
1370
  throw new Error(
599
1371
  `Neither package.json nor Cargo.toml found at ${packageDir}. Checked paths: ${packageJsonPath}, ${cargoTomlPath}. Cannot determine version.`
600
1372
  );
601
1373
  }
602
1374
 
603
1375
  // src/utils/versionUtils.ts
1376
+ import fs7 from "fs";
604
1377
  import semver from "semver";
605
1378
  import * as TOML2 from "smol-toml";
606
1379
  var STANDARD_BUMP_TYPES = ["major", "minor", "patch"];
@@ -849,7 +1622,7 @@ var PackageProcessor = class {
849
1622
  * Process packages based on targeting criteria
850
1623
  */
851
1624
  async processPackages(packages) {
852
- var _a;
1625
+ var _a, _b, _c, _d, _e;
853
1626
  const tags = [];
854
1627
  const updatedPackagesInfo = [];
855
1628
  if (!packages || !Array.isArray(packages)) {
@@ -934,13 +1707,81 @@ var PackageProcessor = class {
934
1707
  if (!nextVersion) {
935
1708
  continue;
936
1709
  }
937
- const packageJsonPath = path3.join(pkgPath, "package.json");
938
- const cargoTomlPath = path3.join(pkgPath, "Cargo.toml");
939
- if (fs5.existsSync(packageJsonPath)) {
1710
+ if (this.fullConfig.updateChangelog !== false) {
1711
+ let changelogEntries = [];
1712
+ try {
1713
+ changelogEntries = extractChangelogEntriesFromCommits(pkgPath, latestTag);
1714
+ if (changelogEntries.length === 0) {
1715
+ changelogEntries = [
1716
+ {
1717
+ type: "changed",
1718
+ description: `Update version to ${nextVersion}`
1719
+ }
1720
+ ];
1721
+ }
1722
+ } catch (error) {
1723
+ log(
1724
+ `Error extracting changelog entries: ${error instanceof Error ? error.message : String(error)}`,
1725
+ "warning"
1726
+ );
1727
+ changelogEntries = [
1728
+ {
1729
+ type: "changed",
1730
+ description: `Update version to ${nextVersion}`
1731
+ }
1732
+ ];
1733
+ }
1734
+ let repoUrl;
1735
+ try {
1736
+ const packageJsonPath2 = path6.join(pkgPath, "package.json");
1737
+ if (fs8.existsSync(packageJsonPath2)) {
1738
+ const packageJson = JSON.parse(fs8.readFileSync(packageJsonPath2, "utf8"));
1739
+ if (packageJson.repository) {
1740
+ if (typeof packageJson.repository === "string") {
1741
+ repoUrl = packageJson.repository;
1742
+ } else if (packageJson.repository.url) {
1743
+ repoUrl = packageJson.repository.url;
1744
+ }
1745
+ if ((repoUrl == null ? void 0 : repoUrl.startsWith("git+")) && (repoUrl == null ? void 0 : repoUrl.endsWith(".git"))) {
1746
+ repoUrl = repoUrl.substring(4, repoUrl.length - 4);
1747
+ }
1748
+ }
1749
+ }
1750
+ } catch (error) {
1751
+ log(
1752
+ `Could not determine repository URL for changelog links: ${error instanceof Error ? error.message : String(error)}`,
1753
+ "warning"
1754
+ );
1755
+ }
1756
+ updateChangelog(
1757
+ pkgPath,
1758
+ name,
1759
+ nextVersion,
1760
+ changelogEntries,
1761
+ repoUrl,
1762
+ this.fullConfig.changelogFormat
1763
+ );
1764
+ }
1765
+ const packageJsonPath = path6.join(pkgPath, "package.json");
1766
+ if (fs8.existsSync(packageJsonPath)) {
940
1767
  updatePackageVersion(packageJsonPath, nextVersion);
941
1768
  }
942
- if (fs5.existsSync(cargoTomlPath)) {
943
- updatePackageVersion(cargoTomlPath, nextVersion);
1769
+ const cargoEnabled = ((_a = this.fullConfig.cargo) == null ? void 0 : _a.enabled) !== false;
1770
+ if (cargoEnabled) {
1771
+ const cargoPaths = (_b = this.fullConfig.cargo) == null ? void 0 : _b.paths;
1772
+ if (cargoPaths && cargoPaths.length > 0) {
1773
+ for (const cargoPath of cargoPaths) {
1774
+ const resolvedCargoPath = path6.resolve(pkgPath, cargoPath, "Cargo.toml");
1775
+ if (fs8.existsSync(resolvedCargoPath)) {
1776
+ updatePackageVersion(resolvedCargoPath, nextVersion);
1777
+ }
1778
+ }
1779
+ } else {
1780
+ const cargoTomlPath = path6.join(pkgPath, "Cargo.toml");
1781
+ if (fs8.existsSync(cargoTomlPath)) {
1782
+ updatePackageVersion(cargoTomlPath, nextVersion);
1783
+ }
1784
+ }
944
1785
  }
945
1786
  const packageTag = formatTag(
946
1787
  nextVersion,
@@ -972,9 +1813,32 @@ var PackageProcessor = class {
972
1813
  log("No targeted packages required a version update.", "info");
973
1814
  return { updatedPackages: [], tags };
974
1815
  }
975
- const filesToCommit = updatedPackagesInfo.map((info) => path3.join(info.path, "package.json"));
1816
+ const filesToCommit = [];
1817
+ for (const info of updatedPackagesInfo) {
1818
+ const packageJsonPath = path6.join(info.path, "package.json");
1819
+ if (fs8.existsSync(packageJsonPath)) {
1820
+ filesToCommit.push(packageJsonPath);
1821
+ }
1822
+ const cargoEnabled = ((_c = this.fullConfig.cargo) == null ? void 0 : _c.enabled) !== false;
1823
+ if (cargoEnabled) {
1824
+ const cargoPaths = (_d = this.fullConfig.cargo) == null ? void 0 : _d.paths;
1825
+ if (cargoPaths && cargoPaths.length > 0) {
1826
+ for (const cargoPath of cargoPaths) {
1827
+ const resolvedCargoPath = path6.resolve(info.path, cargoPath, "Cargo.toml");
1828
+ if (fs8.existsSync(resolvedCargoPath)) {
1829
+ filesToCommit.push(resolvedCargoPath);
1830
+ }
1831
+ }
1832
+ } else {
1833
+ const cargoTomlPath = path6.join(info.path, "Cargo.toml");
1834
+ if (fs8.existsSync(cargoTomlPath)) {
1835
+ filesToCommit.push(cargoTomlPath);
1836
+ }
1837
+ }
1838
+ }
1839
+ }
976
1840
  const packageNames = updatedPackagesInfo.map((p) => p.name).join(", ");
977
- const representativeVersion = ((_a = updatedPackagesInfo[0]) == null ? void 0 : _a.version) || "multiple";
1841
+ const representativeVersion = ((_e = updatedPackagesInfo[0]) == null ? void 0 : _e.version) || "multiple";
978
1842
  let commitMessage = this.commitMessageTemplate || "chore(release): publish packages";
979
1843
  const placeholderRegex = /\$\{[^}]+\}/;
980
1844
  if (updatedPackagesInfo.length === 1 && placeholderRegex.test(commitMessage)) {
@@ -1032,16 +1896,41 @@ function createSyncedStrategy(config) {
1032
1896
  commitMessage = "chore(release): v${version}",
1033
1897
  prereleaseIdentifier,
1034
1898
  dryRun,
1035
- skipHooks
1899
+ skipHooks,
1900
+ mainPackage
1036
1901
  } = config;
1037
1902
  const formattedPrefix = formatVersionPrefix(versionPrefix || "v");
1038
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
+ }
1039
1926
  const nextVersion = await calculateVersion(config, {
1040
1927
  latestTag,
1041
1928
  versionPrefix: formattedPrefix,
1042
1929
  branchPattern,
1043
1930
  baseBranch,
1044
1931
  prereleaseIdentifier,
1932
+ path: mainPkgPath,
1933
+ name: mainPkgName,
1045
1934
  type: config.type
1046
1935
  });
1047
1936
  if (!nextVersion) {
@@ -1051,20 +1940,25 @@ function createSyncedStrategy(config) {
1051
1940
  const files = [];
1052
1941
  const updatedPackages = [];
1053
1942
  try {
1054
- const rootPkgPath = path4.join(packages.root, "package.json");
1055
- if (fs6.existsSync(rootPkgPath)) {
1056
- updatePackageVersion(rootPkgPath, nextVersion);
1057
- files.push(rootPkgPath);
1058
- 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");
1059
1952
  }
1060
- } catch (_error) {
1061
- log("Failed to update root package.json", "error");
1953
+ } catch (error) {
1954
+ const errMessage = error instanceof Error ? error.message : String(error);
1955
+ log(`Failed to update root package.json: ${errMessage}`, "error");
1062
1956
  }
1063
1957
  for (const pkg of packages.packages) {
1064
1958
  if (!shouldProcessPackage(pkg, config)) {
1065
1959
  continue;
1066
1960
  }
1067
- const packageJsonPath = path4.join(pkg.dir, "package.json");
1961
+ const packageJsonPath = path7.join(pkg.dir, "package.json");
1068
1962
  updatePackageVersion(packageJsonPath, nextVersion);
1069
1963
  files.push(packageJsonPath);
1070
1964
  updatedPackages.push(pkg.packageJson.name);
@@ -1094,6 +1988,7 @@ function createSingleStrategy(config) {
1094
1988
  try {
1095
1989
  const {
1096
1990
  packages: configPackages,
1991
+ mainPackage,
1097
1992
  versionPrefix,
1098
1993
  tagTemplate,
1099
1994
  packageTagTemplate,
@@ -1101,13 +1996,17 @@ function createSingleStrategy(config) {
1101
1996
  dryRun,
1102
1997
  skipHooks
1103
1998
  } = config;
1104
- 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 {
1105
2005
  throw createVersionError(
1106
2006
  "INVALID_CONFIG" /* INVALID_CONFIG */,
1107
- "Single mode requires exactly one package name"
2007
+ "Single mode requires either mainPackage or exactly one package in the packages array"
1108
2008
  );
1109
2009
  }
1110
- const packageName = configPackages[0];
1111
2010
  const pkg = packages.packages.find((p) => p.packageJson.name === packageName);
1112
2011
  if (!pkg) {
1113
2012
  throw createVersionError("PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */, packageName);
@@ -1137,7 +2036,7 @@ function createSingleStrategy(config) {
1137
2036
  log(`No version change needed for ${packageName}`, "info");
1138
2037
  return;
1139
2038
  }
1140
- const packageJsonPath = path4.join(pkgPath, "package.json");
2039
+ const packageJsonPath = path7.join(pkgPath, "package.json");
1141
2040
  updatePackageVersion(packageJsonPath, nextVersion);
1142
2041
  log(`Updated package ${packageName} to version ${nextVersion}`, "success");
1143
2042
  const nextTag = formatTag(
@@ -1231,7 +2130,7 @@ function createStrategy(config) {
1231
2130
  if (config.synced) {
1232
2131
  return createSyncedStrategy(config);
1233
2132
  }
1234
- if (((_a = config.packages) == null ? void 0 : _a.length) === 1) {
2133
+ if (config.mainPackage || ((_a = config.packages) == null ? void 0 : _a.length) === 1) {
1235
2134
  return createSingleStrategy(config);
1236
2135
  }
1237
2136
  return createAsyncStrategy(config);
@@ -1276,6 +2175,13 @@ var VersionEngine = class {
1276
2175
  if (!pkgsResult || !pkgsResult.packages) {
1277
2176
  throw createVersionError("PACKAGES_NOT_FOUND" /* PACKAGES_NOT_FOUND */);
1278
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
+ }
1279
2185
  this.workspaceCache = pkgsResult;
1280
2186
  return pkgsResult;
1281
2187
  } catch (error) {
@@ -1296,9 +2202,22 @@ var VersionEngine = class {
1296
2202
  } catch (error) {
1297
2203
  if (error instanceof VersionError || error instanceof GitError) {
1298
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
+ }
1299
2214
  } else {
1300
2215
  const errorMessage = error instanceof Error ? error.message : String(error);
1301
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
+ }
1302
2221
  }
1303
2222
  throw error;
1304
2223
  }
@@ -1315,11 +2234,11 @@ var VersionEngine = class {
1315
2234
  // src/index.ts
1316
2235
  function getPackageVersion() {
1317
2236
  try {
1318
- const packageJsonPath = path5.resolve(
1319
- path5.dirname(import.meta.url.replace("file:", "")),
2237
+ const packageJsonPath = path8.resolve(
2238
+ path8.dirname(import.meta.url.replace("file:", "")),
1320
2239
  "../package.json"
1321
2240
  );
1322
- const packageJsonContent = fs7.readFileSync(packageJsonPath, "utf-8");
2241
+ const packageJsonContent = fs10.readFileSync(packageJsonPath, "utf-8");
1323
2242
  const packageJson = JSON.parse(packageJsonContent);
1324
2243
  return packageJson.version || "0.0.0";
1325
2244
  } catch (error) {
@@ -1328,53 +2247,104 @@ function getPackageVersion() {
1328
2247
  }
1329
2248
  }
1330
2249
  async function run() {
1331
- const buildTimestamp = (/* @__PURE__ */ new Date()).toISOString();
1332
- const packageVersion = getPackageVersion();
1333
- log(`package-versioner v${packageVersion} (Build: ${buildTimestamp})`, "debug");
1334
- const program = new Command();
1335
- program.name("package-versioner").description(
1336
- "A lightweight yet powerful CLI tool for automated semantic versioning based on Git history and conventional commits."
1337
- ).version(packageVersion).option(
1338
- "-c, --config <path>",
1339
- "Path to config file (defaults to version.config.json in current directory)"
1340
- ).option("-d, --dry-run", "Dry run (no changes made)", false).option("-b, --bump <type>", "Specify bump type (patch|minor|major)").option("-p, --prerelease [identifier]", "Create prerelease version").option("-s, --synced", "Use synchronized versioning across all packages").option("-j, --json", "Output results as JSON", false).option("-t, --target <packages>", "Comma-delimited list of package names to target").parse(process.argv);
1341
- const options = program.opts();
1342
- if (options.json) {
1343
- enableJsonOutput(options.dryRun);
1344
- }
1345
2250
  try {
1346
- const config = await loadConfig(options.config);
1347
- log(`Loaded configuration from ${options.config || "version.config.json"}`, "info");
1348
- if (options.dryRun) config.dryRun = true;
1349
- if (options.synced) config.synced = true;
1350
- if (options.bump) config.type = options.bump;
1351
- if (options.prerelease)
1352
- config.prereleaseIdentifier = options.prerelease === true ? "next" : options.prerelease;
1353
- const cliTargets = options.target ? options.target.split(",").map((t) => t.trim()) : [];
1354
- const engine = new VersionEngine(config, !!options.json);
1355
- if (config.synced) {
1356
- log("Using synced versioning strategy.", "info");
1357
- engine.setStrategy("synced");
1358
- await engine.run();
1359
- } else if (config.packages && config.packages.length === 1) {
1360
- log("Using single package versioning strategy.", "info");
1361
- if (cliTargets.length > 0) {
1362
- log("--target flag is ignored for single package strategy.", "warning");
1363
- }
1364
- engine.setStrategy("single");
1365
- await engine.run();
1366
- } else {
1367
- log("Using async versioning strategy.", "info");
1368
- if (cliTargets.length > 0) {
1369
- log(`Targeting specific packages: ${cliTargets.join(", ")}`, "info");
2251
+ const buildTimestamp = (/* @__PURE__ */ new Date()).toISOString();
2252
+ const packageVersion = getPackageVersion();
2253
+ log(`package-versioner v${packageVersion} (Build: ${buildTimestamp})`, "debug");
2254
+ const program = new Command();
2255
+ program.name("package-versioner").description(
2256
+ "A lightweight yet powerful CLI tool for automated semantic versioning based on Git history and conventional commits."
2257
+ ).version(packageVersion);
2258
+ program.command("version", { isDefault: true }).description("Version a package or packages based on configuration").option(
2259
+ "-c, --config <path>",
2260
+ "Path to config file (defaults to version.config.json in current directory)"
2261
+ ).option("-d, --dry-run", "Dry run (no changes made)", false).option("-b, --bump <type>", "Specify bump type (patch|minor|major)").option("-p, --prerelease [identifier]", "Create prerelease version").option("-s, --synced", "Use synchronized versioning across all packages").option("-j, --json", "Output results as JSON", false).option("-t, --target <packages>", "Comma-delimited list of package names to target").action(async (options) => {
2262
+ if (options.json) {
2263
+ enableJsonOutput(options.dryRun);
1370
2264
  }
1371
- engine.setStrategy("async");
1372
- await engine.run(cliTargets);
1373
- }
1374
- log("Versioning process completed.", "success");
1375
- printJsonOutput();
2265
+ try {
2266
+ const config = await loadConfig(options.config);
2267
+ log(`Loaded configuration from ${options.config || "version.config.json"}`, "info");
2268
+ if (options.dryRun) config.dryRun = true;
2269
+ if (options.synced) config.synced = true;
2270
+ if (options.bump) config.type = options.bump;
2271
+ if (options.prerelease)
2272
+ config.prereleaseIdentifier = options.prerelease === true ? "next" : options.prerelease;
2273
+ const cliTargets = options.target ? options.target.split(",").map((t) => t.trim()) : [];
2274
+ const engine = new VersionEngine(config, !!options.json);
2275
+ if (config.synced) {
2276
+ log("Using synced versioning strategy.", "info");
2277
+ engine.setStrategy("synced");
2278
+ await engine.run();
2279
+ } else if (config.packages && config.packages.length === 1) {
2280
+ log("Using single package versioning strategy.", "info");
2281
+ if (cliTargets.length > 0) {
2282
+ log("--target flag is ignored for single package strategy.", "warning");
2283
+ }
2284
+ engine.setStrategy("single");
2285
+ await engine.run();
2286
+ } else {
2287
+ log("Using async versioning strategy.", "info");
2288
+ if (cliTargets.length > 0) {
2289
+ log(`Targeting specific packages: ${cliTargets.join(", ")}`, "info");
2290
+ }
2291
+ engine.setStrategy("async");
2292
+ await engine.run(cliTargets);
2293
+ }
2294
+ log("Versioning process completed.", "success");
2295
+ printJsonOutput();
2296
+ } catch (error) {
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
+ }
2308
+ process.exit(1);
2309
+ }
2310
+ });
2311
+ program.command("regenerate-changelog").description("Regenerate a complete changelog from git history").option("-o, --output <path>", "Output path for changelog file", "CHANGELOG.md").option(
2312
+ "-f, --format <format>",
2313
+ "Changelog format (keep-a-changelog|angular)",
2314
+ "keep-a-changelog"
2315
+ ).option("-s, --since <tag>", "Start changelog from specific tag").option("-u, --repo-url <url>", "Repository URL for changelog links").option("-d, --dry-run", "Preview changelog without writing to file", false).option("-p, --project-dir <path>", "Project directory", process.cwd()).action(async (options) => {
2316
+ try {
2317
+ log("Regenerating changelog from git history...", "info");
2318
+ if (options.format !== "keep-a-changelog" && options.format !== "angular") {
2319
+ throw new Error(
2320
+ 'Invalid format specified. Must be either "keep-a-changelog" or "angular"'
2321
+ );
2322
+ }
2323
+ const regenerateOptions = {
2324
+ format: options.format,
2325
+ since: options.since,
2326
+ output: options.output,
2327
+ dryRun: options.dryRun,
2328
+ projectDir: options.projectDir,
2329
+ repoUrl: options.repoUrl
2330
+ };
2331
+ const content = await regenerateChangelog(regenerateOptions);
2332
+ await writeChangelog(
2333
+ content,
2334
+ path8.resolve(options.projectDir, options.output),
2335
+ options.dryRun
2336
+ );
2337
+ if (!options.dryRun) {
2338
+ log(`Changelog successfully regenerated at ${options.output}`, "success");
2339
+ }
2340
+ } catch (error) {
2341
+ log(error instanceof Error ? error.message : String(error), "error");
2342
+ process.exit(1);
2343
+ }
2344
+ });
2345
+ program.parse(process.argv);
1376
2346
  } catch (error) {
1377
- log(error instanceof Error ? error.message : String(error), "error");
2347
+ console.error("Fatal error:", error);
1378
2348
  process.exit(1);
1379
2349
  }
1380
2350
  }