@diegopetrucci/pi-extensions 0.1.64 → 0.1.66
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/.pi-fleet-tested-version +1 -1
- package/README.md +2 -2
- package/extensions/agent-workflow-audit/.pi-fleet-tested-version +1 -1
- package/extensions/agent-workflow-audit/package.json +1 -1
- package/extensions/annotate-git-diff/.pi-fleet-tested-version +1 -1
- package/extensions/annotate-git-diff/README.md +3 -0
- package/extensions/annotate-git-diff/index.ts +49 -5
- package/extensions/annotate-git-diff/package.json +2 -1
- package/extensions/annotate-git-diff/quiet-glimpse.ts +24 -3
- package/extensions/annotate-git-diff/review-server.ts +379 -0
- package/extensions/annotate-git-diff/ui.ts +17 -41
- package/extensions/annotate-last-message/.pi-fleet-tested-version +1 -1
- package/extensions/annotate-last-message/index.ts +28 -2
- package/extensions/annotate-last-message/package.json +1 -1
- package/extensions/annotate-last-message/quiet-glimpse.ts +24 -3
- package/extensions/brrr/.pi-fleet-tested-version +1 -1
- package/extensions/brrr/package.json +1 -1
- package/extensions/claude-fast/.pi-fleet-tested-version +1 -1
- package/extensions/claude-fast/README.md +1 -1
- package/extensions/claude-fast/index.ts +2 -2
- package/extensions/claude-fast/package.json +1 -1
- package/extensions/code-reviewer/.pi-fleet-tested-version +1 -1
- package/extensions/code-reviewer/package.json +1 -1
- package/extensions/confirm-destructive/.pi-fleet-tested-version +1 -1
- package/extensions/confirm-destructive/package.json +1 -1
- package/extensions/context-cap/.pi-fleet-tested-version +1 -1
- package/extensions/context-cap/package.json +1 -1
- package/extensions/context-inspector/.pi-fleet-tested-version +1 -1
- package/extensions/context-inspector/package.json +1 -1
- package/extensions/contrarian/.pi-fleet-tested-version +1 -1
- package/extensions/contrarian/index.ts +79 -33
- package/extensions/contrarian/package.json +1 -1
- package/extensions/dirty-repo-guard/.pi-fleet-tested-version +1 -1
- package/extensions/dirty-repo-guard/package.json +1 -1
- package/extensions/dynamic-context-pruning/.pi-fleet-tested-version +1 -1
- package/extensions/dynamic-context-pruning/package.json +1 -1
- package/extensions/fast/.pi-fleet-tested-version +1 -1
- package/extensions/fast/README.md +2 -2
- package/extensions/fast/index.ts +2 -3
- package/extensions/fast/package.json +1 -1
- package/extensions/git-footer/.pi-fleet-tested-version +1 -1
- package/extensions/git-footer/package.json +1 -1
- package/extensions/gnosis/.pi-fleet-tested-version +1 -1
- package/extensions/gnosis/package.json +1 -1
- package/extensions/illustrations-to-explain-things/.pi-fleet-tested-version +1 -1
- package/extensions/illustrations-to-explain-things/package.json +1 -1
- package/extensions/inline-bash/.pi-fleet-tested-version +1 -1
- package/extensions/inline-bash/package.json +1 -1
- package/extensions/librarian/.pi-fleet-tested-version +1 -1
- package/extensions/librarian/package.json +1 -1
- package/extensions/minimal-footer/.pi-fleet-tested-version +1 -1
- package/extensions/minimal-footer/package.json +1 -1
- package/extensions/notify/.pi-fleet-tested-version +1 -1
- package/extensions/notify/package.json +1 -1
- package/extensions/openai-fast/.pi-fleet-tested-version +1 -1
- package/extensions/openai-fast/README.md +2 -2
- package/extensions/openai-fast/index.ts +2 -3
- package/extensions/openai-fast/package.json +2 -2
- package/extensions/oracle/.pi-fleet-tested-version +1 -1
- package/extensions/oracle/index.ts +79 -33
- package/extensions/oracle/package.json +1 -1
- package/extensions/permission-gate/.pi-fleet-tested-version +1 -1
- package/extensions/permission-gate/README.md +11 -3
- package/extensions/permission-gate/index.ts +70 -7
- package/extensions/permission-gate/package.json +4 -2
- package/extensions/permission-gate/powershell-safety.ts +1006 -0
- package/extensions/quiet-tools/.pi-fleet-tested-version +1 -1
- package/extensions/quiet-tools/package.json +1 -1
- package/extensions/review/.pi-fleet-tested-version +1 -1
- package/extensions/review/package.json +1 -1
- package/extensions/todo/.pi-fleet-tested-version +1 -1
- package/extensions/todo/package.json +1 -1
- package/extensions/triage-comments/.pi-fleet-tested-version +1 -1
- package/extensions/triage-comments/package.json +1 -1
- package/package.json +4 -4
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
|
-
import { createRequire } from "node:module";
|
|
3
2
|
import { dirname, join } from "node:path";
|
|
4
|
-
import { pathToFileURL } from "node:url";
|
|
5
3
|
import { fileURLToPath } from "node:url";
|
|
6
4
|
import type { ReviewWindowData } from "./types.js";
|
|
7
5
|
|
|
8
|
-
const require = createRequire(import.meta.url);
|
|
9
6
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
7
|
const webDir = join(__dirname, "web");
|
|
11
8
|
|
|
@@ -17,55 +14,34 @@ function escapeInlineScriptSource(value: string): string {
|
|
|
17
14
|
return value.replace(/<\/(script)/gi, "<\\/$1");
|
|
18
15
|
}
|
|
19
16
|
|
|
20
|
-
interface ReviewUiAssets {
|
|
17
|
+
export interface ReviewUiAssets {
|
|
21
18
|
tailwindBrowserJs: string;
|
|
22
19
|
monacoLoaderJs: string;
|
|
23
20
|
monacoVsBaseUrl: string;
|
|
24
|
-
bootstrapError: string | null;
|
|
25
21
|
}
|
|
26
22
|
|
|
27
|
-
function
|
|
28
|
-
return readFileSync(require.resolve(specifier), "utf8");
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function resolveReviewUiAssets(): ReviewUiAssets {
|
|
32
|
-
try {
|
|
33
|
-
const tailwindBrowserJs = safeReadResolvedAsset("@tailwindcss/browser");
|
|
34
|
-
const monacoLoaderPath = join(dirname(require.resolve("monaco-editor/package.json")), "min", "vs", "loader.js");
|
|
35
|
-
const monacoLoaderJs = readFileSync(monacoLoaderPath, "utf8");
|
|
36
|
-
const monacoVsBaseUrl = pathToFileURL(dirname(monacoLoaderPath)).href;
|
|
37
|
-
return {
|
|
38
|
-
tailwindBrowserJs,
|
|
39
|
-
monacoLoaderJs,
|
|
40
|
-
monacoVsBaseUrl,
|
|
41
|
-
bootstrapError: null,
|
|
42
|
-
};
|
|
43
|
-
} catch (error) {
|
|
44
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
45
|
-
return {
|
|
46
|
-
tailwindBrowserJs: "",
|
|
47
|
-
monacoLoaderJs: "",
|
|
48
|
-
monacoVsBaseUrl: "",
|
|
49
|
-
bootstrapError: `Unable to load packaged review UI assets: ${message}`,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function buildReviewHtml(data: ReviewWindowData): string {
|
|
23
|
+
export function buildReviewHtml(data: ReviewWindowData, assets: ReviewUiAssets): string {
|
|
55
24
|
const templateHtml = readFileSync(join(webDir, "index.html"), "utf8");
|
|
56
25
|
const appJs = escapeInlineScriptSource(readFileSync(join(webDir, "app.js"), "utf8"));
|
|
57
|
-
const assets = resolveReviewUiAssets();
|
|
58
26
|
const payload = escapeForInlineScript(JSON.stringify(data));
|
|
59
27
|
const assetConfig = escapeForInlineScript(
|
|
60
28
|
JSON.stringify({
|
|
61
29
|
monacoVsBaseUrl: assets.monacoVsBaseUrl,
|
|
62
|
-
bootstrapError:
|
|
30
|
+
bootstrapError: null,
|
|
63
31
|
}),
|
|
64
32
|
);
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
33
|
+
const replacements = new Map([
|
|
34
|
+
['"__INLINE_DATA__"', payload],
|
|
35
|
+
["__INLINE_ASSET_CONFIG__", assetConfig],
|
|
36
|
+
["__INLINE_TAILWIND_JS__", escapeInlineScriptSource(assets.tailwindBrowserJs)],
|
|
37
|
+
["__INLINE_MONACO_LOADER_JS__", escapeInlineScriptSource(assets.monacoLoaderJs)],
|
|
38
|
+
["__INLINE_JS__", appJs],
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
// Replace the original template in one pass so marker-like repository data
|
|
42
|
+
// or runtime source is never scanned as another template placeholder.
|
|
43
|
+
return templateHtml.replace(
|
|
44
|
+
/"__INLINE_DATA__"|__INLINE_ASSET_CONFIG__|__INLINE_TAILWIND_JS__|__INLINE_MONACO_LOADER_JS__|__INLINE_JS__/g,
|
|
45
|
+
(marker) => replacements.get(marker) ?? marker,
|
|
46
|
+
);
|
|
71
47
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.84.4
|
|
@@ -21,12 +21,15 @@ function appendPrompt(ctx: ExtensionCommandContext, prompt: string): void {
|
|
|
21
21
|
|
|
22
22
|
export function registerAnnotateLastMessageCommand(pi: ExtensionAPI): void {
|
|
23
23
|
let activeWindow: QuietGlimpseWindow | null = null;
|
|
24
|
+
let annotationOpening = false;
|
|
25
|
+
let annotationAttempt = 0;
|
|
24
26
|
const suppressedWindows = new WeakSet<QuietGlimpseWindow>();
|
|
25
27
|
|
|
26
28
|
function closeActiveWindow(options: { suppressResults?: boolean } = {}): void {
|
|
27
|
-
|
|
29
|
+
annotationAttempt += 1;
|
|
28
30
|
const windowToClose = activeWindow;
|
|
29
31
|
activeWindow = null;
|
|
32
|
+
if (windowToClose == null) return;
|
|
30
33
|
if (options.suppressResults) {
|
|
31
34
|
suppressedWindows.add(windowToClose);
|
|
32
35
|
}
|
|
@@ -42,7 +45,7 @@ export function registerAnnotateLastMessageCommand(pi: ExtensionAPI): void {
|
|
|
42
45
|
ctx.ui.notify("annotate-last-message requires interactive mode.", "error");
|
|
43
46
|
return;
|
|
44
47
|
}
|
|
45
|
-
if (activeWindow != null) {
|
|
48
|
+
if (annotationOpening || activeWindow != null) {
|
|
46
49
|
ctx.ui.notify("A last-message annotation window is already open.", "warning");
|
|
47
50
|
return;
|
|
48
51
|
}
|
|
@@ -54,6 +57,8 @@ export function registerAnnotateLastMessageCommand(pi: ExtensionAPI): void {
|
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
const messageData = messageResult.data;
|
|
60
|
+
annotationOpening = true;
|
|
61
|
+
const attempt = ++annotationAttempt;
|
|
57
62
|
|
|
58
63
|
try {
|
|
59
64
|
const html = buildAnnotateLastMessageHtml(messageData);
|
|
@@ -62,13 +67,28 @@ export function registerAnnotateLastMessageCommand(pi: ExtensionAPI): void {
|
|
|
62
67
|
height: 980,
|
|
63
68
|
title: "annotate last message",
|
|
64
69
|
});
|
|
70
|
+
if (attempt !== annotationAttempt) {
|
|
71
|
+
suppressedWindows.add(window);
|
|
72
|
+
window.close();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
65
75
|
activeWindow = window;
|
|
76
|
+
if (window.failure != null) throw window.failure;
|
|
77
|
+
if (window.closed) throw new Error("Glimpse closed while the annotation window was starting.");
|
|
66
78
|
|
|
67
79
|
const terminalMessagePromise = new Promise<AnnotateLastMessageSubmitPayload | AnnotateLastMessageCancelPayload | null>(
|
|
68
80
|
(resolve, reject) => {
|
|
69
81
|
let settled = false;
|
|
70
82
|
let closeTimer: ReturnType<typeof setTimeout> | null = null;
|
|
71
83
|
|
|
84
|
+
const requestWindowClose = (): void => {
|
|
85
|
+
try {
|
|
86
|
+
window.close();
|
|
87
|
+
} catch {
|
|
88
|
+
// Ignore races when the native process has already exited.
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
72
92
|
const cleanup = (): void => {
|
|
73
93
|
if (closeTimer != null) {
|
|
74
94
|
clearTimeout(closeTimer);
|
|
@@ -91,6 +111,7 @@ export function registerAnnotateLastMessageCommand(pi: ExtensionAPI): void {
|
|
|
91
111
|
|
|
92
112
|
const onMessage = (data: unknown): void => {
|
|
93
113
|
if (isSubmitPayload(data) || isCancelPayload(data)) {
|
|
114
|
+
requestWindowClose();
|
|
94
115
|
settle(data);
|
|
95
116
|
}
|
|
96
117
|
};
|
|
@@ -106,6 +127,7 @@ export function registerAnnotateLastMessageCommand(pi: ExtensionAPI): void {
|
|
|
106
127
|
const onError = (error: Error): void => {
|
|
107
128
|
if (settled) return;
|
|
108
129
|
settled = true;
|
|
130
|
+
requestWindowClose();
|
|
109
131
|
cleanup();
|
|
110
132
|
reject(error);
|
|
111
133
|
};
|
|
@@ -113,6 +135,8 @@ export function registerAnnotateLastMessageCommand(pi: ExtensionAPI): void {
|
|
|
113
135
|
window.on("message", onMessage);
|
|
114
136
|
window.on("closed", onClosed);
|
|
115
137
|
window.on("error", onError);
|
|
138
|
+
if (window.failure != null) onError(window.failure);
|
|
139
|
+
else if (window.closed) onClosed();
|
|
116
140
|
},
|
|
117
141
|
);
|
|
118
142
|
|
|
@@ -145,6 +169,8 @@ export function registerAnnotateLastMessageCommand(pi: ExtensionAPI): void {
|
|
|
145
169
|
closeActiveWindow({ suppressResults: true });
|
|
146
170
|
const message = error instanceof Error ? error.message : String(error);
|
|
147
171
|
ctx.ui.notify(`Annotation failed: ${message}`, "error");
|
|
172
|
+
} finally {
|
|
173
|
+
annotationOpening = false;
|
|
148
174
|
}
|
|
149
175
|
}
|
|
150
176
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-annotate-last-message",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "A standalone pi extension that adds /annotate-last-message, a native Glimpse UI for annotating the latest assistant reply.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -23,6 +23,8 @@ interface GlimpseProtocolMessage {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export interface QuietGlimpseWindow {
|
|
26
|
+
readonly closed: boolean;
|
|
27
|
+
readonly failure: Error | null;
|
|
26
28
|
on(event: "message", listener: (data: unknown) => void): this;
|
|
27
29
|
on(event: "closed", listener: () => void): this;
|
|
28
30
|
on(event: "error", listener: (error: Error) => void): this;
|
|
@@ -38,11 +40,15 @@ class QuietGlimpseWindowImpl extends EventEmitter implements QuietGlimpseWindow
|
|
|
38
40
|
#closed = false;
|
|
39
41
|
#pendingHTML: string | null;
|
|
40
42
|
#stderr = "";
|
|
43
|
+
#failure: Error | null = null;
|
|
41
44
|
|
|
42
45
|
constructor(proc: ChildProcessWithoutNullStreams, initialHTML: string) {
|
|
43
46
|
super();
|
|
44
47
|
this.#proc = proc;
|
|
45
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", () => {});
|
|
46
52
|
|
|
47
53
|
proc.stdin.on("error", () => {});
|
|
48
54
|
proc.stderr.on("data", (chunk) => {
|
|
@@ -55,7 +61,7 @@ class QuietGlimpseWindowImpl extends EventEmitter implements QuietGlimpseWindow
|
|
|
55
61
|
try {
|
|
56
62
|
message = JSON.parse(line) as GlimpseProtocolMessage;
|
|
57
63
|
} catch {
|
|
58
|
-
this
|
|
64
|
+
this.#reportError(new Error(`Malformed glimpse protocol line: ${line}`));
|
|
59
65
|
return;
|
|
60
66
|
}
|
|
61
67
|
|
|
@@ -77,16 +83,18 @@ class QuietGlimpseWindowImpl extends EventEmitter implements QuietGlimpseWindow
|
|
|
77
83
|
}
|
|
78
84
|
});
|
|
79
85
|
|
|
80
|
-
proc.on("error", (error) => this
|
|
86
|
+
proc.on("error", (error) => this.#reportError(error));
|
|
81
87
|
proc.on("exit", (code, signal) => {
|
|
82
88
|
const stderr = this.#stderr.trim();
|
|
83
89
|
const failed = signal != null || (code != null && code !== 0);
|
|
84
90
|
if (!this.#closed && failed) {
|
|
85
91
|
const message = stderr || `Glimpse process exited abnormally (code: ${code}, signal: ${signal}).`;
|
|
86
|
-
this
|
|
92
|
+
this.#reportError(new Error(message));
|
|
87
93
|
}
|
|
88
94
|
this.#markClosed();
|
|
89
95
|
});
|
|
96
|
+
// Spawn failures can emit `error` and then `close` without `exit`.
|
|
97
|
+
proc.on("close", () => this.#markClosed());
|
|
90
98
|
}
|
|
91
99
|
|
|
92
100
|
send(js: string): void {
|
|
@@ -97,6 +105,19 @@ class QuietGlimpseWindowImpl extends EventEmitter implements QuietGlimpseWindow
|
|
|
97
105
|
this.#write({ type: "close" });
|
|
98
106
|
}
|
|
99
107
|
|
|
108
|
+
get closed(): boolean {
|
|
109
|
+
return this.#closed;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
get failure(): Error | null {
|
|
113
|
+
return this.#failure;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
#reportError(error: Error): void {
|
|
117
|
+
this.#failure ??= error;
|
|
118
|
+
this.emit("error", error);
|
|
119
|
+
}
|
|
120
|
+
|
|
100
121
|
#markClosed(): void {
|
|
101
122
|
if (this.#closed) return;
|
|
102
123
|
this.#closed = true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.84.4
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.84.4
|
|
@@ -24,7 +24,7 @@ Fast mode is only injected when all of these are true:
|
|
|
24
24
|
|
|
25
25
|
- The current provider is `anthropic`.
|
|
26
26
|
- The current API is `anthropic-messages`.
|
|
27
|
-
- The current model is `claude-opus-4-
|
|
27
|
+
- The current model is `claude-opus-4-8` or `claude-opus-5`.
|
|
28
28
|
- The request payload does not already include `speed`.
|
|
29
29
|
|
|
30
30
|
Claude Fast mode is available for API-key access and Claude Code subscription/OAuth access when the account has access to Anthropic's Fast mode research preview. For Claude Code subscription users, Anthropic documents this as extra usage credits, not included subscription usage.
|
|
@@ -13,7 +13,7 @@ const API_ID = "anthropic-messages";
|
|
|
13
13
|
const FAST_SPEED = "fast";
|
|
14
14
|
const FAST_BETA = "fast-mode-2026-02-01";
|
|
15
15
|
const CLAUDE_CODE_OAUTH_BETAS = ["claude-code-20250219", "oauth-2025-04-20"];
|
|
16
|
-
const SUPPORTED_MODELS = new Set(["claude-opus-4-
|
|
16
|
+
const SUPPORTED_MODELS = new Set(["claude-opus-4-8", "claude-opus-5"]);
|
|
17
17
|
|
|
18
18
|
const DEFAULT_CONFIG: ClaudeFastConfig = {
|
|
19
19
|
enabled: false,
|
|
@@ -153,7 +153,7 @@ function getEligibility(ctx: ExtensionContext): Eligibility {
|
|
|
153
153
|
return {
|
|
154
154
|
eligible: false,
|
|
155
155
|
modelKey: key,
|
|
156
|
-
reason: "Fast mode is only enabled for Claude Opus 4.
|
|
156
|
+
reason: "Fast mode is only enabled for Claude Opus 4.8 and Claude Opus 5",
|
|
157
157
|
};
|
|
158
158
|
}
|
|
159
159
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.84.4
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.84.4
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.84.4
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.84.4
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.84.4
|