pr-shepherd 0.60.0 → 0.60.1
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/.claude-plugin/plugin.json +1 -1
- package/bin/classify/standard/codecov-report.d.mts +1 -1
- package/bin/classify/standard/codecov-report.mjs +7 -2
- package/bin/classify/standard/coderabbit-notices.d.mts +4 -3
- package/bin/classify/standard/coderabbit-notices.mjs +29 -47
- package/bin/classify/standard/codex-notices.mjs +34 -7
- package/bin/classify/standard/dependabot-notices.mjs +5 -1
- package/bin/classify/standard/gemini-notices.d.mts +1 -1
- package/bin/classify/standard/gemini-notices.mjs +16 -5
- package/bin/classify/standard/kilo-no-issues.d.mts +1 -1
- package/bin/classify/standard/kilo-no-issues.mjs +37 -10
- package/bin/classify/standard/sourcery-notices.mjs +1 -1
- package/package.json +1 -1
- package/plugins/pr-shepherd/.claude-plugin/plugin.json +1 -1
- package/plugins/pr-shepherd/.codex-plugin/plugin.json +1 -1
- package/plugins/pr-shepherd/.codex.mcp.json +1 -1
- package/plugins/pr-shepherd/.mcp.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { ClassifyRule } from "../types.mts";
|
|
2
|
-
/** Codecov's coverage report
|
|
2
|
+
/** Codecov's coverage report and first-run welcome. Coverage gates still report through checks. */
|
|
3
3
|
declare const rule: ClassifyRule;
|
|
4
4
|
export default rule;
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { isBotItem } from "./author.mjs";
|
|
2
|
-
|
|
2
|
+
const WELCOME = /^## Welcome to \[Codecov\]\(https:\/\/codecov\.io[^\s)]*\) :tada:\n\nOnce you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests\.\n\nThanks for integrating Codecov - We've got you covered :open_umbrella:$/;
|
|
3
|
+
/** Codecov's coverage report and first-run welcome. Coverage gates still report through checks. */
|
|
3
4
|
const rule = (item) => {
|
|
4
5
|
if (!isBotItem(item, ["codecov"], ["pr-comment"]))
|
|
5
6
|
return null;
|
|
6
|
-
|
|
7
|
+
const body = item.body.trim();
|
|
8
|
+
if (WELCOME.test(body)) {
|
|
9
|
+
return { autoResolve: true, suppress: true, reason: "Codecov welcome notice" };
|
|
10
|
+
}
|
|
11
|
+
if (!/^#{1,6}\s*\[?Codecov\b/i.test(body))
|
|
7
12
|
return null;
|
|
8
13
|
return { autoResolve: true, suppress: true, reason: "Codecov coverage report" };
|
|
9
14
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { ClassifyRule } from "../types.mts";
|
|
2
2
|
/**
|
|
3
|
-
* CodeRabbit progress, rate-limit, review-skipped and draft notices,
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* CodeRabbit progress, rate-limit, review-skipped and draft notices, its status-only command
|
|
4
|
+
* replies, and its zero-findings, skipped-autofix, and failed-edit status comments. If the
|
|
5
|
+
* comment is later edited into a PR walkthrough, its new body no longer matches and Shepherd
|
|
6
|
+
* surfaces the edited minimized comment to the agent.
|
|
6
7
|
*/
|
|
7
8
|
declare const rule: ClassifyRule;
|
|
8
9
|
export default rule;
|
|
@@ -1,54 +1,33 @@
|
|
|
1
1
|
import { isBotItem } from "./author.mjs";
|
|
2
2
|
const NOTICE_ENVELOPE = /^<!-- This is an auto-generated comment: (rate limited|skip review|review in progress) by coderabbit.ai -->\n([\s\S]*?)\n<!-- end of auto-generated comment: \1 by coderabbit.ai -->$/;
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<summary
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
<summary
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
</dl>
|
|
21
|
-
</details>
|
|
22
|
-
<details open>
|
|
23
|
-
<summary><strong>🧪 Generate unit tests (beta)</strong></summary>
|
|
24
|
-
<dl>
|
|
25
|
-
<dd>
|
|
26
|
-
|
|
27
|
-
- [ ] <!-- {"checkboxId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} --> Commit to this branch
|
|
28
|
-
- [ ] <!-- {"checkboxId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} --> Create a new PR
|
|
29
|
-
|
|
30
|
-
</dd>
|
|
31
|
-
</dl>
|
|
32
|
-
</details>
|
|
33
|
-
|
|
34
|
-
</dd>
|
|
35
|
-
</dl>
|
|
36
|
-
</details>
|
|
37
|
-
|
|
38
|
-
<!-- finishing_touch_checkbox_end -->`;
|
|
39
|
-
const AUTOPILOT_BLOCK = /\n<!-- autopilot:start -->\n- \[ \] <!-- \{"checkboxId":"2708ad07-9f24-4260-9c11-7dc76a49f2e3"\} --> <strong title="Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts">Autofix<\/strong> · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts\n<!-- autopilot:end -->$/;
|
|
3
|
+
/**
|
|
4
|
+
* Command replies that only report a known status, optionally followed by one of CodeRabbit's
|
|
5
|
+
* fixed explanations. The invocation id varies between releases; any other text stays visible.
|
|
6
|
+
*/
|
|
7
|
+
const COMMAND_REPLY = /^<!-- This is an auto-generated reply by CodeRabbit -->\n<!-- CodeRabbit review command invocation: [^\n]* -->\n<details>\n<summary>(?:⚠️ Action not completed|✅ Action performed)<\/summary>\n\n(?:Review rate limited\.|Review skipped: \d+ files exceed the limit of \d+\.|(?:Full review|Review) finished\.|Pull request base or head changed\.|Pull request is closed\.)\n\n(?:(?:> Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits\. This command is applicable only when automatic reviews are paused\.|---\n\nYour included review limit is currently reached under our \[Fair Usage Limits Policy\]\(https:\/\/docs\.coderabbit\.ai\/[^\s)]*\)\. This review may still proceed through usage-based billing if eligible\. Your next included review will be available in \d+ minutes?\.)\n\n)?<\/details>$/;
|
|
8
|
+
/** Standalone status comments: zero-findings completion, skipped autofix, and a failed edit. */
|
|
9
|
+
const STATUS_COMMENTS = [
|
|
10
|
+
/^<!-- coderabbit-review-completion-marker -->\n\*\*Actionable comments posted: 0\*\*$/,
|
|
11
|
+
/^<!-- This is an auto-generated comment: autofix status by CodeRabbit -->\n> \[!NOTE\]\n> Autofix is a beta feature\.[^\n]*\n\nAutofix skipped\. No unresolved CodeRabbit review comments with fix instructions found\.\n<!-- autofix-run-id: [^\n]* -->$/,
|
|
12
|
+
/^> \[!CAUTION\]\n> Failed to replace \(edit\) comment\. This is likely due to insufficient permissions or the comment being deleted\.\n> \n> <details>\n> <summary>Error details<\/summary>\n> \n> ```\n> [^`\n]*\n> ```\n> \n> <\/details>$/,
|
|
13
|
+
];
|
|
14
|
+
/** One "Finishing Touches" option group: a bold title and only checkbox lines with plain labels. */
|
|
15
|
+
const FINISHING_TOUCH_GROUP = "<details open>\\n<summary><strong>[^<\\n]+<\\/strong><\\/summary>\\n<dl>\\n<dd>\\n\\n(?:- \\[ \\] <!-- \\{[^\\n]*\\} --> [^<\\n]+\\n)+\\n<\\/dd>\\n<\\/dl>\\n<\\/details>\\n";
|
|
16
|
+
/** The finishing-touch checkbox UI, with any checkbox ids and any number of option groups. */
|
|
17
|
+
const FINISHING_TOUCH_BLOCK = new RegExp(`\\n\\n<!-- finishing_touch_checkbox_start -->\\n\\n<details>\\n<summary><strong>✨ Finishing Touches<\\/strong><\\/summary>\\n<dl>\\n<dd>\\n\\n(?:${FINISHING_TOUCH_GROUP})+\\n<\\/dd>\\n<\\/dl>\\n<\\/details>\\n\\n<!-- finishing_touch_checkbox_end -->$`);
|
|
18
|
+
/** The Autofix/Autopilot checkbox, with any checkbox id, one-word label, and description. */
|
|
19
|
+
const AUTOPILOT_BLOCK = /\n<!-- autopilot:start -->\n- \[ \] <!-- \{[^\n]*\} --> <strong title="[^"\n]*">\w+<\/strong> · [^<\n]+\n<!-- autopilot:end -->$/;
|
|
40
20
|
/** Strips CodeRabbit's footer and header blocks so only the notice envelope remains. */
|
|
41
21
|
function stripChrome(body) {
|
|
42
|
-
|
|
22
|
+
return body
|
|
43
23
|
.trim()
|
|
44
24
|
.replace(/\n<!-- tips_start -->[\s\S]*?<!-- tips_end -->$/, "")
|
|
45
25
|
.trim()
|
|
46
26
|
.replace(AUTOPILOT_BLOCK, "")
|
|
47
|
-
.trim()
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return withoutFinishingTouch
|
|
27
|
+
.trim()
|
|
28
|
+
.replace(FINISHING_TOUCH_BLOCK, "")
|
|
29
|
+
.trim()
|
|
30
|
+
.replace(/^<!-- coderabbit-ai-generated:\S* -->\s*/, "")
|
|
52
31
|
.replace(/^<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\s*/, "")
|
|
53
32
|
.replace(/^<!-- review_stack_entry_start -->[\s\S]*?<!-- review_stack_entry_end -->\s*/, "");
|
|
54
33
|
}
|
|
@@ -57,21 +36,24 @@ function isQuotedNotice(quoted) {
|
|
|
57
36
|
if (!onlyQuotedLines)
|
|
58
37
|
return false;
|
|
59
38
|
return (quoted.includes("> ## Review limit reached\n") ||
|
|
39
|
+
quoted.includes("> ## Rate limit exceeded\n") ||
|
|
60
40
|
quoted.includes("> ## Draft PR not reviewed\n") ||
|
|
61
41
|
quoted.includes("> ## Review skipped\n") ||
|
|
62
42
|
quoted.includes("> Currently processing new changes in this PR. This may take a few minutes, please wait..."));
|
|
63
43
|
}
|
|
64
44
|
/**
|
|
65
|
-
* CodeRabbit progress, rate-limit, review-skipped and draft notices,
|
|
66
|
-
*
|
|
67
|
-
*
|
|
45
|
+
* CodeRabbit progress, rate-limit, review-skipped and draft notices, its status-only command
|
|
46
|
+
* replies, and its zero-findings, skipped-autofix, and failed-edit status comments. If the
|
|
47
|
+
* comment is later edited into a PR walkthrough, its new body no longer matches and Shepherd
|
|
48
|
+
* surfaces the edited minimized comment to the agent.
|
|
68
49
|
*/
|
|
69
50
|
const rule = (item) => {
|
|
70
51
|
if (!isBotItem(item, ["coderabbitai"], ["pr-comment"]))
|
|
71
52
|
return null;
|
|
72
53
|
const body = stripChrome(item.body);
|
|
73
54
|
const quoted = body.match(NOTICE_ENVELOPE)?.[2]?.trim();
|
|
74
|
-
|
|
55
|
+
const isStatus = COMMAND_REPLY.test(body) || STATUS_COMMENTS.some((notice) => notice.test(body));
|
|
56
|
+
if (!(quoted && isQuotedNotice(quoted)) && !isStatus)
|
|
75
57
|
return null;
|
|
76
58
|
return {
|
|
77
59
|
autoResolve: true,
|
|
@@ -1,14 +1,37 @@
|
|
|
1
1
|
import { isBotItem } from "./author.mjs";
|
|
2
2
|
const QUOTA_NOTICES = [
|
|
3
3
|
/^You have reached your Codex usage limits for security reviews\. Please try again later\.$/,
|
|
4
|
-
/^You have reached your Codex usage limits for code reviews\. You can see your limits in the \[Codex usage dashboard\]\(https:\/\/chatgpt
|
|
5
|
-
/^Codex usage limits have been reached for code reviews\. Please check with the admins of this repo to increase the limits by adding credits\.\nRepo admins can enable using credits for code reviews in their \[settings\]\(https:\/\/chatgpt
|
|
4
|
+
/^You have reached your Codex usage limits for code reviews\. You can see your limits in the \[Codex usage dashboard\]\(https:\/\/chatgpt\.com\/[^\s)]*\)\.(?:\nTo continue using code reviews, add credits to your account and enable them for code reviews in your \[settings\]\(https:\/\/chatgpt\.com\/[^\s)]*\)\.)?$/,
|
|
5
|
+
/^Codex usage limits have been reached for code reviews\. Please check with the admins of this repo to increase the limits by adding credits\.\nRepo admins can enable using credits for code reviews in their \[settings\]\(https:\/\/chatgpt\.com\/[^\s)]*\)\.$/,
|
|
6
6
|
/^Codex usage limits have been reached\. Please try again later\.$/,
|
|
7
7
|
];
|
|
8
8
|
const ABOUT_BLOCK = /\n\n<details> <summary>ℹ️ About Codex (?:in GitHub|security reviews in GitHub)<\/summary>[\s\S]*?<\/details>$/;
|
|
9
|
-
const ACTIVITY_SUMMARY = /^<!-- codex-pull-request-review-summary -->\n(?:<!-- codex-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
const ACTIVITY_SUMMARY = /^<!-- codex-pull-request-review-summary -->\n(?:<!-- codex-[a-z0-9-]+:[^\n]* -->\n)*\n?## Codex Review Summary\n\nThis comment shows the latest Codex review activity on this pull request\.\n\n\| Review \| Status \| Commit \| Review trigger \|\n\| --- \| --- \| --- \| --- \|\n(?:\|[^\n]+\|\n?)+$/;
|
|
10
|
+
/**
|
|
11
|
+
* Codex's rotating clean-review sign-offs, as observed. Prose is matched only from this list so a
|
|
12
|
+
* short piece of advice in that position stays visible; a new sign-off is shown until added here.
|
|
13
|
+
*/
|
|
14
|
+
const SIGN_OFFS = [
|
|
15
|
+
"Already looking forward to the next diff.",
|
|
16
|
+
"Another round soon, please!",
|
|
17
|
+
"Bravo.",
|
|
18
|
+
"Breezy!",
|
|
19
|
+
"Can't wait for the next one!",
|
|
20
|
+
"Chef's kiss.",
|
|
21
|
+
"Delightful!",
|
|
22
|
+
"Hooray!",
|
|
23
|
+
"Keep it up!",
|
|
24
|
+
"Keep them coming!",
|
|
25
|
+
"More of your lovely PRs please.",
|
|
26
|
+
"Nice work!",
|
|
27
|
+
"Swish!",
|
|
28
|
+
"What shall we delve into next?",
|
|
29
|
+
"You're on a roll.",
|
|
30
|
+
];
|
|
31
|
+
const escapeRegExp = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
32
|
+
/** A clean review closes with a known sign-off, a `:shortcode:`, or a single emoji. */
|
|
33
|
+
const CLEAN_REVIEW = new RegExp(`^Codex Review: Didn't find any major issues\\. (?:${SIGN_OFFS.map(escapeRegExp).join("|")}|:[a-z0-9_+-]+:|\\p{Extended_Pictographic}\\uFE0F?)\\n\\n\\*\\*Reviewed commit:\\*\\* \`[a-f0-9]+\`$`, "u");
|
|
34
|
+
const CLEAN_SECURITY = /^### 🛡️ Codex Security Review(?: · _Automatically triggered_)?\n\nSecurity review completed\. No security issues were found in this pull request\.\n\n\*\*Reviewed commit:\*\* `[a-f0-9]+`\n\n\[View security finding report\]\(https:\/\/chatgpt\.com\/[^\s)]*\)\n\n_Only the user who started this review can view the report in Codex\._$/;
|
|
12
35
|
/**
|
|
13
36
|
* Codex quota notices, the review-activity status table, and no-findings notices on conversation
|
|
14
37
|
* comments. Each pattern matches the whole comment, so a notice with any appended finding stays
|
|
@@ -21,8 +44,12 @@ const rule = (item) => {
|
|
|
21
44
|
if (QUOTA_NOTICES.some((notice) => notice.test(body))) {
|
|
22
45
|
return { autoResolve: true, suppress: true, reason: "Codex usage-limit notice" };
|
|
23
46
|
}
|
|
24
|
-
// Strip only the trailing About block; extra findings
|
|
25
|
-
|
|
47
|
+
// Strip only leading codex-* metadata markers and the trailing About block; extra findings stay
|
|
48
|
+
// visible. The activity table's own marker has no colon, so it is kept for ACTIVITY_SUMMARY.
|
|
49
|
+
const content = body
|
|
50
|
+
.replace(ABOUT_BLOCK, "")
|
|
51
|
+
.trim()
|
|
52
|
+
.replace(/^(?:<!-- codex-[a-z0-9-]+:[^\n]* -->\s*)+/, "");
|
|
26
53
|
if (ACTIVITY_SUMMARY.test(content)) {
|
|
27
54
|
return { autoResolve: true, suppress: true, reason: "Codex review-activity table" };
|
|
28
55
|
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { isBotItem } from "./author.mjs";
|
|
2
2
|
const NOTICES = [
|
|
3
3
|
/^Looks like this PR is already up-to-date with [^\s!]+! If you'd still like to recreate it from scratch, overwriting any edits, you can request `@dependabot recreate`\.$/,
|
|
4
|
-
/^Looks like these dependencies are updatable in another way, so this is no longer needed\.$/,
|
|
4
|
+
/^Looks like (?:these dependencies are|\S+ is) updatable in another way, so this is no longer needed\.$/,
|
|
5
|
+
/^Superseded by #\d+\.$/,
|
|
6
|
+
/^OK, I won't notify you again about this release, but will get in touch when a new version is available\. If you'd rather skip all updates until the next major or minor version, let me know by commenting `@dependabot ignore this major version` or `@dependabot ignore this minor version`\. You can also ignore all major, minor, or patch releases for a dependency by adding an \[`ignore` condition\]\(https:\/\/docs\.github\.com\/[^\s)]*\) with the desired `update_types` to your config file\.\n\nIf you change your mind, just re-open this PR and I'll resolve any conflicts on it\.$/,
|
|
7
|
+
/^This pull request was built based on a group rule\. Closing it will not ignore any of these versions in future pull requests\.\n\nTo ignore these dependencies, configure \[ignore rules\]\(https:\/\/docs\.github\.com\/[^\s)]*\) in dependabot\.yml$/,
|
|
8
|
+
/^Looks like this PR has been edited by someone other than Dependabot\. That means Dependabot can't rebase it - sorry!\n\nIf you're happy for Dependabot to recreate it from scratch, overwriting any edits, you can request `@dependabot recreate`\.$/,
|
|
5
9
|
];
|
|
6
10
|
/** Dependabot's replies that report no change to make. */
|
|
7
11
|
const rule = (item) => {
|
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import { isBotItem } from "./author.mjs";
|
|
2
|
-
const
|
|
2
|
+
const QUOTA_NOTICES = [
|
|
3
3
|
"You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!",
|
|
4
4
|
"Review limit reached. I'll be able to review this pull request again tomorrow.",
|
|
5
5
|
];
|
|
6
|
-
|
|
6
|
+
const UNSUPPORTED_NOTICES = [
|
|
7
|
+
"Gemini is unable to generate a review for this pull request due to the file types involved not being currently supported.",
|
|
8
|
+
"Gemini is unable to generate a summary for this pull request due to the file types involved not being currently supported.",
|
|
9
|
+
];
|
|
10
|
+
/** A GitHub alert prefix such as `> [!WARNING]`, with the notice on the following quoted line. */
|
|
11
|
+
const ALERT_PREFIX = /^> \[!(?:NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]\n> /;
|
|
12
|
+
/** Complete Gemini Code Assist quota, review-limit, and unsupported-file notices. */
|
|
7
13
|
const rule = (item) => {
|
|
8
14
|
if (!isBotItem(item, ["gemini-code-assist"], ["pr-comment"]))
|
|
9
15
|
return null;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
16
|
+
const notice = item.body.trim().replace(ALERT_PREFIX, "");
|
|
17
|
+
if (QUOTA_NOTICES.includes(notice)) {
|
|
18
|
+
return { autoResolve: true, suppress: true, reason: "Gemini quota or review-limit notice" };
|
|
19
|
+
}
|
|
20
|
+
if (UNSUPPORTED_NOTICES.includes(notice)) {
|
|
21
|
+
return { autoResolve: true, suppress: true, reason: "Gemini unsupported-file-type notice" };
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
13
24
|
};
|
|
14
25
|
export default rule;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { ClassifyRule } from "../types.mts";
|
|
2
|
-
/** Complete Kilo Code no-issues
|
|
2
|
+
/** Complete Kilo Code no-issues reports and its out-of-credits notice, with no extra findings. */
|
|
3
3
|
declare const rule: ClassifyRule;
|
|
4
4
|
export default rule;
|
|
@@ -1,20 +1,47 @@
|
|
|
1
1
|
import { isBotItem } from "./author.mjs";
|
|
2
2
|
const PLAIN_STATUS = /^Status: ✅ No Issues Found \| Recommendation: Merge$/;
|
|
3
3
|
const REVIEW_REPORT = /^## Code Review Summary\n\n\*\*Status:\*\* No Issues Found \| \*\*Recommendation:\*\* Merge(?:\n\n### Files Reviewed \((\d+) files\)\n((?:- `[^`\n]+`(?:\n|$))+))?$/;
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* The marked report: a no-issues status, an optional plain overview (see `isPlainOverview`), the
|
|
6
|
+
* collapsed file list, and `kilo-*` usage footers. Any other status, such as "N Issues Found",
|
|
7
|
+
* does not match, and Kilo rewrites this same comment when a later push finds issues. A stray
|
|
8
|
+
* `EOF` line, left by some models before the footer, is tolerated.
|
|
9
|
+
*/
|
|
10
|
+
const MARKED_REPORT = /^<!-- kilo-review -->\n\n?## Code Review Summary\n\n\*\*Status:\*\* No (?:New )?Issues Found \| \*\*Recommendation:\*\* Merge(?: \([^)\n]*\))?\n\n([\s\S]*?\n)?<details>\n<summary><b>Files Reviewed \([^)\n]*\)<\/b><\/summary>\n(?:(?!<details>)[\s\S])*?<\/details>\n+(?:EOF\n+)?---\n(?:<!-- kilo-[a-z-]+ -->\n<sub>[^\n]*<\/sub>(?:\n|$))+$/;
|
|
11
|
+
const BILLING = /^<!-- kilo-billing-notice -->\n\*\*Kilo Code Review could not run — your account is out of credits\.\*\*\n\n\[Add credits\]\(https:\/\/app\.kilo\.ai\/[^\s)]*\) or \[switch to a free model\]\(https:\/\/app\.kilo\.ai\/[^\s)]*\) to enable reviews on this change\.$/;
|
|
12
|
+
/**
|
|
13
|
+
* True when the overview is only prose and lists, optionally under `### Overview`. Any other
|
|
14
|
+
* heading, HTML block, or table could carry a finding, so it keeps the report visible.
|
|
15
|
+
*/
|
|
16
|
+
function isPlainOverview(overview) {
|
|
17
|
+
return (overview ?? "")
|
|
18
|
+
.split("\n")
|
|
19
|
+
.every((line) => line === "### Overview" || !/^\s*(?:#|<|\|)/.test(line));
|
|
20
|
+
}
|
|
21
|
+
/** True for the marked report when its overview is plain. */
|
|
22
|
+
function isMarkedReport(body) {
|
|
23
|
+
const report = body.match(MARKED_REPORT);
|
|
24
|
+
return report != null && isPlainOverview(report[1]);
|
|
25
|
+
}
|
|
26
|
+
/** True for the unmarked report when its file count agrees with the listed files. */
|
|
27
|
+
function isConsistentReport(body) {
|
|
28
|
+
const report = body.match(REVIEW_REPORT);
|
|
29
|
+
if (!report)
|
|
30
|
+
return false;
|
|
31
|
+
if (report[1] === undefined)
|
|
32
|
+
return true;
|
|
33
|
+
return report[2].trimEnd().split("\n").length === Number(report[1]);
|
|
34
|
+
}
|
|
35
|
+
/** Complete Kilo Code no-issues reports and its out-of-credits notice, with no extra findings. */
|
|
5
36
|
const rule = (item) => {
|
|
6
37
|
if (!isBotItem(item, ["kilo-code-bot"], ["pr-comment"]))
|
|
7
38
|
return null;
|
|
8
39
|
const body = item.body.trim();
|
|
9
|
-
if (
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const listed = report[2].trimEnd().split("\n").length;
|
|
15
|
-
if (listed !== Number(report[1]))
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
40
|
+
if (BILLING.test(body)) {
|
|
41
|
+
return { autoResolve: true, suppress: true, reason: "Kilo Code out-of-credits notice" };
|
|
42
|
+
}
|
|
43
|
+
if (!PLAIN_STATUS.test(body) && !isMarkedReport(body) && !isConsistentReport(body)) {
|
|
44
|
+
return null;
|
|
18
45
|
}
|
|
19
46
|
return { autoResolve: true, suppress: true, reason: "Kilo Code no-issues report" };
|
|
20
47
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isBotItem } from "./author.mjs";
|
|
2
|
-
const NO_ACCESS = /^Hi @[A-Za-z0-9-]+! 👋\n\nYour private repo does not have access to Sourcery\.\n\nPlease \[upgrade\]\(https:\/\/app\.sourcery\.ai\/
|
|
2
|
+
const NO_ACCESS = /^Hi @[A-Za-z0-9-]+! 👋\n\nYour private repo does not have access to Sourcery\.\n\nPlease \[upgrade\]\(https:\/\/app\.sourcery\.ai\/[^\s)]*\) to continue using Sourcery ✨$/;
|
|
3
3
|
const RATE_LIMIT = /^Sorry @[A-Za-z0-9-]+, you have reached your weekly rate limit for Sourcery\. Please try again later\.$/;
|
|
4
4
|
/** Complete Sourcery private-repo upsell and weekly rate-limit notices. */
|
|
5
5
|
const rule = (item) => {
|
package/package.json
CHANGED