@mrkaran/hodor 0.7.5 → 0.7.7

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.
@@ -111,24 +111,48 @@ function renderSummaryMarkdown(review, options = {}) {
111
111
  else if (finding.priority === 2) counts.important++;
112
112
  else counts.minor++;
113
113
  }
114
- lines.push("");
114
+ const totalOpen = counts.blocking + counts.important + counts.minor;
115
115
  lines.push(
116
- `**Open findings:** ${counts.blocking} blocking \xB7 ${counts.important} important \xB7 ${counts.minor} minor`
116
+ "",
117
+ "| Open findings | Count |",
118
+ "| --- | ---: |",
119
+ `| Critical (P0/P1) | ${counts.blocking} |`,
120
+ `| Important (P2) | ${counts.important} |`,
121
+ `| Minor (P3) | ${counts.minor} |`,
122
+ ""
117
123
  );
118
- if (options.inlineCreated != null || options.inlineDeduplicated != null) {
124
+ const verdict = totalOpen === 0 ? "No open findings" : counts.blocking > 0 ? "Blocking findings remain" : "Non-blocking findings remain";
125
+ lines.push(`**Overall verdict:** ${verdict}`);
126
+ const scope = options.reviewMode ? `${options.reviewMode[0].toUpperCase()}${options.reviewMode.slice(1)} review` : "Latest review";
127
+ if (review.overall_explanation) {
119
128
  lines.push("");
120
- lines.push(
121
- `**Inline delivery:** ${options.inlineCreated ?? 0} new \xB7 ${options.inlineDeduplicated ?? 0} already open`
122
- );
129
+ lines.push(`**${scope}:** ${review.overall_explanation}`);
130
+ }
131
+ const inlineCreated = options.inlineCreated ?? 0;
132
+ const inlineDeduplicated = options.inlineDeduplicated ?? 0;
133
+ if (inlineCreated > 0 || inlineDeduplicated > 0) {
134
+ const delivery = [
135
+ inlineCreated > 0 ? `${inlineCreated} new` : null,
136
+ inlineDeduplicated > 0 ? `${inlineDeduplicated} already open` : null
137
+ ].filter((item) => item !== null);
138
+ lines.push("");
139
+ lines.push(`**Inline comments:** ${delivery.join(" \xB7 ")}`);
123
140
  }
124
- const scope = options.reviewMode ? `${options.reviewMode} review` : "Latest review";
125
- lines.push("");
126
- lines.push(`**${scope}:** ${review.overall_explanation}`);
127
141
  if (fallbackFindings.length > 0) {
128
- lines.push("");
129
- lines.push(`### ${options.fallbackHeading ?? "Findings"}`);
142
+ lines.push(
143
+ "",
144
+ `### ${options.fallbackHeading ?? "Findings"}`,
145
+ "",
146
+ "| Finding | Location | Priority |",
147
+ "| --- | --- | ---: |"
148
+ );
130
149
  for (const finding of fallbackFindings) {
131
- lines.push(formatFinding(finding));
150
+ const title = escapeTableCell(finding.title);
151
+ const body = escapeTableCell(finding.body);
152
+ const location = escapeTableCell(formatLocation(finding.code_location));
153
+ lines.push(
154
+ `| **${title}**<br>${body} | \`${location}\` | P${finding.priority} |`
155
+ );
132
156
  }
133
157
  }
134
158
  return lines.join("\n").trimEnd() + "\n";
@@ -140,6 +164,9 @@ function formatFinding(f) {
140
164
  return `${title}
141
165
  ${body}`;
142
166
  }
167
+ function escapeTableCell(value) {
168
+ return value.replace(/\r?\n/g, " ").replace(/\|/g, "\\|");
169
+ }
143
170
  function formatLocation(loc) {
144
171
  let filePath = loc.absolute_file_path;
145
172
  const buildsMatch = filePath.match(/\/builds\/[^/]+\/[^/]+\/(.+)/);
@@ -1279,22 +1306,19 @@ function formatDuration(seconds) {
1279
1306
  }
1280
1307
  function formatMetricsMarkdown(metrics) {
1281
1308
  const totalInput = metrics.inputTokens + metrics.cacheReadTokens;
1282
- const parts = [`in \`${tok(totalInput)}\``, `fresh \`${tok(metrics.inputTokens)}\``];
1309
+ const work = `${metrics.turns} turns \xB7 ${metrics.toolCalls} tool calls \xB7 ${formatDuration(metrics.durationSeconds)}`;
1310
+ const cost = metrics.cost > 0 ? ` \xB7 \`$${metrics.cost.toFixed(4)}\`` : "";
1311
+ const tokens = [`\`${tok(totalInput)}\` input`];
1283
1312
  if (metrics.cacheReadTokens > 0) {
1284
- parts.push(`cache read \`${tok(metrics.cacheReadTokens)}\``);
1313
+ const hitPct = (metrics.cacheReadTokens / totalInput * 100).toFixed(0);
1314
+ tokens.push(`\`${tok(metrics.cacheReadTokens)}\` cached (${hitPct}%)`);
1285
1315
  }
1316
+ tokens.push(`\`${tok(metrics.outputTokens)}\` output`);
1286
1317
  if (metrics.cacheWriteTokens > 0) {
1287
- parts.push(`cache write \`${tok(metrics.cacheWriteTokens)}\``);
1318
+ tokens.push(`\`${tok(metrics.cacheWriteTokens)}\` cache write`);
1288
1319
  }
1289
- parts.push(`out \`${tok(metrics.outputTokens)}\``);
1290
- const lines = [
1291
- `**Review Metrics** \u2014 ${metrics.turns} turns, ${metrics.toolCalls} tool calls, ${formatDuration(metrics.durationSeconds)}`,
1292
- `- Tokens: ${parts.join(" | ")} (total \`${tok(metrics.totalTokens)}\`)`
1293
- ];
1294
- if (metrics.cost > 0) {
1295
- lines.push(`- Cost: \`$${metrics.cost.toFixed(4)}\``);
1296
- }
1297
- return lines.join("\n");
1320
+ return `**Review metrics:** ${work}${cost}
1321
+ - Tokens: ${tokens.join(" \xB7 ")}`;
1298
1322
  }
1299
1323
  function printMetrics(metrics, stream = process.stderr) {
1300
1324
  const dim = chalk2.dim;
@@ -1944,7 +1968,7 @@ async function postGitlabReviewCommitStatus(parsed, findings, diffRefs) {
1944
1968
  function appendReviewDetails(body, model, metricsFooter) {
1945
1969
  if (!model && !metricsFooter) return body;
1946
1970
  const details = ["<details>", "<summary>Review details</summary>", ""];
1947
- if (model) details.push(`- Model: \`${model}\``);
1971
+ if (model) details.push(`- Model: \`${displayModel(model)}\``);
1948
1972
  if (metricsFooter) {
1949
1973
  if (model) details.push("");
1950
1974
  details.push(metricsFooter);
@@ -1955,6 +1979,10 @@ function appendReviewDetails(body, model, metricsFooter) {
1955
1979
  ${details.join("\n")}
1956
1980
  `;
1957
1981
  }
1982
+ function displayModel(model) {
1983
+ const baseModel = model.slice(model.lastIndexOf("@") + 1);
1984
+ return baseModel.startsWith("arn:") ? baseModel.slice(baseModel.lastIndexOf("/") + 1) : baseModel;
1985
+ }
1958
1986
  async function postReviewComment(opts) {
1959
1987
  const { prUrl, reviewText, model, metricsFooter, headSha, cacheMarker } = opts;
1960
1988
  const platform = detectPlatform(prUrl);
@@ -2205,11 +2233,11 @@ ${finding.suggestion}
2205
2233
  }
2206
2234
  let summaryPosted = false;
2207
2235
  if (!skipSummary && (reviewStyle === "summary" || reviewStyle === "hybrid" || review.findings.length === 0 || failedFindings.length > 0)) {
2208
- const fallbackFindings = reviewStyle === "summary" ? review.findings : failedFindings;
2236
+ const summaryFindings = review.findings;
2209
2237
  let summaryBody = renderSummaryMarkdown(review, {
2210
2238
  openFindings: reviewFindings,
2211
- fallbackFindings,
2212
- fallbackHeading: reviewStyle === "summary" ? "Findings" : "Findings not posted inline",
2239
+ fallbackFindings: summaryFindings,
2240
+ fallbackHeading: reviewMode === "incremental" ? "Findings from this review" : "Findings",
2213
2241
  inlineCreated: reviewStyle === "summary" ? void 0 : inlineCreated,
2214
2242
  inlineDeduplicated: reviewStyle === "summary" ? void 0 : inlineDeduplicated,
2215
2243
  reviewMode
@@ -3767,4 +3795,4 @@ export {
3767
3795
  postReviewStructured,
3768
3796
  reviewPr
3769
3797
  };
3770
- //# sourceMappingURL=chunk-AFEJ4DRL.js.map
3798
+ //# sourceMappingURL=chunk-PXII2GLB.js.map