-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdiff.ts
More file actions
92 lines (85 loc) · 2.59 KB
/
diff.ts
File metadata and controls
92 lines (85 loc) · 2.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/**
* Diff Extension — quick diff viewer via /diff command.
*
* Shells out to tuicr (preferred), delta, or plain git diff.
* For agent-triggered code review with feedback capture, use the tuicr tool instead.
*
* Usage:
* /diff — show all uncommitted changes
* /diff --staged — show only staged changes
* /diff <revisions> — show changes for a commit range (e.g. HEAD~3..HEAD)
*/
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { execSync, spawnSync } from "node:child_process";
function which(cmd: string): boolean {
try {
execSync(`which ${cmd}`, { stdio: "ignore" });
return true;
} catch {
return false;
}
}
export default function (pi: ExtensionAPI) {
pi.registerCommand("diff", {
description: "View uncommitted changes (tuicr/delta/git diff)",
getArgumentCompletions: (prefix: string) => {
const opts = ["--staged", "--cached", "HEAD~1", "HEAD~3..HEAD"];
const filtered = opts.filter((o) => o.startsWith(prefix));
return filtered.length > 0 ? filtered.map((o) => ({ value: o, label: o })) : null;
},
handler: async (args, ctx) => {
if (!ctx.hasUI) {
ctx.ui.notify("Diff viewer requires interactive mode", "error");
return;
}
const trimmed = args.trim();
if (which("tuicr")) {
// tuicr: full interactive TUI
const tuicrArgs: string[] = [];
if (trimmed) tuicrArgs.push("-r", trimmed);
await ctx.ui.custom<void>((tui, _theme, _kb, done) => {
tui.stop();
process.stdout.write("\x1b[2J\x1b[H");
spawnSync("tuicr", tuicrArgs, {
stdio: "inherit",
cwd: ctx.cwd,
env: process.env,
});
tui.start();
tui.requestRender(true);
done();
return { render: () => [], invalidate: () => {} };
});
} else if (which("delta")) {
// delta: syntax-highlighted pager
const cmd = trimmed
? `git diff ${trimmed} | delta --pager 'less -R'`
: `git diff | delta --pager 'less -R'`;
await ctx.ui.custom<void>((tui, _theme, _kb, done) => {
tui.stop();
spawnSync("bash", ["-c", cmd], {
stdio: "inherit",
cwd: ctx.cwd,
});
tui.start();
tui.requestRender(true);
done();
return { render: () => [], invalidate: () => {} };
});
} else {
// Fallback: plain git diff
await ctx.ui.custom<void>((tui, _theme, _kb, done) => {
tui.stop();
spawnSync("git", ["diff", ...(trimmed ? [trimmed] : [])], {
stdio: "inherit",
cwd: ctx.cwd,
});
tui.start();
tui.requestRender(true);
done();
return { render: () => [], invalidate: () => {} };
});
}
},
});
}