Skip to content

Commit d9394a1

Browse files
authored
Merge branch 'main' into fix/apply-patch-non-openai-providers
2 parents 86803f9 + ba88b7a commit d9394a1

3,234 files changed

Lines changed: 118924 additions & 44171 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/skills/openclaw-pr-maintainer/SKILL.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,37 @@ gh pr view <number> --json additions,deletions,changedFiles \
187187
## Read beyond the diff
188188

189189
- Review the surrounding code path, not just changed lines. Open the caller, callee, data contracts, adjacent tests, and owner module.
190+
- Before any verdict, read enough code to fill this map: changed surface, runtime entry point, owner boundary, one caller, one callee, sibling implementations sharing the invariant, adjacent tests, current `main` behavior, and shipped/dependency/Codex contracts when relevant.
190191
- For large-codebase PRs, sample enough related files to understand the runtime boundary before deciding. Default to more code reading when the change touches agents, gateway, plugins, auth, sessions, process, config, or provider/runtime seams.
191192
- Compare the PR against current `origin/main` behavior. Check whether recent main already changed the same surface.
192193
- Dependency-backed behavior: MUST read upstream docs/source/types before judging API use, defaults, output shapes, errors, timeouts, memory behavior, or compatibility. Do not assume dependency contracts from memory or PR text.
193194
- Judge solution quality, not only correctness. Ask whether the PR is the clean owner-boundary fix or a wart/workaround that should be replaced by a small refactor, moved seam, contract change, or deletion of duplicate logic.
194195
- Mention the main files read when the verdict depends on code-path evidence.
196+
- If the user challenges the verdict or asks whether the idea is really good, resume code reading first. Do not defend, soften, or reverse the verdict until the missing caller/callee/sibling/dependency path is checked.
197+
198+
## Best-fix review loop
199+
200+
Every PR review must explicitly answer: "Is this the best fix, or only a plausible fix?"
201+
202+
Before verdict:
203+
204+
1. Reconstruct the bug, feature need, or behavior claim from issue/PR/proof.
205+
2. Trace current behavior from entry point to failure or decision point.
206+
3. Read touched files, callers, callees, owner modules, adjacent tests, and relevant docs.
207+
4. Read sibling surfaces that should share the invariant or could be broken by a one-sided fix.
208+
5. Compare against current `origin/main` and shipped behavior when regression/compat matters.
209+
6. Inspect upstream dependency/Codex source or docs for dependency-backed behavior.
210+
7. Identify at least one alternative fix location or shape, then reject it with evidence.
211+
8. If any required path above is uninspected, keep reading or mark `Remaining uncertainty`; do not call the PR best, blocked, proof-sufficient, or merge-ready.
212+
213+
Review output must include:
214+
215+
- `Best-fix verdict:` best / acceptable mitigation / wrong layer / too narrow / too broad.
216+
- `Alternatives considered:` 1-3 concrete alternatives and why rejected.
217+
- `Code read:` compact list of main files/contracts checked.
218+
- `Remaining uncertainty:` what was not proven.
219+
220+
If the best-fix answer is only "maybe", keep reading or state the missing evidence. Do not call proof sufficient until the best-fix judgment is explicit.
195221

196222
## Enforce the bug-fix evidence bar
197223

.agents/skills/openclaw-secret-scanning-maintainer/scripts/secret-scanning.mjs

Lines changed: 72 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Secret scanning alert handler for OpenClaw maintainers.
33
// Usage: node secret-scanning.mjs <command> [options]
44

5-
import { execFileSync, spawnSync } from "node:child_process";
5+
import { spawnSync } from "node:child_process";
66
import crypto from "node:crypto";
77
import fs from "node:fs";
88
import os from "node:os";
@@ -39,7 +39,9 @@ function gh(args, { json = true, allowFailure = false } = {}) {
3939
stderr: proc.stderr,
4040
};
4141
}
42-
if (!json) return proc.stdout;
42+
if (!json) {
43+
return proc.stdout;
44+
}
4345
try {
4446
return JSON.parse(proc.stdout);
4547
} catch {
@@ -70,7 +72,9 @@ export function loadBodyRedactionResult(locationType, resultFile) {
7072
if (!resultFile) {
7173
fail("Body notifications require a redaction result file from redact-body-if-needed");
7274
}
73-
if (!fs.existsSync(resultFile)) fail(`File not found: ${resultFile}`);
75+
if (!fs.existsSync(resultFile)) {
76+
fail(`File not found: ${resultFile}`);
77+
}
7478

7579
const result = JSON.parse(fs.readFileSync(resultFile, "utf8"));
7680
if (typeof result.notify_required !== "boolean") {
@@ -182,10 +186,11 @@ function fetchDiscussionComment(discussionNumber, discussionCommentDbId) {
182186
failOnGraphQLFailure(gql, `Failed to fetch discussion #${discussionNumber}`);
183187

184188
const discussion = gql?.data?.repository?.discussion;
185-
if (!discussion)
189+
if (!discussion) {
186190
fail(
187191
`Discussion #${discussionNumber} not found — it may have been deleted. The alert cannot be processed via this skill.`,
188192
);
193+
}
189194

190195
discussionId = discussion.id;
191196

@@ -205,15 +210,18 @@ function fetchDiscussionComment(discussionNumber, discussionCommentDbId) {
205210
`Failed to fetch replies for discussion comment ${topLevelComment.id}`,
206211
);
207212
const replies = replyPage?.data?.node?.replies;
208-
if (!replies)
213+
if (!replies) {
209214
fail(`Failed to paginate replies for discussion comment ${topLevelComment.id}`);
215+
}
210216

211217
reply = findDiscussionCommentNode(replies.nodes, discussionCommentDbId);
212218
hasMoreReplies = replies.pageInfo.hasNextPage;
213219
replyCursor = replies.pageInfo.endCursor;
214220
}
215221

216-
if (reply) return { discussionId, comment: reply };
222+
if (reply) {
223+
return { discussionId, comment: reply };
224+
}
217225
}
218226

219227
hasNextPage = discussion.comments.pageInfo.hasNextPage;
@@ -241,7 +249,9 @@ function createDiscussionComment(discussionNodeId, body, replyToNodeId) {
241249
* Fetch alert metadata + locations. Never exposes .secret.
242250
*/
243251
function cmdFetchAlert(alertNumber) {
244-
if (!alertNumber) fail("Usage: fetch-alert <number>");
252+
if (!alertNumber) {
253+
fail("Usage: fetch-alert <number>");
254+
}
245255

246256
const alert = gh(["api", `repos/${REPO}/secret-scanning/alerts/${alertNumber}?hide_secret=true`]);
247257

@@ -280,28 +290,35 @@ function cmdFetchAlert(alertNumber) {
280290
* Saves full body to a temp file. Prints metadata + file path to stdout.
281291
*/
282292
function cmdFetchContent(locationJson) {
283-
if (!locationJson) fail("Usage: fetch-content '<location-json>'");
293+
if (!locationJson) {
294+
fail("Usage: fetch-content '<location-json>'");
295+
}
284296
const location = JSON.parse(locationJson);
285297
const type = location.type;
286298
const details = location.details;
287299

288300
if (type === "discussion_comment") {
289301
const commentUrl = details.discussion_comment_url;
290-
if (!commentUrl) fail("No discussion_comment_url in location details");
302+
if (!commentUrl) {
303+
fail("No discussion_comment_url in location details");
304+
}
291305

292306
const urlMatch = commentUrl.match(/discussions\/(\d+)#discussioncomment-(\d+)/);
293-
if (!urlMatch) fail(`Cannot parse discussion comment URL: ${commentUrl}`);
307+
if (!urlMatch) {
308+
fail(`Cannot parse discussion comment URL: ${commentUrl}`);
309+
}
294310
const discussionNumber = urlMatch[1];
295311
const discussionCommentDbId = urlMatch[2];
296312

297313
const { discussionId, comment } = fetchDiscussionComment(
298314
discussionNumber,
299315
discussionCommentDbId,
300316
);
301-
if (!comment)
317+
if (!comment) {
302318
fail(
303319
`Discussion comment #${discussionCommentDbId} not found in discussion #${discussionNumber}`,
304320
);
321+
}
305322

306323
const bodyFile = tmpFile("body.md");
307324
fs.writeFileSync(bodyFile, comment.body || "");
@@ -334,7 +351,9 @@ function cmdFetchContent(locationJson) {
334351
details.issue_comment_url ||
335352
details.pull_request_comment_url ||
336353
details.pull_request_review_comment_url;
337-
if (!commentUrl) fail(`No comment URL in location details`);
354+
if (!commentUrl) {
355+
fail(`No comment URL in location details`);
356+
}
338357

339358
const comment = gh(["api", commentUrl]);
340359
const bodyFile = tmpFile("body.md");
@@ -378,7 +397,9 @@ function cmdFetchContent(locationJson) {
378397
);
379398
} else if (type === "issue_body") {
380399
const issueUrl = details.issue_body_url || details.issue_url;
381-
if (!issueUrl) fail("No issue URL in location details");
400+
if (!issueUrl) {
401+
fail("No issue URL in location details");
402+
}
382403

383404
const issue = gh(["api", issueUrl]);
384405
const bodyFile = tmpFile("body.md");
@@ -414,7 +435,9 @@ function cmdFetchContent(locationJson) {
414435
);
415436
} else if (type === "pull_request_body") {
416437
const prUrl = details.pull_request_body_url || details.pull_request_url;
417-
if (!prUrl) fail("No PR URL in location details");
438+
if (!prUrl) {
439+
fail("No PR URL in location details");
440+
}
418441

419442
const pr = gh(["api", prUrl]);
420443
const bodyFile = tmpFile("body.md");
@@ -490,7 +513,9 @@ function cmdRedactBody(kind, number, bodyFile) {
490513
if (!kind || !number || !bodyFile) {
491514
fail("Usage: redact-body <issue|pr> <number> <redacted-body-file>");
492515
}
493-
if (!fs.existsSync(bodyFile)) fail(`File not found: ${bodyFile}`);
516+
if (!fs.existsSync(bodyFile)) {
517+
fail(`File not found: ${bodyFile}`);
518+
}
494519

495520
const endpoint =
496521
kind === "pr" ? `repos/${REPO}/pulls/${number}` : `repos/${REPO}/issues/${number}`;
@@ -509,8 +534,12 @@ function cmdRedactBodyIfNeeded(kind, number, currentBodyFile, redactedBodyFile,
509534
"Usage: redact-body-if-needed <issue|pr> <number> <current-body-file> <redacted-body-file> <result-file>",
510535
);
511536
}
512-
if (!fs.existsSync(currentBodyFile)) fail(`File not found: ${currentBodyFile}`);
513-
if (!fs.existsSync(redactedBodyFile)) fail(`File not found: ${redactedBodyFile}`);
537+
if (!fs.existsSync(currentBodyFile)) {
538+
fail(`File not found: ${currentBodyFile}`);
539+
}
540+
if (!fs.existsSync(redactedBodyFile)) {
541+
fail(`File not found: ${redactedBodyFile}`);
542+
}
514543

515544
const currentBody = fs.readFileSync(currentBodyFile, "utf8");
516545
const redactedBody = fs.readFileSync(redactedBodyFile, "utf8");
@@ -541,7 +570,9 @@ function cmdRedactBodyIfNeeded(kind, number, currentBodyFile, redactedBodyFile,
541570
* Delete a comment (and all its edit history).
542571
*/
543572
function cmdDeleteComment(commentId) {
544-
if (!commentId) fail("Usage: delete-comment <comment-id>");
573+
if (!commentId) {
574+
fail("Usage: delete-comment <comment-id>");
575+
}
545576
gh(["api", `repos/${REPO}/issues/comments/${commentId}`, "-X", "DELETE"], { json: false });
546577
console.log(JSON.stringify({ ok: true, deleted_comment_id: Number(commentId) }));
547578
}
@@ -551,7 +582,9 @@ function cmdDeleteComment(commentId) {
551582
* Delete a discussion comment via GraphQL (and all its edit history).
552583
*/
553584
function cmdDeleteDiscussionComment(nodeId) {
554-
if (!nodeId) fail("Usage: delete-discussion-comment <node-id>");
585+
if (!nodeId) {
586+
fail("Usage: delete-discussion-comment <node-id>");
587+
}
555588
const result = ghGraphQL(
556589
`mutation { deleteDiscussionComment(input: { id: "${nodeId}" }) { comment { id } } }`,
557590
);
@@ -566,9 +599,12 @@ function cmdDeleteDiscussionComment(nodeId) {
566599
* Create a new discussion comment via GraphQL.
567600
*/
568601
function cmdRecreateDiscussionComment(discussionNodeId, bodyFile, replyToNodeId) {
569-
if (!discussionNodeId || !bodyFile)
602+
if (!discussionNodeId || !bodyFile) {
570603
fail("Usage: recreate-discussion-comment <discussion-node-id> <body-file> [reply-to-node-id]");
571-
if (!fs.existsSync(bodyFile)) fail(`File not found: ${bodyFile}`);
604+
}
605+
if (!fs.existsSync(bodyFile)) {
606+
fail(`File not found: ${bodyFile}`);
607+
}
572608

573609
const body = fs.readFileSync(bodyFile, "utf8");
574610
const newComment = createDiscussionComment(discussionNodeId, body, replyToNodeId);
@@ -586,8 +622,12 @@ function cmdRecreateDiscussionComment(discussionNodeId, bodyFile, replyToNodeId)
586622
* Create a new comment from a file.
587623
*/
588624
function cmdRecreateComment(issueNumber, bodyFile) {
589-
if (!issueNumber || !bodyFile) fail("Usage: recreate-comment <issue-number> <body-file>");
590-
if (!fs.existsSync(bodyFile)) fail(`File not found: ${bodyFile}`);
625+
if (!issueNumber || !bodyFile) {
626+
fail("Usage: recreate-comment <issue-number> <body-file>");
627+
}
628+
if (!fs.existsSync(bodyFile)) {
629+
fail(`File not found: ${bodyFile}`);
630+
}
591631

592632
const result = gh([
593633
"api",
@@ -715,7 +755,9 @@ function cmdNotify(target, author, locationType, secretTypes, replyToNodeId) {
715755
* Close a secret scanning alert.
716756
*/
717757
function cmdResolve(alertNumber, resolution, comment) {
718-
if (!alertNumber) fail("Usage: resolve <alert-number> [resolution] [comment]");
758+
if (!alertNumber) {
759+
fail("Usage: resolve <alert-number> [resolution] [comment]");
760+
}
719761

720762
const res = resolution || "revoked";
721763
const resComment = comment || "Content redacted and author notified to rotate credentials.";
@@ -773,8 +815,12 @@ function cmdListOpen() {
773815
* Print a formatted summary table from a JSON results file.
774816
*/
775817
function cmdSummary(jsonFile) {
776-
if (!jsonFile) fail("Usage: summary <json-file>");
777-
if (!fs.existsSync(jsonFile)) fail(`File not found: ${jsonFile}`);
818+
if (!jsonFile) {
819+
fail("Usage: summary <json-file>");
820+
}
821+
if (!fs.existsSync(jsonFile)) {
822+
fail(`File not found: ${jsonFile}`);
823+
}
778824

779825
const results = JSON.parse(fs.readFileSync(jsonFile, "utf8"));
780826
const lines = [];

0 commit comments

Comments
 (0)