Load Superpowers review instructions
Check / deno (pull_request) Successful in 1m33s

This commit is contained in:
2026-09-16 21:14:08 +09:00
parent 58d3c12c25
commit 8a09467194
4 changed files with 245 additions and 36 deletions
+24 -9
View File
@@ -6,8 +6,10 @@ import { TextLineStream } from "jsr:@std/streams@1/text-line-stream";
import { retryInvalidToken } from "./auth.ts";
import {
type BotType,
loadSuperpowersReviewGuide,
parseBotType,
superpowersInstallCommands,
type SuperpowersReviewGuide,
} from "./superpowers.ts";
type GiteaUser = { login: string; email: string };
@@ -160,6 +162,20 @@ async function installSuperpowers(bot: BotType): Promise<void> {
}
}
async function prepareSuperpowers(
bot: BotType,
): Promise<SuperpowersReviewGuide> {
await installSuperpowers(bot);
const guide = await loadSuperpowersReviewGuide(bot, env("HOME"));
console.log(
`Loaded Superpowers requesting-code-review ${guide.version} from ${guide.skillPath}`,
);
console.log(
`Loaded Superpowers reviewer template from ${guide.templatePath}`,
);
return guide;
}
// Commits belong to the same account as the pull request they end up in.
async function configureGitAuthor(): Promise<void> {
const user: GiteaUser = await (await gitea(AUTHOR_TOKEN, "user")).json();
@@ -168,7 +184,7 @@ async function configureGitAuthor(): Promise<void> {
}
}
async function renderPrompt(): Promise<string> {
async function renderPrompt(guide: SuperpowersReviewGuide): Promise<string> {
const comments: GiteaComment[] = await (await gitea(
REVIEWER_TOKEN,
`repos/${REPO}/issues/${INDEX}/comments?limit=100`,
@@ -185,6 +201,8 @@ async function renderPrompt(): Promise<string> {
ISSUE_INDEX: INDEX,
REVIEW_PATH,
ANCHORS_PATH,
SUPERPOWERS_REVIEW_SKILL: guide.skill,
SUPERPOWERS_REVIEW_TEMPLATE: guide.template,
};
const template = await Deno.readTextFile(
new URL("prompt.md", import.meta.url),
@@ -195,14 +213,14 @@ async function renderPrompt(): Promise<string> {
);
}
async function runClaude(prompt: string): Promise<string> {
async function runClaude(): Promise<string> {
const token = Deno.env.get("BOT_TOKEN");
if (!token) {
throw new Error(
"Run `claude setup-token` locally and set the `bot-token` action input.",
);
}
await installSuperpowers("claude");
const prompt = await renderPrompt(await prepareSuperpowers("claude"));
const claude = new Deno.Command("claude", {
args: [
"--print",
@@ -266,13 +284,13 @@ async function codexDeviceLogin(): Promise<void> {
await Promise.all([status, drained]);
}
async function runCodex(prompt: string): Promise<string> {
async function runCodex(): Promise<string> {
const loggedIn = await new Deno.Command("codex", {
args: ["login", "status"],
})
.output();
if (!loggedIn.success) await codexDeviceLogin();
await installSuperpowers("codex");
const prompt = await renderPrompt(await prepareSuperpowers("codex"));
const file = await Deno.makeTempFile();
const attempt = async () => {
const codex = new Deno.Command("codex", {
@@ -309,10 +327,7 @@ async function runCodex(prompt: string): Promise<string> {
try {
await configureGitAuthor();
const prompt = await renderPrompt();
const result = BOT === "claude"
? await runClaude(prompt)
: await runCodex(prompt);
const result = BOT === "claude" ? await runClaude() : await runCodex();
await postResult(result);
} catch (error) {
await postComment(`Bot failed: ${error}`);