Compare commits

..

No commits in common. "be277b762388cdc95bbc24441bb07a8a575eb4d3" and "c6ef48384eb2e15e6a2f42eb0e20559d030eccf7" have entirely different histories.

5 changed files with 4 additions and 124 deletions

View File

@ -16,7 +16,6 @@ import { action as rebaseAction } from "./commands/rebase.ts"
import { action as saveAction } from "./commands/save.ts" import { action as saveAction } from "./commands/save.ts"
import { action as diffAction } from "./commands/diff.ts" import { action as diffAction } from "./commands/diff.ts"
import { action as showAction } from "./commands/show.ts" import { action as showAction } from "./commands/show.ts"
import { action as webAction } from "./commands/web.ts"
import { action as logAction } from "./commands/log.ts" import { action as logAction } from "./commands/log.ts"
import { action as dirAction } from "./commands/dir.ts" import { action as dirAction } from "./commands/dir.ts"
import { action as editAction } from "./commands/edit.ts" import { action as editAction } from "./commands/edit.ts"
@ -103,12 +102,6 @@ program
.description("Show the prompt and full diff for a branch") .description("Show the prompt and full diff for a branch")
.action(showAction) .action(showAction)
program
.command("web")
.argument("<branch>", "branch name")
.description("Open the branch diff in a web browser")
.action(webAction)
program program
.command("save") .command("save")
.argument("<branch>", "branch name") .argument("<branch>", "branch name")

View File

@ -1,49 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{{BRANCH}} — sandlot diff</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release/build/styles/github-dark.min.css">
<style>
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; margin: 0; padding: 0; background: #0d1117; color: #e6edf3; }
.header { padding: 24px 32px; border-bottom: 1px solid #30363d; }
.header h1 { margin: 0 0 8px; font-size: 24px; font-weight: 600; }
.header h1 code { background: #1f2937; padding: 2px 8px; border-radius: 6px; font-size: 22px; }
.prompt { color: #8b949e; margin: 0 0 16px; font-style: italic; }
.meta { display: flex; gap: 32px; }
.meta-section h3 { margin: 0 0 6px; font-size: 13px; text-transform: uppercase; color: #8b949e; letter-spacing: 0.05em; }
.meta-section pre { margin: 0; font-size: 13px; line-height: 1.5; color: #c9d1d9; white-space: pre-wrap; }
.diff-container { padding: 16px 32px; }
.d2h-file-wrapper { margin-bottom: 16px; border-radius: 6px; overflow: hidden; }
.d2h-code-line-ctn { background: transparent; }
</style>
</head>
<body>
<div class="header">
<h1><code>{{BRANCH}}</code></h1>
{{PROMPT_SECTION}}
<div class="meta">
{{LOG_SECTION}}
{{STAT_SECTION}}
</div>
</div>
<div class="diff-container" id="diff"></div>
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release/build/highlight.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui.min.js"></script>
<script>
const diffString = {{DIFF_JSON}};
const targetElement = document.getElementById("diff");
const configuration = {
drawFileList: true,
matching: "lines",
outputFormat: "side-by-side",
highlight: true,
colorScheme: "dark",
};
const diff2htmlUi = new Diff2HtmlUI(targetElement, diffString, configuration);
diff2htmlUi.draw();
diff2htmlUi.highlightCode();
</script>
</body>
</html>

View File

@ -97,10 +97,10 @@ async function squashCommit(branch: string, cwd: string): Promise<void> {
if (diff.trim()) { if (diff.trim()) {
const gen = await vm.claudePipe( const gen = await vm.claudePipe(
diff, diff,
"write a single-line commit message for these changes, max 50 characters. no body, no blank line, just the subject. output only the message, no quotes or extra text.", "write a commit message for these changes following the 50/72 rule: subject line ≤50 chars, blank line, body wrapped at 72 chars. the body should briefly explain what changed and why. output only the message, no quotes or extra text.",
) )
if (gen.exitCode === 0 && gen.stdout.trim()) { if (gen.exitCode === 0 && gen.stdout.trim()) {
await git.commit(gen.stdout.trim().split("\n")[0], cwd) await git.commit(gen.stdout.trim(), cwd)
return return
} }
} }
@ -133,7 +133,7 @@ export async function saveChanges(worktree: string, branch: string, message?: st
const gen = await vm.claudePipe( const gen = await vm.claudePipe(
diff, diff,
"write a single-line commit message for these changes, max 50 characters. no body, no blank line, just the subject. output only the message, no quotes or extra text.", "write a commit message for these changes following the 50/72 rule: subject line ≤50 chars, blank line, body wrapped at 72 chars. the body should briefly explain what changed and why. output only the message, no quotes or extra text.",
) )
if (gen.exitCode !== 0) { if (gen.exitCode !== 0) {

View File

@ -1,57 +0,0 @@
import { $ } from "bun"
import * as git from "../git.ts"
import { die } from "../fmt.ts"
import { requireSession } from "./helpers.ts"
const template = await Bun.file(new URL("diff.html", import.meta.url).pathname).text()
export async function action(branch: string) {
const { session } = await requireSession(branch)
const worktree = session.worktree
const main = await git.mainBranch(worktree)
const [diff, log, stat] = await Promise.all([
git.branchDiff(branch, main, worktree),
git.commitLog(`${main}..${branch}`, worktree),
git.diffStat(`${main}...${branch}`, worktree),
])
if (!diff.trim()) {
die(`No changes on branch "${branch}" compared to ${main}.`)
}
const diffJson = JSON.stringify(diff).replaceAll("<", "\\u003c")
const html = template
.replaceAll("{{BRANCH}}", escapeHtml(branch))
.replace("{{PROMPT_SECTION}}", () => session.prompt ? `<p class="prompt">${escapeHtml(session.prompt)}</p>` : "")
.replace("{{LOG_SECTION}}", () => log ? `<div class="meta-section"><h3>Commits</h3><pre>${escapeHtml(log)}</pre></div>` : "")
.replace("{{STAT_SECTION}}", () => stat ? `<div class="meta-section"><h3>Stats</h3><pre>${formatStat(stat)}</pre></div>` : "")
.replace("{{DIFF_JSON}}", () => diffJson)
const tmpPath = `/tmp/sandlot-${branch}.html`
await Bun.write(tmpPath, html)
await $`open ${tmpPath}`.nothrow().quiet()
}
function formatStat(raw: string): string {
// strip leading space from lines to match the unindented first line
const trimmed = raw.split("\n").map(l => l.startsWith(" ") ? l.slice(1) : l).join("\n")
const escaped = escapeHtml(trimmed)
// colorize + and - in the bar portion (after the |)
return escaped.split("\n").map(line => {
const pipe = line.indexOf("|")
if (pipe === -1) return line
return line.slice(0, pipe + 1) +
line.slice(pipe + 1)
.replace(/\+/g, '<span style="color:#3fb950">+</span>')
.replace(/-/g, '<span style="color:#f85149">-</span>')
}).join("\n")
}
function escapeHtml(str: string): string {
return str
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
}

View File

@ -198,7 +198,7 @@ export async function commitLog(range: string, cwd: string): Promise<string> {
/** Get a diff stat summary for a revision range. Returns empty string on failure. */ /** Get a diff stat summary for a revision range. Returns empty string on failure. */
export async function diffStat(range: string, cwd: string): Promise<string> { export async function diffStat(range: string, cwd: string): Promise<string> {
const result = await $`git diff --stat --stat-width=68 ${range}`.cwd(cwd).nothrow().quiet() const result = await $`git diff --stat ${range}`.cwd(cwd).nothrow().quiet()
if (result.exitCode !== 0) return "" if (result.exitCode !== 0) return ""
return result.text().trim() return result.text().trim()
} }
@ -218,13 +218,6 @@ export async function hasNewCommits(worktreePath: string): Promise<boolean> {
return parseInt(result.text().trim(), 10) > 0 return parseInt(result.text().trim(), 10) > 0
} }
/** Get the full unified diff of a branch vs main as a string. */
export async function branchDiff(branch: string, main: string, cwd: string): Promise<string> {
const result = await $`git diff --no-ext-diff ${main}...${branch}`.cwd(cwd).nothrow().quiet()
if (result.exitCode !== 0) return ""
return result.text()
}
/** Detect the main branch name (main or master). */ /** Detect the main branch name (main or master). */
export async function mainBranch(cwd?: string): Promise<string> { export async function mainBranch(cwd?: string): Promise<string> {
const dir = cwd ?? "." const dir = cwd ?? "."