@h-rig/runtime 0.0.6-alpha.12 → 0.0.6-alpha.13

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.
@@ -3722,12 +3722,6 @@ function containsBlockerText(input) {
3722
3722
  const text = stripHtml(input).replace(/\b(?:no|without|zero)\s+blockers?\b/gi, " ").replace(/\bno\s+changes\s+requested\b/gi, " ");
3723
3723
  return /not safe(?: to merge)?|unsafe(?: to merge)?|do not merge|cannot merge|blockers?|must fix|changes requested|please fix|needs? fix|fix this|address this/i.test(text);
3724
3724
  }
3725
- function containsGreptileNegativeVerdict(input) {
3726
- const text = stripHtml(input).replace(/\s+/g, " ").trim();
3727
- if (!text)
3728
- return false;
3729
- return /\b(?:status|verdict|review state|state|conclusion|result)\s*:?\s*(?:reject(?:ed|ion)?|skip(?:ped)?|fail(?:ed|ure)?|changes[_ ]requested|not approved)\b/i.test(text) || /\bgreptile\b.{0,160}\b(?:reject(?:ed|s|ion)?|skip(?:ped|s)?|fail(?:ed|s|ure)?|changes requested|did not approve|not approved)\b/i.test(text);
3730
- }
3731
3725
  function isStrictFiveOfFive(score) {
3732
3726
  return score.value === 5 && score.scale === 5;
3733
3727
  }
@@ -3896,7 +3890,7 @@ function makeGreptileSignal(input) {
3896
3890
  const scores = parseGreptileScores(input.body);
3897
3891
  const reviewedSha = input.reviewedSha?.trim() || null;
3898
3892
  const current = reviewedSha ? reviewedSha === input.currentHeadSha : null;
3899
- const blocker = input.blocker ?? (containsBlockerText(input.body) || containsGreptileNegativeVerdict(input.body));
3893
+ const blocker = input.blocker ?? containsBlockerText(input.body);
3900
3894
  const explicitApproval = input.explicitApproval ?? false;
3901
3895
  return {
3902
3896
  source: input.source,
@@ -4058,6 +4052,9 @@ function unresolvedGreptileThreadSummaries(threads) {
4058
4052
  return [`Unresolved Greptile review thread${path}: ${(latest.body ?? "").trim() || "(empty comment)"}`];
4059
4053
  });
4060
4054
  }
4055
+ function actionableChangedFileCommentSummaries(_comments) {
4056
+ return [];
4057
+ }
4061
4058
  function issueLevelBlockerSummaries(comments) {
4062
4059
  return comments.flatMap((comment) => {
4063
4060
  const body = comment.body?.trim() ?? "";
@@ -4104,7 +4101,7 @@ function deriveGreptileEvidence(input) {
4104
4101
  const lowestScore = lowScoreEntries.map((entry) => entry.score).sort((left, right) => left.value - right.value)[0] ?? null;
4105
4102
  const score = lowestScore ?? approvingScoreEntry?.score ?? trustedScoreEntries[0]?.score ?? contextScoreEntries[0]?.score ?? null;
4106
4103
  const failedGreptileChecks = input.checks.filter((check) => isGreptileLabel(checkName(check)) && isFailingCheck(check)).map((check) => `${checkName(check)} (${checkState(check) || "failed"})`);
4107
- const blockerSignals = signals.filter((signal) => signal.source !== "changed-file-comment" && (signal.blocker || signal.actionable) && (!signal.reviewedSha || signal.reviewedSha === input.currentHeadSha));
4104
+ const blockerSignals = signals.filter((signal) => (signal.blocker || signal.actionable) && (!signal.reviewedSha || signal.reviewedSha === input.currentHeadSha));
4108
4105
  const staleBlockingSignals = [];
4109
4106
  const blockers = [
4110
4107
  ...blockerSignals.map((signal) => `${signalLabel(signal)}: ${signal.bodyExcerpt || "blocker text"}`),
@@ -4115,7 +4112,8 @@ function deriveGreptileEvidence(input) {
4115
4112
  ...failedGreptileChecks.map((entry) => `Greptile check failed: ${entry}`)
4116
4113
  ];
4117
4114
  const unresolvedComments = [
4118
- ...unresolvedGreptileThreadSummaries(input.reviewThreads)
4115
+ ...unresolvedGreptileThreadSummaries(input.reviewThreads),
4116
+ ...actionableChangedFileCommentSummaries(input.changedFileReviewComments)
4119
4117
  ];
4120
4118
  const greptileChecks = input.checks.filter((check) => isGreptileLabel(checkName(check)));
4121
4119
  const greptileReviews = input.reviews.filter((review) => isGreptileGithubLogin(review.author?.login));
@@ -4279,7 +4277,7 @@ async function collectPrReviewEvidence(input) {
4279
4277
  }
4280
4278
  const checksWithGreptileDetails = [...statusCheckRollup, ...greptileCheckDetails];
4281
4279
  const checkFailures = statusCheckRollup.filter((check) => !isGreptileLabel(checkName(check)) && isFailingCheck(check) && !isAllowedFailure(checkName(check), input.allowedFailures ?? [])).map((check) => `Check failed: ${checkName(check)}${check.detailsUrl || check.link ? ` (${check.detailsUrl ?? check.link})` : ""}`);
4282
- const pendingChecks = statusCheckRollup.filter((check) => isPendingCheck(check) && (isGreptileLabel(checkName(check)) || !isAllowedFailure(checkName(check), input.allowedFailures ?? []))).map((check) => `Check pending: ${checkName(check)}`);
4280
+ const pendingChecks = statusCheckRollup.filter((check) => isPendingCheck(check) && !isAllowedFailure(checkName(check), input.allowedFailures ?? [])).map((check) => `Check pending: ${checkName(check)}`);
4283
4281
  const evidenceBase = {
4284
4282
  title: firstString(view, ["title"]),
4285
4283
  body: firstString(view, ["body"]),
@@ -5547,25 +5545,21 @@ function shouldTriggerGreptileReview(existingReview, expectedHeadSha) {
5547
5545
  if ((existingReview.metadata?.checkHeadSha || "") !== expectedHeadSha) {
5548
5546
  return true;
5549
5547
  }
5550
- return false;
5548
+ return isGreptileReviewTerminal(existingReview.status);
5551
5549
  }
5552
5550
  function shouldContinueGreptileMcpPolling(options) {
5553
5551
  if (options.githubCheckState.completed) {
5554
5552
  return false;
5555
5553
  }
5556
- const hasRemainingBudget = options.attempt + 1 < options.pollAttempts;
5557
- if (!hasRemainingBudget) {
5558
- return false;
5559
- }
5560
5554
  if (options.selectedReview && !isGreptileReviewTerminal(options.selectedReview.status)) {
5561
5555
  return true;
5562
5556
  }
5563
- return true;
5557
+ return options.attempt + 1 < options.pollAttempts;
5564
5558
  }
5565
5559
  function shouldContinueGithubGreptileFallbackPolling(options) {
5566
5560
  const waitingForVisiblePendingReview = options.checkState.pending && (!options.fallbackReview || !options.selectedReview && !options.approvedViaReviewedAncestor);
5567
5561
  if (waitingForVisiblePendingReview) {
5568
- return options.attempt + 1 < options.pollAttempts;
5562
+ return true;
5569
5563
  }
5570
5564
  const reviewNotVisibleYet = !options.fallbackReview && !options.checkState.pending && !options.checkState.completed;
5571
5565
  if (reviewNotVisibleYet) {
@@ -4354,12 +4354,6 @@ function containsBlockerText(input) {
4354
4354
  const text = stripHtml(input).replace(/\b(?:no|without|zero)\s+blockers?\b/gi, " ").replace(/\bno\s+changes\s+requested\b/gi, " ");
4355
4355
  return /not safe(?: to merge)?|unsafe(?: to merge)?|do not merge|cannot merge|blockers?|must fix|changes requested|please fix|needs? fix|fix this|address this/i.test(text);
4356
4356
  }
4357
- function containsGreptileNegativeVerdict(input) {
4358
- const text = stripHtml(input).replace(/\s+/g, " ").trim();
4359
- if (!text)
4360
- return false;
4361
- return /\b(?:status|verdict|review state|state|conclusion|result)\s*:?\s*(?:reject(?:ed|ion)?|skip(?:ped)?|fail(?:ed|ure)?|changes[_ ]requested|not approved)\b/i.test(text) || /\bgreptile\b.{0,160}\b(?:reject(?:ed|s|ion)?|skip(?:ped|s)?|fail(?:ed|s|ure)?|changes requested|did not approve|not approved)\b/i.test(text);
4362
- }
4363
4357
  function isStrictFiveOfFive(score) {
4364
4358
  return score.value === 5 && score.scale === 5;
4365
4359
  }
@@ -4528,7 +4522,7 @@ function makeGreptileSignal(input) {
4528
4522
  const scores = parseGreptileScores(input.body);
4529
4523
  const reviewedSha = input.reviewedSha?.trim() || null;
4530
4524
  const current = reviewedSha ? reviewedSha === input.currentHeadSha : null;
4531
- const blocker = input.blocker ?? (containsBlockerText(input.body) || containsGreptileNegativeVerdict(input.body));
4525
+ const blocker = input.blocker ?? containsBlockerText(input.body);
4532
4526
  const explicitApproval = input.explicitApproval ?? false;
4533
4527
  return {
4534
4528
  source: input.source,
@@ -4690,6 +4684,9 @@ function unresolvedGreptileThreadSummaries(threads) {
4690
4684
  return [`Unresolved Greptile review thread${path}: ${(latest.body ?? "").trim() || "(empty comment)"}`];
4691
4685
  });
4692
4686
  }
4687
+ function actionableChangedFileCommentSummaries(_comments) {
4688
+ return [];
4689
+ }
4693
4690
  function issueLevelBlockerSummaries(comments) {
4694
4691
  return comments.flatMap((comment) => {
4695
4692
  const body = comment.body?.trim() ?? "";
@@ -4736,7 +4733,7 @@ function deriveGreptileEvidence(input) {
4736
4733
  const lowestScore = lowScoreEntries.map((entry) => entry.score).sort((left, right) => left.value - right.value)[0] ?? null;
4737
4734
  const score = lowestScore ?? approvingScoreEntry?.score ?? trustedScoreEntries[0]?.score ?? contextScoreEntries[0]?.score ?? null;
4738
4735
  const failedGreptileChecks = input.checks.filter((check) => isGreptileLabel(checkName(check)) && isFailingCheck(check)).map((check) => `${checkName(check)} (${checkState(check) || "failed"})`);
4739
- const blockerSignals = signals.filter((signal) => signal.source !== "changed-file-comment" && (signal.blocker || signal.actionable) && (!signal.reviewedSha || signal.reviewedSha === input.currentHeadSha));
4736
+ const blockerSignals = signals.filter((signal) => (signal.blocker || signal.actionable) && (!signal.reviewedSha || signal.reviewedSha === input.currentHeadSha));
4740
4737
  const staleBlockingSignals = [];
4741
4738
  const blockers = [
4742
4739
  ...blockerSignals.map((signal) => `${signalLabel(signal)}: ${signal.bodyExcerpt || "blocker text"}`),
@@ -4747,7 +4744,8 @@ function deriveGreptileEvidence(input) {
4747
4744
  ...failedGreptileChecks.map((entry) => `Greptile check failed: ${entry}`)
4748
4745
  ];
4749
4746
  const unresolvedComments = [
4750
- ...unresolvedGreptileThreadSummaries(input.reviewThreads)
4747
+ ...unresolvedGreptileThreadSummaries(input.reviewThreads),
4748
+ ...actionableChangedFileCommentSummaries(input.changedFileReviewComments)
4751
4749
  ];
4752
4750
  const greptileChecks = input.checks.filter((check) => isGreptileLabel(checkName(check)));
4753
4751
  const greptileReviews = input.reviews.filter((review) => isGreptileGithubLogin(review.author?.login));
@@ -4911,7 +4909,7 @@ async function collectPrReviewEvidence(input) {
4911
4909
  }
4912
4910
  const checksWithGreptileDetails = [...statusCheckRollup, ...greptileCheckDetails];
4913
4911
  const checkFailures = statusCheckRollup.filter((check) => !isGreptileLabel(checkName(check)) && isFailingCheck(check) && !isAllowedFailure(checkName(check), input.allowedFailures ?? [])).map((check) => `Check failed: ${checkName(check)}${check.detailsUrl || check.link ? ` (${check.detailsUrl ?? check.link})` : ""}`);
4914
- const pendingChecks = statusCheckRollup.filter((check) => isPendingCheck(check) && (isGreptileLabel(checkName(check)) || !isAllowedFailure(checkName(check), input.allowedFailures ?? []))).map((check) => `Check pending: ${checkName(check)}`);
4912
+ const pendingChecks = statusCheckRollup.filter((check) => isPendingCheck(check) && !isAllowedFailure(checkName(check), input.allowedFailures ?? [])).map((check) => `Check pending: ${checkName(check)}`);
4915
4913
  const evidenceBase = {
4916
4914
  title: firstString(view, ["title"]),
4917
4915
  body: firstString(view, ["body"]),
@@ -6301,25 +6299,21 @@ function shouldTriggerGreptileReview(existingReview, expectedHeadSha) {
6301
6299
  if ((existingReview.metadata?.checkHeadSha || "") !== expectedHeadSha) {
6302
6300
  return true;
6303
6301
  }
6304
- return false;
6302
+ return isGreptileReviewTerminal(existingReview.status);
6305
6303
  }
6306
6304
  function shouldContinueGreptileMcpPolling(options) {
6307
6305
  if (options.githubCheckState.completed) {
6308
6306
  return false;
6309
6307
  }
6310
- const hasRemainingBudget = options.attempt + 1 < options.pollAttempts;
6311
- if (!hasRemainingBudget) {
6312
- return false;
6313
- }
6314
6308
  if (options.selectedReview && !isGreptileReviewTerminal(options.selectedReview.status)) {
6315
6309
  return true;
6316
6310
  }
6317
- return true;
6311
+ return options.attempt + 1 < options.pollAttempts;
6318
6312
  }
6319
6313
  function shouldContinueGithubGreptileFallbackPolling(options) {
6320
6314
  const waitingForVisiblePendingReview = options.checkState.pending && (!options.fallbackReview || !options.selectedReview && !options.approvedViaReviewedAncestor);
6321
6315
  if (waitingForVisiblePendingReview) {
6322
- return options.attempt + 1 < options.pollAttempts;
6316
+ return true;
6323
6317
  }
6324
6318
  const reviewNotVisibleYet = !options.fallbackReview && !options.checkState.pending && !options.checkState.completed;
6325
6319
  if (reviewNotVisibleYet) {
@@ -3716,12 +3716,6 @@ function containsBlockerText(input) {
3716
3716
  const text = stripHtml(input).replace(/\b(?:no|without|zero)\s+blockers?\b/gi, " ").replace(/\bno\s+changes\s+requested\b/gi, " ");
3717
3717
  return /not safe(?: to merge)?|unsafe(?: to merge)?|do not merge|cannot merge|blockers?|must fix|changes requested|please fix|needs? fix|fix this|address this/i.test(text);
3718
3718
  }
3719
- function containsGreptileNegativeVerdict(input) {
3720
- const text = stripHtml(input).replace(/\s+/g, " ").trim();
3721
- if (!text)
3722
- return false;
3723
- return /\b(?:status|verdict|review state|state|conclusion|result)\s*:?\s*(?:reject(?:ed|ion)?|skip(?:ped)?|fail(?:ed|ure)?|changes[_ ]requested|not approved)\b/i.test(text) || /\bgreptile\b.{0,160}\b(?:reject(?:ed|s|ion)?|skip(?:ped|s)?|fail(?:ed|s|ure)?|changes requested|did not approve|not approved)\b/i.test(text);
3724
- }
3725
3719
  function isStrictFiveOfFive(score) {
3726
3720
  return score.value === 5 && score.scale === 5;
3727
3721
  }
@@ -3890,7 +3884,7 @@ function makeGreptileSignal(input) {
3890
3884
  const scores = parseGreptileScores(input.body);
3891
3885
  const reviewedSha = input.reviewedSha?.trim() || null;
3892
3886
  const current = reviewedSha ? reviewedSha === input.currentHeadSha : null;
3893
- const blocker = input.blocker ?? (containsBlockerText(input.body) || containsGreptileNegativeVerdict(input.body));
3887
+ const blocker = input.blocker ?? containsBlockerText(input.body);
3894
3888
  const explicitApproval = input.explicitApproval ?? false;
3895
3889
  return {
3896
3890
  source: input.source,
@@ -4052,6 +4046,9 @@ function unresolvedGreptileThreadSummaries(threads) {
4052
4046
  return [`Unresolved Greptile review thread${path}: ${(latest.body ?? "").trim() || "(empty comment)"}`];
4053
4047
  });
4054
4048
  }
4049
+ function actionableChangedFileCommentSummaries(_comments) {
4050
+ return [];
4051
+ }
4055
4052
  function issueLevelBlockerSummaries(comments) {
4056
4053
  return comments.flatMap((comment) => {
4057
4054
  const body = comment.body?.trim() ?? "";
@@ -4098,7 +4095,7 @@ function deriveGreptileEvidence(input) {
4098
4095
  const lowestScore = lowScoreEntries.map((entry) => entry.score).sort((left, right) => left.value - right.value)[0] ?? null;
4099
4096
  const score = lowestScore ?? approvingScoreEntry?.score ?? trustedScoreEntries[0]?.score ?? contextScoreEntries[0]?.score ?? null;
4100
4097
  const failedGreptileChecks = input.checks.filter((check) => isGreptileLabel(checkName(check)) && isFailingCheck(check)).map((check) => `${checkName(check)} (${checkState(check) || "failed"})`);
4101
- const blockerSignals = signals.filter((signal) => signal.source !== "changed-file-comment" && (signal.blocker || signal.actionable) && (!signal.reviewedSha || signal.reviewedSha === input.currentHeadSha));
4098
+ const blockerSignals = signals.filter((signal) => (signal.blocker || signal.actionable) && (!signal.reviewedSha || signal.reviewedSha === input.currentHeadSha));
4102
4099
  const staleBlockingSignals = [];
4103
4100
  const blockers = [
4104
4101
  ...blockerSignals.map((signal) => `${signalLabel(signal)}: ${signal.bodyExcerpt || "blocker text"}`),
@@ -4109,7 +4106,8 @@ function deriveGreptileEvidence(input) {
4109
4106
  ...failedGreptileChecks.map((entry) => `Greptile check failed: ${entry}`)
4110
4107
  ];
4111
4108
  const unresolvedComments = [
4112
- ...unresolvedGreptileThreadSummaries(input.reviewThreads)
4109
+ ...unresolvedGreptileThreadSummaries(input.reviewThreads),
4110
+ ...actionableChangedFileCommentSummaries(input.changedFileReviewComments)
4113
4111
  ];
4114
4112
  const greptileChecks = input.checks.filter((check) => isGreptileLabel(checkName(check)));
4115
4113
  const greptileReviews = input.reviews.filter((review) => isGreptileGithubLogin(review.author?.login));
@@ -4273,7 +4271,7 @@ async function collectPrReviewEvidence(input) {
4273
4271
  }
4274
4272
  const checksWithGreptileDetails = [...statusCheckRollup, ...greptileCheckDetails];
4275
4273
  const checkFailures = statusCheckRollup.filter((check) => !isGreptileLabel(checkName(check)) && isFailingCheck(check) && !isAllowedFailure(checkName(check), input.allowedFailures ?? [])).map((check) => `Check failed: ${checkName(check)}${check.detailsUrl || check.link ? ` (${check.detailsUrl ?? check.link})` : ""}`);
4276
- const pendingChecks = statusCheckRollup.filter((check) => isPendingCheck(check) && (isGreptileLabel(checkName(check)) || !isAllowedFailure(checkName(check), input.allowedFailures ?? []))).map((check) => `Check pending: ${checkName(check)}`);
4274
+ const pendingChecks = statusCheckRollup.filter((check) => isPendingCheck(check) && !isAllowedFailure(checkName(check), input.allowedFailures ?? [])).map((check) => `Check pending: ${checkName(check)}`);
4277
4275
  const evidenceBase = {
4278
4276
  title: firstString(view, ["title"]),
4279
4277
  body: firstString(view, ["body"]),
@@ -5541,25 +5539,21 @@ function shouldTriggerGreptileReview(existingReview, expectedHeadSha) {
5541
5539
  if ((existingReview.metadata?.checkHeadSha || "") !== expectedHeadSha) {
5542
5540
  return true;
5543
5541
  }
5544
- return false;
5542
+ return isGreptileReviewTerminal(existingReview.status);
5545
5543
  }
5546
5544
  function shouldContinueGreptileMcpPolling(options) {
5547
5545
  if (options.githubCheckState.completed) {
5548
5546
  return false;
5549
5547
  }
5550
- const hasRemainingBudget = options.attempt + 1 < options.pollAttempts;
5551
- if (!hasRemainingBudget) {
5552
- return false;
5553
- }
5554
5548
  if (options.selectedReview && !isGreptileReviewTerminal(options.selectedReview.status)) {
5555
5549
  return true;
5556
5550
  }
5557
- return true;
5551
+ return options.attempt + 1 < options.pollAttempts;
5558
5552
  }
5559
5553
  function shouldContinueGithubGreptileFallbackPolling(options) {
5560
5554
  const waitingForVisiblePendingReview = options.checkState.pending && (!options.fallbackReview || !options.selectedReview && !options.approvedViaReviewedAncestor);
5561
5555
  if (waitingForVisiblePendingReview) {
5562
- return options.attempt + 1 < options.pollAttempts;
5556
+ return true;
5563
5557
  }
5564
5558
  const reviewNotVisibleYet = !options.fallbackReview && !options.checkState.pending && !options.checkState.completed;
5565
5559
  if (reviewNotVisibleYet) {
@@ -108,12 +108,6 @@ function containsBlockerText(input) {
108
108
  const text = stripHtml(input).replace(/\b(?:no|without|zero)\s+blockers?\b/gi, " ").replace(/\bno\s+changes\s+requested\b/gi, " ");
109
109
  return /not safe(?: to merge)?|unsafe(?: to merge)?|do not merge|cannot merge|blockers?|must fix|changes requested|please fix|needs? fix|fix this|address this/i.test(text);
110
110
  }
111
- function containsGreptileNegativeVerdict(input) {
112
- const text = stripHtml(input).replace(/\s+/g, " ").trim();
113
- if (!text)
114
- return false;
115
- return /\b(?:status|verdict|review state|state|conclusion|result)\s*:?\s*(?:reject(?:ed|ion)?|skip(?:ped)?|fail(?:ed|ure)?|changes[_ ]requested|not approved)\b/i.test(text) || /\bgreptile\b.{0,160}\b(?:reject(?:ed|s|ion)?|skip(?:ped|s)?|fail(?:ed|s|ure)?|changes requested|did not approve|not approved)\b/i.test(text);
116
- }
117
111
  function isStrictFiveOfFive(score) {
118
112
  return score.value === 5 && score.scale === 5;
119
113
  }
@@ -282,7 +276,7 @@ function makeGreptileSignal(input) {
282
276
  const scores = parseGreptileScores(input.body);
283
277
  const reviewedSha = input.reviewedSha?.trim() || null;
284
278
  const current = reviewedSha ? reviewedSha === input.currentHeadSha : null;
285
- const blocker = input.blocker ?? (containsBlockerText(input.body) || containsGreptileNegativeVerdict(input.body));
279
+ const blocker = input.blocker ?? containsBlockerText(input.body);
286
280
  const explicitApproval = input.explicitApproval ?? false;
287
281
  return {
288
282
  source: input.source,
@@ -444,6 +438,9 @@ function unresolvedGreptileThreadSummaries(threads) {
444
438
  return [`Unresolved Greptile review thread${path}: ${(latest.body ?? "").trim() || "(empty comment)"}`];
445
439
  });
446
440
  }
441
+ function actionableChangedFileCommentSummaries(_comments) {
442
+ return [];
443
+ }
447
444
  function issueLevelBlockerSummaries(comments) {
448
445
  return comments.flatMap((comment) => {
449
446
  const body = comment.body?.trim() ?? "";
@@ -490,7 +487,7 @@ function deriveGreptileEvidence(input) {
490
487
  const lowestScore = lowScoreEntries.map((entry) => entry.score).sort((left, right) => left.value - right.value)[0] ?? null;
491
488
  const score = lowestScore ?? approvingScoreEntry?.score ?? trustedScoreEntries[0]?.score ?? contextScoreEntries[0]?.score ?? null;
492
489
  const failedGreptileChecks = input.checks.filter((check) => isGreptileLabel(checkName(check)) && isFailingCheck(check)).map((check) => `${checkName(check)} (${checkState(check) || "failed"})`);
493
- const blockerSignals = signals.filter((signal) => signal.source !== "changed-file-comment" && (signal.blocker || signal.actionable) && (!signal.reviewedSha || signal.reviewedSha === input.currentHeadSha));
490
+ const blockerSignals = signals.filter((signal) => (signal.blocker || signal.actionable) && (!signal.reviewedSha || signal.reviewedSha === input.currentHeadSha));
494
491
  const staleBlockingSignals = [];
495
492
  const blockers = [
496
493
  ...blockerSignals.map((signal) => `${signalLabel(signal)}: ${signal.bodyExcerpt || "blocker text"}`),
@@ -501,7 +498,8 @@ function deriveGreptileEvidence(input) {
501
498
  ...failedGreptileChecks.map((entry) => `Greptile check failed: ${entry}`)
502
499
  ];
503
500
  const unresolvedComments = [
504
- ...unresolvedGreptileThreadSummaries(input.reviewThreads)
501
+ ...unresolvedGreptileThreadSummaries(input.reviewThreads),
502
+ ...actionableChangedFileCommentSummaries(input.changedFileReviewComments)
505
503
  ];
506
504
  const greptileChecks = input.checks.filter((check) => isGreptileLabel(checkName(check)));
507
505
  const greptileReviews = input.reviews.filter((review) => isGreptileGithubLogin(review.author?.login));
@@ -665,7 +663,7 @@ async function collectPrReviewEvidence(input) {
665
663
  }
666
664
  const checksWithGreptileDetails = [...statusCheckRollup, ...greptileCheckDetails];
667
665
  const checkFailures = statusCheckRollup.filter((check) => !isGreptileLabel(checkName(check)) && isFailingCheck(check) && !isAllowedFailure(checkName(check), input.allowedFailures ?? [])).map((check) => `Check failed: ${checkName(check)}${check.detailsUrl || check.link ? ` (${check.detailsUrl ?? check.link})` : ""}`);
668
- const pendingChecks = statusCheckRollup.filter((check) => isPendingCheck(check) && (isGreptileLabel(checkName(check)) || !isAllowedFailure(checkName(check), input.allowedFailures ?? []))).map((check) => `Check pending: ${checkName(check)}`);
666
+ const pendingChecks = statusCheckRollup.filter((check) => isPendingCheck(check) && !isAllowedFailure(checkName(check), input.allowedFailures ?? [])).map((check) => `Check pending: ${checkName(check)}`);
669
667
  const evidenceBase = {
670
668
  title: firstString(view, ["title"]),
671
669
  body: firstString(view, ["body"]),
@@ -111,12 +111,6 @@ function containsBlockerText(input) {
111
111
  const text = stripHtml(input).replace(/\b(?:no|without|zero)\s+blockers?\b/gi, " ").replace(/\bno\s+changes\s+requested\b/gi, " ");
112
112
  return /not safe(?: to merge)?|unsafe(?: to merge)?|do not merge|cannot merge|blockers?|must fix|changes requested|please fix|needs? fix|fix this|address this/i.test(text);
113
113
  }
114
- function containsGreptileNegativeVerdict(input) {
115
- const text = stripHtml(input).replace(/\s+/g, " ").trim();
116
- if (!text)
117
- return false;
118
- return /\b(?:status|verdict|review state|state|conclusion|result)\s*:?\s*(?:reject(?:ed|ion)?|skip(?:ped)?|fail(?:ed|ure)?|changes[_ ]requested|not approved)\b/i.test(text) || /\bgreptile\b.{0,160}\b(?:reject(?:ed|s|ion)?|skip(?:ped|s)?|fail(?:ed|s|ure)?|changes requested|did not approve|not approved)\b/i.test(text);
119
- }
120
114
  function isStrictFiveOfFive(score) {
121
115
  return score.value === 5 && score.scale === 5;
122
116
  }
@@ -285,7 +279,7 @@ function makeGreptileSignal(input) {
285
279
  const scores = parseGreptileScores(input.body);
286
280
  const reviewedSha = input.reviewedSha?.trim() || null;
287
281
  const current = reviewedSha ? reviewedSha === input.currentHeadSha : null;
288
- const blocker = input.blocker ?? (containsBlockerText(input.body) || containsGreptileNegativeVerdict(input.body));
282
+ const blocker = input.blocker ?? containsBlockerText(input.body);
289
283
  const explicitApproval = input.explicitApproval ?? false;
290
284
  return {
291
285
  source: input.source,
@@ -447,6 +441,9 @@ function unresolvedGreptileThreadSummaries(threads) {
447
441
  return [`Unresolved Greptile review thread${path}: ${(latest.body ?? "").trim() || "(empty comment)"}`];
448
442
  });
449
443
  }
444
+ function actionableChangedFileCommentSummaries(_comments) {
445
+ return [];
446
+ }
450
447
  function issueLevelBlockerSummaries(comments) {
451
448
  return comments.flatMap((comment) => {
452
449
  const body = comment.body?.trim() ?? "";
@@ -493,7 +490,7 @@ function deriveGreptileEvidence(input) {
493
490
  const lowestScore = lowScoreEntries.map((entry) => entry.score).sort((left, right) => left.value - right.value)[0] ?? null;
494
491
  const score = lowestScore ?? approvingScoreEntry?.score ?? trustedScoreEntries[0]?.score ?? contextScoreEntries[0]?.score ?? null;
495
492
  const failedGreptileChecks = input.checks.filter((check) => isGreptileLabel(checkName(check)) && isFailingCheck(check)).map((check) => `${checkName(check)} (${checkState(check) || "failed"})`);
496
- const blockerSignals = signals.filter((signal) => signal.source !== "changed-file-comment" && (signal.blocker || signal.actionable) && (!signal.reviewedSha || signal.reviewedSha === input.currentHeadSha));
493
+ const blockerSignals = signals.filter((signal) => (signal.blocker || signal.actionable) && (!signal.reviewedSha || signal.reviewedSha === input.currentHeadSha));
497
494
  const staleBlockingSignals = [];
498
495
  const blockers = [
499
496
  ...blockerSignals.map((signal) => `${signalLabel(signal)}: ${signal.bodyExcerpt || "blocker text"}`),
@@ -504,7 +501,8 @@ function deriveGreptileEvidence(input) {
504
501
  ...failedGreptileChecks.map((entry) => `Greptile check failed: ${entry}`)
505
502
  ];
506
503
  const unresolvedComments = [
507
- ...unresolvedGreptileThreadSummaries(input.reviewThreads)
504
+ ...unresolvedGreptileThreadSummaries(input.reviewThreads),
505
+ ...actionableChangedFileCommentSummaries(input.changedFileReviewComments)
508
506
  ];
509
507
  const greptileChecks = input.checks.filter((check) => isGreptileLabel(checkName(check)));
510
508
  const greptileReviews = input.reviews.filter((review) => isGreptileGithubLogin(review.author?.login));
@@ -668,7 +666,7 @@ async function collectPrReviewEvidence(input) {
668
666
  }
669
667
  const checksWithGreptileDetails = [...statusCheckRollup, ...greptileCheckDetails];
670
668
  const checkFailures = statusCheckRollup.filter((check) => !isGreptileLabel(checkName(check)) && isFailingCheck(check) && !isAllowedFailure(checkName(check), input.allowedFailures ?? [])).map((check) => `Check failed: ${checkName(check)}${check.detailsUrl || check.link ? ` (${check.detailsUrl ?? check.link})` : ""}`);
671
- const pendingChecks = statusCheckRollup.filter((check) => isPendingCheck(check) && (isGreptileLabel(checkName(check)) || !isAllowedFailure(checkName(check), input.allowedFailures ?? []))).map((check) => `Check pending: ${checkName(check)}`);
669
+ const pendingChecks = statusCheckRollup.filter((check) => isPendingCheck(check) && !isAllowedFailure(checkName(check), input.allowedFailures ?? [])).map((check) => `Check pending: ${checkName(check)}`);
672
670
  const evidenceBase = {
673
671
  title: firstString(view, ["title"]),
674
672
  body: firstString(view, ["body"]),
@@ -3885,12 +3885,6 @@ function containsBlockerText(input) {
3885
3885
  const text = stripHtml(input).replace(/\b(?:no|without|zero)\s+blockers?\b/gi, " ").replace(/\bno\s+changes\s+requested\b/gi, " ");
3886
3886
  return /not safe(?: to merge)?|unsafe(?: to merge)?|do not merge|cannot merge|blockers?|must fix|changes requested|please fix|needs? fix|fix this|address this/i.test(text);
3887
3887
  }
3888
- function containsGreptileNegativeVerdict(input) {
3889
- const text = stripHtml(input).replace(/\s+/g, " ").trim();
3890
- if (!text)
3891
- return false;
3892
- return /\b(?:status|verdict|review state|state|conclusion|result)\s*:?\s*(?:reject(?:ed|ion)?|skip(?:ped)?|fail(?:ed|ure)?|changes[_ ]requested|not approved)\b/i.test(text) || /\bgreptile\b.{0,160}\b(?:reject(?:ed|s|ion)?|skip(?:ped|s)?|fail(?:ed|s|ure)?|changes requested|did not approve|not approved)\b/i.test(text);
3893
- }
3894
3888
  function isStrictFiveOfFive(score) {
3895
3889
  return score.value === 5 && score.scale === 5;
3896
3890
  }
@@ -4059,7 +4053,7 @@ function makeGreptileSignal(input) {
4059
4053
  const scores = parseGreptileScores(input.body);
4060
4054
  const reviewedSha = input.reviewedSha?.trim() || null;
4061
4055
  const current = reviewedSha ? reviewedSha === input.currentHeadSha : null;
4062
- const blocker = input.blocker ?? (containsBlockerText(input.body) || containsGreptileNegativeVerdict(input.body));
4056
+ const blocker = input.blocker ?? containsBlockerText(input.body);
4063
4057
  const explicitApproval = input.explicitApproval ?? false;
4064
4058
  return {
4065
4059
  source: input.source,
@@ -4221,6 +4215,9 @@ function unresolvedGreptileThreadSummaries(threads) {
4221
4215
  return [`Unresolved Greptile review thread${path}: ${(latest.body ?? "").trim() || "(empty comment)"}`];
4222
4216
  });
4223
4217
  }
4218
+ function actionableChangedFileCommentSummaries(_comments) {
4219
+ return [];
4220
+ }
4224
4221
  function issueLevelBlockerSummaries(comments) {
4225
4222
  return comments.flatMap((comment) => {
4226
4223
  const body = comment.body?.trim() ?? "";
@@ -4267,7 +4264,7 @@ function deriveGreptileEvidence(input) {
4267
4264
  const lowestScore = lowScoreEntries.map((entry) => entry.score).sort((left, right) => left.value - right.value)[0] ?? null;
4268
4265
  const score = lowestScore ?? approvingScoreEntry?.score ?? trustedScoreEntries[0]?.score ?? contextScoreEntries[0]?.score ?? null;
4269
4266
  const failedGreptileChecks = input.checks.filter((check) => isGreptileLabel(checkName(check)) && isFailingCheck(check)).map((check) => `${checkName(check)} (${checkState(check) || "failed"})`);
4270
- const blockerSignals = signals.filter((signal) => signal.source !== "changed-file-comment" && (signal.blocker || signal.actionable) && (!signal.reviewedSha || signal.reviewedSha === input.currentHeadSha));
4267
+ const blockerSignals = signals.filter((signal) => (signal.blocker || signal.actionable) && (!signal.reviewedSha || signal.reviewedSha === input.currentHeadSha));
4271
4268
  const staleBlockingSignals = [];
4272
4269
  const blockers = [
4273
4270
  ...blockerSignals.map((signal) => `${signalLabel(signal)}: ${signal.bodyExcerpt || "blocker text"}`),
@@ -4278,7 +4275,8 @@ function deriveGreptileEvidence(input) {
4278
4275
  ...failedGreptileChecks.map((entry) => `Greptile check failed: ${entry}`)
4279
4276
  ];
4280
4277
  const unresolvedComments = [
4281
- ...unresolvedGreptileThreadSummaries(input.reviewThreads)
4278
+ ...unresolvedGreptileThreadSummaries(input.reviewThreads),
4279
+ ...actionableChangedFileCommentSummaries(input.changedFileReviewComments)
4282
4280
  ];
4283
4281
  const greptileChecks = input.checks.filter((check) => isGreptileLabel(checkName(check)));
4284
4282
  const greptileReviews = input.reviews.filter((review) => isGreptileGithubLogin(review.author?.login));
@@ -4442,7 +4440,7 @@ async function collectPrReviewEvidence(input) {
4442
4440
  }
4443
4441
  const checksWithGreptileDetails = [...statusCheckRollup, ...greptileCheckDetails];
4444
4442
  const checkFailures = statusCheckRollup.filter((check) => !isGreptileLabel(checkName(check)) && isFailingCheck(check) && !isAllowedFailure(checkName(check), input.allowedFailures ?? [])).map((check) => `Check failed: ${checkName(check)}${check.detailsUrl || check.link ? ` (${check.detailsUrl ?? check.link})` : ""}`);
4445
- const pendingChecks = statusCheckRollup.filter((check) => isPendingCheck(check) && (isGreptileLabel(checkName(check)) || !isAllowedFailure(checkName(check), input.allowedFailures ?? []))).map((check) => `Check pending: ${checkName(check)}`);
4443
+ const pendingChecks = statusCheckRollup.filter((check) => isPendingCheck(check) && !isAllowedFailure(checkName(check), input.allowedFailures ?? [])).map((check) => `Check pending: ${checkName(check)}`);
4446
4444
  const evidenceBase = {
4447
4445
  title: firstString(view, ["title"]),
4448
4446
  body: firstString(view, ["body"]),
@@ -5710,25 +5708,21 @@ function shouldTriggerGreptileReview(existingReview, expectedHeadSha) {
5710
5708
  if ((existingReview.metadata?.checkHeadSha || "") !== expectedHeadSha) {
5711
5709
  return true;
5712
5710
  }
5713
- return false;
5711
+ return isGreptileReviewTerminal(existingReview.status);
5714
5712
  }
5715
5713
  function shouldContinueGreptileMcpPolling(options) {
5716
5714
  if (options.githubCheckState.completed) {
5717
5715
  return false;
5718
5716
  }
5719
- const hasRemainingBudget = options.attempt + 1 < options.pollAttempts;
5720
- if (!hasRemainingBudget) {
5721
- return false;
5722
- }
5723
5717
  if (options.selectedReview && !isGreptileReviewTerminal(options.selectedReview.status)) {
5724
5718
  return true;
5725
5719
  }
5726
- return true;
5720
+ return options.attempt + 1 < options.pollAttempts;
5727
5721
  }
5728
5722
  function shouldContinueGithubGreptileFallbackPolling(options) {
5729
5723
  const waitingForVisiblePendingReview = options.checkState.pending && (!options.fallbackReview || !options.selectedReview && !options.approvedViaReviewedAncestor);
5730
5724
  if (waitingForVisiblePendingReview) {
5731
- return options.attempt + 1 < options.pollAttempts;
5725
+ return true;
5732
5726
  }
5733
5727
  const reviewNotVisibleYet = !options.fallbackReview && !options.checkState.pending && !options.checkState.completed;
5734
5728
  if (reviewNotVisibleYet) {
@@ -1903,12 +1903,6 @@ function containsBlockerText(input) {
1903
1903
  const text = stripHtml(input).replace(/\b(?:no|without|zero)\s+blockers?\b/gi, " ").replace(/\bno\s+changes\s+requested\b/gi, " ");
1904
1904
  return /not safe(?: to merge)?|unsafe(?: to merge)?|do not merge|cannot merge|blockers?|must fix|changes requested|please fix|needs? fix|fix this|address this/i.test(text);
1905
1905
  }
1906
- function containsGreptileNegativeVerdict(input) {
1907
- const text = stripHtml(input).replace(/\s+/g, " ").trim();
1908
- if (!text)
1909
- return false;
1910
- return /\b(?:status|verdict|review state|state|conclusion|result)\s*:?\s*(?:reject(?:ed|ion)?|skip(?:ped)?|fail(?:ed|ure)?|changes[_ ]requested|not approved)\b/i.test(text) || /\bgreptile\b.{0,160}\b(?:reject(?:ed|s|ion)?|skip(?:ped|s)?|fail(?:ed|s|ure)?|changes requested|did not approve|not approved)\b/i.test(text);
1911
- }
1912
1906
  function isStrictFiveOfFive(score) {
1913
1907
  return score.value === 5 && score.scale === 5;
1914
1908
  }
@@ -2077,7 +2071,7 @@ function makeGreptileSignal(input) {
2077
2071
  const scores = parseGreptileScores(input.body);
2078
2072
  const reviewedSha = input.reviewedSha?.trim() || null;
2079
2073
  const current = reviewedSha ? reviewedSha === input.currentHeadSha : null;
2080
- const blocker = input.blocker ?? (containsBlockerText(input.body) || containsGreptileNegativeVerdict(input.body));
2074
+ const blocker = input.blocker ?? containsBlockerText(input.body);
2081
2075
  const explicitApproval = input.explicitApproval ?? false;
2082
2076
  return {
2083
2077
  source: input.source,
@@ -2239,6 +2233,9 @@ function unresolvedGreptileThreadSummaries(threads) {
2239
2233
  return [`Unresolved Greptile review thread${path}: ${(latest.body ?? "").trim() || "(empty comment)"}`];
2240
2234
  });
2241
2235
  }
2236
+ function actionableChangedFileCommentSummaries(_comments) {
2237
+ return [];
2238
+ }
2242
2239
  function issueLevelBlockerSummaries(comments) {
2243
2240
  return comments.flatMap((comment) => {
2244
2241
  const body = comment.body?.trim() ?? "";
@@ -2285,7 +2282,7 @@ function deriveGreptileEvidence(input) {
2285
2282
  const lowestScore = lowScoreEntries.map((entry) => entry.score).sort((left, right) => left.value - right.value)[0] ?? null;
2286
2283
  const score = lowestScore ?? approvingScoreEntry?.score ?? trustedScoreEntries[0]?.score ?? contextScoreEntries[0]?.score ?? null;
2287
2284
  const failedGreptileChecks = input.checks.filter((check) => isGreptileLabel(checkName(check)) && isFailingCheck(check)).map((check) => `${checkName(check)} (${checkState(check) || "failed"})`);
2288
- const blockerSignals = signals.filter((signal) => signal.source !== "changed-file-comment" && (signal.blocker || signal.actionable) && (!signal.reviewedSha || signal.reviewedSha === input.currentHeadSha));
2285
+ const blockerSignals = signals.filter((signal) => (signal.blocker || signal.actionable) && (!signal.reviewedSha || signal.reviewedSha === input.currentHeadSha));
2289
2286
  const staleBlockingSignals = [];
2290
2287
  const blockers = [
2291
2288
  ...blockerSignals.map((signal) => `${signalLabel(signal)}: ${signal.bodyExcerpt || "blocker text"}`),
@@ -2296,7 +2293,8 @@ function deriveGreptileEvidence(input) {
2296
2293
  ...failedGreptileChecks.map((entry) => `Greptile check failed: ${entry}`)
2297
2294
  ];
2298
2295
  const unresolvedComments = [
2299
- ...unresolvedGreptileThreadSummaries(input.reviewThreads)
2296
+ ...unresolvedGreptileThreadSummaries(input.reviewThreads),
2297
+ ...actionableChangedFileCommentSummaries(input.changedFileReviewComments)
2300
2298
  ];
2301
2299
  const greptileChecks = input.checks.filter((check) => isGreptileLabel(checkName(check)));
2302
2300
  const greptileReviews = input.reviews.filter((review) => isGreptileGithubLogin(review.author?.login));
@@ -2460,7 +2458,7 @@ async function collectPrReviewEvidence(input) {
2460
2458
  }
2461
2459
  const checksWithGreptileDetails = [...statusCheckRollup, ...greptileCheckDetails];
2462
2460
  const checkFailures = statusCheckRollup.filter((check) => !isGreptileLabel(checkName(check)) && isFailingCheck(check) && !isAllowedFailure(checkName(check), input.allowedFailures ?? [])).map((check) => `Check failed: ${checkName(check)}${check.detailsUrl || check.link ? ` (${check.detailsUrl ?? check.link})` : ""}`);
2463
- const pendingChecks = statusCheckRollup.filter((check) => isPendingCheck(check) && (isGreptileLabel(checkName(check)) || !isAllowedFailure(checkName(check), input.allowedFailures ?? []))).map((check) => `Check pending: ${checkName(check)}`);
2461
+ const pendingChecks = statusCheckRollup.filter((check) => isPendingCheck(check) && !isAllowedFailure(checkName(check), input.allowedFailures ?? [])).map((check) => `Check pending: ${checkName(check)}`);
2464
2462
  const evidenceBase = {
2465
2463
  title: firstString(view, ["title"]),
2466
2464
  body: firstString(view, ["body"]),
@@ -3728,25 +3726,21 @@ function shouldTriggerGreptileReview(existingReview, expectedHeadSha) {
3728
3726
  if ((existingReview.metadata?.checkHeadSha || "") !== expectedHeadSha) {
3729
3727
  return true;
3730
3728
  }
3731
- return false;
3729
+ return isGreptileReviewTerminal(existingReview.status);
3732
3730
  }
3733
3731
  function shouldContinueGreptileMcpPolling(options) {
3734
3732
  if (options.githubCheckState.completed) {
3735
3733
  return false;
3736
3734
  }
3737
- const hasRemainingBudget = options.attempt + 1 < options.pollAttempts;
3738
- if (!hasRemainingBudget) {
3739
- return false;
3740
- }
3741
3735
  if (options.selectedReview && !isGreptileReviewTerminal(options.selectedReview.status)) {
3742
3736
  return true;
3743
3737
  }
3744
- return true;
3738
+ return options.attempt + 1 < options.pollAttempts;
3745
3739
  }
3746
3740
  function shouldContinueGithubGreptileFallbackPolling(options) {
3747
3741
  const waitingForVisiblePendingReview = options.checkState.pending && (!options.fallbackReview || !options.selectedReview && !options.approvedViaReviewedAncestor);
3748
3742
  if (waitingForVisiblePendingReview) {
3749
- return options.attempt + 1 < options.pollAttempts;
3743
+ return true;
3750
3744
  }
3751
3745
  const reviewNotVisibleYet = !options.fallbackReview && !options.checkState.pending && !options.checkState.completed;
3752
3746
  if (reviewNotVisibleYet) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@h-rig/runtime",
3
- "version": "0.0.6-alpha.12",
3
+ "version": "0.0.6-alpha.13",
4
4
  "type": "module",
5
5
  "description": "Rig package",
6
6
  "license": "UNLICENSED",
@@ -64,11 +64,11 @@
64
64
  "module": "./dist/src/index.js",
65
65
  "dependencies": {
66
66
  "@libsql/client": "^0.17.2",
67
- "@rig/contracts": "npm:@h-rig/contracts@0.0.6-alpha.12",
68
- "@rig/core": "npm:@h-rig/core@0.0.6-alpha.12",
69
- "@rig/hook-kit": "npm:@h-rig/hook-kit@0.0.6-alpha.12",
70
- "@rig/shared": "npm:@h-rig/shared@0.0.6-alpha.12",
71
- "@rig/validator-kit": "npm:@h-rig/validator-kit@0.0.6-alpha.12",
67
+ "@rig/contracts": "npm:@h-rig/contracts@0.0.6-alpha.13",
68
+ "@rig/core": "npm:@h-rig/core@0.0.6-alpha.13",
69
+ "@rig/hook-kit": "npm:@h-rig/hook-kit@0.0.6-alpha.13",
70
+ "@rig/shared": "npm:@h-rig/shared@0.0.6-alpha.13",
71
+ "@rig/validator-kit": "npm:@h-rig/validator-kit@0.0.6-alpha.13",
72
72
  "effect": "4.0.0-beta.78",
73
73
  "smol-toml": "^1.6.0"
74
74
  }