gitxplain 0.1.3 → 0.1.8

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.
@@ -1,26 +1,22 @@
1
1
  import process from "node:process";
2
2
  import {
3
- deletePaths,
3
+ createCommitFromTree,
4
+ getCommitMetadata,
4
5
  getCurrentBranchName,
5
- getCurrentHeadSha,
6
6
  getDefaultBaseRef,
7
7
  getMergeBase,
8
8
  gitCheckout,
9
- gitCheckoutOrphan,
10
- gitCherryPickAbort,
11
- gitCherryPickNoCommit,
12
- gitCommit,
9
+ gitCreateBranch,
13
10
  gitCreateAnnotatedTag,
14
11
  gitDeleteBranch,
12
+ gitForceBranch,
15
13
  gitDeleteTag,
16
- gitRemoveCachedAll,
17
- gitResetHard,
18
14
  isWorkingTreeClean,
19
15
  listBranchCommits,
20
16
  listCommitsAfter,
21
- listFilesInRef,
22
17
  listTags,
23
18
  localBranchExists,
19
+ resolveTreeSha,
24
20
  resolveCommitSha,
25
21
  runGitCommand
26
22
  } from "./gitService.js";
@@ -310,27 +306,37 @@ export function buildReleaseWindows(sourceCommits) {
310
306
  return windows;
311
307
  }
312
308
 
309
+ function selectLatestWindowsPerVersion(windows) {
310
+ const seenVersions = new Set();
311
+ const latestWindows = [];
312
+
313
+ for (let index = windows.length - 1; index >= 0; index -= 1) {
314
+ const window = windows[index];
315
+ if (!window.version || seenVersions.has(window.version)) {
316
+ continue;
317
+ }
318
+
319
+ seenVersions.add(window.version);
320
+ latestWindows.push(window);
321
+ }
322
+
323
+ return latestWindows.reverse();
324
+ }
325
+
313
326
  export function selectReleaseWindows(sourceCommits, releaseCommits = []) {
314
327
  const windows = buildReleaseWindows(sourceCommits);
315
328
  const releasedVersions = getReleasedVersions(releaseCommits);
316
329
  const unreleasedWindows = windows.filter((window) => !releasedVersions.has(window.version));
317
330
 
318
- const selectedWindows =
319
- releasedVersions.size === 0
320
- ? unreleasedWindows
321
- : unreleasedWindows.length > 0
322
- ? [unreleasedWindows.at(-1)]
323
- : [];
324
-
325
331
  return {
326
- windows: selectedWindows,
332
+ windows: unreleasedWindows,
327
333
  releasedVersions: [...releasedVersions],
328
334
  latestDetectedVersion: windows.at(-1)?.version ?? null
329
335
  };
330
336
  }
331
337
 
332
338
  export function selectReleaseTags(sourceCommits, existingTagNames = []) {
333
- const windows = buildReleaseWindows(sourceCommits);
339
+ const windows = selectLatestWindowsPerVersion(buildReleaseWindows(sourceCommits));
334
340
  const taggedVersions = extractTaggedVersions(existingTagNames);
335
341
  const tags = windows
336
342
  .filter((window) => !taggedVersions.has(window.version))
@@ -353,37 +359,88 @@ export function selectReleaseTags(sourceCommits, existingTagNames = []) {
353
359
  };
354
360
  }
355
361
 
356
- function getReleaseTrackSourceCommitShas(releaseExists, baseRef, cwd) {
362
+ function findLatestTaggedSourceVersion(sourceCommits, taggedVersions) {
363
+ const tagged = new Set(taggedVersions);
364
+ return selectLatestWindowsPerVersion(buildReleaseWindows(sourceCommits))
365
+ .map((window) => window.version)
366
+ .filter((version) => version && tagged.has(version))
367
+ .at(-1) ?? null;
368
+ }
369
+
370
+ function buildReleaseTagPlanForSource(sourceBranch, sourceRef, cwd) {
371
+ const sourceCommits = listBranchCommits(sourceRef, cwd).map((sha) => inspectCommit(sha, cwd));
372
+ const existingTagNames = listTags(cwd);
373
+ const selection = selectReleaseTags(sourceCommits, existingTagNames);
374
+
375
+ return {
376
+ sourceBranch,
377
+ baseRef: sourceRef,
378
+ mergeBase: null,
379
+ releaseExists: localBranchExists(RELEASE_BRANCH, cwd),
380
+ taggedVersions: selection.taggedVersions,
381
+ latestDetectedVersion: selection.latestDetectedVersion,
382
+ latestTaggedVersion: findLatestTaggedSourceVersion(sourceCommits, selection.taggedVersions),
383
+ tags: selection.tags
384
+ };
385
+ }
386
+
387
+ export function selectReleaseTagsFromReleaseCommits(releaseCommits, existingTagNames = []) {
388
+ const taggedVersions = extractTaggedVersions(existingTagNames);
389
+ const tags = releaseCommits
390
+ .map((commit) => ({
391
+ commit,
392
+ version: commit.subject.match(RELEASE_SUBJECT_PATTERN)?.[1]?.trim() ?? null
393
+ }))
394
+ .filter((entry) => entry.version)
395
+ .filter((entry) => !taggedVersions.has(entry.version))
396
+ .map(({ commit, version }) => ({
397
+ version,
398
+ tagName: version,
399
+ startRef: commit.shortSha,
400
+ endRef: commit.shortSha,
401
+ targetSha: commit.sha,
402
+ targetShortSha: commit.shortSha,
403
+ targetSubject: commit.subject,
404
+ commits: [commit]
405
+ }));
406
+
407
+ return {
408
+ tags,
409
+ taggedVersions: [...taggedVersions],
410
+ latestDetectedVersion:
411
+ releaseCommits
412
+ .map((commit) => commit.subject.match(RELEASE_SUBJECT_PATTERN)?.[1]?.trim() ?? null)
413
+ .filter(Boolean)
414
+ .at(-1) ?? null
415
+ };
416
+ }
417
+
418
+ function getReleaseTrackSourceCommitShas(releaseExists, baseRef, sourceRef, cwd) {
357
419
  if (!releaseExists) {
358
420
  return {
359
421
  mergeBase: null,
360
- sourceCommitShas: listBranchCommits("HEAD", cwd)
422
+ sourceCommitShas: listBranchCommits(sourceRef, cwd)
361
423
  };
362
424
  }
363
425
 
364
426
  try {
365
- const mergeBase = getMergeBase(baseRef, "HEAD", cwd);
427
+ const mergeBase = getMergeBase(baseRef, sourceRef, cwd);
366
428
  return {
367
429
  mergeBase,
368
- sourceCommitShas: listCommitsAfter(mergeBase, "HEAD", cwd)
430
+ sourceCommitShas: listCommitsAfter(mergeBase, sourceRef, cwd)
369
431
  };
370
432
  } catch {
371
433
  return {
372
434
  mergeBase: null,
373
- sourceCommitShas: listBranchCommits("HEAD", cwd)
435
+ sourceCommitShas: listBranchCommits(sourceRef, cwd)
374
436
  };
375
437
  }
376
438
  }
377
439
 
378
- export function buildReleaseMergePlan(cwd) {
379
- const sourceBranch = getCurrentBranchName(cwd);
380
- if (sourceBranch === RELEASE_BRANCH) {
381
- throw new Error(`Already on "${RELEASE_BRANCH}". Switch to a source branch before running --merge.`);
382
- }
383
-
440
+ function buildReleaseMergePlanForSource(sourceBranch, sourceRef, cwd) {
384
441
  const releaseExists = localBranchExists(RELEASE_BRANCH, cwd);
385
442
  const baseRef = releaseExists ? RELEASE_BRANCH : getDefaultBaseRef(cwd);
386
- const { mergeBase, sourceCommitShas } = getReleaseTrackSourceCommitShas(releaseExists, baseRef, cwd);
443
+ const { mergeBase, sourceCommitShas } = getReleaseTrackSourceCommitShas(releaseExists, baseRef, sourceRef, cwd);
387
444
  const sourceCommits = sourceCommitShas.map((sha) => inspectCommit(sha, cwd));
388
445
  const releaseCommits = releaseExists ? listBranchCommits(RELEASE_BRANCH, cwd).map((sha) => inspectCommit(sha, cwd)) : [];
389
446
  const selection = selectReleaseWindows(sourceCommits, releaseCommits);
@@ -401,27 +458,22 @@ export function buildReleaseMergePlan(cwd) {
401
458
  };
402
459
  }
403
460
 
461
+ export function buildReleaseMergePlan(cwd) {
462
+ const sourceBranch = getCurrentBranchName(cwd);
463
+ if (sourceBranch === RELEASE_BRANCH) {
464
+ throw new Error(`Already on "${RELEASE_BRANCH}". Switch to a source branch before running --merge.`);
465
+ }
466
+
467
+ return buildReleaseMergePlanForSource(sourceBranch, "HEAD", cwd);
468
+ }
469
+
404
470
  export function buildReleaseTagPlan(cwd) {
405
471
  const sourceBranch = getCurrentBranchName(cwd);
406
472
  if (sourceBranch === RELEASE_BRANCH) {
407
473
  throw new Error(`Already on "${RELEASE_BRANCH}". Switch to a source branch before running --tag.`);
408
474
  }
409
475
 
410
- const releaseExists = localBranchExists(RELEASE_BRANCH, cwd);
411
- const baseRef = releaseExists ? RELEASE_BRANCH : getDefaultBaseRef(cwd);
412
- const { mergeBase, sourceCommitShas } = getReleaseTrackSourceCommitShas(releaseExists, baseRef, cwd);
413
- const sourceCommits = sourceCommitShas.map((sha) => inspectCommit(sha, cwd));
414
- const selection = selectReleaseTags(sourceCommits, listTags(cwd));
415
-
416
- return {
417
- sourceBranch,
418
- baseRef,
419
- mergeBase,
420
- releaseExists,
421
- taggedVersions: selection.taggedVersions,
422
- latestDetectedVersion: selection.latestDetectedVersion,
423
- tags: selection.tags
424
- };
476
+ return buildReleaseTagPlanForSource(sourceBranch, "HEAD", cwd);
425
477
  }
426
478
 
427
479
  export function finalizeReleaseMergePlan(plan) {
@@ -438,6 +490,126 @@ export function finalizeReleaseTagPlan(plan) {
438
490
  };
439
491
  }
440
492
 
493
+ function findLatestReleaseVersion(releaseCommits) {
494
+ return releaseCommits
495
+ .map((commit) => commit.subject.match(RELEASE_SUBJECT_PATTERN)?.[1]?.trim() ?? null)
496
+ .filter(Boolean)
497
+ .at(-1) ?? null;
498
+ }
499
+
500
+ function findLatestTaggedReleaseVersion(releaseCommits, taggedVersions) {
501
+ const tagged = new Set(taggedVersions);
502
+ return releaseCommits
503
+ .map((commit) => commit.subject.match(RELEASE_SUBJECT_PATTERN)?.[1]?.trim() ?? null)
504
+ .filter((version) => version && tagged.has(version))
505
+ .at(-1) ?? null;
506
+ }
507
+
508
+ function buildDriftStatus(sourceRef, sourceLabel, releaseExists, cwd) {
509
+ if (!releaseExists) {
510
+ return {
511
+ hasReleaseBranch: false,
512
+ disconnectedHistory: false,
513
+ sourceOnlyCount: listBranchCommits(sourceRef, cwd).length,
514
+ releaseOnlyCount: 0,
515
+ summary: `Release branch "${RELEASE_BRANCH}" does not exist yet.`
516
+ };
517
+ }
518
+
519
+ try {
520
+ const mergeBase = getMergeBase(sourceRef, RELEASE_BRANCH, cwd);
521
+ const sourceOnlyCount = listCommitsAfter(mergeBase, sourceRef, cwd).length;
522
+ const releaseOnlyCount = listCommitsAfter(mergeBase, RELEASE_BRANCH, cwd).length;
523
+
524
+ return {
525
+ hasReleaseBranch: true,
526
+ disconnectedHistory: false,
527
+ mergeBase,
528
+ sourceOnlyCount,
529
+ releaseOnlyCount,
530
+ summary:
531
+ sourceOnlyCount === 0 && releaseOnlyCount === 0
532
+ ? `${sourceLabel} and ${RELEASE_BRANCH} point at the same history.`
533
+ : `${sourceLabel} has ${sourceOnlyCount} unique commit(s); ${RELEASE_BRANCH} has ${releaseOnlyCount} unique commit(s).`
534
+ };
535
+ } catch {
536
+ return {
537
+ hasReleaseBranch: true,
538
+ disconnectedHistory: true,
539
+ mergeBase: null,
540
+ sourceOnlyCount: listBranchCommits(sourceRef, cwd).length,
541
+ releaseOnlyCount: listBranchCommits(RELEASE_BRANCH, cwd).length,
542
+ summary: `${sourceLabel} and ${RELEASE_BRANCH} do not share a merge base. This is expected when the release branch is orphaned.`
543
+ };
544
+ }
545
+ }
546
+
547
+ function getNextRecommendedAction({ releaseExists, mergePlan, missingTagCount }) {
548
+ if (!releaseExists && mergePlan.windows.length > 0) {
549
+ return `Run \`gitxplain --merge --execute\` to create ${RELEASE_BRANCH} and promote ${mergePlan.windows.length} unreleased version(s).`;
550
+ }
551
+
552
+ if (!releaseExists && missingTagCount > 0) {
553
+ return `Run \`gitxplain --tag --execute\` to create ${missingTagCount} missing version tag(s) on the current branch.`;
554
+ }
555
+
556
+ if (!releaseExists) {
557
+ return `No ${RELEASE_BRANCH} branch exists yet, and no releasable version bumps were detected.`;
558
+ }
559
+
560
+ if (mergePlan.windows.length > 0 && missingTagCount > 0) {
561
+ return `Run \`gitxplain --merge --execute\` to update ${RELEASE_BRANCH}, and \`gitxplain --tag --execute\` to create ${missingTagCount} missing version tag(s).`;
562
+ }
563
+
564
+ if (mergePlan.windows.length > 0) {
565
+ return `Run \`gitxplain --merge --execute\` to promote ${mergePlan.windows.length} unreleased version(s) to ${RELEASE_BRANCH}.`;
566
+ }
567
+
568
+ if (missingTagCount > 0) {
569
+ return `Run \`gitxplain --tag --execute\` to create ${missingTagCount} missing version tag(s).`;
570
+ }
571
+
572
+ return "No action required. Release branch and tags are up to date.";
573
+ }
574
+
575
+ export function buildReleaseStatus(cwd) {
576
+ const currentBranch = getCurrentBranchName(cwd);
577
+ const releaseExists = localBranchExists(RELEASE_BRANCH, cwd);
578
+ const sourceBranch = currentBranch === RELEASE_BRANCH ? getDefaultBaseRef(cwd) : currentBranch;
579
+ const sourceRef = currentBranch === RELEASE_BRANCH ? sourceBranch : "HEAD";
580
+ const mergePlan = finalizeReleaseMergePlan(buildReleaseMergePlanForSource(sourceBranch, sourceRef, cwd));
581
+ const releaseCommits = releaseExists ? listBranchCommits(RELEASE_BRANCH, cwd).map((sha) => inspectCommit(sha, cwd)) : [];
582
+ const tagPlan = finalizeReleaseTagPlan(buildReleaseTagPlanForSource(sourceBranch, sourceRef, cwd));
583
+ const drift = buildDriftStatus(sourceRef, sourceBranch, releaseExists, cwd);
584
+ const missingTagVersions = tagPlan.tags.map((tag) => tag.tagName);
585
+ const unmergedVersions = mergePlan.windows.map((window) => window.version);
586
+
587
+ return {
588
+ sourceBranch,
589
+ sourceRef,
590
+ releaseBranch: RELEASE_BRANCH,
591
+ releaseExists,
592
+ currentBranch,
593
+ health:
594
+ !releaseExists || unmergedVersions.length > 0 || missingTagVersions.length > 0
595
+ ? "needs attention"
596
+ : "healthy",
597
+ latestSourceVersion: mergePlan.latestDetectedVersion,
598
+ latestReleaseVersion: findLatestReleaseVersion(releaseCommits),
599
+ latestTaggedVersion: tagPlan.latestTaggedVersion,
600
+ unmergedVersions,
601
+ missingTagVersions,
602
+ drift,
603
+ mergePlan,
604
+ tagPlan,
605
+ nextRecommendedAction: getNextRecommendedAction({
606
+ releaseExists,
607
+ mergePlan,
608
+ missingTagCount: missingTagVersions.length
609
+ })
610
+ };
611
+ }
612
+
441
613
  export function formatReleaseMergePlan(plan) {
442
614
  const lines = [
443
615
  colorize("Release Merge Plan", ANSI.bold + ANSI.cyan),
@@ -504,6 +676,50 @@ export function formatReleaseTagPlan(plan) {
504
676
  return lines.join("\n");
505
677
  }
506
678
 
679
+ export function formatReleaseStatus(status) {
680
+ const lines = [
681
+ colorize("Release Status", ANSI.bold + ANSI.cyan),
682
+ `${colorize("Source Branch:", ANSI.bold + ANSI.cyan)} ${status.sourceBranch}`,
683
+ `${colorize("Release Branch:", ANSI.bold + ANSI.cyan)} ${status.releaseBranch}`,
684
+ `${colorize("Current Branch:", ANSI.bold + ANSI.cyan)} ${status.currentBranch}`,
685
+ `${colorize("Overall:", ANSI.bold + ANSI.cyan)} ${status.health}`,
686
+ `${colorize("Latest Source Version:", ANSI.bold + ANSI.cyan)} ${status.latestSourceVersion ?? "none"}`,
687
+ `${colorize("Latest Release Version:", ANSI.bold + ANSI.cyan)} ${status.latestReleaseVersion ?? "none"}`,
688
+ `${colorize("Latest Tagged Version:", ANSI.bold + ANSI.cyan)} ${status.latestTaggedVersion ?? "none"}`
689
+ ];
690
+
691
+ lines.push("");
692
+ lines.push(colorize("Unmerged Version Bumps", ANSI.bold + ANSI.yellow));
693
+ if (status.unmergedVersions.length === 0) {
694
+ lines.push("none");
695
+ } else {
696
+ for (const window of status.mergePlan.windows) {
697
+ lines.push(`- ${window.version} (${window.startRef}..${window.endRef})`);
698
+ }
699
+ }
700
+
701
+ lines.push("");
702
+ lines.push(colorize("Missing Release Tags", ANSI.bold + ANSI.yellow));
703
+ if (status.missingTagVersions.length === 0) {
704
+ lines.push("none");
705
+ } else {
706
+ for (const tag of status.tagPlan.tags) {
707
+ lines.push(`- ${tag.tagName} -> ${tag.targetShortSha} ${tag.targetSubject}`);
708
+ }
709
+ }
710
+
711
+ lines.push("");
712
+ lines.push(colorize("Branch Drift", ANSI.bold + ANSI.yellow));
713
+ lines.push(status.drift.summary);
714
+ lines.push(`- Commits only on ${status.sourceBranch}: ${status.drift.sourceOnlyCount}`);
715
+ lines.push(`- Commits only on ${status.releaseBranch}: ${status.drift.releaseOnlyCount}`);
716
+
717
+ lines.push("");
718
+ lines.push(`${colorize("Next Recommended Action:", ANSI.bold + ANSI.cyan)} ${status.nextRecommendedAction}`);
719
+
720
+ return lines.join("\n");
721
+ }
722
+
507
723
  function buildRecoveryMessage({ originalBranch, originalReleaseSha, createdReleaseBranch }) {
508
724
  const lines = ["Release promotion failed. Recovery steps:"];
509
725
 
@@ -518,6 +734,15 @@ function buildRecoveryMessage({ originalBranch, originalReleaseSha, createdRelea
518
734
  return lines.join("\n");
519
735
  }
520
736
 
737
+ function buildReleaseCommitMetadata(ref, version, cwd) {
738
+ const metadata = getCommitMetadata(ref, cwd);
739
+
740
+ return {
741
+ ...metadata,
742
+ message: `release ${version}`
743
+ };
744
+ }
745
+
521
746
  export function executeReleaseMerge(plan, cwd) {
522
747
  if (plan.windows.length === 0) {
523
748
  throw new Error("No unreleased release commits detected. Nothing to merge.");
@@ -530,36 +755,50 @@ export function executeReleaseMerge(plan, cwd) {
530
755
  const originalBranch = getCurrentBranchName(cwd);
531
756
  const releaseExists = localBranchExists(RELEASE_BRANCH, cwd);
532
757
  const originalReleaseSha = releaseExists ? resolveCommitSha(RELEASE_BRANCH, cwd) : null;
533
- const originalHeadSha = getCurrentHeadSha(cwd);
534
- const originalHeadFiles = releaseExists ? [] : listFilesInRef("HEAD", cwd);
758
+ let updatedReleaseSha = originalReleaseSha;
535
759
 
536
760
  try {
537
- if (releaseExists) {
538
- gitCheckout(RELEASE_BRANCH, cwd);
539
- } else {
540
- gitCheckoutOrphan(RELEASE_BRANCH, cwd);
541
- gitRemoveCachedAll(cwd);
542
- deletePaths(originalHeadFiles, cwd);
543
- }
544
-
545
761
  for (const window of plan.windows) {
546
- for (const commit of window.commits) {
547
- gitCherryPickNoCommit(commit.sha, cwd);
762
+ const targetCommit = window.commits.at(-1);
763
+ if (targetCommit?.sha == null) {
764
+ throw new Error(`Unable to determine the source commit for release ${window.version}.`);
548
765
  }
549
766
 
550
- gitCommit(`release ${window.version}`, cwd);
767
+ const treeSha = resolveTreeSha(targetCommit.sha, cwd);
768
+ const metadata = buildReleaseCommitMetadata(targetCommit.sha, window.version, cwd);
769
+ updatedReleaseSha = createCommitFromTree(
770
+ treeSha,
771
+ updatedReleaseSha == null ? [] : [updatedReleaseSha],
772
+ metadata,
773
+ cwd
774
+ );
775
+ }
776
+
777
+ if (updatedReleaseSha == null || updatedReleaseSha === originalReleaseSha) {
778
+ throw new Error("Release merge did not create any new commits.");
779
+ }
780
+
781
+ if (releaseExists) {
782
+ gitForceBranch(RELEASE_BRANCH, updatedReleaseSha, cwd);
783
+ } else {
784
+ gitCreateBranch(RELEASE_BRANCH, updatedReleaseSha, cwd);
551
785
  }
552
- } catch (error) {
553
- gitCherryPickAbort(cwd);
554
786
 
787
+ gitCheckout(RELEASE_BRANCH, cwd);
788
+ } catch (error) {
555
789
  try {
556
790
  if (releaseExists) {
557
- gitResetHard(originalReleaseSha, cwd);
558
- gitCheckout(originalBranch, cwd);
559
- } else {
560
- gitCheckout(originalBranch, cwd);
791
+ gitForceBranch(RELEASE_BRANCH, originalReleaseSha, cwd);
792
+ } else if (localBranchExists(RELEASE_BRANCH, cwd)) {
793
+ if (getCurrentBranchName(cwd) === RELEASE_BRANCH) {
794
+ gitCheckout(originalBranch, cwd);
795
+ }
561
796
  gitDeleteBranch(RELEASE_BRANCH, cwd);
562
797
  }
798
+
799
+ if (getCurrentBranchName(cwd) !== originalBranch) {
800
+ gitCheckout(originalBranch, cwd);
801
+ }
563
802
  } catch {
564
803
  // Preserve original failure and print recovery guidance below.
565
804
  }
@@ -574,11 +813,6 @@ export function executeReleaseMerge(plan, cwd) {
574
813
  );
575
814
  throw new Error("Release merge aborted.");
576
815
  }
577
-
578
- const updatedReleaseSha = getCurrentHeadSha(cwd);
579
- if (updatedReleaseSha === originalHeadSha) {
580
- throw new Error("Release merge did not create any new commits.");
581
- }
582
816
  }
583
817
 
584
818
  export function executeReleaseTagPlan(plan, cwd) {
@@ -138,18 +138,6 @@ function classifyTone(line) {
138
138
  }
139
139
 
140
140
  function colorizeByTone(line, tone) {
141
- if (tone === "good") {
142
- return colorize(line, ANSI.green);
143
- }
144
-
145
- if (tone === "bad") {
146
- return colorize(line, ANSI.red);
147
- }
148
-
149
- if (tone === "neutral") {
150
- return colorize(line, ANSI.yellow);
151
- }
152
-
153
141
  return line;
154
142
  }
155
143
 
@@ -161,17 +149,7 @@ function formatBulletLine(line) {
161
149
  }
162
150
 
163
151
  const [, indent, marker, content] = match;
164
- const tone = classifyTone(content);
165
- const coloredMarker =
166
- tone === "good"
167
- ? colorize(marker, ANSI.green)
168
- : tone === "bad"
169
- ? colorize(marker, ANSI.red)
170
- : tone === "neutral"
171
- ? colorize(marker, ANSI.yellow)
172
- : colorize(marker, ANSI.cyan);
173
-
174
- return `${indent}${coloredMarker} ${colorizeByTone(content, tone)}`;
152
+ return `${indent}${colorize(marker, ANSI.cyan)} ${content}`;
175
153
  }
176
154
 
177
155
  function formatSeverityLine(line) {
@@ -179,19 +157,7 @@ function formatSeverityLine(line) {
179
157
  return null;
180
158
  }
181
159
 
182
- if (/\blow\b/i.test(line)) {
183
- return colorize(line, ANSI.green);
184
- }
185
-
186
- if (/\bmedium\b/i.test(line)) {
187
- return colorize(line, ANSI.yellow);
188
- }
189
-
190
- if (/\bhigh\b/i.test(line)) {
191
- return colorize(line, ANSI.red);
192
- }
193
-
194
- return colorize(line, ANSI.bold + ANSI.yellow);
160
+ return line;
195
161
  }
196
162
 
197
163
  function formatLine(line) {