pi-diff-review 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/package.json +1 -1
- package/src/index.ts +76 -1
- package/src/review-component.ts +2 -0
package/README.md
CHANGED
|
@@ -36,6 +36,7 @@ pi install https://github.com/cmpadden/pi-diff-review
|
|
|
36
36
|
- `C` to add or edit an overall diff comment
|
|
37
37
|
- `x` to delete a comment for the current line or selected range
|
|
38
38
|
- `Enter` to submit comments back to pi
|
|
39
|
+
- Comments are cached per session and restored when reopening the same diff
|
|
39
40
|
- `q` to exit
|
|
40
41
|
|
|
41
42
|
## Release
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
1
2
|
import type {
|
|
2
3
|
ExtensionAPI,
|
|
3
4
|
ExtensionCommandContext,
|
|
@@ -9,6 +10,67 @@ import { buildReviewPrompt } from "./prompt.ts";
|
|
|
9
10
|
import { ReviewComponent } from "./review-component.ts";
|
|
10
11
|
import type { DiffSource, ReviewComment, ReviewResult } from "./types.ts";
|
|
11
12
|
|
|
13
|
+
const DIFF_REVIEW_CACHE_ENTRY = "pi-diff-review-cache";
|
|
14
|
+
|
|
15
|
+
type DiffReviewCacheEntry = {
|
|
16
|
+
cacheKey: string;
|
|
17
|
+
comments: ReviewComment[];
|
|
18
|
+
updatedAt: number;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function getDiffCacheKey(
|
|
22
|
+
cwd: string,
|
|
23
|
+
source: DiffSource,
|
|
24
|
+
diffText: string,
|
|
25
|
+
): string {
|
|
26
|
+
const hash = createHash("sha256").update(diffText).digest("hex");
|
|
27
|
+
return `${cwd}\0${source.label}\0${hash}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getCachedComments(
|
|
31
|
+
ctx: ExtensionCommandContext,
|
|
32
|
+
cacheKey: string,
|
|
33
|
+
): Map<string, ReviewComment> {
|
|
34
|
+
let latest: DiffReviewCacheEntry | undefined;
|
|
35
|
+
for (const entry of ctx.sessionManager.getEntries()) {
|
|
36
|
+
if (
|
|
37
|
+
entry.type !== "custom" ||
|
|
38
|
+
entry.customType !== DIFF_REVIEW_CACHE_ENTRY
|
|
39
|
+
) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const data = entry.data as Partial<DiffReviewCacheEntry> | undefined;
|
|
44
|
+
if (data?.cacheKey !== cacheKey || !Array.isArray(data.comments)) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!latest || (data.updatedAt ?? 0) >= latest.updatedAt) {
|
|
49
|
+
latest = {
|
|
50
|
+
cacheKey: data.cacheKey,
|
|
51
|
+
comments: data.comments,
|
|
52
|
+
updatedAt: data.updatedAt ?? 0,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return new Map(
|
|
58
|
+
(latest?.comments ?? []).map((comment) => [comment.id, comment]),
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function persistCachedComments(
|
|
63
|
+
pi: ExtensionAPI,
|
|
64
|
+
cacheKey: string,
|
|
65
|
+
comments: Iterable<ReviewComment>,
|
|
66
|
+
): void {
|
|
67
|
+
pi.appendEntry(DIFF_REVIEW_CACHE_ENTRY, {
|
|
68
|
+
cacheKey,
|
|
69
|
+
comments: [...comments],
|
|
70
|
+
updatedAt: Date.now(),
|
|
71
|
+
} satisfies DiffReviewCacheEntry);
|
|
72
|
+
}
|
|
73
|
+
|
|
12
74
|
export function registerDiffReviewCommand(pi: ExtensionAPI): void {
|
|
13
75
|
pi.registerCommand("diff", {
|
|
14
76
|
description: "Review a git diff in a custom TUI (/diff [git diff args])",
|
|
@@ -30,9 +92,17 @@ export function registerDiffReviewCommand(pi: ExtensionAPI): void {
|
|
|
30
92
|
}
|
|
31
93
|
|
|
32
94
|
const reviewLines = parseDiff(diffText);
|
|
95
|
+
const cacheKey = getDiffCacheKey(ctx.cwd, source, diffText);
|
|
96
|
+
const comments = getCachedComments(ctx, cacheKey);
|
|
97
|
+
if (comments.size > 0) {
|
|
98
|
+
ctx.ui.notify(
|
|
99
|
+
`Restored ${comments.size} cached diff comment${comments.size === 1 ? "" : "s"}.`,
|
|
100
|
+
"info",
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
33
104
|
const result = await ctx.ui.custom<ReviewResult>(
|
|
34
105
|
(tui, theme, _keybindings, done) => {
|
|
35
|
-
const comments = new Map<string, ReviewComment>();
|
|
36
106
|
return new ReviewComponent(
|
|
37
107
|
tui,
|
|
38
108
|
theme,
|
|
@@ -41,6 +111,9 @@ export function registerDiffReviewCommand(pi: ExtensionAPI): void {
|
|
|
41
111
|
comments,
|
|
42
112
|
done,
|
|
43
113
|
new PiModelDiffExplainer(ctx),
|
|
114
|
+
(updatedComments) => {
|
|
115
|
+
persistCachedComments(pi, cacheKey, updatedComments.values());
|
|
116
|
+
},
|
|
44
117
|
);
|
|
45
118
|
},
|
|
46
119
|
);
|
|
@@ -48,9 +121,11 @@ export function registerDiffReviewCommand(pi: ExtensionAPI): void {
|
|
|
48
121
|
if (!result || result.action !== "submit") return;
|
|
49
122
|
if (result.comments.length === 0) {
|
|
50
123
|
ctx.ui.notify("No review comments to send.", "info");
|
|
124
|
+
persistCachedComments(pi, cacheKey, []);
|
|
51
125
|
return;
|
|
52
126
|
}
|
|
53
127
|
|
|
128
|
+
persistCachedComments(pi, cacheKey, []);
|
|
54
129
|
pi.sendUserMessage(
|
|
55
130
|
buildReviewPrompt(result.comments, source.promptLabel),
|
|
56
131
|
);
|
package/src/review-component.ts
CHANGED
|
@@ -67,6 +67,7 @@ export class ReviewComponent {
|
|
|
67
67
|
private comments: Map<string, ReviewComment>,
|
|
68
68
|
private done: (result: ReviewResult) => void,
|
|
69
69
|
private explainer?: DiffExplainer,
|
|
70
|
+
private onCommentsChanged?: (comments: Map<string, ReviewComment>) => void,
|
|
70
71
|
) {
|
|
71
72
|
const firstCommentable = this.lines.findIndex((line) => line.commentable);
|
|
72
73
|
this.selected = firstCommentable >= 0 ? firstCommentable : 0;
|
|
@@ -508,6 +509,7 @@ export class ReviewComponent {
|
|
|
508
509
|
|
|
509
510
|
private markCommentsChanged(): void {
|
|
510
511
|
this.commentsRevision++;
|
|
512
|
+
this.onCommentsChanged?.(this.comments);
|
|
511
513
|
}
|
|
512
514
|
|
|
513
515
|
private ensureCommentLineKeys(): void {
|