diff --git a/mcp/selectMode.ts b/mcp/selectMode.ts index 35929eb..3df16d3 100644 --- a/mcp/selectMode.ts +++ b/mcp/selectMode.ts @@ -1,6 +1,6 @@ import { type } from "arktype"; import { formatMcpToolRef } from "../external.ts"; -import type { Mode } from "../modes.ts"; +import { PR_SUMMARY_FORMAT, type Mode } from "../modes.ts"; import { apiFetch } from "../utils/apiFetch.ts"; import { log } from "../utils/log.ts"; import type { ToolContext } from "./server.ts"; @@ -39,9 +39,11 @@ An existing summary comment was found for this PR. Update it rather than creatin 1. Use \`previousSummaryBody\` from this response as the current summary to revise. 2. Checkout the PR via \`${t("checkout_pr")}\` — this returns PR metadata and a \`diffPath\`. -3. Read the diff using the TOC to selectively read relevant sections. Produce an updated summary reflecting the current state of the PR, using the existing summary (\`previousSummaryBody\`) as a starting point. Follow format instructions from EVENT INSTRUCTIONS (if any). +3. Read the diff using the TOC to selectively read relevant sections. Produce an updated summary reflecting the current state of the PR, using the existing summary (\`previousSummaryBody\`) as a starting point. If EVENT INSTRUCTIONS specify a custom format, follow that instead of the default format below. 4. Call \`${t("edit_issue_comment")}\` with \`commentId: existingSummaryCommentId\` (from this response) and the updated summary body. -5. Call \`${t("report_progress")}\` with a brief note (e.g., "Updated PR summary.").`, +5. Call \`${t("report_progress")}\` with a brief note (e.g., "Updated PR summary."). + +${PR_SUMMARY_FORMAT}`, }; } diff --git a/modes.ts b/modes.ts index ccb440d..a3ad290 100644 --- a/modes.ts +++ b/modes.ts @@ -9,6 +9,55 @@ export interface Mode { prompt?: string | undefined; } +export const PR_SUMMARY_FORMAT = `### Default format + +Follow this structure exactly: + +TL;DR — 1-3 sentences on what the PR does and why. Focus on intent, not mechanics. +NOTE: use HTML bold TL;DR, NOT markdown bold **TL;DR**. + +### Key changes + +- **Short human-readable title** — 1 sentence per change. Write a short prose phrase (title case or sentence case); when you name a file, type, or function, put that name in backticks (e.g. **Add \`TodoTracker\` for live checklists**). A reviewer should understand the full PR from this list alone. + +Summary | {file_count} files | {commit_count} commits | base: \`{base}\` ← \`{head}\` +NOTE: the metadata line goes AFTER the bullet list, not before it. + +Then for each key change, a ## section with a short descriptive title that reads like a documentation heading (e.g. ## Live todo checklist tracking). + +
+ +## Example readable section title + +> **Before:** [old behavior/state]
**After:** [new behavior/state] +IMPORTANT: Before and After MUST be on a SINGLE blockquote line with an inline
between them. Two separate \`>\` lines creates a double line break. + +1-2 sentences of explanation. Break up text with tables, blockquotes, or lists — NEVER 3+ plain paragraphs in a row. + +If a change warrants deeper explanation, use a blockquoted details/summary framed as a question: +>
How does X work? +> Extended explanation here. +>
+ +End each section with a file links trail (3-4 key files max): +[\`file.ts\`](https://github.com/{owner}/{repo}/pull/{number}/files#diff-{sha256hex_of_filepath}) · ... + +Single-feature PRs: skip the ## sections. Fold before/after and explanation into the header after key changes. + +CRITICAL — GitHub markdown rendering rule: +GitHub's markdown parser requires a blank line between ALL block-level elements. This includes transitions between: HTML tags (
, ,
, , etc.) and markdown syntax (headings, lists, blockquotes, paragraphs). Without a blank line, GitHub treats the following content as a continuation of the HTML block and renders markdown syntax as literal text. ALWAYS separate block-level elements with a blank line. + +Rules: +- \`##\` titles and key-change bullet lead-ins are plain-language summaries; backtick only actual code tokens (files, types, functions) where they appear in the title +- ALL variable names, identifiers, and file names in body text must be in backticks +- ALL file references MUST link to the PR Files Changed view. Compute anchors by running \`echo -n 'path/to/file.ts' | sha256sum\` via shell for each file. NEVER fabricate hex strings — run the actual command. If shell is unavailable, omit the #diff- anchor rather than guessing. +- Add
before each ## heading for visual spacing. Do NOT use horizontal rules (---) +- Do NOT include raw diff stats like '+123 / -45' or line counts +- Do NOT include code blocks or repeat diff contents +- Do NOT include a changelog section — the key changes list serves this purpose +- Focus on *intent*, not *what* — the diff already shows what changed +- Get the file count and commit count from the checkout_pr metadata, not by counting manually`; + function learningsStep(t: (toolName: string) => string, n: number): string { return `${n}. **learnings** (only if high confidence): if you discovered something about repo setup, test commands, conventions, or patterns that you are confident is correct and would reliably help future runs, call \`${t("update_learnings")}\` to persist it. skip this step if you are unsure or the finding is speculative/one-off. format as a flat bullet list (\`- \` per line, one fact per bullet). merge with existing learnings from the prompt — pass the FULL merged list. deduplicate, and drop bullets that are clearly wrong or no longer relevant to the current codebase.`; } @@ -240,9 +289,11 @@ ${learningsStep(t, 4)}`, prompt: `### Checklist 1. Checkout the PR via \`${t("checkout_pr")}\` — this returns PR metadata and a \`diffPath\`. -2. Read the diff using the TOC to selectively read relevant sections (not the entire file). Produce a structured summary using format instructions from EVENT INSTRUCTIONS (if any); otherwise use default format: TL;DR, key changes list, per-change sections with plain-language \`##\` titles and before/after framing. +2. Read the diff using the TOC to selectively read relevant sections (not the entire file). Produce a structured summary. If EVENT INSTRUCTIONS specify a custom format, follow that instead of the default format below. 3. Call \`${t("create_issue_comment")}\` with \`type: "Summary"\` and the summary body. -4. Call \`${t("report_progress")}\` with a brief note (e.g., "Posted PR summary.").`, +4. Call \`${t("report_progress")}\` with a brief note (e.g., "Posted PR summary."). + +${PR_SUMMARY_FORMAT}`, }, ]; } diff --git a/package.json b/package.json index 013e935..0aa5182 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,6 @@ "scratch": "node scratch.ts", "upDeps": "pnpm up --latest", "lock": "pnpm install --no-frozen-lockfile", - "postinstall": "node scripts/generate-proxies.ts", "prepare": "cd .. && husky action/.husky" }, "devDependencies": { diff --git a/scripts/generate-proxies.ts b/scripts/generate-proxies.ts deleted file mode 100644 index 390c5cd..0000000 --- a/scripts/generate-proxies.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { mkdirSync, writeFileSync } from "node:fs"; - -const proxies = [ - { dest: "dist/index.js", source: "../index.ts" }, - { dest: "dist/internal.js", source: "../internal/index.ts" }, -]; - -mkdirSync("dist", { recursive: true }); - -for (const proxy of proxies) { - writeFileSync(proxy.dest, `export * from "${proxy.source}";\n`); - writeFileSync(proxy.dest.replace(/\.js$/, ".d.ts"), `export * from "${proxy.source}";\n`); -}