@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.
Files changed (93) hide show
  1. package/LICENSE +2 -0
  2. package/README.md +9 -4
  3. package/extensions/agent-workflow-audit/index.ts +1398 -1009
  4. package/extensions/agent-workflow-audit/package.json +1 -1
  5. package/extensions/annotate-git-diff/README.md +3 -1
  6. package/extensions/annotate-git-diff/clipboard.ts +109 -100
  7. package/extensions/annotate-git-diff/git.ts +853 -767
  8. package/extensions/annotate-git-diff/glimpseui.d.ts +87 -78
  9. package/extensions/annotate-git-diff/index.ts +712 -671
  10. package/extensions/annotate-git-diff/package.json +1 -1
  11. package/extensions/annotate-git-diff/prompt.ts +45 -45
  12. package/extensions/annotate-git-diff/quiet-glimpse.ts +161 -155
  13. package/extensions/annotate-git-diff/review-server.ts +337 -311
  14. package/extensions/annotate-git-diff/types.ts +132 -132
  15. package/extensions/annotate-git-diff/ui.ts +27 -27
  16. package/extensions/annotate-git-diff/watch.ts +74 -74
  17. package/extensions/annotate-git-diff/web/app.js +1947 -1884
  18. package/extensions/annotate-git-diff/web/index.html +5 -6
  19. package/extensions/annotate-last-message/README.md +1 -1
  20. package/extensions/annotate-last-message/glimpseui.d.ts +87 -78
  21. package/extensions/annotate-last-message/index.ts +210 -206
  22. package/extensions/annotate-last-message/package.json +1 -1
  23. package/extensions/annotate-last-message/prompt.ts +87 -66
  24. package/extensions/annotate-last-message/quiet-glimpse.ts +161 -155
  25. package/extensions/annotate-last-message/session.ts +94 -89
  26. package/extensions/annotate-last-message/theme.ts +199 -193
  27. package/extensions/annotate-last-message/types.ts +23 -23
  28. package/extensions/annotate-last-message/ui.ts +27 -25
  29. package/extensions/annotate-last-message/web/app.js +4 -7
  30. package/extensions/annotate-last-message/web/md-renderer.js +1 -1
  31. package/extensions/brrr/README.md +1 -1
  32. package/extensions/brrr/index.ts +213 -191
  33. package/extensions/brrr/package.json +1 -1
  34. package/extensions/claude-fast/README.md +5 -79
  35. package/extensions/claude-fast/index.ts +31 -289
  36. package/extensions/claude-fast/package.json +2 -3
  37. package/extensions/code-reviewer/README.md +1 -1
  38. package/extensions/code-reviewer/index.ts +1598 -1350
  39. package/extensions/code-reviewer/package.json +1 -1
  40. package/extensions/confirm-destructive/README.md +1 -1
  41. package/extensions/confirm-destructive/index.ts +55 -51
  42. package/extensions/confirm-destructive/package.json +1 -1
  43. package/extensions/context-cap/index.ts +312 -304
  44. package/extensions/context-cap/package.json +1 -1
  45. package/extensions/context-inspector/index.ts +1211 -1064
  46. package/extensions/context-inspector/package.json +1 -1
  47. package/extensions/contrarian/index.ts +1854 -1735
  48. package/extensions/contrarian/package.json +1 -1
  49. package/extensions/dirty-repo-guard/index.ts +41 -41
  50. package/extensions/dynamic-context-pruning/README.md +6 -38
  51. package/extensions/dynamic-context-pruning/index.ts +2124 -1980
  52. package/extensions/dynamic-context-pruning/package.json +1 -1
  53. package/extensions/fast/README.md +50 -12
  54. package/extensions/fast/index.ts +513 -317
  55. package/extensions/fast/package.json +1 -1
  56. package/extensions/git-footer/README.md +1 -1
  57. package/extensions/git-footer/index.ts +458 -411
  58. package/extensions/git-footer/package.json +2 -3
  59. package/extensions/gnosis/index.ts +180 -130
  60. package/extensions/gnosis/package.json +1 -1
  61. package/extensions/inline-bash/index.ts +88 -88
  62. package/extensions/inline-bash/package.json +1 -1
  63. package/extensions/librarian/index.ts +1669 -1419
  64. package/extensions/librarian/package.json +1 -1
  65. package/extensions/minimal-footer/index.ts +994 -1012
  66. package/extensions/minimal-footer/openai-usage.ts +195 -190
  67. package/extensions/notify/index.ts +222 -230
  68. package/extensions/notify/package.json +1 -1
  69. package/extensions/openai-fast/README.md +5 -73
  70. package/extensions/openai-fast/index.ts +32 -272
  71. package/extensions/openai-fast/package.json +2 -3
  72. package/extensions/oracle/index.ts +1731 -1625
  73. package/extensions/oracle/package.json +1 -1
  74. package/extensions/permission-gate/index.ts +658 -608
  75. package/extensions/permission-gate/package.json +1 -1
  76. package/extensions/permission-gate/powershell-safety.ts +840 -793
  77. package/extensions/project-mcp-json/.pi-fleet-tested-version +1 -0
  78. package/extensions/project-mcp-json/README.md +199 -0
  79. package/extensions/project-mcp-json/config.ts +564 -0
  80. package/extensions/project-mcp-json/index.ts +119 -0
  81. package/extensions/project-mcp-json/package.json +38 -0
  82. package/extensions/quiet-tools/index.ts +282 -264
  83. package/extensions/review/README.md +2 -2
  84. package/extensions/review/index.ts +1745 -1872
  85. package/extensions/review/package.json +1 -1
  86. package/extensions/todo/index.ts +284 -265
  87. package/extensions/triage-comments/README.md +2 -2
  88. package/extensions/triage-comments/index.ts +2294 -1882
  89. package/extensions/triage-comments/package.json +1 -1
  90. package/package.json +6 -3
  91. package/assets/social-preview.png +0 -0
  92. package/extensions/claude-fast/claude-fast.example.json +0 -4
  93. 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.12",
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
- 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
- }
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
- if (file == null) return "(unknown file)";
20
- return file.gitDiff?.displayPath ?? file.path;
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
- const filePath = getCommentFilePath(file);
25
- const scopePrefix = `[${formatScopeLabel(comment)}] `;
24
+ const filePath = getCommentFilePath(file);
25
+ const scopePrefix = `[${formatScopeLabel(comment)}] `;
26
26
 
27
- if (comment.side === "file" || comment.startLine == null) {
28
- return `${scopePrefix}${filePath}`;
29
- }
27
+ if (comment.side === "file" || comment.startLine == null) {
28
+ return `${scopePrefix}${filePath}`;
29
+ }
30
30
 
31
- const range =
32
- comment.endLine != null && comment.endLine !== comment.startLine
33
- ? `${comment.startLine}-${comment.endLine}`
34
- : `${comment.startLine}`;
31
+ const range =
32
+ comment.endLine != null && comment.endLine !== comment.startLine
33
+ ? `${comment.startLine}-${comment.endLine}`
34
+ : `${comment.startLine}`;
35
35
 
36
- if (comment.scope === "all") {
37
- return `${scopePrefix}${filePath}:${range}`;
38
- }
36
+ if (comment.scope === "all") {
37
+ return `${scopePrefix}${filePath}:${range}`;
38
+ }
39
39
 
40
- const suffix = comment.side === "original" ? " (old)" : " (new)";
41
- return `${scopePrefix}${filePath}:${range}${suffix}`;
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
- 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[] = [];
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
- lines.push("Please address the following feedback");
50
- lines.push("");
49
+ lines.push("Please address the following feedback");
50
+ lines.push("");
51
51
 
52
- const overallComment = payload.overallComment.trim();
53
- if (overallComment.length > 0) {
54
- lines.push(overallComment);
55
- lines.push("");
56
- }
52
+ const overallComment = payload.overallComment.trim();
53
+ if (overallComment.length > 0) {
54
+ lines.push(overallComment);
55
+ lines.push("");
56
+ }
57
57
 
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
- });
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
- return lines.join("\n").trim();
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
- path: string;
11
- extraArgs?: string[];
12
- buildHint?: string;
10
+ path: string;
11
+ extraArgs?: string[];
12
+ buildHint?: string;
13
13
  }
14
14
 
15
15
  interface GlimpseProtocolMessage {
16
- type?: string;
17
- data?: unknown;
18
- screen?: unknown;
19
- screens?: unknown;
20
- appearance?: unknown;
21
- cursor?: unknown;
22
- cursorTip?: unknown;
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
- 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;
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
- #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 = stderr || `Glimpse process exited abnormally (code: ${code}, signal: ${signal}).`;
94
- this.#reportError(new Error(message));
95
- }
96
- this.#markClosed();
97
- });
98
- // Spawn failures can emit `error` and then `close` without `exit`.
99
- proc.on("close", () => this.#markClosed());
100
- }
101
-
102
- send(js: string): void {
103
- this.#write({ type: "eval", js });
104
- }
105
-
106
- close(): void {
107
- this.#write({ type: "close" });
108
- }
109
-
110
- get closed(): boolean {
111
- return this.#closed;
112
- }
113
-
114
- get failure(): Error | null {
115
- return this.#failure;
116
- }
117
-
118
- #reportError(error: Error): void {
119
- this.#failure ??= error;
120
- this.emit("error", error);
121
- }
122
-
123
- #markClosed(): void {
124
- if (this.#closed) return;
125
- this.#closed = true;
126
- this.emit("closed");
127
- }
128
-
129
- #write(obj: Record<string, unknown>): void {
130
- if (this.#closed) return;
131
- this.#proc.stdin.write(`${JSON.stringify(obj)}\n`);
132
- }
133
-
134
- setHTML(html: string): void {
135
- this.#write({ type: "html", html: Buffer.from(html).toString("base64") });
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
- const glimpseModule = (await import("glimpseui")) as unknown as { getNativeHostInfo: () => NativeHostInfo };
141
- return glimpseModule.getNativeHostInfo();
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(html: string, options: GlimpseOpenOptions = {}): Promise<QuietGlimpseWindow> {
145
- const host = await getNativeHostInfo();
146
- if (!existsSync(host.path)) {
147
- const hint = host.buildHint ? ` ${host.buildHint}` : "";
148
- throw new Error(`Glimpse host not found at '${host.path}'.${hint}`);
149
- }
150
- const args: string[] = [];
151
-
152
- if (options.width != null) args.push("--width", String(options.width));
153
- if (options.height != null) args.push("--height", String(options.height));
154
- if (options.title != null) args.push("--title", options.title);
155
- if (options.frameless) args.push("--frameless");
156
- if (options.floating) args.push("--floating");
157
- if (options.transparent) args.push("--transparent");
158
- if (options.clickThrough) args.push("--click-through");
159
- if (options.hidden) args.push("--hidden");
160
- if (options.autoClose) args.push("--auto-close");
161
- if (options.x != null) args.push(`--x=${options.x}`);
162
- if (options.y != null) args.push(`--y=${options.y}`);
163
- if (options.cursorOffset?.x != null) args.push(`--cursor-offset-x=${options.cursorOffset.x}`);
164
- if (options.cursorOffset?.y != null) args.push(`--cursor-offset-y=${options.cursorOffset.y}`);
165
- if (options.cursorAnchor != null) args.push("--cursor-anchor", options.cursorAnchor);
166
- if (options.followMode != null) args.push("--follow-mode", options.followMode);
167
- if (options.followCursor) args.push("--follow-cursor");
168
-
169
- const proc = spawn(host.path, [...(host.extraArgs ?? []), ...args], {
170
- stdio: ["pipe", "pipe", "pipe"],
171
- windowsHide: process.platform === "win32",
172
- env: {
173
- ...process.env,
174
- OS_ACTIVITY_MODE: process.env.OS_ACTIVITY_MODE ?? "disable",
175
- },
176
- });
177
-
178
- return new QuietGlimpseWindowImpl(proc, html);
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
  }