relizy 1.4.6 → 1.4.8-beta.0

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/cli.mjs CHANGED
@@ -5,7 +5,7 @@ import process from 'node:process';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import { printBanner, logger } from '@maz-ui/node';
7
7
  import { Command } from 'commander';
8
- import { aq as isInCI, ar as getCIName, b as bump, c as changelog, g as publish, e as providerRelease, h as social, p as prComment, r as release } from './shared/relizy.CzL6Efad.mjs';
8
+ import { aA as isInCI, aB as getCIName, b as bump, c as changelog, g as publish, e as providerRelease, h as social, p as prComment, r as release } from './shared/relizy.00ntGDTg.mjs';
9
9
  import 'node:child_process';
10
10
  import '@maz-ui/utils';
11
11
  import 'c12';
package/dist/index.d.mts CHANGED
@@ -27,8 +27,8 @@ declare function getDefaultConfig(): {
27
27
  private: false;
28
28
  args: never[];
29
29
  token: string | undefined;
30
- registry: string;
31
30
  safetyCheck: true;
31
+ safetyCheckTimeout: number;
32
32
  packageManager: PackageManager;
33
33
  };
34
34
  tokens: {
@@ -69,6 +69,7 @@ declare function getDefaultConfig(): {
69
69
  ai: AIConfig;
70
70
  logLevel: LogLevel;
71
71
  safetyCheck: boolean;
72
+ detectRewrittenTags: boolean;
72
73
  };
73
74
  /**
74
75
  * Merge user types with defaults: each user-defined entry replaces the default entirely.
@@ -210,6 +211,44 @@ declare function getCurrentGitBranch(cwd: string): string;
210
211
  declare function getCurrentGitRef(cwd: string): string;
211
212
  declare function getShortCommitSha(cwd: string, length?: number): string;
212
213
 
214
+ /**
215
+ * Returns true when `ancestor` is an ancestor of `descendant` (i.e. reachable
216
+ * from it). Uses `git merge-base --is-ancestor`, which exits 0 when true and
217
+ * non-zero otherwise. Any error (e.g. unknown ref) is treated as "not an
218
+ * ancestor".
219
+ */
220
+ declare function isAncestor(ancestor: string, descendant: string, cwd?: string): Promise<boolean>;
221
+ /**
222
+ * Returns the subject (first line) of the commit a ref points to, or null.
223
+ */
224
+ declare function getCommitSubject(ref: string, cwd?: string): Promise<string | null>;
225
+ /**
226
+ * Find the most recent commit reachable from `to` whose subject matches
227
+ * `subject` literally. Used to locate the "twin" of a release commit that was
228
+ * rewritten by a rebase (the orphaned tag still points to the old commit).
229
+ */
230
+ declare function findReachableCommitBySubject(subject: string, to: string, cwd?: string): Promise<string | null>;
231
+ /**
232
+ * Returns true when a tag with the given name exists locally.
233
+ */
234
+ declare function tagExists(tag: string, cwd?: string): Promise<boolean>;
235
+ /**
236
+ * Move an annotated tag to a different commit locally (force). Never rewrites
237
+ * any commit; only the tag pointer moves.
238
+ */
239
+ declare function retagAnnotatedLocal({ tag, commit, message, signed, cwd, logLevel, }: {
240
+ tag: string;
241
+ commit: string;
242
+ message: string;
243
+ signed?: boolean;
244
+ cwd?: string;
245
+ logLevel?: LogLevel;
246
+ }): Promise<void>;
247
+ /**
248
+ * Force-push a single tag to origin. Used only after explicit confirmation.
249
+ */
250
+ declare function pushTagForce(tag: string, cwd?: string, logLevel?: LogLevel): Promise<void>;
251
+
213
252
  declare function github(options: ProviderReleaseOptions): Promise<PostedRelease[]>;
214
253
 
215
254
  interface GitlabRelease {
@@ -287,6 +326,16 @@ declare function parseChangelogMarkdown(contents: string): {
287
326
  }[];
288
327
  };
289
328
 
329
+ /**
330
+ * Resolve the effective npm registry from the environment (`.npmrc` files, env
331
+ * variables, npm/pnpm defaults) via `npm config get registry`. Falls back to the
332
+ * public registry when npm is unavailable or returns nothing.
333
+ *
334
+ * Used when the user did not set `publish.registry`, so Relizy honors a custom
335
+ * registry (e.g. a corporate proxy) configured in the user's `.npmrc` instead of
336
+ * forcing the public registry.
337
+ */
338
+ declare function getNpmRegistry(cwd?: string): string;
290
339
  declare function detectPackageManager(cwd?: string): PackageManager;
291
340
  declare function determinePublishTag(version: string, configTag?: string): string;
292
341
  declare function getPackagesToPublishInSelectiveMode(sortedPackages: PackageBase[], rootVersion: string | undefined): PackageBase[];
@@ -371,19 +420,27 @@ declare function postPrComment({ config, pr, body, }: {
371
420
  body: string;
372
421
  }): Promise<boolean>;
373
422
 
423
+ /**
424
+ * Return a deep clone of `value` with every secret masked, without mutating the
425
+ * original. Secrets are detected by sensitive key name and by living under a
426
+ * secret container (e.g. `tokens.*`).
427
+ */
428
+ declare function redactSecrets<T>(value: T): T;
429
+
374
430
  declare function readPackageJson(packagePath: string): ReadPackage | undefined;
375
431
  interface RootPackage extends ReadPackage {
376
432
  fromTag: string;
377
433
  commits: GitCommit[];
378
434
  newVersion?: string;
379
435
  }
380
- declare function getRootPackage({ config, force, from, to, suffix, changelog, }: {
436
+ declare function getRootPackage({ config, force, from, to, suffix, changelog, dryRun, }: {
381
437
  config: ResolvedRelizyConfig;
382
438
  force: boolean;
383
439
  from: string;
384
440
  to: string;
385
441
  suffix: string | undefined;
386
442
  changelog: boolean;
443
+ dryRun?: boolean;
387
444
  }): Promise<RootPackage>;
388
445
  declare function readPackages({ cwd, patterns, ignorePackageNames, includePrivates, }: {
389
446
  cwd: string;
@@ -391,21 +448,42 @@ declare function readPackages({ cwd, patterns, ignorePackageNames, includePrivat
391
448
  ignorePackageNames: NonNullable<ResolvedRelizyConfig['monorepo']>['ignorePackageNames'];
392
449
  includePrivates?: boolean;
393
450
  }): ReadPackage[];
394
- declare function getPackages({ config, suffix, force, includeAll, }: {
451
+ declare function getPackages({ config, suffix, force, includeAll, dryRun, }: {
395
452
  config: ResolvedRelizyConfig;
396
453
  suffix: string | undefined;
397
454
  force: boolean;
398
455
  includeAll?: boolean;
456
+ dryRun?: boolean;
399
457
  }): Promise<PackageBase[]>;
400
- declare function getPackageCommits({ pkg, from, to, config, changelog, }: {
458
+ declare function getPackageCommits({ pkg, from, to, config, changelog, dryRun, }: {
401
459
  pkg: ReadPackage;
402
460
  from: string;
403
461
  to: string;
404
462
  config: ResolvedRelizyConfig;
405
463
  changelog: boolean;
464
+ dryRun?: boolean;
406
465
  }): Promise<GitCommit[]>;
407
466
  declare function hasLernaJson(rootDir: string): boolean;
408
467
 
468
+ /** Test helper: clear the per-process decision cache. */
469
+ declare function resetRewrittenTagCache(): void;
470
+ /**
471
+ * Ensure the resolved `from` tag is reachable from `to`. When it is not (a
472
+ * rewritten / orphaned tag), explain the situation and either prompt the user
473
+ * or auto-correct, depending on the configured strategy. Returns the effective
474
+ * `from` to use (the original tag, the rebound tag, or the equivalent commit
475
+ * SHA for an ephemeral correction).
476
+ *
477
+ * No commit is ever rewritten; the only mutation possible is moving a tag.
478
+ */
479
+ declare function reconcileFromTag({ from, to, config, dryRun, }: {
480
+ from: string;
481
+ to: string;
482
+ config: ResolvedRelizyConfig;
483
+ pkg?: ReadPackage;
484
+ dryRun?: boolean;
485
+ }): Promise<string>;
486
+
409
487
  /**
410
488
  * Get Slack token from config
411
489
  * Priority: social.slack.credentials > config.tokens.slack > environment variables (handled in config.ts)
@@ -563,11 +641,12 @@ declare function isBumpedPackage(pkg: PackageBase): pkg is PackageBase & {
563
641
  declare function filterOutPrivatePackages<T extends {
564
642
  private: boolean;
565
643
  }>(packages: T[]): T[];
566
- declare function getPackagesOrBumpedPackages({ config, bumpResult, suffix, force, }: {
644
+ declare function getPackagesOrBumpedPackages({ config, bumpResult, suffix, force, dryRun, }: {
567
645
  config: ResolvedRelizyConfig;
568
646
  bumpResult: BumpResultTruthy | undefined;
569
647
  suffix: string | undefined;
570
648
  force: boolean;
649
+ dryRun?: boolean;
571
650
  }): Promise<PackageBase[]>;
572
651
 
573
652
  declare function isGraduatingToStableBetweenVersion(version: string, newVersion: string): boolean;
@@ -1158,6 +1237,13 @@ type PublishConfig = ChangelogConfig$1['publish'] & {
1158
1237
  * @default true
1159
1238
  */
1160
1239
  safetyCheck?: boolean;
1240
+ /**
1241
+ * Maximum time in milliseconds for the registry authentication safety check
1242
+ * before it is aborted. Prevents the release from hanging indefinitely when
1243
+ * the registry (or a proxy) never answers.
1244
+ * @default 15000
1245
+ */
1246
+ safetyCheckTimeout?: number;
1161
1247
  };
1162
1248
  interface PublishOptions extends PublishConfig {
1163
1249
  /**
@@ -1764,6 +1850,7 @@ type HookConfig = {
1764
1850
  * Relizy configuration
1765
1851
  * @see https://relizy.dev/config/overview
1766
1852
  */
1853
+ type OnRewrittenTag = 'prompt' | 'ephemeral' | 'rebind' | 'error';
1767
1854
  interface RelizyConfig extends Partial<Omit<ChangelogConfig$1, 'output' | 'templates' | 'publish' | 'types' | 'tokens'>> {
1768
1855
  /**
1769
1856
  * Project name
@@ -1845,6 +1932,24 @@ interface RelizyConfig extends Partial<Omit<ChangelogConfig$1, 'output' | 'templ
1845
1932
  * @default true
1846
1933
  */
1847
1934
  safetyCheck?: boolean;
1935
+ /**
1936
+ * Detect when the resolved `from` tag points to a commit that is no longer
1937
+ * reachable from `to` (typically because the history was rebased after the
1938
+ * tag was created). When enabled, relizy explains the situation and either
1939
+ * prompts or auto-corrects, avoiding bloated changelogs and over-bumping.
1940
+ * @default true
1941
+ */
1942
+ detectRewrittenTags?: boolean;
1943
+ /**
1944
+ * Strategy applied when a rewritten/orphaned `from` tag is detected.
1945
+ * Defaults to `prompt` interactively, or `ephemeral` when non-interactive
1946
+ * (`--yes` / no TTY / CI).
1947
+ * - `prompt`: interactive selection.
1948
+ * - `ephemeral`: use the reachable equivalent commit for this run only.
1949
+ * - `rebind`: move the local tag onto the equivalent commit (no push).
1950
+ * - `error`: throw and stop.
1951
+ */
1952
+ onRewrittenTag?: OnRewrittenTag;
1848
1953
  }
1849
1954
 
1850
1955
  declare function bump(options?: Partial<BumpOptions>): Promise<BumpResult>;
@@ -1897,5 +2002,5 @@ declare function socialSafetyCheck({ config }: {
1897
2002
  }): Promise<void>;
1898
2003
  declare function social(options?: Partial<SocialOptions>): Promise<SocialResult>;
1899
2004
 
1900
- export { NEW_PACKAGE_MARKER, PR_COMMENT_MARKER, buildChangelogBody, buildCommentBody, buildCompareLink, buildContributors, bump, capReleaseTypeForZeroMajor, changelog, checkGitStatusIfDirty, collectContributorNames, collectPackageBumps, confirmBump, createCommitAndTags, createGitlabRelease, defineConfig, detectGitProvider, detectPackageManager, detectPullRequest, determinePublishTag, determineReleaseType, determineSemverChange, executeBuildCmd, executeFormatCmd, executeHook, expandPackagesToBumpWithDependents, extractChangelogSummary, extractVersionFromPackageTag, extractVersionFromTag, fetchGitTags, filterOutPrivatePackages, findGitHubPR, findGitLabMR, formatChangelogForSlack, formatPackagesForSlack, formatSlackMessage, formatTweetMessage, generateChangelog, generateMarkDown, getAuthCommand, getBumpedIndependentPackages, getBumpedPackageIndependently, getCIName, getCanaryVersion, getCurrentGitBranch, getCurrentGitRef, getDefaultConfig, getDependentsOf, getFirstCommit, getGitStatus, getIndependentTag, getLastPackageTag, getLastRepoTag, getLastStableTag, getLastTag, getModifiedReleaseFilePatterns, getPackageCommits, getPackageDependencies, getPackageNewVersion, getPackages, getPackagesOrBumpedPackages, getPackagesToPublishInIndependentMode, getPackagesToPublishInSelectiveMode, getPreid, getReleaseUrl, getRootPackage, getShortCommitSha, getSlackToken, getSlackWebhookUrl, getTwitterCredentials, github, gitlab, hasLernaJson, isBumpedPackage, isChangedPreid, isGraduating, isGraduatingToStableBetweenVersion, isInCI, isPrerelease, isPrereleaseReleaseType, isStableReleaseType, isTagVersionCompatibleWithCurrent, loadRelizyConfig, mergeTypes, parseChangelogMarkdown, parseGitRemoteUrl, postPrComment, postReleaseToSlack, postReleaseToTwitter, prComment, providerRelease, providerReleaseSafetyCheck, publish, publishPackage, publishSafetyCheck, pushCommitAndTags, readPackageJson, readPackages, release, resolveTags, rollbackModifiedFiles, shouldFilterPrereleaseTags, social, socialSafetyCheck, topologicalSort, updateLernaVersion, writeChangelogToFile, writeVersion };
1901
- export type { AIConfig, AIPromptTarget, AIProviderName, AISocialConfig, AISystemPromptOverrides, AITargetConfig, BumpConfig, BumpOptions, BumpResult, BumpResultFalsy, BumpResultTruthy, ChangelogConfig, ChangelogInclude, ChangelogOptions, ClaudeCodeProviderOptions, ConfigType, GitProvider, GitlabRelease, GitlabReleaseResponse, HookConfig, HookStep, HookType, MonorepoConfig, PackageBase, PackageBumpEntry, PackageManager, PostedRelease, PrCommentConfig, PrCommentMode, PrCommentOptions, PrCommentStatus, ProviderReleaseOptions, ProviderReleaseResult, PublishConfig, PublishOptions, PublishResponse, PullRequestInfo, ReadPackage, Reference, ReleaseConfig, ReleaseContext, ReleaseOptions, RelizyConfig, RepoConfig, ResolvedConfig, ResolvedRelizyConfig, ResolvedTags, ResolvedTwitterCredentials, RootPackage, SlackCredentials, SlackOptions, SlackPackageEntry, SlackSocialConfig, SocialConfig, SocialNetworkResult, SocialOptions, SocialResult, Step, TemplatesConfig, TokensConfig, TwitterCredentials, TwitterOptions, TwitterSocialConfig, VersionMode };
2005
+ export { NEW_PACKAGE_MARKER, PR_COMMENT_MARKER, buildChangelogBody, buildCommentBody, buildCompareLink, buildContributors, bump, capReleaseTypeForZeroMajor, changelog, checkGitStatusIfDirty, collectContributorNames, collectPackageBumps, confirmBump, createCommitAndTags, createGitlabRelease, defineConfig, detectGitProvider, detectPackageManager, detectPullRequest, determinePublishTag, determineReleaseType, determineSemverChange, executeBuildCmd, executeFormatCmd, executeHook, expandPackagesToBumpWithDependents, extractChangelogSummary, extractVersionFromPackageTag, extractVersionFromTag, fetchGitTags, filterOutPrivatePackages, findGitHubPR, findGitLabMR, findReachableCommitBySubject, formatChangelogForSlack, formatPackagesForSlack, formatSlackMessage, formatTweetMessage, generateChangelog, generateMarkDown, getAuthCommand, getBumpedIndependentPackages, getBumpedPackageIndependently, getCIName, getCanaryVersion, getCommitSubject, getCurrentGitBranch, getCurrentGitRef, getDefaultConfig, getDependentsOf, getFirstCommit, getGitStatus, getIndependentTag, getLastPackageTag, getLastRepoTag, getLastStableTag, getLastTag, getModifiedReleaseFilePatterns, getNpmRegistry, getPackageCommits, getPackageDependencies, getPackageNewVersion, getPackages, getPackagesOrBumpedPackages, getPackagesToPublishInIndependentMode, getPackagesToPublishInSelectiveMode, getPreid, getReleaseUrl, getRootPackage, getShortCommitSha, getSlackToken, getSlackWebhookUrl, getTwitterCredentials, github, gitlab, hasLernaJson, isAncestor, isBumpedPackage, isChangedPreid, isGraduating, isGraduatingToStableBetweenVersion, isInCI, isPrerelease, isPrereleaseReleaseType, isStableReleaseType, isTagVersionCompatibleWithCurrent, loadRelizyConfig, mergeTypes, parseChangelogMarkdown, parseGitRemoteUrl, postPrComment, postReleaseToSlack, postReleaseToTwitter, prComment, providerRelease, providerReleaseSafetyCheck, publish, publishPackage, publishSafetyCheck, pushCommitAndTags, pushTagForce, readPackageJson, readPackages, reconcileFromTag, redactSecrets, release, resetRewrittenTagCache, resolveTags, retagAnnotatedLocal, rollbackModifiedFiles, shouldFilterPrereleaseTags, social, socialSafetyCheck, tagExists, topologicalSort, updateLernaVersion, writeChangelogToFile, writeVersion };
2006
+ export type { AIConfig, AIPromptTarget, AIProviderName, AISocialConfig, AISystemPromptOverrides, AITargetConfig, BumpConfig, BumpOptions, BumpResult, BumpResultFalsy, BumpResultTruthy, ChangelogConfig, ChangelogInclude, ChangelogOptions, ClaudeCodeProviderOptions, ConfigType, GitProvider, GitlabRelease, GitlabReleaseResponse, HookConfig, HookStep, HookType, MonorepoConfig, OnRewrittenTag, PackageBase, PackageBumpEntry, PackageManager, PostedRelease, PrCommentConfig, PrCommentMode, PrCommentOptions, PrCommentStatus, ProviderReleaseOptions, ProviderReleaseResult, PublishConfig, PublishOptions, PublishResponse, PullRequestInfo, ReadPackage, Reference, ReleaseConfig, ReleaseContext, ReleaseOptions, RelizyConfig, RepoConfig, ResolvedConfig, ResolvedRelizyConfig, ResolvedTags, ResolvedTwitterCredentials, RootPackage, SlackCredentials, SlackOptions, SlackPackageEntry, SlackSocialConfig, SocialConfig, SocialNetworkResult, SocialOptions, SocialResult, Step, TemplatesConfig, TokensConfig, TwitterCredentials, TwitterOptions, TwitterSocialConfig, VersionMode };
package/dist/index.d.ts CHANGED
@@ -27,8 +27,8 @@ declare function getDefaultConfig(): {
27
27
  private: false;
28
28
  args: never[];
29
29
  token: string | undefined;
30
- registry: string;
31
30
  safetyCheck: true;
31
+ safetyCheckTimeout: number;
32
32
  packageManager: PackageManager;
33
33
  };
34
34
  tokens: {
@@ -69,6 +69,7 @@ declare function getDefaultConfig(): {
69
69
  ai: AIConfig;
70
70
  logLevel: LogLevel;
71
71
  safetyCheck: boolean;
72
+ detectRewrittenTags: boolean;
72
73
  };
73
74
  /**
74
75
  * Merge user types with defaults: each user-defined entry replaces the default entirely.
@@ -210,6 +211,44 @@ declare function getCurrentGitBranch(cwd: string): string;
210
211
  declare function getCurrentGitRef(cwd: string): string;
211
212
  declare function getShortCommitSha(cwd: string, length?: number): string;
212
213
 
214
+ /**
215
+ * Returns true when `ancestor` is an ancestor of `descendant` (i.e. reachable
216
+ * from it). Uses `git merge-base --is-ancestor`, which exits 0 when true and
217
+ * non-zero otherwise. Any error (e.g. unknown ref) is treated as "not an
218
+ * ancestor".
219
+ */
220
+ declare function isAncestor(ancestor: string, descendant: string, cwd?: string): Promise<boolean>;
221
+ /**
222
+ * Returns the subject (first line) of the commit a ref points to, or null.
223
+ */
224
+ declare function getCommitSubject(ref: string, cwd?: string): Promise<string | null>;
225
+ /**
226
+ * Find the most recent commit reachable from `to` whose subject matches
227
+ * `subject` literally. Used to locate the "twin" of a release commit that was
228
+ * rewritten by a rebase (the orphaned tag still points to the old commit).
229
+ */
230
+ declare function findReachableCommitBySubject(subject: string, to: string, cwd?: string): Promise<string | null>;
231
+ /**
232
+ * Returns true when a tag with the given name exists locally.
233
+ */
234
+ declare function tagExists(tag: string, cwd?: string): Promise<boolean>;
235
+ /**
236
+ * Move an annotated tag to a different commit locally (force). Never rewrites
237
+ * any commit; only the tag pointer moves.
238
+ */
239
+ declare function retagAnnotatedLocal({ tag, commit, message, signed, cwd, logLevel, }: {
240
+ tag: string;
241
+ commit: string;
242
+ message: string;
243
+ signed?: boolean;
244
+ cwd?: string;
245
+ logLevel?: LogLevel;
246
+ }): Promise<void>;
247
+ /**
248
+ * Force-push a single tag to origin. Used only after explicit confirmation.
249
+ */
250
+ declare function pushTagForce(tag: string, cwd?: string, logLevel?: LogLevel): Promise<void>;
251
+
213
252
  declare function github(options: ProviderReleaseOptions): Promise<PostedRelease[]>;
214
253
 
215
254
  interface GitlabRelease {
@@ -287,6 +326,16 @@ declare function parseChangelogMarkdown(contents: string): {
287
326
  }[];
288
327
  };
289
328
 
329
+ /**
330
+ * Resolve the effective npm registry from the environment (`.npmrc` files, env
331
+ * variables, npm/pnpm defaults) via `npm config get registry`. Falls back to the
332
+ * public registry when npm is unavailable or returns nothing.
333
+ *
334
+ * Used when the user did not set `publish.registry`, so Relizy honors a custom
335
+ * registry (e.g. a corporate proxy) configured in the user's `.npmrc` instead of
336
+ * forcing the public registry.
337
+ */
338
+ declare function getNpmRegistry(cwd?: string): string;
290
339
  declare function detectPackageManager(cwd?: string): PackageManager;
291
340
  declare function determinePublishTag(version: string, configTag?: string): string;
292
341
  declare function getPackagesToPublishInSelectiveMode(sortedPackages: PackageBase[], rootVersion: string | undefined): PackageBase[];
@@ -371,19 +420,27 @@ declare function postPrComment({ config, pr, body, }: {
371
420
  body: string;
372
421
  }): Promise<boolean>;
373
422
 
423
+ /**
424
+ * Return a deep clone of `value` with every secret masked, without mutating the
425
+ * original. Secrets are detected by sensitive key name and by living under a
426
+ * secret container (e.g. `tokens.*`).
427
+ */
428
+ declare function redactSecrets<T>(value: T): T;
429
+
374
430
  declare function readPackageJson(packagePath: string): ReadPackage | undefined;
375
431
  interface RootPackage extends ReadPackage {
376
432
  fromTag: string;
377
433
  commits: GitCommit[];
378
434
  newVersion?: string;
379
435
  }
380
- declare function getRootPackage({ config, force, from, to, suffix, changelog, }: {
436
+ declare function getRootPackage({ config, force, from, to, suffix, changelog, dryRun, }: {
381
437
  config: ResolvedRelizyConfig;
382
438
  force: boolean;
383
439
  from: string;
384
440
  to: string;
385
441
  suffix: string | undefined;
386
442
  changelog: boolean;
443
+ dryRun?: boolean;
387
444
  }): Promise<RootPackage>;
388
445
  declare function readPackages({ cwd, patterns, ignorePackageNames, includePrivates, }: {
389
446
  cwd: string;
@@ -391,21 +448,42 @@ declare function readPackages({ cwd, patterns, ignorePackageNames, includePrivat
391
448
  ignorePackageNames: NonNullable<ResolvedRelizyConfig['monorepo']>['ignorePackageNames'];
392
449
  includePrivates?: boolean;
393
450
  }): ReadPackage[];
394
- declare function getPackages({ config, suffix, force, includeAll, }: {
451
+ declare function getPackages({ config, suffix, force, includeAll, dryRun, }: {
395
452
  config: ResolvedRelizyConfig;
396
453
  suffix: string | undefined;
397
454
  force: boolean;
398
455
  includeAll?: boolean;
456
+ dryRun?: boolean;
399
457
  }): Promise<PackageBase[]>;
400
- declare function getPackageCommits({ pkg, from, to, config, changelog, }: {
458
+ declare function getPackageCommits({ pkg, from, to, config, changelog, dryRun, }: {
401
459
  pkg: ReadPackage;
402
460
  from: string;
403
461
  to: string;
404
462
  config: ResolvedRelizyConfig;
405
463
  changelog: boolean;
464
+ dryRun?: boolean;
406
465
  }): Promise<GitCommit[]>;
407
466
  declare function hasLernaJson(rootDir: string): boolean;
408
467
 
468
+ /** Test helper: clear the per-process decision cache. */
469
+ declare function resetRewrittenTagCache(): void;
470
+ /**
471
+ * Ensure the resolved `from` tag is reachable from `to`. When it is not (a
472
+ * rewritten / orphaned tag), explain the situation and either prompt the user
473
+ * or auto-correct, depending on the configured strategy. Returns the effective
474
+ * `from` to use (the original tag, the rebound tag, or the equivalent commit
475
+ * SHA for an ephemeral correction).
476
+ *
477
+ * No commit is ever rewritten; the only mutation possible is moving a tag.
478
+ */
479
+ declare function reconcileFromTag({ from, to, config, dryRun, }: {
480
+ from: string;
481
+ to: string;
482
+ config: ResolvedRelizyConfig;
483
+ pkg?: ReadPackage;
484
+ dryRun?: boolean;
485
+ }): Promise<string>;
486
+
409
487
  /**
410
488
  * Get Slack token from config
411
489
  * Priority: social.slack.credentials > config.tokens.slack > environment variables (handled in config.ts)
@@ -563,11 +641,12 @@ declare function isBumpedPackage(pkg: PackageBase): pkg is PackageBase & {
563
641
  declare function filterOutPrivatePackages<T extends {
564
642
  private: boolean;
565
643
  }>(packages: T[]): T[];
566
- declare function getPackagesOrBumpedPackages({ config, bumpResult, suffix, force, }: {
644
+ declare function getPackagesOrBumpedPackages({ config, bumpResult, suffix, force, dryRun, }: {
567
645
  config: ResolvedRelizyConfig;
568
646
  bumpResult: BumpResultTruthy | undefined;
569
647
  suffix: string | undefined;
570
648
  force: boolean;
649
+ dryRun?: boolean;
571
650
  }): Promise<PackageBase[]>;
572
651
 
573
652
  declare function isGraduatingToStableBetweenVersion(version: string, newVersion: string): boolean;
@@ -1158,6 +1237,13 @@ type PublishConfig = ChangelogConfig$1['publish'] & {
1158
1237
  * @default true
1159
1238
  */
1160
1239
  safetyCheck?: boolean;
1240
+ /**
1241
+ * Maximum time in milliseconds for the registry authentication safety check
1242
+ * before it is aborted. Prevents the release from hanging indefinitely when
1243
+ * the registry (or a proxy) never answers.
1244
+ * @default 15000
1245
+ */
1246
+ safetyCheckTimeout?: number;
1161
1247
  };
1162
1248
  interface PublishOptions extends PublishConfig {
1163
1249
  /**
@@ -1764,6 +1850,7 @@ type HookConfig = {
1764
1850
  * Relizy configuration
1765
1851
  * @see https://relizy.dev/config/overview
1766
1852
  */
1853
+ type OnRewrittenTag = 'prompt' | 'ephemeral' | 'rebind' | 'error';
1767
1854
  interface RelizyConfig extends Partial<Omit<ChangelogConfig$1, 'output' | 'templates' | 'publish' | 'types' | 'tokens'>> {
1768
1855
  /**
1769
1856
  * Project name
@@ -1845,6 +1932,24 @@ interface RelizyConfig extends Partial<Omit<ChangelogConfig$1, 'output' | 'templ
1845
1932
  * @default true
1846
1933
  */
1847
1934
  safetyCheck?: boolean;
1935
+ /**
1936
+ * Detect when the resolved `from` tag points to a commit that is no longer
1937
+ * reachable from `to` (typically because the history was rebased after the
1938
+ * tag was created). When enabled, relizy explains the situation and either
1939
+ * prompts or auto-corrects, avoiding bloated changelogs and over-bumping.
1940
+ * @default true
1941
+ */
1942
+ detectRewrittenTags?: boolean;
1943
+ /**
1944
+ * Strategy applied when a rewritten/orphaned `from` tag is detected.
1945
+ * Defaults to `prompt` interactively, or `ephemeral` when non-interactive
1946
+ * (`--yes` / no TTY / CI).
1947
+ * - `prompt`: interactive selection.
1948
+ * - `ephemeral`: use the reachable equivalent commit for this run only.
1949
+ * - `rebind`: move the local tag onto the equivalent commit (no push).
1950
+ * - `error`: throw and stop.
1951
+ */
1952
+ onRewrittenTag?: OnRewrittenTag;
1848
1953
  }
1849
1954
 
1850
1955
  declare function bump(options?: Partial<BumpOptions>): Promise<BumpResult>;
@@ -1897,5 +2002,5 @@ declare function socialSafetyCheck({ config }: {
1897
2002
  }): Promise<void>;
1898
2003
  declare function social(options?: Partial<SocialOptions>): Promise<SocialResult>;
1899
2004
 
1900
- export { NEW_PACKAGE_MARKER, PR_COMMENT_MARKER, buildChangelogBody, buildCommentBody, buildCompareLink, buildContributors, bump, capReleaseTypeForZeroMajor, changelog, checkGitStatusIfDirty, collectContributorNames, collectPackageBumps, confirmBump, createCommitAndTags, createGitlabRelease, defineConfig, detectGitProvider, detectPackageManager, detectPullRequest, determinePublishTag, determineReleaseType, determineSemverChange, executeBuildCmd, executeFormatCmd, executeHook, expandPackagesToBumpWithDependents, extractChangelogSummary, extractVersionFromPackageTag, extractVersionFromTag, fetchGitTags, filterOutPrivatePackages, findGitHubPR, findGitLabMR, formatChangelogForSlack, formatPackagesForSlack, formatSlackMessage, formatTweetMessage, generateChangelog, generateMarkDown, getAuthCommand, getBumpedIndependentPackages, getBumpedPackageIndependently, getCIName, getCanaryVersion, getCurrentGitBranch, getCurrentGitRef, getDefaultConfig, getDependentsOf, getFirstCommit, getGitStatus, getIndependentTag, getLastPackageTag, getLastRepoTag, getLastStableTag, getLastTag, getModifiedReleaseFilePatterns, getPackageCommits, getPackageDependencies, getPackageNewVersion, getPackages, getPackagesOrBumpedPackages, getPackagesToPublishInIndependentMode, getPackagesToPublishInSelectiveMode, getPreid, getReleaseUrl, getRootPackage, getShortCommitSha, getSlackToken, getSlackWebhookUrl, getTwitterCredentials, github, gitlab, hasLernaJson, isBumpedPackage, isChangedPreid, isGraduating, isGraduatingToStableBetweenVersion, isInCI, isPrerelease, isPrereleaseReleaseType, isStableReleaseType, isTagVersionCompatibleWithCurrent, loadRelizyConfig, mergeTypes, parseChangelogMarkdown, parseGitRemoteUrl, postPrComment, postReleaseToSlack, postReleaseToTwitter, prComment, providerRelease, providerReleaseSafetyCheck, publish, publishPackage, publishSafetyCheck, pushCommitAndTags, readPackageJson, readPackages, release, resolveTags, rollbackModifiedFiles, shouldFilterPrereleaseTags, social, socialSafetyCheck, topologicalSort, updateLernaVersion, writeChangelogToFile, writeVersion };
1901
- export type { AIConfig, AIPromptTarget, AIProviderName, AISocialConfig, AISystemPromptOverrides, AITargetConfig, BumpConfig, BumpOptions, BumpResult, BumpResultFalsy, BumpResultTruthy, ChangelogConfig, ChangelogInclude, ChangelogOptions, ClaudeCodeProviderOptions, ConfigType, GitProvider, GitlabRelease, GitlabReleaseResponse, HookConfig, HookStep, HookType, MonorepoConfig, PackageBase, PackageBumpEntry, PackageManager, PostedRelease, PrCommentConfig, PrCommentMode, PrCommentOptions, PrCommentStatus, ProviderReleaseOptions, ProviderReleaseResult, PublishConfig, PublishOptions, PublishResponse, PullRequestInfo, ReadPackage, Reference, ReleaseConfig, ReleaseContext, ReleaseOptions, RelizyConfig, RepoConfig, ResolvedConfig, ResolvedRelizyConfig, ResolvedTags, ResolvedTwitterCredentials, RootPackage, SlackCredentials, SlackOptions, SlackPackageEntry, SlackSocialConfig, SocialConfig, SocialNetworkResult, SocialOptions, SocialResult, Step, TemplatesConfig, TokensConfig, TwitterCredentials, TwitterOptions, TwitterSocialConfig, VersionMode };
2005
+ export { NEW_PACKAGE_MARKER, PR_COMMENT_MARKER, buildChangelogBody, buildCommentBody, buildCompareLink, buildContributors, bump, capReleaseTypeForZeroMajor, changelog, checkGitStatusIfDirty, collectContributorNames, collectPackageBumps, confirmBump, createCommitAndTags, createGitlabRelease, defineConfig, detectGitProvider, detectPackageManager, detectPullRequest, determinePublishTag, determineReleaseType, determineSemverChange, executeBuildCmd, executeFormatCmd, executeHook, expandPackagesToBumpWithDependents, extractChangelogSummary, extractVersionFromPackageTag, extractVersionFromTag, fetchGitTags, filterOutPrivatePackages, findGitHubPR, findGitLabMR, findReachableCommitBySubject, formatChangelogForSlack, formatPackagesForSlack, formatSlackMessage, formatTweetMessage, generateChangelog, generateMarkDown, getAuthCommand, getBumpedIndependentPackages, getBumpedPackageIndependently, getCIName, getCanaryVersion, getCommitSubject, getCurrentGitBranch, getCurrentGitRef, getDefaultConfig, getDependentsOf, getFirstCommit, getGitStatus, getIndependentTag, getLastPackageTag, getLastRepoTag, getLastStableTag, getLastTag, getModifiedReleaseFilePatterns, getNpmRegistry, getPackageCommits, getPackageDependencies, getPackageNewVersion, getPackages, getPackagesOrBumpedPackages, getPackagesToPublishInIndependentMode, getPackagesToPublishInSelectiveMode, getPreid, getReleaseUrl, getRootPackage, getShortCommitSha, getSlackToken, getSlackWebhookUrl, getTwitterCredentials, github, gitlab, hasLernaJson, isAncestor, isBumpedPackage, isChangedPreid, isGraduating, isGraduatingToStableBetweenVersion, isInCI, isPrerelease, isPrereleaseReleaseType, isStableReleaseType, isTagVersionCompatibleWithCurrent, loadRelizyConfig, mergeTypes, parseChangelogMarkdown, parseGitRemoteUrl, postPrComment, postReleaseToSlack, postReleaseToTwitter, prComment, providerRelease, providerReleaseSafetyCheck, publish, publishPackage, publishSafetyCheck, pushCommitAndTags, pushTagForce, readPackageJson, readPackages, reconcileFromTag, redactSecrets, release, resetRewrittenTagCache, resolveTags, retagAnnotatedLocal, rollbackModifiedFiles, shouldFilterPrereleaseTags, social, socialSafetyCheck, tagExists, topologicalSort, updateLernaVersion, writeChangelogToFile, writeVersion };
2006
+ export type { AIConfig, AIPromptTarget, AIProviderName, AISocialConfig, AISystemPromptOverrides, AITargetConfig, BumpConfig, BumpOptions, BumpResult, BumpResultFalsy, BumpResultTruthy, ChangelogConfig, ChangelogInclude, ChangelogOptions, ClaudeCodeProviderOptions, ConfigType, GitProvider, GitlabRelease, GitlabReleaseResponse, HookConfig, HookStep, HookType, MonorepoConfig, OnRewrittenTag, PackageBase, PackageBumpEntry, PackageManager, PostedRelease, PrCommentConfig, PrCommentMode, PrCommentOptions, PrCommentStatus, ProviderReleaseOptions, ProviderReleaseResult, PublishConfig, PublishOptions, PublishResponse, PullRequestInfo, ReadPackage, Reference, ReleaseConfig, ReleaseContext, ReleaseOptions, RelizyConfig, RepoConfig, ResolvedConfig, ResolvedRelizyConfig, ResolvedTags, ResolvedTwitterCredentials, RootPackage, SlackCredentials, SlackOptions, SlackPackageEntry, SlackSocialConfig, SocialConfig, SocialNetworkResult, SocialOptions, SocialResult, Step, TemplatesConfig, TokensConfig, TwitterCredentials, TwitterOptions, TwitterSocialConfig, VersionMode };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { ak as NEW_PACKAGE_MARKER, $ as PR_COMMENT_MARKER, M as buildChangelogBody, a as buildCommentBody, L as buildCompareLink, O as buildContributors, b as bump, ay as capReleaseTypeForZeroMajor, c as changelog, v as checkGitStatusIfDirty, N as collectContributorNames, X as collectPackageBumps, aM as confirmBump, B as createCommitAndTags, J as createGitlabRelease, k as defineConfig, y as detectGitProvider, R as detectPackageManager, _ as detectPullRequest, S as determinePublishTag, aA as determineReleaseType, az as determineSemverChange, at as executeBuildCmd, as as executeFormatCmd, ap as executeHook, q as expandPackagesToBumpWithDependents, ad as extractChangelogSummary, aE as extractVersionFromPackageTag, aP as extractVersionFromTag, x as fetchGitTags, av as filterOutPrivatePackages, Y as findGitHubPR, Z as findGitLabMR, a9 as formatChangelogForSlack, aa as formatPackagesForSlack, ab as formatSlackMessage, an as formatTweetMessage, i as generateChangelog, P as generateMarkDown, V as getAuthCommand, aN as getBumpedIndependentPackages, aL as getBumpedPackageIndependently, ar as getCIName, aQ as getCanaryVersion, F as getCurrentGitBranch, G as getCurrentGitRef, j as getDefaultConfig, o as getDependentsOf, E as getFirstCommit, u as getGitStatus, af as getIndependentTag, aj as getLastPackageTag, ai as getLastRepoTag, ag as getLastStableTag, ah as getLastTag, A as getModifiedReleaseFilePatterns, a5 as getPackageCommits, n as getPackageDependencies, aC as getPackageNewVersion, a4 as getPackages, aw as getPackagesOrBumpedPackages, U as getPackagesToPublishInIndependentMode, T as getPackagesToPublishInSelectiveMode, aJ as getPreid, ae as getReleaseUrl, a2 as getRootPackage, H as getShortCommitSha, a7 as getSlackToken, a8 as getSlackWebhookUrl, am as getTwitterCredentials, I as github, K as gitlab, a6 as hasLernaJson, au as isBumpedPackage, aK as isChangedPreid, aI as isGraduating, ax as isGraduatingToStableBetweenVersion, aq as isInCI, aF as isPrerelease, aH as isPrereleaseReleaseType, aG as isStableReleaseType, aR as isTagVersionCompatibleWithCurrent, l as loadRelizyConfig, m as mergeTypes, Q as parseChangelogMarkdown, z as parseGitRemoteUrl, a0 as postPrComment, ac as postReleaseToSlack, ao as postReleaseToTwitter, p as prComment, e as providerRelease, d as providerReleaseSafetyCheck, g as publish, W as publishPackage, f as publishSafetyCheck, C as pushCommitAndTags, a1 as readPackageJson, a3 as readPackages, r as release, al as resolveTags, D as rollbackModifiedFiles, aO as shouldFilterPrereleaseTags, h as social, s as socialSafetyCheck, t as topologicalSort, aD as updateLernaVersion, w as writeChangelogToFile, aB as writeVersion } from './shared/relizy.CzL6Efad.mjs';
1
+ export { au as NEW_PACKAGE_MARKER, a6 as PR_COMMENT_MARKER, S as buildChangelogBody, a as buildCommentBody, R as buildCompareLink, U as buildContributors, b as bump, aI as capReleaseTypeForZeroMajor, c as changelog, v as checkGitStatusIfDirty, T as collectContributorNames, a2 as collectPackageBumps, aW as confirmBump, B as createCommitAndTags, P as createGitlabRelease, k as defineConfig, y as detectGitProvider, Y as detectPackageManager, a5 as detectPullRequest, Z as determinePublishTag, aK as determineReleaseType, aJ as determineSemverChange, aD as executeBuildCmd, aC as executeFormatCmd, az as executeHook, q as expandPackagesToBumpWithDependents, an as extractChangelogSummary, aO as extractVersionFromPackageTag, aZ as extractVersionFromTag, x as fetchGitTags, aF as filterOutPrivatePackages, a3 as findGitHubPR, a4 as findGitLabMR, K as findReachableCommitBySubject, aj as formatChangelogForSlack, ak as formatPackagesForSlack, al as formatSlackMessage, ax as formatTweetMessage, i as generateChangelog, V as generateMarkDown, a0 as getAuthCommand, aX as getBumpedIndependentPackages, aV as getBumpedPackageIndependently, aB as getCIName, a_ as getCanaryVersion, J as getCommitSubject, F as getCurrentGitBranch, G as getCurrentGitRef, j as getDefaultConfig, o as getDependentsOf, E as getFirstCommit, u as getGitStatus, ap as getIndependentTag, at as getLastPackageTag, as as getLastRepoTag, aq as getLastStableTag, ar as getLastTag, A as getModifiedReleaseFilePatterns, X as getNpmRegistry, ad as getPackageCommits, n as getPackageDependencies, aM as getPackageNewVersion, ac as getPackages, aG as getPackagesOrBumpedPackages, $ as getPackagesToPublishInIndependentMode, _ as getPackagesToPublishInSelectiveMode, aT as getPreid, ao as getReleaseUrl, aa as getRootPackage, H as getShortCommitSha, ah as getSlackToken, ai as getSlackWebhookUrl, aw as getTwitterCredentials, O as github, Q as gitlab, ae as hasLernaJson, I as isAncestor, aE as isBumpedPackage, aU as isChangedPreid, aS as isGraduating, aH as isGraduatingToStableBetweenVersion, aA as isInCI, aP as isPrerelease, aR as isPrereleaseReleaseType, aQ as isStableReleaseType, a$ as isTagVersionCompatibleWithCurrent, l as loadRelizyConfig, m as mergeTypes, W as parseChangelogMarkdown, z as parseGitRemoteUrl, a7 as postPrComment, am as postReleaseToSlack, ay as postReleaseToTwitter, p as prComment, e as providerRelease, d as providerReleaseSafetyCheck, g as publish, a1 as publishPackage, f as publishSafetyCheck, C as pushCommitAndTags, N as pushTagForce, a9 as readPackageJson, ab as readPackages, ag as reconcileFromTag, a8 as redactSecrets, r as release, af as resetRewrittenTagCache, av as resolveTags, M as retagAnnotatedLocal, D as rollbackModifiedFiles, aY as shouldFilterPrereleaseTags, h as social, s as socialSafetyCheck, L as tagExists, t as topologicalSort, aN as updateLernaVersion, w as writeChangelogToFile, aL as writeVersion } from './shared/relizy.00ntGDTg.mjs';
2
2
  import '@maz-ui/node';
3
3
  import 'node:child_process';
4
4
  import 'node:process';
@@ -7,7 +7,7 @@ import { getGitDiff, parseCommits, resolveRepoConfig, getRepoConfig, formatCompa
7
7
  import { defu } from 'defu';
8
8
  import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
9
9
  import path, { join, relative, sep } from 'node:path';
10
- import { confirm, input } from '@inquirer/prompts';
10
+ import { select, confirm, input } from '@inquirer/prompts';
11
11
  import fastGlob from 'fast-glob';
12
12
  import * as semver from 'semver';
13
13
  import { convert } from 'convert-gitmoji';
@@ -131,6 +131,250 @@ function topologicalSort(packages) {
131
131
  return sorted;
132
132
  }
133
133
 
134
+ function shellSingleQuote(value) {
135
+ return `'${value.replaceAll("'", "'\\''")}'`;
136
+ }
137
+ async function isAncestor(ancestor, descendant, cwd) {
138
+ try {
139
+ await execPromise(
140
+ `git merge-base --is-ancestor ${shellSingleQuote(ancestor)} ${shellSingleQuote(descendant)}`,
141
+ { cwd, noStderr: true, noStdout: true, noSuccess: true, noError: true }
142
+ );
143
+ return true;
144
+ } catch {
145
+ return false;
146
+ }
147
+ }
148
+ async function getCommitSubject(ref, cwd) {
149
+ try {
150
+ const { stdout } = await execPromise(
151
+ `git log -1 --format=%s ${shellSingleQuote(ref)}`,
152
+ { cwd, noStderr: true, noStdout: true, noSuccess: true, noError: true }
153
+ );
154
+ return stdout.trim() || null;
155
+ } catch {
156
+ return null;
157
+ }
158
+ }
159
+ async function findReachableCommitBySubject(subject, to, cwd) {
160
+ try {
161
+ const { stdout } = await execPromise(
162
+ `git log ${shellSingleQuote(to)} --grep=${shellSingleQuote(subject)} --fixed-strings --format=%H -n 1`,
163
+ { cwd, noStderr: true, noStdout: true, noSuccess: true, noError: true }
164
+ );
165
+ return stdout.trim().split("\n")[0]?.trim() || null;
166
+ } catch {
167
+ return null;
168
+ }
169
+ }
170
+ async function tagExists(tag, cwd) {
171
+ try {
172
+ const tagRef = `refs/tags/${tag}`;
173
+ await execPromise(
174
+ `git rev-parse --verify --quiet ${shellSingleQuote(tagRef)}`,
175
+ { cwd, noStderr: true, noStdout: true, noSuccess: true, noError: true }
176
+ );
177
+ return true;
178
+ } catch {
179
+ return false;
180
+ }
181
+ }
182
+ async function retagAnnotatedLocal({
183
+ tag,
184
+ commit,
185
+ message,
186
+ signed,
187
+ cwd,
188
+ logLevel
189
+ }) {
190
+ const sign = signed ? "-s " : "";
191
+ await execPromise(
192
+ `git tag -f ${sign}-a ${shellSingleQuote(tag)} ${shellSingleQuote(commit)} -m ${shellSingleQuote(message)}`,
193
+ { cwd, logLevel, noStderr: true, noStdout: true }
194
+ );
195
+ }
196
+ async function pushTagForce(tag, cwd, logLevel) {
197
+ await execPromise(
198
+ `git push origin ${shellSingleQuote(tag)} --force`,
199
+ { cwd, logLevel, noStderr: true, noStdout: true }
200
+ );
201
+ }
202
+
203
+ const sessionCache = /* @__PURE__ */ new Map();
204
+ function resetRewrittenTagCache() {
205
+ sessionCache.clear();
206
+ }
207
+ function short(sha) {
208
+ return sha.slice(0, 9);
209
+ }
210
+ function extractVersionFromRef(ref) {
211
+ const atIndex = ref.lastIndexOf("@");
212
+ const candidate = atIndex >= 0 ? ref.slice(atIndex + 1) : ref;
213
+ return candidate.startsWith("v") ? candidate.slice(1) : candidate;
214
+ }
215
+ function resolveStrategy(config) {
216
+ const isTTY = Boolean(process$1.stdout?.isTTY);
217
+ const strategy = config.onRewrittenTag ?? (!config.bump?.yes && isTTY ? "prompt" : "ephemeral");
218
+ if (strategy === "prompt" && !isTTY) {
219
+ return "ephemeral";
220
+ }
221
+ return strategy;
222
+ }
223
+ function buildExplanation({
224
+ from,
225
+ to,
226
+ twin,
227
+ subject
228
+ }) {
229
+ const lines = [
230
+ `\u26A0\uFE0F Tag "${from}" points to a commit that is no longer in the history of "${to}".`,
231
+ `It was most likely rewritten by a "git rebase" after the tag was created.`,
232
+ `Generating a changelog from it would span the whole divergent range (often the entire history since the last stable release, with duplicated commits) instead of the real changes.`
233
+ ];
234
+ if (twin) {
235
+ const subjectSuffix = subject ? ` ("${subject}")` : "";
236
+ lines.push(`Equivalent commit found on "${to}": ${short(twin)}${subjectSuffix}.`);
237
+ } else {
238
+ lines.push(`No equivalent commit could be found on "${to}".`);
239
+ }
240
+ lines.push(`Tip: never rebase "develop"/"main" (commits that are tagged or pushed are immutable). Integrate branches via merge or fast-forward instead.`);
241
+ return lines.join("\n");
242
+ }
243
+ async function rebind({
244
+ from,
245
+ twin,
246
+ config,
247
+ dryRun,
248
+ push
249
+ }) {
250
+ const message = config.templates?.tagMessage?.replaceAll("{{newVersion}}", extractVersionFromRef(from)) || from;
251
+ if (dryRun) {
252
+ logger.info(`[dry-run] git tag -f -a ${from} ${short(twin)} -m "${message}" (re-bind orphaned tag)`);
253
+ if (push) {
254
+ logger.info(`[dry-run] git push origin ${from} --force`);
255
+ }
256
+ return from;
257
+ }
258
+ await retagAnnotatedLocal({
259
+ tag: from,
260
+ commit: twin,
261
+ message,
262
+ signed: config.signTags,
263
+ cwd: config.cwd,
264
+ logLevel: config.logLevel
265
+ });
266
+ logger.success(`Re-bound tag "${from}" -> ${short(twin)} locally.`);
267
+ if (push) {
268
+ await pushTagForce(from, config.cwd, config.logLevel);
269
+ logger.success(`Force-pushed tag "${from}" to origin.`);
270
+ } else {
271
+ logger.info(`To publish the corrected tag later: git push origin ${from} --force`);
272
+ }
273
+ return from;
274
+ }
275
+ async function promptOrphan({
276
+ from,
277
+ twin,
278
+ config,
279
+ dryRun,
280
+ explanation
281
+ }) {
282
+ logger.warn(explanation);
283
+ const choices = [];
284
+ if (twin) {
285
+ choices.push({ name: `Use equivalent commit ${short(twin)} for this run only (recommended, non-destructive)`, value: "ephemeral" });
286
+ choices.push({ name: `Re-bind tag "${from}" -> ${short(twin)} locally (push it manually later)`, value: "rebind-local" });
287
+ choices.push({ name: `Re-bind tag "${from}" -> ${short(twin)} locally AND force-push to origin`, value: "rebind-push" });
288
+ }
289
+ choices.push({ name: `Keep the orphaned tag (changelog will span the full divergent range)`, value: "keep" });
290
+ choices.push({ name: `Abort`, value: "abort" });
291
+ let answer;
292
+ try {
293
+ answer = await select({
294
+ message: `How should relizy handle the rewritten tag "${from}"?`,
295
+ choices,
296
+ default: twin ? "ephemeral" : "keep"
297
+ });
298
+ } catch (error) {
299
+ const userHasExited = error instanceof Error && error.name === "ExitPromptError";
300
+ logger.log("");
301
+ logger.fail(userHasExited ? "Cancelled" : "Error while resolving rewritten tag");
302
+ process$1.exit(userHasExited ? 0 : 1);
303
+ }
304
+ switch (answer) {
305
+ case "ephemeral":
306
+ logger.info(`Using equivalent commit ${short(twin)} as the changelog base for this run.`);
307
+ return twin;
308
+ case "rebind-local":
309
+ return rebind({ from, twin, config, dryRun, push: false });
310
+ case "rebind-push": {
311
+ const confirmed = await confirm({
312
+ message: `Force-push tag "${from}" to origin? This rewrites the already-published tag.`,
313
+ default: false
314
+ }).catch(() => false);
315
+ if (!confirmed) {
316
+ logger.info("Skipping force-push; re-binding the tag locally only.");
317
+ return rebind({ from, twin, config, dryRun, push: false });
318
+ }
319
+ return rebind({ from, twin, config, dryRun, push: true });
320
+ }
321
+ case "keep":
322
+ logger.warn(`Keeping orphaned tag "${from}"; the changelog range may be incorrect.`);
323
+ return from;
324
+ case "abort":
325
+ default:
326
+ logger.log("");
327
+ logger.fail("Aborted. Re-bind the tag or fix your history, then retry.");
328
+ process$1.exit(0);
329
+ }
330
+ }
331
+ async function reconcileFromTag({
332
+ from,
333
+ to,
334
+ config,
335
+ dryRun = false
336
+ }) {
337
+ if (config.detectRewrittenTags === false || !from || from === to) {
338
+ return from;
339
+ }
340
+ const cwd = config.cwd;
341
+ if (!await tagExists(from, cwd)) {
342
+ return from;
343
+ }
344
+ const cached = sessionCache.get(from);
345
+ if (cached !== void 0) {
346
+ return cached;
347
+ }
348
+ if (await isAncestor(from, to, cwd)) {
349
+ sessionCache.set(from, from);
350
+ return from;
351
+ }
352
+ const subject = await getCommitSubject(from, cwd);
353
+ const twin = subject ? await findReachableCommitBySubject(subject, to, cwd) : null;
354
+ const explanation = buildExplanation({ from, to, twin, subject });
355
+ const strategy = resolveStrategy(config);
356
+ let result;
357
+ if (strategy === "error") {
358
+ logger.error(explanation);
359
+ throw new Error(`Tag "${from}" was rewritten (rebased) and is no longer reachable from "${to}". Re-bind the tag or fix your history.`);
360
+ } else if (strategy === "prompt") {
361
+ result = await promptOrphan({ from, twin, config, dryRun, explanation });
362
+ } else if (!twin) {
363
+ logger.warn(explanation);
364
+ logger.warn(`Falling back to the original tag "${from}"; the changelog range may be incorrect.`);
365
+ result = from;
366
+ } else if (strategy === "rebind") {
367
+ logger.warn(explanation);
368
+ result = await rebind({ from, twin, config, dryRun, push: false });
369
+ } else {
370
+ logger.warn(explanation);
371
+ logger.info(`Using equivalent commit ${short(twin)} as the changelog base for this run (tag "${from}" left untouched).`);
372
+ result = twin;
373
+ }
374
+ sessionCache.set(from, result);
375
+ return result;
376
+ }
377
+
134
378
  function getFirstPackageCommitHash(packagePath, cwd) {
135
379
  const relativePath = relative(cwd, packagePath);
136
380
  try {
@@ -175,7 +419,8 @@ async function getRootPackage({
175
419
  from,
176
420
  to,
177
421
  suffix,
178
- changelog
422
+ changelog,
423
+ dryRun = false
179
424
  }) {
180
425
  try {
181
426
  const packageJson = readPackageJson(config.cwd);
@@ -187,7 +432,8 @@ async function getRootPackage({
187
432
  from,
188
433
  to,
189
434
  config,
190
- changelog
435
+ changelog,
436
+ dryRun
191
437
  });
192
438
  let newVersion;
193
439
  if (config.monorepo?.versionMode !== "independent") {
@@ -296,7 +542,8 @@ async function getPackages({
296
542
  config,
297
543
  suffix,
298
544
  force,
299
- includeAll = false
545
+ includeAll = false,
546
+ dryRun = false
300
547
  }) {
301
548
  const patterns = config.monorepo?.packages;
302
549
  const readedPackages = readPackages({
@@ -349,7 +596,8 @@ async function getPackages({
349
596
  from,
350
597
  to,
351
598
  config,
352
- changelog: false
599
+ changelog: false,
600
+ dryRun
353
601
  });
354
602
  foundPaths.add(matchPath);
355
603
  const dependencies = getPackageDependencies({
@@ -427,19 +675,21 @@ async function getPackageCommits({
427
675
  from,
428
676
  to,
429
677
  config,
430
- changelog
678
+ changelog,
679
+ dryRun = false
431
680
  }) {
432
681
  logger.debug(`Analyzing commits for ${pkg.name} since ${from} to ${to}`);
433
- let actualFrom = from;
682
+ let actualFrom;
434
683
  if (from === NEW_PACKAGE_MARKER) {
435
684
  const firstPackageCommit = getFirstPackageCommitHash(pkg.path, config.cwd);
436
- if (firstPackageCommit) {
437
- logger.debug(`${pkg.name} is a new package, using first package commit: ${firstPackageCommit.slice(0, 8)}`);
438
- actualFrom = `${firstPackageCommit}^`;
439
- } else {
685
+ if (!firstPackageCommit) {
440
686
  logger.debug(`${pkg.name} has no commits yet, returning empty`);
441
687
  return [];
442
688
  }
689
+ logger.debug(`${pkg.name} is a new package, using first package commit: ${firstPackageCommit.slice(0, 8)}`);
690
+ actualFrom = `${firstPackageCommit}^`;
691
+ } else {
692
+ actualFrom = await reconcileFromTag({ from, to, config, dryRun });
443
693
  }
444
694
  const changelogConfig = {
445
695
  ...config,
@@ -1536,7 +1786,8 @@ async function getPackagesOrBumpedPackages({
1536
1786
  config,
1537
1787
  bumpResult,
1538
1788
  suffix,
1539
- force
1789
+ force,
1790
+ dryRun = false
1540
1791
  }) {
1541
1792
  if (bumpResult?.bumpedPackages && bumpResult.bumpedPackages.length > 0) {
1542
1793
  return bumpResult.bumpedPackages;
@@ -1544,11 +1795,25 @@ async function getPackagesOrBumpedPackages({
1544
1795
  return await getPackages({
1545
1796
  config,
1546
1797
  suffix,
1547
- force
1798
+ force,
1799
+ dryRun
1548
1800
  });
1549
1801
  }
1550
1802
 
1803
+ const DEFAULT_REGISTRY = "https://registry.npmjs.org/";
1551
1804
  let sessionOtp;
1805
+ function getNpmRegistry(cwd = process.cwd()) {
1806
+ try {
1807
+ const output = execSync("npm config get registry", {
1808
+ cwd,
1809
+ encoding: "utf8",
1810
+ stdio: ["ignore", "pipe", "ignore"]
1811
+ }).trim();
1812
+ return output && output !== "undefined" ? output : DEFAULT_REGISTRY;
1813
+ } catch {
1814
+ return DEFAULT_REGISTRY;
1815
+ }
1816
+ }
1552
1817
  function detectPackageManager(cwd = process.cwd()) {
1553
1818
  try {
1554
1819
  const packageJsonPath = join(cwd, "package.json");
@@ -1752,7 +2017,7 @@ async function executePublishCommand({
1752
2017
  logger.info(`${dryRun ? "[dry-run] " : ""}Skipping actual publish for ${packageNameAndVersion}`);
1753
2018
  return;
1754
2019
  }
1755
- const { stdout, stderr } = await execPromise(command, {
2020
+ await execPromise(command, {
1756
2021
  noStderr: true,
1757
2022
  noStdout: true,
1758
2023
  noSuccess: true,
@@ -1760,8 +2025,6 @@ async function executePublishCommand({
1760
2025
  logLevel: config.logLevel,
1761
2026
  cwd: pkg.path
1762
2027
  });
1763
- logger.debug("Publish stdout:", stdout);
1764
- logger.debug("Publish stderr:", stderr);
1765
2028
  }
1766
2029
  function getAuthCommand({
1767
2030
  packageManager,
@@ -1859,6 +2122,53 @@ async function publishPackage({
1859
2122
  }
1860
2123
  }
1861
2124
 
2125
+ const REDACTED = "[redacted]";
2126
+ const SENSITIVE_KEYS = /* @__PURE__ */ new Set([
2127
+ "token",
2128
+ "publishtoken",
2129
+ "oauthtoken",
2130
+ "apikey",
2131
+ "apikeysecret",
2132
+ "accesstoken",
2133
+ "accesstokensecret",
2134
+ "password",
2135
+ "secret",
2136
+ "webhookurl",
2137
+ "_authtoken"
2138
+ ]);
2139
+ const SECRET_CONTAINER_KEYS = /* @__PURE__ */ new Set(["tokens"]);
2140
+ function redactValue(value, inSecretContainer, keyIsSensitive) {
2141
+ if (typeof value === "string") {
2142
+ if (value === "") {
2143
+ return value;
2144
+ }
2145
+ if (inSecretContainer || keyIsSensitive) {
2146
+ return REDACTED;
2147
+ }
2148
+ return value;
2149
+ }
2150
+ if (Array.isArray(value)) {
2151
+ return value.map((item) => redactValue(item, inSecretContainer, false));
2152
+ }
2153
+ if (value && typeof value === "object") {
2154
+ return redactObject(value, inSecretContainer);
2155
+ }
2156
+ return value;
2157
+ }
2158
+ function redactObject(obj, inSecretContainer) {
2159
+ const result = {};
2160
+ for (const [key, value] of Object.entries(obj)) {
2161
+ const lowerKey = key.toLowerCase();
2162
+ const childInContainer = inSecretContainer || SECRET_CONTAINER_KEYS.has(lowerKey);
2163
+ const keyIsSensitive = SENSITIVE_KEYS.has(lowerKey);
2164
+ result[key] = redactValue(value, childInContainer, keyIsSensitive);
2165
+ }
2166
+ return result;
2167
+ }
2168
+ function redactSecrets(value) {
2169
+ return redactValue(value, false, false);
2170
+ }
2171
+
1862
2172
  function getDefaultConfig() {
1863
2173
  return {
1864
2174
  cwd: process$1.cwd(),
@@ -1907,8 +2217,11 @@ function getDefaultConfig() {
1907
2217
  private: false,
1908
2218
  args: [],
1909
2219
  token: process$1.env.RELIZY_NPM_TOKEN || process$1.env.NPM_TOKEN || process$1.env.NODE_AUTH_TOKEN,
1910
- registry: "https://registry.npmjs.org/",
2220
+ // registry is intentionally left undefined: it is resolved later from the
2221
+ // user's npm config / .npmrc (see resolveConfig) so a custom registry
2222
+ // (e.g. a corporate proxy) is honored instead of forcing the public one.
1911
2223
  safetyCheck: true,
2224
+ safetyCheckTimeout: 15e3,
1912
2225
  packageManager: detectPackageManager(process$1.cwd())
1913
2226
  },
1914
2227
  tokens: {
@@ -1975,7 +2288,8 @@ function getDefaultConfig() {
1975
2288
  }
1976
2289
  },
1977
2290
  logLevel: "default",
1978
- safetyCheck: true
2291
+ safetyCheck: true,
2292
+ detectRewrittenTags: true
1979
2293
  };
1980
2294
  }
1981
2295
  function resolveTemplateDefaults(config) {
@@ -2009,6 +2323,9 @@ async function resolveConfig(config, cwd) {
2009
2323
  provider: resolvedRepoConfig.provider
2010
2324
  };
2011
2325
  }
2326
+ if (config.publish && !config.publish.registry) {
2327
+ config.publish.registry = getNpmRegistry(cwd);
2328
+ }
2012
2329
  return config;
2013
2330
  }
2014
2331
  function mergeTypes(userTypes, defaultTypes) {
@@ -2050,7 +2367,7 @@ async function loadRelizyConfig(options) {
2050
2367
  logger.verbose("User config:", formatJson(results.config.changelog));
2051
2368
  resolveTemplateDefaults(results.config);
2052
2369
  const resolvedConfig = await resolveConfig(results.config, cwd);
2053
- logger.debug("Resolved config:", formatJson(resolvedConfig));
2370
+ logger.debug("Resolved config:", formatJson(redactSecrets(resolvedConfig)));
2054
2371
  return resolvedConfig;
2055
2372
  }
2056
2373
  function defineConfig(config) {
@@ -2680,7 +2997,8 @@ async function generateChangelog({
2680
2997
  from: gitFromRef,
2681
2998
  to: gitToRef,
2682
2999
  config: { ...config, from: gitFromRef, to: gitToRef },
2683
- changelog: true
3000
+ changelog: true,
3001
+ dryRun
2684
3002
  });
2685
3003
  const displayConfig = { ...config, from: displayFromTag, to: displayToTag };
2686
3004
  const parts = await renderChangelogParts({
@@ -3035,7 +3353,8 @@ async function githubIndependentMode({
3035
3353
  config,
3036
3354
  bumpResult,
3037
3355
  suffix,
3038
- force
3356
+ force,
3357
+ dryRun
3039
3358
  }));
3040
3359
  logger.info(`Creating ${packages.length} GitHub release(s)`);
3041
3360
  const postedReleases = [];
@@ -3156,7 +3475,8 @@ async function github(options) {
3156
3475
  suffix: options.suffix,
3157
3476
  changelog: true,
3158
3477
  from,
3159
- to
3478
+ to,
3479
+ dryRun
3160
3480
  });
3161
3481
  return await githubUnified({
3162
3482
  config,
@@ -3243,7 +3563,8 @@ async function gitlabIndependentMode({
3243
3563
  config,
3244
3564
  bumpResult,
3245
3565
  suffix,
3246
- force
3566
+ force,
3567
+ dryRun
3247
3568
  }));
3248
3569
  logger.info(`Creating ${packages.length} GitLab release(s) for independent packages`);
3249
3570
  logger.debug("Getting current branch...");
@@ -3417,7 +3738,8 @@ async function gitlab(options = {}) {
3417
3738
  suffix: options.suffix,
3418
3739
  changelog: true,
3419
3740
  from,
3420
- to
3741
+ to,
3742
+ dryRun
3421
3743
  });
3422
3744
  logger.debug(`Root package: ${getIndependentTag({ name: rootPackage.name, version: newVersion })}`);
3423
3745
  return await gitlabUnified({
@@ -4265,7 +4587,8 @@ async function bumpUnifiedMode({
4265
4587
  from,
4266
4588
  to,
4267
4589
  suffix,
4268
- changelog: false
4590
+ changelog: false,
4591
+ dryRun
4269
4592
  });
4270
4593
  const currentVersion = rootPackage.version;
4271
4594
  const newVersion = rootPackage.newVersion;
@@ -4279,7 +4602,8 @@ async function bumpUnifiedMode({
4279
4602
  config,
4280
4603
  suffix,
4281
4604
  force,
4282
- includeAll: true
4605
+ includeAll: true,
4606
+ dryRun
4283
4607
  });
4284
4608
  if (packages.length === 0) {
4285
4609
  logger.debug("No packages to bump");
@@ -4349,7 +4673,8 @@ async function bumpSelectiveMode({
4349
4673
  from,
4350
4674
  to,
4351
4675
  suffix,
4352
- changelog: false
4676
+ changelog: false,
4677
+ dryRun
4353
4678
  });
4354
4679
  const currentVersion = rootPackage.version;
4355
4680
  const newVersion = rootPackage.newVersion;
@@ -4362,7 +4687,8 @@ async function bumpSelectiveMode({
4362
4687
  const packages = await getPackages({
4363
4688
  config,
4364
4689
  suffix,
4365
- force
4690
+ force,
4691
+ dryRun
4366
4692
  });
4367
4693
  if (packages.length === 0) {
4368
4694
  logger.debug("No packages to bump");
@@ -4430,7 +4756,8 @@ async function bumpIndependentMode({
4430
4756
  const packagesToBump = await getPackages({
4431
4757
  config,
4432
4758
  suffix,
4433
- force
4759
+ force,
4760
+ dryRun
4434
4761
  });
4435
4762
  if (packagesToBump.length === 0) {
4436
4763
  logger.debug("No packages to bump");
@@ -4483,7 +4810,7 @@ async function bumpCanaryMode({
4483
4810
  logger.debug("Starting bump in canary mode");
4484
4811
  if (config.monorepo?.versionMode === "independent") {
4485
4812
  const sha2 = getShortCommitSha(config.cwd);
4486
- const packages2 = await getPackages({ config, suffix: void 0, force: false });
4813
+ const packages2 = await getPackages({ config, suffix: void 0, force: false, dryRun });
4487
4814
  if (packages2.length === 0) {
4488
4815
  logger.debug("No packages to bump");
4489
4816
  return { bumped: false };
@@ -4506,7 +4833,8 @@ async function bumpCanaryMode({
4506
4833
  from,
4507
4834
  to,
4508
4835
  config,
4509
- changelog: false
4836
+ changelog: false,
4837
+ dryRun
4510
4838
  });
4511
4839
  const releaseType = determineSemverChange(commits, config.types);
4512
4840
  const sha = getShortCommitSha(config.cwd);
@@ -4523,7 +4851,8 @@ async function bumpCanaryMode({
4523
4851
  config,
4524
4852
  suffix: void 0,
4525
4853
  force: false,
4526
- includeAll: isUnified
4854
+ includeAll: isUnified,
4855
+ dryRun
4527
4856
  });
4528
4857
  if (packages.length === 0) {
4529
4858
  logger.debug("No packages to bump");
@@ -4772,7 +5101,8 @@ async function generateSimpleRootChangelog({
4772
5101
  suffix,
4773
5102
  changelog: true,
4774
5103
  from: fromTag,
4775
- to
5104
+ to,
5105
+ dryRun
4776
5106
  });
4777
5107
  logger.debug(`Generating ${rootPackage.name} changelog (${fromTag}...${to})`);
4778
5108
  const rootChangelog = await generateChangelog({
@@ -4821,7 +5151,8 @@ async function changelog(options = {}) {
4821
5151
  config,
4822
5152
  bumpResult: options.bumpResult,
4823
5153
  suffix: options.suffix,
4824
- force: options.force ?? false
5154
+ force: options.force ?? false,
5155
+ dryRun
4825
5156
  });
4826
5157
  if (config.changelog?.rootChangelog && config.monorepo?.versionMode) {
4827
5158
  if (config.monorepo.versionMode === "independent") {
@@ -5252,27 +5583,42 @@ async function publishSafetyCheck({ config }) {
5252
5583
  }
5253
5584
  logger.debug("Start checking auth config to package registry");
5254
5585
  const isPnpmOrNpm = config.publish.packageManager === "pnpm" || config.publish.packageManager === "npm";
5255
- if (isPnpmOrNpm) {
5256
- const authCommand = getAuthCommand({
5257
- packageManager: config.publish.packageManager,
5258
- config,
5259
- otp: config.publish.otp
5586
+ if (!isPnpmOrNpm) {
5587
+ logger.debug(`Skipping authentication to package registry because "${config.publish.packageManager}" is not supported`);
5588
+ return;
5589
+ }
5590
+ const authCommand = getAuthCommand({
5591
+ packageManager: config.publish.packageManager,
5592
+ config,
5593
+ otp: config.publish.otp
5594
+ });
5595
+ const timeoutMs = config.publish.safetyCheckTimeout ?? 15e3;
5596
+ const patienceDelay = Math.min(5e3, Math.floor(timeoutMs / 2));
5597
+ const patienceTimer = setTimeout(() => {
5598
+ logger.info(`The package registry is taking longer than expected to respond (will time out at ${Math.round(timeoutMs / 1e3)}s)...`);
5599
+ }, patienceDelay);
5600
+ try {
5601
+ logger.info("Authenticating to package registry...");
5602
+ await execPromise(authCommand, {
5603
+ cwd: config.cwd,
5604
+ timeout: timeoutMs,
5605
+ noStdout: true,
5606
+ noStderr: true,
5607
+ noSuccess: true,
5608
+ noError: true,
5609
+ logLevel: config.logLevel
5260
5610
  });
5261
- try {
5262
- logger.debug("Authenticating to package registry...");
5263
- await execPromise(authCommand, {
5264
- cwd: config.cwd,
5265
- noStderr: true,
5266
- noStdout: true,
5267
- logLevel: config.logLevel,
5268
- noSuccess: true
5269
- });
5270
- logger.info("Successfully authenticated to package registry");
5271
- } catch (error) {
5272
- throw new Error("Failed to authenticate to package registry", { cause: error });
5611
+ logger.info("Successfully authenticated to package registry");
5612
+ } catch (error) {
5613
+ if (error?.killed) {
5614
+ throw new Error(
5615
+ `Authentication to package registry timed out after ${timeoutMs}ms. The registry did not respond - check your network or registry access, increase publish.safetyCheckTimeout, or skip this check with --no-safety-check.`,
5616
+ { cause: error }
5617
+ );
5273
5618
  }
5274
- } else {
5275
- logger.debug(`Skipping authentication to package registry because "${config.publish.packageManager}" is not supported`);
5619
+ throw new Error("Failed to authenticate to package registry", { cause: error });
5620
+ } finally {
5621
+ clearTimeout(patienceTimer);
5276
5622
  }
5277
5623
  }
5278
5624
  async function publish(options = {}) {
@@ -5314,7 +5660,8 @@ async function publish(options = {}) {
5314
5660
  config,
5315
5661
  bumpResult: options.bumpResult,
5316
5662
  suffix: options.suffix,
5317
- force: options.force ?? false
5663
+ force: options.force ?? false,
5664
+ dryRun
5318
5665
  });
5319
5666
  const packages = filterOutPrivatePackages(discoveredPackages);
5320
5667
  if (discoveredPackages.length !== packages.length) {
@@ -5644,7 +5991,8 @@ async function social(options = {}) {
5644
5991
  suffix: void 0,
5645
5992
  changelog: true,
5646
5993
  from: fromTag,
5647
- to
5994
+ to,
5995
+ dryRun
5648
5996
  });
5649
5997
  const minifiedBody = await generateChangelog({
5650
5998
  pkg: { ...rootPackage, fromTag },
@@ -5716,7 +6064,8 @@ ${twitterChangelog}`);
5716
6064
  from: fromTag,
5717
6065
  to: "HEAD",
5718
6066
  config,
5719
- changelog: true
6067
+ changelog: true,
6068
+ dryRun
5720
6069
  });
5721
6070
  const slackResponse = await handleSlackPost({
5722
6071
  config,
@@ -6095,4 +6444,4 @@ Git provider: ${provider}`);
6095
6444
  }
6096
6445
  }
6097
6446
 
6098
- export { PR_COMMENT_MARKER as $, getModifiedReleaseFilePatterns as A, createCommitAndTags as B, pushCommitAndTags as C, rollbackModifiedFiles as D, getFirstCommit as E, getCurrentGitBranch as F, getCurrentGitRef as G, getShortCommitSha as H, github as I, createGitlabRelease as J, gitlab as K, buildCompareLink as L, buildChangelogBody as M, collectContributorNames as N, buildContributors as O, generateMarkDown as P, parseChangelogMarkdown as Q, detectPackageManager as R, determinePublishTag as S, getPackagesToPublishInSelectiveMode as T, getPackagesToPublishInIndependentMode as U, getAuthCommand as V, publishPackage as W, collectPackageBumps as X, findGitHubPR as Y, findGitLabMR as Z, detectPullRequest as _, buildCommentBody as a, postPrComment as a0, readPackageJson as a1, getRootPackage as a2, readPackages as a3, getPackages as a4, getPackageCommits as a5, hasLernaJson as a6, getSlackToken as a7, getSlackWebhookUrl as a8, formatChangelogForSlack as a9, determineReleaseType as aA, writeVersion as aB, getPackageNewVersion as aC, updateLernaVersion as aD, extractVersionFromPackageTag as aE, isPrerelease as aF, isStableReleaseType as aG, isPrereleaseReleaseType as aH, isGraduating as aI, getPreid as aJ, isChangedPreid as aK, getBumpedPackageIndependently as aL, confirmBump as aM, getBumpedIndependentPackages as aN, shouldFilterPrereleaseTags as aO, extractVersionFromTag as aP, getCanaryVersion as aQ, isTagVersionCompatibleWithCurrent as aR, formatPackagesForSlack as aa, formatSlackMessage as ab, postReleaseToSlack as ac, extractChangelogSummary as ad, getReleaseUrl as ae, getIndependentTag as af, getLastStableTag as ag, getLastTag as ah, getLastRepoTag as ai, getLastPackageTag as aj, NEW_PACKAGE_MARKER as ak, resolveTags as al, getTwitterCredentials as am, formatTweetMessage as an, postReleaseToTwitter as ao, executeHook as ap, isInCI as aq, getCIName as ar, executeFormatCmd as as, executeBuildCmd as at, isBumpedPackage as au, filterOutPrivatePackages as av, getPackagesOrBumpedPackages as aw, isGraduatingToStableBetweenVersion as ax, capReleaseTypeForZeroMajor as ay, determineSemverChange as az, bump as b, changelog as c, providerReleaseSafetyCheck as d, providerRelease as e, publishSafetyCheck as f, publish as g, social as h, generateChangelog as i, getDefaultConfig as j, defineConfig as k, loadRelizyConfig as l, mergeTypes as m, getPackageDependencies as n, getDependentsOf as o, prComment as p, expandPackagesToBumpWithDependents as q, release as r, socialSafetyCheck as s, topologicalSort as t, getGitStatus as u, checkGitStatusIfDirty as v, writeChangelogToFile as w, fetchGitTags as x, detectGitProvider as y, parseGitRemoteUrl as z };
6447
+ export { getPackagesToPublishInIndependentMode as $, getModifiedReleaseFilePatterns as A, createCommitAndTags as B, pushCommitAndTags as C, rollbackModifiedFiles as D, getFirstCommit as E, getCurrentGitBranch as F, getCurrentGitRef as G, getShortCommitSha as H, isAncestor as I, getCommitSubject as J, findReachableCommitBySubject as K, tagExists as L, retagAnnotatedLocal as M, pushTagForce as N, github as O, createGitlabRelease as P, gitlab as Q, buildCompareLink as R, buildChangelogBody as S, collectContributorNames as T, buildContributors as U, generateMarkDown as V, parseChangelogMarkdown as W, getNpmRegistry as X, detectPackageManager as Y, determinePublishTag as Z, getPackagesToPublishInSelectiveMode as _, buildCommentBody as a, isTagVersionCompatibleWithCurrent as a$, getAuthCommand as a0, publishPackage as a1, collectPackageBumps as a2, findGitHubPR as a3, findGitLabMR as a4, detectPullRequest as a5, PR_COMMENT_MARKER as a6, postPrComment as a7, redactSecrets as a8, readPackageJson as a9, isInCI as aA, getCIName as aB, executeFormatCmd as aC, executeBuildCmd as aD, isBumpedPackage as aE, filterOutPrivatePackages as aF, getPackagesOrBumpedPackages as aG, isGraduatingToStableBetweenVersion as aH, capReleaseTypeForZeroMajor as aI, determineSemverChange as aJ, determineReleaseType as aK, writeVersion as aL, getPackageNewVersion as aM, updateLernaVersion as aN, extractVersionFromPackageTag as aO, isPrerelease as aP, isStableReleaseType as aQ, isPrereleaseReleaseType as aR, isGraduating as aS, getPreid as aT, isChangedPreid as aU, getBumpedPackageIndependently as aV, confirmBump as aW, getBumpedIndependentPackages as aX, shouldFilterPrereleaseTags as aY, extractVersionFromTag as aZ, getCanaryVersion as a_, getRootPackage as aa, readPackages as ab, getPackages as ac, getPackageCommits as ad, hasLernaJson as ae, resetRewrittenTagCache as af, reconcileFromTag as ag, getSlackToken as ah, getSlackWebhookUrl as ai, formatChangelogForSlack as aj, formatPackagesForSlack as ak, formatSlackMessage as al, postReleaseToSlack as am, extractChangelogSummary as an, getReleaseUrl as ao, getIndependentTag as ap, getLastStableTag as aq, getLastTag as ar, getLastRepoTag as as, getLastPackageTag as at, NEW_PACKAGE_MARKER as au, resolveTags as av, getTwitterCredentials as aw, formatTweetMessage as ax, postReleaseToTwitter as ay, executeHook as az, bump as b, changelog as c, providerReleaseSafetyCheck as d, providerRelease as e, publishSafetyCheck as f, publish as g, social as h, generateChangelog as i, getDefaultConfig as j, defineConfig as k, loadRelizyConfig as l, mergeTypes as m, getPackageDependencies as n, getDependentsOf as o, prComment as p, expandPackagesToBumpWithDependents as q, release as r, socialSafetyCheck as s, topologicalSort as t, getGitStatus as u, checkGitStatusIfDirty as v, writeChangelogToFile as w, fetchGitTags as x, detectGitProvider as y, parseGitRemoteUrl as z };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "relizy",
3
3
  "type": "module",
4
- "version": "1.4.6",
4
+ "version": "1.4.8-beta.0",
5
5
  "description": "Changelogen adapter for monorepo management with unified and independent versioning",
6
6
  "author": "Louis Mazel <me@loicmazuel.com>",
7
7
  "license": "MIT",
@@ -56,7 +56,7 @@
56
56
  },
57
57
  "peerDependencies": {
58
58
  "@slack/web-api": "^7.0.0",
59
- "@yoloship/claude-sdk": "^0.1.0",
59
+ "@yoloship/claude-sdk": "^0.2.0-beta.6",
60
60
  "twitter-api-v2": "^1.20.0"
61
61
  },
62
62
  "peerDependenciesMeta": {
@@ -71,40 +71,40 @@
71
71
  }
72
72
  },
73
73
  "dependencies": {
74
- "@inquirer/prompts": "^8.4.2",
75
- "@maz-ui/node": "4.6.1",
76
- "@maz-ui/utils": "^4.7.6",
74
+ "@inquirer/prompts": "^8.5.2",
75
+ "@maz-ui/node": "5.0.0-beta.26",
76
+ "@maz-ui/utils": "5.0.0-beta.25",
77
77
  "c12": "^3.3.3",
78
78
  "changelogen": "^0.6.2",
79
- "commander": "^14.0.3",
79
+ "commander": "^15.0.0",
80
80
  "convert-gitmoji": "^0.1.5",
81
81
  "defu": "6.1.7",
82
82
  "fast-glob": "^3.3.2",
83
83
  "node-fetch-native": "^1.6.7",
84
- "semver": "^7.7.4"
84
+ "semver": "^7.8.3"
85
85
  },
86
86
  "devDependencies": {
87
- "@commitlint/cli": "^20.5.0",
88
- "@commitlint/config-conventional": "20.5.0",
89
- "@commitlint/cz-commitlint": "^20.5.1",
90
- "@commitlint/types": "^20.5.0",
91
- "@maz-ui/eslint-config": "^4.9.1",
92
- "@slack/web-api": "7.15.1",
93
- "@types/node": "^25.6.0",
87
+ "@commitlint/cli": "^21.0.2",
88
+ "@commitlint/config-conventional": "21.0.2",
89
+ "@commitlint/cz-commitlint": "^21.0.2",
90
+ "@commitlint/types": "^21.0.1",
91
+ "@maz-ui/eslint-config": "5.0.0-beta.25",
92
+ "@slack/web-api": "7.16.0",
93
+ "@types/node": "^25.9.2",
94
94
  "@types/semver": "^7.7.1",
95
- "@vitest/coverage-v8": "^4.1.5",
96
- "@yoloship/claude-sdk": "0.1.0-beta.3",
95
+ "@vitest/coverage-v8": "^4.1.8",
96
+ "@yoloship/claude-sdk": "0.2.0-beta.6",
97
97
  "cross-env": "10.1.0",
98
- "eslint": "^10.2.1",
98
+ "eslint": "^10.4.1",
99
99
  "husky": "9.1.7",
100
- "jiti": "2.6.1",
101
- "lint-staged": "^16.4.0",
102
- "memfs": "^4.57.2",
103
- "tsx": "^4.21.0",
100
+ "jiti": "2.7.0",
101
+ "lint-staged": "^17.0.7",
102
+ "memfs": "^4.57.6",
103
+ "tsx": "^4.22.4",
104
104
  "twitter-api-v2": "^1.29.0",
105
- "typescript": "^5.9.3",
105
+ "typescript": "^6.0.3",
106
106
  "unbuild": "^3.6.1",
107
- "vitest": "^4.1.5"
107
+ "vitest": "^4.1.8"
108
108
  },
109
109
  "lint-staged": {
110
110
  "*.{js,jsx,ts,tsx,mjs,mts,cjs,md,yml,json}": [