@kaitranntt/ccs 7.65.2 → 7.65.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaitranntt/ccs",
3
- "version": "7.65.2",
3
+ "version": "7.65.3",
4
4
  "description": "Claude Code Switch - Instant profile switching between Claude, GLM, Kimi, and more",
5
5
  "keywords": [
6
6
  "cli",
@@ -65,7 +65,9 @@ function cleanMultilineText(value) {
65
65
  }
66
66
 
67
67
  function escapeMarkdown(value) {
68
- return String(value).replace(/\\/g, '\\\\').replace(/([`*_{}[\]<>|])/g, '\\$1');
68
+ return String(value)
69
+ .replace(/\\/g, '\\\\')
70
+ .replace(/([`*_{}[\]<>|])/g, '\\$1');
69
71
  }
70
72
 
71
73
  function escapeMarkdownText(value) {
@@ -155,7 +157,8 @@ function normalizeRenderingMetadata(raw) {
155
157
  if (packetIncludedFiles !== null) metadata.packetIncludedFiles = packetIncludedFiles;
156
158
  if (packetTotalFiles !== null) metadata.packetTotalFiles = packetTotalFiles;
157
159
  if (packetOmittedFiles !== null) metadata.packetOmittedFiles = packetOmittedFiles;
158
- if (scopeLabel === 'reviewable files' || scopeLabel === 'changed files') metadata.scopeLabel = scopeLabel;
160
+ if (scopeLabel === 'reviewable files' || scopeLabel === 'changed files')
161
+ metadata.scopeLabel = scopeLabel;
159
162
 
160
163
  return metadata;
161
164
  }
@@ -203,7 +206,8 @@ function formatScopeSummary(rendering) {
203
206
  typeof rendering.selectedChanges === 'number' &&
204
207
  typeof rendering.reviewableChanges === 'number'
205
208
  ) {
206
- const changeLabel = scopeLabel === 'reviewable files' ? 'reviewable changed lines' : 'changed lines';
209
+ const changeLabel =
210
+ scopeLabel === 'reviewable files' ? 'reviewable changed lines' : 'changed lines';
207
211
  return `${fileScope}; ${rendering.selectedChanges}/${rendering.reviewableChanges} ${changeLabel}`;
208
212
  }
209
213
 
@@ -254,7 +258,8 @@ function formatReviewContext(rendering) {
254
258
  parts.push(`packet ${rendering.packetIncludedFiles}/${rendering.packetTotalFiles}`);
255
259
  }
256
260
 
257
- const runtimeBudget = formatCombinedBudget(rendering) || formatTimeBudget(rendering) || formatTurnBudget(rendering);
261
+ const runtimeBudget =
262
+ formatCombinedBudget(rendering) || formatTimeBudget(rendering) || formatTurnBudget(rendering);
258
263
  if (runtimeBudget) {
259
264
  parts.push(runtimeBudget);
260
265
  }
@@ -301,7 +306,10 @@ function describeIncompleteOutcome({ reason, rendering, turnsUsed, status }) {
301
306
  return `The ${reviewLabel} ended before it could produce validated structured output within the available ${combinedBudget} runtime budget.`;
302
307
  }
303
308
 
304
- if (classifyFallbackReason(reason) === 'missing' || classifyFallbackReason(reason) === 'invalid_json') {
309
+ if (
310
+ classifyFallbackReason(reason) === 'missing' ||
311
+ classifyFallbackReason(reason) === 'invalid_json'
312
+ ) {
305
313
  return `The ${reviewLabel} ended without validated structured output, so the normalizer published the safe fallback comment instead.`;
306
314
  }
307
315
 
@@ -344,7 +352,10 @@ function normalizeChecklistRows(fieldName, labelField, raw) {
344
352
 
345
353
  const rows = [];
346
354
  for (const [index, item] of raw.entries()) {
347
- const label = validatePlainTextField(`${fieldName}[${index}].${labelField}`, item?.[labelField]);
355
+ const label = validatePlainTextField(
356
+ `${fieldName}[${index}].${labelField}`,
357
+ item?.[labelField]
358
+ );
348
359
  if (!label.ok) return label;
349
360
 
350
361
  const notes = validatePlainTextField(`${fieldName}[${index}].notes`, item?.notes);
@@ -479,16 +490,19 @@ function formatHotspotFiles(files) {
479
490
  function formatRemainingCoverage(rendering) {
480
491
  if (
481
492
  typeof rendering.reviewableFiles !== 'number' ||
482
- (typeof rendering.packetIncludedFiles !== 'number' && typeof rendering.selectedFiles !== 'number')
493
+ (typeof rendering.packetIncludedFiles !== 'number' &&
494
+ typeof rendering.selectedFiles !== 'number')
483
495
  ) {
484
496
  return null;
485
497
  }
486
498
 
487
- const coveredFiles = typeof rendering.packetIncludedFiles === 'number'
488
- ? rendering.packetIncludedFiles
489
- : rendering.selectedFiles;
499
+ const coveredFiles =
500
+ typeof rendering.packetIncludedFiles === 'number'
501
+ ? rendering.packetIncludedFiles
502
+ : rendering.selectedFiles;
490
503
  const remainingFiles = Math.max(rendering.reviewableFiles - coveredFiles, 0);
491
- const packetOmittedFiles = typeof rendering.packetOmittedFiles === 'number' ? rendering.packetOmittedFiles : 0;
504
+ const packetOmittedFiles =
505
+ typeof rendering.packetOmittedFiles === 'number' ? rendering.packetOmittedFiles : 0;
492
506
  const hasChangeCounts =
493
507
  packetOmittedFiles === 0 &&
494
508
  typeof rendering.selectedChanges === 'number' &&
@@ -540,7 +554,11 @@ export function normalizeStructuredOutput(raw) {
540
554
  if (!overallRationale.ok) return overallRationale;
541
555
 
542
556
  const findings = Array.isArray(parsed.findings) ? parsed.findings : null;
543
- const securityChecklist = normalizeChecklistRows('securityChecklist', 'check', parsed.securityChecklist);
557
+ const securityChecklist = normalizeChecklistRows(
558
+ 'securityChecklist',
559
+ 'check',
560
+ parsed.securityChecklist
561
+ );
544
562
  if (!securityChecklist.ok) return securityChecklist;
545
563
 
546
564
  const ccsCompliance = normalizeChecklistRows('ccsCompliance', 'rule', parsed.ccsCompliance);
@@ -582,7 +600,11 @@ export function normalizeStructuredOutput(raw) {
582
600
  if (finding && Object.hasOwn(finding, 'line')) {
583
601
  if (finding.line === null) {
584
602
  line = null;
585
- } else if (typeof finding.line === 'number' && Number.isInteger(finding.line) && finding.line > 0) {
603
+ } else if (
604
+ typeof finding.line === 'number' &&
605
+ Number.isInteger(finding.line) &&
606
+ finding.line > 0
607
+ ) {
586
608
  line = finding.line;
587
609
  } else {
588
610
  return { ok: false, reason: `findings[${index}].line is invalid` };
@@ -668,7 +690,9 @@ function renderFindingReference(finding) {
668
690
  }
669
691
 
670
692
  function getOrderedFindings(findings) {
671
- return SEVERITY_ORDER.flatMap((severity) => findings.filter((finding) => finding.severity === severity));
693
+ return SEVERITY_ORDER.flatMap((severity) =>
694
+ findings.filter((finding) => finding.severity === severity)
695
+ );
672
696
  }
673
697
 
674
698
  function renderTopFindings(findings) {
@@ -726,37 +750,65 @@ function renderDetailedFindings(findings) {
726
750
 
727
751
  export function renderStructuredReview(review, { model, rendering: renderOptions } = {}) {
728
752
  const rendering = mergeRenderingMetadata(review?.rendering, renderOptions);
729
- const lines = [
730
- '### Verdict',
731
- '',
732
- `**${ASSESSMENTS[review.overallAssessment]}** — ${renderInlineText(review.overallRationale)}`,
733
- '',
734
- renderInlineText(review.summary),
735
- ];
753
+ const lines = ['### 📋 Summary', '', renderInlineText(review.summary)];
736
754
  const reviewContext = formatReviewContext(rendering);
737
755
 
738
756
  if (reviewContext) {
739
757
  lines.push('', reviewContext);
740
758
  }
741
759
 
742
- lines.push('', '### Top Findings', '', ...renderTopFindings(review.findings));
743
- lines.push(...renderSection(`### Detailed Findings (${review.findings.length})`, renderDetailedFindings(review.findings)));
760
+ lines.push('', '### 🔍 Findings');
761
+ if (review.findings.length === 0) {
762
+ lines.push('', 'No confirmed issues found after reviewing the diff and surrounding code.');
763
+ } else {
764
+ for (const severity of SEVERITY_ORDER) {
765
+ const scopedFindings = review.findings.filter((finding) => finding.severity === severity);
766
+ if (scopedFindings.length === 0) continue;
767
+
768
+ lines.push('', SEVERITY_HEADERS[severity], '');
769
+ for (const finding of scopedFindings) {
770
+ const snippets = Array.isArray(finding.snippets) ? finding.snippets : [];
771
+ lines.push(
772
+ `- **${renderCode(renderFindingReference(finding))} — ${renderInlineText(finding.title)}**`
773
+ );
774
+ lines.push(` Problem: ${renderInlineText(finding.what)}`);
775
+ lines.push(` Why it matters: ${renderInlineText(finding.why)}`);
776
+ lines.push(` Suggested fix: ${renderInlineText(finding.fix)}`);
777
+
778
+ if (snippets.length > 0) {
779
+ lines.push('');
780
+ lines.push(...renderFindingSnippets(snippets));
781
+ }
782
+
783
+ lines.push('');
784
+ }
785
+ }
786
+
787
+ if (lines[lines.length - 1] === '') {
788
+ lines.pop();
789
+ }
790
+ }
791
+
744
792
  lines.push(
745
793
  ...renderSection(
746
- `### Security Checklist (${review.securityChecklist.length})`,
794
+ '### 🔒 Security Checklist',
747
795
  renderChecklistTable('Check', 'check', review.securityChecklist)
748
796
  )
749
797
  );
750
798
  lines.push(
751
799
  ...renderSection(
752
- `### CCS Compliance (${review.ccsCompliance.length})`,
800
+ '### 📊 CCS Compliance',
753
801
  renderChecklistTable('Rule', 'rule', review.ccsCompliance)
754
802
  )
755
803
  );
756
- lines.push(...renderSection(`### Informational (${review.informational.length})`, renderBulletSection(review.informational)));
757
- lines.push(...renderSection(`### What's Done Well (${review.strengths.length})`, renderBulletSection(review.strengths)));
804
+ lines.push(...renderSection('### 💡 Informational', renderBulletSection(review.informational)));
805
+ lines.push(...renderSection("### What's Done Well", renderBulletSection(review.strengths)));
758
806
 
759
807
  lines.push(
808
+ '',
809
+ '### 🎯 Overall Assessment',
810
+ '',
811
+ `**${ASSESSMENTS[review.overallAssessment]}** — ${renderInlineText(review.overallRationale)}`,
760
812
  '',
761
813
  `> 🤖 Reviewed by \`${model}\``
762
814
  );
@@ -784,7 +836,9 @@ export function renderIncompleteReview({
784
836
  ];
785
837
 
786
838
  if (rendering.mode) {
787
- lines.push(`- Review mode: ${renderCode(rendering.mode)} (${escapeMarkdownText(REVIEW_MODE_DETAILS[rendering.mode])})`);
839
+ lines.push(
840
+ `- Review mode: ${renderCode(rendering.mode)} (${escapeMarkdownText(REVIEW_MODE_DETAILS[rendering.mode])})`
841
+ );
788
842
  }
789
843
  const scopeSummary = formatScopeSummary(rendering);
790
844
  if (scopeSummary) {
@@ -804,7 +858,9 @@ export function renderIncompleteReview({
804
858
  }
805
859
  const remainingCoverage = formatRemainingCoverage(rendering);
806
860
  if (remainingCoverage) {
807
- lines.push(`- Remaining reviewable scope not fully covered: ${escapeMarkdownText(remainingCoverage)}`);
861
+ lines.push(
862
+ `- Remaining reviewable scope not fully covered: ${escapeMarkdownText(remainingCoverage)}`
863
+ );
808
864
  }
809
865
  lines.push(`- Manual follow-up: ${escapeMarkdownText(formatFallbackFollowUp(rendering))}`);
810
866
  if (runtimeTools?.length) {
@@ -814,7 +870,12 @@ export function renderIncompleteReview({
814
870
  lines.push(`- Turns used: ${turnsUsed}`);
815
871
  }
816
872
 
817
- lines.push('', `Re-run \`/review\` or inspect [the workflow run](${runUrl}).`, '', `> 🤖 Reviewed by \`${model}\``);
873
+ lines.push(
874
+ '',
875
+ `Re-run \`/review\` or inspect [the workflow run](${runUrl}).`,
876
+ '',
877
+ `> 🤖 Reviewed by \`${model}\``
878
+ );
818
879
  return lines.join('\n');
819
880
  }
820
881
 
@@ -857,15 +918,16 @@ export function writeReviewFromEnv(env = process.env) {
857
918
  fs.writeFileSync(outputFile, `${content}\n`, 'utf8');
858
919
 
859
920
  if (!validation.ok) {
860
- console.warn(`::warning::AI review output normalization fell back to incomplete comment: ${validation.reason}`);
921
+ console.warn(
922
+ `::warning::AI review output normalization fell back to incomplete comment: ${validation.reason}`
923
+ );
861
924
  }
862
925
 
863
926
  return { usedFallback: !validation.ok, content };
864
927
  }
865
928
 
866
929
  const isMain =
867
- process.argv[1] &&
868
- path.resolve(process.argv[1]) === path.resolve(fileURLToPath(import.meta.url));
930
+ process.argv[1] && path.resolve(process.argv[1]) === path.resolve(fileURLToPath(import.meta.url));
869
931
 
870
932
  if (isMain) {
871
933
  writeReviewFromEnv();