@diegopetrucci/pi-extensions 0.1.42 → 0.1.43

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 (28) hide show
  1. package/README.md +2 -0
  2. package/extensions/annotate-git-diff/.pi-fleet-tested-version +1 -0
  3. package/extensions/annotate-git-diff/README.md +43 -0
  4. package/extensions/annotate-git-diff/clipboard.ts +143 -0
  5. package/extensions/annotate-git-diff/git.ts +943 -0
  6. package/extensions/annotate-git-diff/glimpseui.d.ts +89 -0
  7. package/extensions/annotate-git-diff/index.ts +412 -0
  8. package/extensions/annotate-git-diff/package.json +50 -0
  9. package/extensions/annotate-git-diff/prompt.ts +65 -0
  10. package/extensions/annotate-git-diff/quiet-glimpse.ts +156 -0
  11. package/extensions/annotate-git-diff/types.ts +202 -0
  12. package/extensions/annotate-git-diff/ui.ts +71 -0
  13. package/extensions/annotate-git-diff/watch.ts +104 -0
  14. package/extensions/annotate-git-diff/web/app.js +2381 -0
  15. package/extensions/annotate-git-diff/web/index.html +913 -0
  16. package/extensions/annotate-last-message/.pi-fleet-tested-version +1 -0
  17. package/extensions/annotate-last-message/README.md +40 -0
  18. package/extensions/annotate-last-message/glimpseui.d.ts +89 -0
  19. package/extensions/annotate-last-message/index.ts +165 -0
  20. package/extensions/annotate-last-message/package.json +45 -0
  21. package/extensions/annotate-last-message/prompt.ts +93 -0
  22. package/extensions/annotate-last-message/quiet-glimpse.ts +156 -0
  23. package/extensions/annotate-last-message/session.ts +112 -0
  24. package/extensions/annotate-last-message/types.ts +46 -0
  25. package/extensions/annotate-last-message/ui.ts +23 -0
  26. package/extensions/annotate-last-message/web/app.js +229 -0
  27. package/extensions/annotate-last-message/web/index.html +322 -0
  28. package/package.json +14 -7
package/README.md CHANGED
@@ -3,6 +3,8 @@
3
3
  A collection of [pi](https://github.com/earendil-works/pi-mono) agent extensions I made.
4
4
 
5
5
  - [`agent-workflow-audit`](./extensions/agent-workflow-audit): Adds `/agent-workflow-audit`, which runs an isolated repo workflow audit subagent and returns only the final distilled report to the main session.
6
+ - [`annotate-git-diff`](./extensions/annotate-git-diff): Adds `/annotate-git-diff`, a native Glimpse UI for annotating git diffs and appending structured feedback prompts to the editor.
7
+ - [`annotate-last-message`](./extensions/annotate-last-message): Adds `/annotate-last-message`, a native Glimpse UI for annotating the latest assistant reply and sending planning-oriented feedback back through the editor.
6
8
  - [`brrr`](./extensions/brrr): Sends brrr push notifications when pi finishes an agent turn and is ready for input, with optional macOS idle gating.
7
9
  - [`claude-fast`](./extensions/claude-fast): Adds `/claude-fast` to enable Anthropic Claude Fast mode for supported Claude Opus models by injecting `speed: "fast"`.
8
10
  - [`confirm-destructive`](./extensions/confirm-destructive): Confirms before destructive session actions like clear, switch, and fork.
@@ -0,0 +1,43 @@
1
+ # annotate-git-diff
2
+
3
+ A standalone pi extension that adds `/annotate-git-diff`, a native Glimpse window for reviewing git changes and sending structured feedback back to the current editor buffer.
4
+
5
+ ## Attribution
6
+
7
+ This extension was ported from the first-party The Last Harness implementation. It adapts the MIT-licensed `@ryan_nookpi/pi-extension-diff-review` implementation from the `Jonghakseo/pi-extension` monorepo and preserves its original inspiration credit to [badlogic/pi-diff-review](https://github.com/badlogic/pi-diff-review).
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ pi install npm:@diegopetrucci/pi-annotate-git-diff
13
+ ```
14
+
15
+ Then reload pi:
16
+
17
+ ```text
18
+ /reload
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ Run `/annotate-git-diff` inside a git repository. The command opens a native review window with:
24
+
25
+ - Monaco-based diff viewing,
26
+ - branch diff, per-commit including working tree, and all-files scopes,
27
+ - inline, file-level, and overall review comments,
28
+ - submit-to-editor feedback prompt insertion.
29
+
30
+ Submitting feedback does not auto-apply code changes. The extension appends a structured prompt to the current editor buffer so you can send that feedback back to the active agent.
31
+
32
+ ## Requirements
33
+
34
+ - Run inside a git repository.
35
+ - Local desktop support for opening a native [Glimpse](https://github.com/mariozechner/glimpse) window.
36
+ - Packaged Monaco and Tailwind assets from this npm package.
37
+ - POSIX shell utilities (`bash`, `mktemp`, `base64`, and `tr`) for some git snapshot/binary-file paths.
38
+
39
+ ## Troubleshooting
40
+
41
+ - `Review failed: Not inside a git repository.` → change into a git repo and rerun `/annotate-git-diff`.
42
+ - `No reviewable files found.` → make or fetch reviewable changes, then rerun.
43
+ - `Review failed: Glimpse host not found ...` → the native window runtime is unavailable; reinstall/update the package and rerun from a machine/session that can open native windows.
@@ -0,0 +1,143 @@
1
+ import { spawnSync } from "node:child_process";
2
+
3
+ const MAX_CLIPBOARD_BYTES = 16 * 1024 * 1024;
4
+
5
+ type ClipboardPlatform = NodeJS.Platform;
6
+
7
+ interface ClipboardCommand {
8
+ command: string;
9
+ args: string[];
10
+ }
11
+
12
+ export interface ClipboardCommandResult {
13
+ status: number | null;
14
+ signal?: NodeJS.Signals | null;
15
+ stdout?: string | Buffer;
16
+ stderr?: string | Buffer;
17
+ error?: Error;
18
+ }
19
+
20
+ export type ClipboardCommandRunner = (
21
+ command: string,
22
+ args: string[],
23
+ options: { encoding: "utf8"; maxBuffer: number; input?: string },
24
+ ) => ClipboardCommandResult;
25
+
26
+ interface ClipboardOptions {
27
+ platform?: ClipboardPlatform;
28
+ runner?: ClipboardCommandRunner;
29
+ }
30
+
31
+ const defaultRunner: ClipboardCommandRunner = (command, args, options) => spawnSync(command, args, options);
32
+
33
+ function clipboardReadCommands(platform: ClipboardPlatform): ClipboardCommand[] {
34
+ switch (platform) {
35
+ case "darwin":
36
+ return [{ command: "pbpaste", args: [] }];
37
+ case "win32":
38
+ return [
39
+ {
40
+ command: "powershell.exe",
41
+ args: [
42
+ "-NoProfile",
43
+ "-NonInteractive",
44
+ "-Command",
45
+ "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Get-Clipboard -Raw",
46
+ ],
47
+ },
48
+ ];
49
+ case "linux":
50
+ return [
51
+ { command: "wl-paste", args: ["--type", "text/plain"] },
52
+ { command: "xclip", args: ["-selection", "clipboard", "-out"] },
53
+ { command: "xsel", args: ["--clipboard", "--output"] },
54
+ ];
55
+ default:
56
+ return [];
57
+ }
58
+ }
59
+
60
+ function clipboardWriteCommands(platform: ClipboardPlatform): ClipboardCommand[] {
61
+ switch (platform) {
62
+ case "darwin":
63
+ return [{ command: "pbcopy", args: [] }];
64
+ case "win32":
65
+ return [
66
+ {
67
+ command: "powershell.exe",
68
+ args: [
69
+ "-NoProfile",
70
+ "-NonInteractive",
71
+ "-Command",
72
+ "[Console]::InputEncoding = [System.Text.Encoding]::UTF8; $text = [Console]::In.ReadToEnd(); Set-Clipboard -Value $text",
73
+ ],
74
+ },
75
+ ];
76
+ case "linux":
77
+ return [
78
+ { command: "wl-copy", args: ["--type", "text/plain"] },
79
+ { command: "xclip", args: ["-selection", "clipboard", "-in"] },
80
+ { command: "xsel", args: ["--clipboard", "--input"] },
81
+ ];
82
+ default:
83
+ return [];
84
+ }
85
+ }
86
+
87
+ function commandLabel(command: ClipboardCommand): string {
88
+ return [command.command, ...command.args].join(" ");
89
+ }
90
+
91
+ function outputToString(value: string | Buffer | undefined): string {
92
+ if (value == null) return "";
93
+ return typeof value === "string" ? value : value.toString("utf8");
94
+ }
95
+
96
+ function runClipboardCommand(command: ClipboardCommand, runner: ClipboardCommandRunner, input?: string): string {
97
+ const result = runner(command.command, command.args, {
98
+ encoding: "utf8",
99
+ maxBuffer: MAX_CLIPBOARD_BYTES,
100
+ ...(input == null ? {} : { input }),
101
+ });
102
+ if (result.error) throw result.error;
103
+ if (result.status !== 0) {
104
+ const stderr = outputToString(result.stderr).trim();
105
+ const status = result.status == null ? result.signal || "unknown" : result.status;
106
+ throw new Error(`${commandLabel(command)} exited with ${status}${stderr ? `: ${stderr}` : ""}`);
107
+ }
108
+ return outputToString(result.stdout);
109
+ }
110
+
111
+ function runFirstAvailable(commands: ClipboardCommand[], runner: ClipboardCommandRunner, input?: string): string {
112
+ if (commands.length === 0) {
113
+ throw new Error(`System clipboard is unsupported on ${process.platform}.`);
114
+ }
115
+
116
+ const errors: string[] = [];
117
+ for (const command of commands) {
118
+ try {
119
+ return runClipboardCommand(command, runner, input);
120
+ } catch (error) {
121
+ const message = error instanceof Error ? error.message : String(error);
122
+ errors.push(`${commandLabel(command)}: ${message}`);
123
+ }
124
+ }
125
+ throw new Error(`No system clipboard command succeeded. ${errors.join("; ")}`);
126
+ }
127
+
128
+ export function readSystemClipboard(options: ClipboardOptions = {}): string {
129
+ const platform = options.platform ?? process.platform;
130
+ const runner = options.runner ?? defaultRunner;
131
+ return runFirstAvailable(clipboardReadCommands(platform), runner);
132
+ }
133
+
134
+ export function writeSystemClipboard(text: string, options: ClipboardOptions = {}): void {
135
+ const platform = options.platform ?? process.platform;
136
+ const runner = options.runner ?? defaultRunner;
137
+ runFirstAvailable(clipboardWriteCommands(platform), runner, text);
138
+ }
139
+
140
+ export const __testing = {
141
+ clipboardReadCommands,
142
+ clipboardWriteCommands,
143
+ };