Some checks are pending
CI / build-check-test (push) Waiting to run
New extensions shipping with Agent JAE: - jae-rules: Per-project .jae/rules.md injection - cost-tracker: Token/cost tracking with budget limits - project-dna: Auto-analyze project fingerprint - teach-mode: Pedagogical explanation mode - bookmarks: File bookmark management - replay: Session recording and asciicast export - checkpoints: Git-based undo/time-travel - pr-review: Autonomous PR diff review - auto-docs: Auto-generate README and docs - screenshot-context: Vision analysis for screenshots - deploy: One-command deploy (Docker/Vercel/rsync/static) - pair-programming: Real-time file watching with feedback - dashboard: Terminal HUD with live stats - swarm: Multi-agent parallel task execution - skill-marketplace: Search/install/publish skills - widget-api-demo: TUI widget API demonstration
112 lines
3.3 KiB
TypeScript
112 lines
3.3 KiB
TypeScript
import type { ExtensionAPI } from "@jaeswift/jae-coding-agent";
|
|
import { Type } from "@sinclair/typebox";
|
|
|
|
export default function (pi: ExtensionAPI) {
|
|
async function reviewDiff(diff: string, ctx: any): Promise<string> {
|
|
if (!diff.trim()) return "No diff content to review.";
|
|
|
|
const lines = diff.split("\n");
|
|
const stats = {
|
|
filesChanged: 0,
|
|
additions: 0,
|
|
deletions: 0,
|
|
files: [] as string[],
|
|
};
|
|
|
|
for (const line of lines) {
|
|
if (line.startsWith("+++ b/")) {
|
|
stats.filesChanged++;
|
|
stats.files.push(line.replace("+++ b/", ""));
|
|
} else if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
stats.additions++;
|
|
} else if (line.startsWith("-") && !line.startsWith("---")) {
|
|
stats.deletions++;
|
|
}
|
|
}
|
|
|
|
return [
|
|
`## PR Review Summary`,
|
|
``,
|
|
`**Files changed:** ${stats.filesChanged}`,
|
|
`**Additions:** +${stats.additions}`,
|
|
`**Deletions:** -${stats.deletions}`,
|
|
``,
|
|
`### Files:`,
|
|
...stats.files.map((f) => `- ${f}`),
|
|
``,
|
|
`### Diff Preview (first 200 lines):`,
|
|
"```diff",
|
|
lines.slice(0, 200).join("\n"),
|
|
"```",
|
|
``,
|
|
`> Full review requires LLM analysis. Send this diff as context to JAE for detailed review.`,
|
|
].join("\n");
|
|
}
|
|
|
|
pi.registerTool({
|
|
name: "pr_review",
|
|
label: "PR Review",
|
|
description: "Review a pull request or git diff. Provide a branch name, PR URL, or commit range.",
|
|
parameters: Type.Object({
|
|
target: Type.String({ description: "Branch name, PR URL, or commit range (e.g., 'main..feature', 'origin/main')" }),
|
|
}),
|
|
execute: async (args, ctx) => {
|
|
const { target } = args;
|
|
let diff = "";
|
|
|
|
// Try as branch comparison
|
|
const diffResult = await pi.exec(
|
|
"git",
|
|
["diff", target],
|
|
{ cwd: ctx.cwd },
|
|
);
|
|
|
|
if (diffResult.code === 0 && diffResult.stdout.trim()) {
|
|
diff = diffResult.stdout;
|
|
} else {
|
|
// Try as range
|
|
const rangeResult = await pi.exec(
|
|
"git",
|
|
["diff", `${target}`],
|
|
{ cwd: ctx.cwd },
|
|
);
|
|
if (rangeResult.code === 0) {
|
|
diff = rangeResult.stdout;
|
|
} else {
|
|
return { error: `Could not get diff for: ${target}. Error: ${diffResult.stderr || rangeResult.stderr}` };
|
|
}
|
|
}
|
|
|
|
const review = await reviewDiff(diff, ctx);
|
|
return { output: review };
|
|
},
|
|
});
|
|
|
|
pi.registerCommand("pr-review", {
|
|
description: "Review a PR or branch diff: /pr-review <branch|range>",
|
|
handler: async (args, ctx) => {
|
|
const target = args.trim();
|
|
if (!target) {
|
|
ctx.ui.notify("Usage: /pr-review <branch|commit-range>\nExamples:\n /pr-review main..feature\n /pr-review origin/main", "info");
|
|
return;
|
|
}
|
|
|
|
ctx.ui.notify(`\u{1F50D} Fetching diff for: ${target}...`, "info");
|
|
|
|
const diffResult = await pi.exec("git", ["diff", target], { cwd: ctx.cwd });
|
|
|
|
if (diffResult.code !== 0) {
|
|
ctx.ui.notify(`Failed to get diff: ${diffResult.stderr}`, "error");
|
|
return;
|
|
}
|
|
|
|
if (!diffResult.stdout.trim()) {
|
|
ctx.ui.notify("No differences found.", "info");
|
|
return;
|
|
}
|
|
|
|
const review = await reviewDiff(diffResult.stdout, ctx);
|
|
ctx.ui.notify(review, "info");
|
|
},
|
|
});
|
|
}
|