@diegopetrucci/pi-extensions 0.1.74 → 0.1.76
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/LICENSE +2 -0
- package/README.md +9 -4
- package/extensions/agent-workflow-audit/index.ts +1398 -1009
- package/extensions/agent-workflow-audit/package.json +1 -1
- package/extensions/annotate-git-diff/README.md +3 -1
- package/extensions/annotate-git-diff/clipboard.ts +109 -100
- package/extensions/annotate-git-diff/git.ts +853 -767
- package/extensions/annotate-git-diff/glimpseui.d.ts +87 -78
- package/extensions/annotate-git-diff/index.ts +712 -671
- package/extensions/annotate-git-diff/package.json +1 -1
- package/extensions/annotate-git-diff/prompt.ts +45 -45
- package/extensions/annotate-git-diff/quiet-glimpse.ts +161 -155
- package/extensions/annotate-git-diff/review-server.ts +337 -311
- package/extensions/annotate-git-diff/types.ts +132 -132
- package/extensions/annotate-git-diff/ui.ts +27 -27
- package/extensions/annotate-git-diff/watch.ts +74 -74
- package/extensions/annotate-git-diff/web/app.js +1947 -1884
- package/extensions/annotate-git-diff/web/index.html +5 -6
- package/extensions/annotate-last-message/README.md +1 -1
- package/extensions/annotate-last-message/glimpseui.d.ts +87 -78
- package/extensions/annotate-last-message/index.ts +210 -206
- package/extensions/annotate-last-message/package.json +1 -1
- package/extensions/annotate-last-message/prompt.ts +87 -66
- package/extensions/annotate-last-message/quiet-glimpse.ts +161 -155
- package/extensions/annotate-last-message/session.ts +94 -89
- package/extensions/annotate-last-message/theme.ts +199 -193
- package/extensions/annotate-last-message/types.ts +23 -23
- package/extensions/annotate-last-message/ui.ts +27 -25
- package/extensions/annotate-last-message/web/app.js +4 -7
- package/extensions/annotate-last-message/web/md-renderer.js +1 -1
- package/extensions/brrr/README.md +1 -1
- package/extensions/brrr/index.ts +213 -191
- package/extensions/brrr/package.json +1 -1
- package/extensions/claude-fast/README.md +5 -79
- package/extensions/claude-fast/index.ts +31 -289
- package/extensions/claude-fast/package.json +2 -3
- package/extensions/code-reviewer/README.md +1 -1
- package/extensions/code-reviewer/index.ts +1598 -1350
- package/extensions/code-reviewer/package.json +1 -1
- package/extensions/confirm-destructive/README.md +1 -1
- package/extensions/confirm-destructive/index.ts +55 -51
- package/extensions/confirm-destructive/package.json +1 -1
- package/extensions/context-cap/index.ts +312 -304
- package/extensions/context-cap/package.json +1 -1
- package/extensions/context-inspector/index.ts +1211 -1064
- package/extensions/context-inspector/package.json +1 -1
- package/extensions/contrarian/index.ts +1854 -1735
- package/extensions/contrarian/package.json +1 -1
- package/extensions/dirty-repo-guard/index.ts +41 -41
- package/extensions/dynamic-context-pruning/README.md +6 -38
- package/extensions/dynamic-context-pruning/index.ts +2124 -1980
- package/extensions/dynamic-context-pruning/package.json +1 -1
- package/extensions/fast/README.md +50 -12
- package/extensions/fast/index.ts +513 -317
- package/extensions/fast/package.json +1 -1
- package/extensions/git-footer/README.md +1 -1
- package/extensions/git-footer/index.ts +458 -411
- package/extensions/git-footer/package.json +2 -3
- package/extensions/gnosis/index.ts +180 -130
- package/extensions/gnosis/package.json +1 -1
- package/extensions/inline-bash/index.ts +88 -88
- package/extensions/inline-bash/package.json +1 -1
- package/extensions/librarian/index.ts +1669 -1419
- package/extensions/librarian/package.json +1 -1
- package/extensions/minimal-footer/index.ts +994 -1012
- package/extensions/minimal-footer/openai-usage.ts +195 -190
- package/extensions/notify/index.ts +222 -230
- package/extensions/notify/package.json +1 -1
- package/extensions/openai-fast/README.md +5 -73
- package/extensions/openai-fast/index.ts +32 -272
- package/extensions/openai-fast/package.json +2 -3
- package/extensions/oracle/index.ts +1731 -1625
- package/extensions/oracle/package.json +1 -1
- package/extensions/permission-gate/index.ts +658 -608
- package/extensions/permission-gate/package.json +1 -1
- package/extensions/permission-gate/powershell-safety.ts +840 -793
- package/extensions/project-mcp-json/.pi-fleet-tested-version +1 -0
- package/extensions/project-mcp-json/README.md +199 -0
- package/extensions/project-mcp-json/config.ts +564 -0
- package/extensions/project-mcp-json/index.ts +119 -0
- package/extensions/project-mcp-json/package.json +38 -0
- package/extensions/quiet-tools/index.ts +282 -264
- package/extensions/review/README.md +2 -2
- package/extensions/review/index.ts +1745 -1872
- package/extensions/review/package.json +1 -1
- package/extensions/todo/index.ts +284 -265
- package/extensions/triage-comments/README.md +2 -2
- package/extensions/triage-comments/index.ts +2294 -1882
- package/extensions/triage-comments/package.json +1 -1
- package/package.json +6 -3
- package/assets/social-preview.png +0 -0
- package/extensions/claude-fast/claude-fast.example.json +0 -4
- package/extensions/openai-fast/openai-fast.example.json +0 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-annotate-git-diff",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"description": "A standalone pi extension that adds /annotate-git-diff, a native Glimpse UI for annotating git diffs and sending explicit feedback directly to the agent; close recovery keeps unsent drafts in the editor.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -1,66 +1,66 @@
|
|
|
1
1
|
import type { DiffReviewComment, ReviewFile, ReviewSubmitPayload } from "./types.js";
|
|
2
2
|
|
|
3
3
|
function formatScopeLabel(comment: DiffReviewComment): string {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
4
|
+
switch (comment.scope) {
|
|
5
|
+
case "branch":
|
|
6
|
+
return "branch diff";
|
|
7
|
+
case "commits":
|
|
8
|
+
return comment.commitKind === "working-tree"
|
|
9
|
+
? "working tree changes"
|
|
10
|
+
: comment.commitShort
|
|
11
|
+
? `commit ${comment.commitShort}`
|
|
12
|
+
: "commit";
|
|
13
|
+
default:
|
|
14
|
+
return "all files";
|
|
15
|
+
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
function getCommentFilePath(file: ReviewFile | undefined): string {
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
if (file == null) return "(unknown file)";
|
|
20
|
+
return file.gitDiff?.displayPath ?? file.path;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
function formatLocation(comment: DiffReviewComment, file: ReviewFile | undefined): string {
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
const filePath = getCommentFilePath(file);
|
|
25
|
+
const scopePrefix = `[${formatScopeLabel(comment)}] `;
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
if (comment.side === "file" || comment.startLine == null) {
|
|
28
|
+
return `${scopePrefix}${filePath}`;
|
|
29
|
+
}
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
const range =
|
|
32
|
+
comment.endLine != null && comment.endLine !== comment.startLine
|
|
33
|
+
? `${comment.startLine}-${comment.endLine}`
|
|
34
|
+
: `${comment.startLine}`;
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
if (comment.scope === "all") {
|
|
37
|
+
return `${scopePrefix}${filePath}:${range}`;
|
|
38
|
+
}
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
const suffix = comment.side === "original" ? " (old)" : " (new)";
|
|
41
|
+
return `${scopePrefix}${filePath}:${range}${suffix}`;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
export function composeReviewPrompt(files: ReviewFile[], payload: ReviewSubmitPayload): string {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
const fileMap = new Map(files.map((file) => [file.id, file]));
|
|
46
|
+
const comments = payload.comments.filter((comment) => comment.body.trim().length > 0);
|
|
47
|
+
const lines: string[] = [];
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
lines.push("Please address the following feedback");
|
|
50
|
+
lines.push("");
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
const overallComment = payload.overallComment.trim();
|
|
53
|
+
if (overallComment.length > 0) {
|
|
54
|
+
lines.push(overallComment);
|
|
55
|
+
lines.push("");
|
|
56
|
+
}
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
comments.forEach((comment, index) => {
|
|
59
|
+
const file = fileMap.get(comment.fileId);
|
|
60
|
+
lines.push(`${index + 1}. ${formatLocation(comment, file)}`);
|
|
61
|
+
lines.push(` ${comment.body.trim()}`);
|
|
62
|
+
lines.push("");
|
|
63
|
+
});
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
return lines.join("\n").trim();
|
|
66
66
|
}
|
|
@@ -7,173 +7,179 @@ import { createInterface } from "node:readline";
|
|
|
7
7
|
import type { GlimpseOpenOptions } from "glimpseui";
|
|
8
8
|
|
|
9
9
|
interface NativeHostInfo {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
path: string;
|
|
11
|
+
extraArgs?: string[];
|
|
12
|
+
buildHint?: string;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
interface GlimpseProtocolMessage {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
type?: string;
|
|
17
|
+
data?: unknown;
|
|
18
|
+
screen?: unknown;
|
|
19
|
+
screens?: unknown;
|
|
20
|
+
appearance?: unknown;
|
|
21
|
+
cursor?: unknown;
|
|
22
|
+
cursorTip?: unknown;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export interface QuietGlimpseWindow {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
26
|
+
readonly closed: boolean;
|
|
27
|
+
readonly failure: Error | null;
|
|
28
|
+
on(event: "message", listener: (data: unknown) => void): this;
|
|
29
|
+
on(event: "closed", listener: () => void): this;
|
|
30
|
+
on(event: "error", listener: (error: Error) => void): this;
|
|
31
|
+
removeListener(event: "message", listener: (data: unknown) => void): this;
|
|
32
|
+
removeListener(event: "closed", listener: () => void): this;
|
|
33
|
+
removeListener(event: "error", listener: (error: Error) => void): this;
|
|
34
|
+
send(js: string): void;
|
|
35
|
+
close(): void;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
class QuietGlimpseWindowImpl extends EventEmitter implements QuietGlimpseWindow {
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
39
|
+
#proc: ChildProcessWithoutNullStreams;
|
|
40
|
+
#closed = false;
|
|
41
|
+
#pendingHTML: string | null;
|
|
42
|
+
#stderr = "";
|
|
43
|
+
#failure: Error | null = null;
|
|
44
|
+
|
|
45
|
+
constructor(proc: ChildProcessWithoutNullStreams, initialHTML: string) {
|
|
46
|
+
super();
|
|
47
|
+
this.#proc = proc;
|
|
48
|
+
this.#pendingHTML = initialHTML;
|
|
49
|
+
// EventEmitter treats an unobserved `error` as fatal. Keep a permanent
|
|
50
|
+
// fallback while callers attach and detach their lifecycle listeners.
|
|
51
|
+
this.on("error", () => {});
|
|
52
|
+
|
|
53
|
+
proc.stdin.on("error", () => {});
|
|
54
|
+
proc.stderr.on("data", (chunk) => {
|
|
55
|
+
this.#stderr += chunk.toString();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const rl = createInterface({ input: proc.stdout, crlfDelay: Infinity });
|
|
59
|
+
rl.on("line", (line) => {
|
|
60
|
+
let parsed: unknown;
|
|
61
|
+
try {
|
|
62
|
+
parsed = JSON.parse(line);
|
|
63
|
+
} catch {
|
|
64
|
+
this.#reportError(new Error(`Malformed glimpse protocol line: ${line}`));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return;
|
|
68
|
+
const message = parsed as GlimpseProtocolMessage;
|
|
69
|
+
|
|
70
|
+
switch (message.type) {
|
|
71
|
+
case "ready":
|
|
72
|
+
if (this.#pendingHTML != null) {
|
|
73
|
+
this.setHTML(this.#pendingHTML);
|
|
74
|
+
this.#pendingHTML = null;
|
|
75
|
+
}
|
|
76
|
+
break;
|
|
77
|
+
case "message":
|
|
78
|
+
this.emit("message", message.data);
|
|
79
|
+
break;
|
|
80
|
+
case "closed":
|
|
81
|
+
this.#markClosed();
|
|
82
|
+
break;
|
|
83
|
+
default:
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
proc.on("error", (error) => this.#reportError(error));
|
|
89
|
+
proc.on("exit", (code, signal) => {
|
|
90
|
+
const stderr = this.#stderr.trim();
|
|
91
|
+
const failed = signal != null || (code != null && code !== 0);
|
|
92
|
+
if (!this.#closed && failed) {
|
|
93
|
+
const message =
|
|
94
|
+
stderr || `Glimpse process exited abnormally (code: ${code}, signal: ${signal}).`;
|
|
95
|
+
this.#reportError(new Error(message));
|
|
96
|
+
}
|
|
97
|
+
this.#markClosed();
|
|
98
|
+
});
|
|
99
|
+
// Spawn failures can emit `error` and then `close` without `exit`.
|
|
100
|
+
proc.on("close", () => this.#markClosed());
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
send(js: string): void {
|
|
104
|
+
this.#write({ type: "eval", js });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
close(): void {
|
|
108
|
+
this.#write({ type: "close" });
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
get closed(): boolean {
|
|
112
|
+
return this.#closed;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
get failure(): Error | null {
|
|
116
|
+
return this.#failure;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
#reportError(error: Error): void {
|
|
120
|
+
this.#failure ??= error;
|
|
121
|
+
this.emit("error", error);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
#markClosed(): void {
|
|
125
|
+
if (this.#closed) return;
|
|
126
|
+
this.#closed = true;
|
|
127
|
+
this.emit("closed");
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
#write(obj: Record<string, unknown>): void {
|
|
131
|
+
if (this.#closed) return;
|
|
132
|
+
this.#proc.stdin.write(`${JSON.stringify(obj)}\n`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
setHTML(html: string): void {
|
|
136
|
+
this.#write({ type: "html", html: Buffer.from(html).toString("base64") });
|
|
137
|
+
}
|
|
137
138
|
}
|
|
138
139
|
|
|
139
140
|
async function getNativeHostInfo(): Promise<NativeHostInfo> {
|
|
140
|
-
|
|
141
|
-
|
|
141
|
+
const glimpseModule = (await import("glimpseui")) as unknown as {
|
|
142
|
+
getNativeHostInfo: () => NativeHostInfo;
|
|
143
|
+
};
|
|
144
|
+
return glimpseModule.getNativeHostInfo();
|
|
142
145
|
}
|
|
143
146
|
|
|
144
|
-
export async function openQuietGlimpse(
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
147
|
+
export async function openQuietGlimpse(
|
|
148
|
+
html: string,
|
|
149
|
+
options: GlimpseOpenOptions = {},
|
|
150
|
+
): Promise<QuietGlimpseWindow> {
|
|
151
|
+
const host = await getNativeHostInfo();
|
|
152
|
+
if (!existsSync(host.path)) {
|
|
153
|
+
const hint = host.buildHint ? ` ${host.buildHint}` : "";
|
|
154
|
+
throw new Error(`Glimpse host not found at '${host.path}'.${hint}`);
|
|
155
|
+
}
|
|
156
|
+
const args: string[] = [];
|
|
157
|
+
|
|
158
|
+
if (options.width != null) args.push("--width", String(options.width));
|
|
159
|
+
if (options.height != null) args.push("--height", String(options.height));
|
|
160
|
+
if (options.title != null) args.push("--title", options.title);
|
|
161
|
+
if (options.frameless) args.push("--frameless");
|
|
162
|
+
if (options.floating) args.push("--floating");
|
|
163
|
+
if (options.transparent) args.push("--transparent");
|
|
164
|
+
if (options.clickThrough) args.push("--click-through");
|
|
165
|
+
if (options.hidden) args.push("--hidden");
|
|
166
|
+
if (options.autoClose) args.push("--auto-close");
|
|
167
|
+
if (options.x != null) args.push(`--x=${options.x}`);
|
|
168
|
+
if (options.y != null) args.push(`--y=${options.y}`);
|
|
169
|
+
if (options.cursorOffset?.x != null) args.push(`--cursor-offset-x=${options.cursorOffset.x}`);
|
|
170
|
+
if (options.cursorOffset?.y != null) args.push(`--cursor-offset-y=${options.cursorOffset.y}`);
|
|
171
|
+
if (options.cursorAnchor != null) args.push("--cursor-anchor", options.cursorAnchor);
|
|
172
|
+
if (options.followMode != null) args.push("--follow-mode", options.followMode);
|
|
173
|
+
if (options.followCursor) args.push("--follow-cursor");
|
|
174
|
+
|
|
175
|
+
const proc = spawn(host.path, [...(host.extraArgs ?? []), ...args], {
|
|
176
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
177
|
+
windowsHide: process.platform === "win32",
|
|
178
|
+
env: {
|
|
179
|
+
...process.env,
|
|
180
|
+
OS_ACTIVITY_MODE: process.env.OS_ACTIVITY_MODE ?? "disable",
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
return new QuietGlimpseWindowImpl(proc, html);
|
|
179
185
|
}
|