@diegopetrucci/pi-extensions 0.1.74 → 0.1.78
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 +17 -12
- package/extensions/agent-workflow-audit/README.md +1 -1
- package/extensions/agent-workflow-audit/index.ts +1631 -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 +846 -768
- 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/index.html +3 -3
- 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 +6 -6
- package/extensions/code-reviewer/index.ts +1825 -1373
- package/extensions/code-reviewer/package.json +1 -1
- package/extensions/confirm-destructive/README.md +1 -1
- package/extensions/confirm-destructive/index.ts +50 -52
- package/extensions/confirm-destructive/package.json +1 -1
- package/extensions/context-cap/README.md +9 -9
- package/extensions/context-cap/index.ts +313 -305
- package/extensions/context-cap/package.json +2 -2
- package/extensions/context-inspector/index.ts +1211 -1064
- package/extensions/context-inspector/package.json +1 -1
- package/extensions/contrarian/README.md +4 -3
- package/extensions/contrarian/index.ts +1863 -1737
- package/extensions/contrarian/package.json +1 -1
- package/extensions/dirty-repo-guard/index.ts +37 -41
- package/extensions/dirty-repo-guard/package.json +1 -1
- package/extensions/dynamic-context-pruning/README.md +11 -43
- package/extensions/dynamic-context-pruning/index.ts +2131 -2105
- package/extensions/dynamic-context-pruning/package.json +1 -1
- package/extensions/fast/README.md +52 -14
- 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 +87 -103
- package/extensions/inline-bash/package.json +1 -1
- package/extensions/librarian/README.md +1 -1
- package/extensions/librarian/index.ts +1877 -1419
- package/extensions/librarian/package.json +1 -1
- package/extensions/minimal-footer/README.md +5 -5
- package/extensions/minimal-footer/index.ts +987 -1012
- package/extensions/minimal-footer/minimal-footer.example.json +1 -1
- package/extensions/minimal-footer/openai-usage.ts +195 -190
- package/extensions/minimal-footer/package.json +1 -1
- 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/README.md +4 -3
- package/extensions/oracle/index.ts +1740 -1627
- package/extensions/oracle/package.json +1 -1
- package/extensions/permission-gate/README.md +3 -0
- package/extensions/permission-gate/index.ts +785 -612
- 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/.pi-fleet-tested-version +1 -1
- package/extensions/quiet-tools/README.md +30 -19
- package/extensions/quiet-tools/index.ts +376 -291
- package/extensions/quiet-tools/package.json +2 -2
- 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 +280 -280
- package/extensions/todo/package.json +1 -1
- package/extensions/triage-comments/README.md +6 -4
- package/extensions/triage-comments/index.ts +2620 -1888
- package/extensions/triage-comments/package.json +1 -1
- package/package.json +9 -6
- 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
|
@@ -25,308 +25,300 @@ type DesktopBackend = "auto" | "macos" | "linux" | "windows-toast" | "none";
|
|
|
25
25
|
type SoundBackend = "auto" | "macos" | "linux" | "windows-beep" | "command" | "none";
|
|
26
26
|
|
|
27
27
|
type ProjectConfigContext = {
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
cwd: string;
|
|
29
|
+
isProjectTrusted?: () => boolean;
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
interface NotifyConfig {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
33
|
+
enabled: boolean;
|
|
34
|
+
onlyWhenInteractive: boolean;
|
|
35
|
+
title: string;
|
|
36
|
+
body: string;
|
|
37
|
+
channels: {
|
|
38
|
+
terminal: boolean;
|
|
39
|
+
desktop: boolean;
|
|
40
|
+
bell: boolean;
|
|
41
|
+
sound: boolean;
|
|
42
|
+
};
|
|
43
|
+
terminal: {
|
|
44
|
+
backend: TerminalBackend;
|
|
45
|
+
tmuxPassthrough: TmuxPassthrough;
|
|
46
|
+
};
|
|
47
|
+
desktop: {
|
|
48
|
+
backend: DesktopBackend;
|
|
49
|
+
};
|
|
50
|
+
sound: {
|
|
51
|
+
backend: SoundBackend;
|
|
52
|
+
name: string;
|
|
53
|
+
linuxSoundId: string;
|
|
54
|
+
frequencyHz: number;
|
|
55
|
+
durationMs: number;
|
|
56
|
+
command: string;
|
|
57
|
+
};
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
const DEFAULT_CONFIG: NotifyConfig = {
|
|
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
|
-
|
|
61
|
+
enabled: true,
|
|
62
|
+
onlyWhenInteractive: true,
|
|
63
|
+
title: "Pi",
|
|
64
|
+
body: "Ready for input",
|
|
65
|
+
channels: {
|
|
66
|
+
terminal: true,
|
|
67
|
+
desktop: true,
|
|
68
|
+
bell: true,
|
|
69
|
+
sound: false,
|
|
70
|
+
},
|
|
71
|
+
terminal: {
|
|
72
|
+
backend: "auto",
|
|
73
|
+
tmuxPassthrough: "auto",
|
|
74
|
+
},
|
|
75
|
+
desktop: {
|
|
76
|
+
backend: "auto",
|
|
77
|
+
},
|
|
78
|
+
sound: {
|
|
79
|
+
backend: "auto",
|
|
80
|
+
name: "Glass",
|
|
81
|
+
linuxSoundId: "complete",
|
|
82
|
+
frequencyHz: 1000,
|
|
83
|
+
durationMs: 250,
|
|
84
|
+
command: "",
|
|
85
|
+
},
|
|
86
86
|
};
|
|
87
87
|
|
|
88
88
|
function readConfigFile(path: string): Partial<NotifyConfig> {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
89
|
+
if (!existsSync(path)) return {};
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
return JSON.parse(readFileSync(path, "utf-8")) as Partial<NotifyConfig>;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error(`Warning: Could not parse ${path}: ${error}`);
|
|
95
|
+
return {};
|
|
96
|
+
}
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
function mergeConfig(base: NotifyConfig, overrides: Partial<NotifyConfig>): NotifyConfig {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
100
|
+
return {
|
|
101
|
+
...base,
|
|
102
|
+
...overrides,
|
|
103
|
+
channels: {
|
|
104
|
+
...base.channels,
|
|
105
|
+
...overrides.channels,
|
|
106
|
+
},
|
|
107
|
+
terminal: {
|
|
108
|
+
...base.terminal,
|
|
109
|
+
...overrides.terminal,
|
|
110
|
+
},
|
|
111
|
+
desktop: {
|
|
112
|
+
...base.desktop,
|
|
113
|
+
...overrides.desktop,
|
|
114
|
+
},
|
|
115
|
+
sound: {
|
|
116
|
+
...base.sound,
|
|
117
|
+
...overrides.sound,
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
function canReadProjectConfig(ctx: ProjectConfigContext): boolean {
|
|
123
|
-
|
|
123
|
+
return typeof ctx.isProjectTrusted === "function" && ctx.isProjectTrusted();
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
function loadConfig(ctx: ProjectConfigContext): NotifyConfig {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
127
|
+
const globalConfig = readConfigFile(join(getAgentDir(), "extensions", "notify.json"));
|
|
128
|
+
const projectConfig = canReadProjectConfig(ctx)
|
|
129
|
+
? readConfigFile(join(ctx.cwd, CONFIG_DIR_NAME, "notify.json"))
|
|
130
|
+
: {};
|
|
131
|
+
return mergeConfig(mergeConfig(DEFAULT_CONFIG, globalConfig), projectConfig);
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
function powershellString(value: string): string {
|
|
135
|
-
|
|
135
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
function windowsToastScript(title: string, body: string): string {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
139
|
+
const type = "Windows.UI.Notifications";
|
|
140
|
+
const mgr = `[${type}.ToastNotificationManager, ${type}, ContentType = WindowsRuntime]`;
|
|
141
|
+
const template = `[${type}.ToastTemplateType]::ToastText01`;
|
|
142
|
+
const toast = `[${type}.ToastNotification]::new($xml)`;
|
|
143
|
+
return [
|
|
144
|
+
`${mgr} > $null`,
|
|
145
|
+
`$xml = [${type}.ToastNotificationManager]::GetTemplateContent(${template})`,
|
|
146
|
+
`$xml.GetElementsByTagName('text')[0].AppendChild($xml.CreateTextNode(${powershellString(body)})) > $null`,
|
|
147
|
+
`[${type}.ToastNotificationManager]::CreateToastNotifier(${powershellString(title)}).Show(${toast})`,
|
|
148
|
+
].join("; ");
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
/**
|
|
152
|
-
* Inside tmux, terminal notifications are written to tmux, not to the terminal
|
|
153
|
-
* that can act on them: tmux is the pane's emulator and parses the sequence
|
|
154
|
-
* itself. tmux has no OSC 777 or OSC 99 handler (checked in 3.7b, whose OSC
|
|
155
|
-
* dispatch covers 4/7/8/9;4/10/11/12/52/104/133) and does not forward OSC codes
|
|
156
|
-
* it does not recognise, so both backends are silently dropped.
|
|
157
|
-
*
|
|
158
|
-
* tmux's DCS passthrough asks it to write a payload to the outer terminal
|
|
159
|
-
* verbatim. Every ESC inside the payload must be doubled.
|
|
160
|
-
*
|
|
161
|
-
* Users must also allow passthrough in tmux.conf:
|
|
162
|
-
*
|
|
163
|
-
* set -g allow-passthrough all
|
|
164
|
-
*
|
|
165
|
-
* `all` rather than `on`, because `on` only honours passthrough from panes that
|
|
166
|
-
* are currently visible - which drops exactly the notification that matters,
|
|
167
|
-
* the one fired while the user is looking at a different window. When
|
|
168
|
-
* passthrough is disabled entirely, the wrapped sequence is dropped just like
|
|
169
|
-
* the bare one, so wrapping is never a regression.
|
|
170
|
-
*/
|
|
151
|
+
/** tmux drops unrecognized OSC, so wrap in DCS passthrough with doubled ESC. */
|
|
171
152
|
function wrapForTmux(sequence: string): string {
|
|
172
|
-
|
|
153
|
+
return `\x1bPtmux;${sequence.replaceAll("\x1b", "\x1b\x1b")}\x1b\\`;
|
|
173
154
|
}
|
|
174
155
|
|
|
175
156
|
function shouldWrapForTmux(config: NotifyConfig): boolean {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
157
|
+
if (config.terminal.tmuxPassthrough === "never") return false;
|
|
158
|
+
if (config.terminal.tmuxPassthrough === "always") return true;
|
|
159
|
+
return Boolean(process.env.TMUX);
|
|
179
160
|
}
|
|
180
161
|
|
|
181
162
|
function writeTerminalSequence(sequence: string, wrap: boolean): void {
|
|
182
|
-
|
|
163
|
+
process.stdout.write(wrap ? wrapForTmux(sequence) : sequence);
|
|
183
164
|
}
|
|
184
165
|
|
|
185
166
|
function notifyOSC777(title: string, body: string, wrap: boolean): void {
|
|
186
|
-
|
|
167
|
+
writeTerminalSequence(`\x1b]777;notify;${title};${body}\x07`, wrap);
|
|
187
168
|
}
|
|
188
169
|
|
|
189
170
|
function notifyOSC99(title: string, body: string, wrap: boolean): void {
|
|
190
|
-
|
|
191
|
-
|
|
171
|
+
writeTerminalSequence(`\x1b]99;i=1:d=0;${title}\x1b\\`, wrap);
|
|
172
|
+
writeTerminalSequence(`\x1b]99;i=1:p=body;${body}\x1b\\`, wrap);
|
|
192
173
|
}
|
|
193
174
|
|
|
194
175
|
function ringBell(): void {
|
|
195
|
-
|
|
176
|
+
process.stdout.write("\x07");
|
|
196
177
|
}
|
|
197
178
|
|
|
198
179
|
function runCommand(command: string, args: string[]): Promise<boolean> {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
180
|
+
return new Promise((resolve) => {
|
|
181
|
+
execFile(command, args, (error) => resolve(!error));
|
|
182
|
+
});
|
|
202
183
|
}
|
|
203
184
|
|
|
204
185
|
function runShellCommand(command: string): Promise<boolean> {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
186
|
+
if (process.platform === "win32") {
|
|
187
|
+
return runCommand("cmd.exe", ["/d", "/s", "/c", command]);
|
|
188
|
+
}
|
|
208
189
|
|
|
209
|
-
|
|
190
|
+
return runCommand(process.env.SHELL || "/bin/sh", ["-lc", command]);
|
|
210
191
|
}
|
|
211
192
|
|
|
212
193
|
function detectTerminalBackend(config: NotifyConfig): Exclude<TerminalBackend, "auto"> {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
194
|
+
if (config.terminal.backend !== "auto") return config.terminal.backend;
|
|
195
|
+
if (process.env.KITTY_WINDOW_ID) return "osc99";
|
|
196
|
+
return "osc777";
|
|
216
197
|
}
|
|
217
198
|
|
|
218
199
|
function detectDesktopBackend(config: NotifyConfig): Exclude<DesktopBackend, "auto"> {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
200
|
+
if (config.desktop.backend !== "auto") return config.desktop.backend;
|
|
201
|
+
if (process.env.WT_SESSION || process.env.WSL_DISTRO_NAME) return "windows-toast";
|
|
202
|
+
if (process.platform === "darwin") return "macos";
|
|
203
|
+
if (process.platform === "linux") return "linux";
|
|
204
|
+
if (process.platform === "win32") return "windows-toast";
|
|
205
|
+
return "none";
|
|
225
206
|
}
|
|
226
207
|
|
|
227
208
|
function detectSoundBackend(config: NotifyConfig): Exclude<SoundBackend, "auto"> {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
209
|
+
if (config.sound.backend !== "auto") return config.sound.backend;
|
|
210
|
+
if (process.env.WT_SESSION || process.platform === "win32" || process.env.WSL_DISTRO_NAME)
|
|
211
|
+
return "windows-beep";
|
|
212
|
+
if (process.platform === "darwin") return "macos";
|
|
213
|
+
if (process.platform === "linux") return "linux";
|
|
214
|
+
return "none";
|
|
233
215
|
}
|
|
234
216
|
|
|
235
217
|
function sendTerminalNotification(
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
218
|
+
title: string,
|
|
219
|
+
body: string,
|
|
220
|
+
backend: Exclude<TerminalBackend, "auto">,
|
|
221
|
+
wrap: boolean,
|
|
240
222
|
): void {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
223
|
+
if (backend === "osc99") {
|
|
224
|
+
notifyOSC99(title, body, wrap);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
if (backend === "osc777") {
|
|
228
|
+
notifyOSC777(title, body, wrap);
|
|
229
|
+
}
|
|
248
230
|
}
|
|
249
231
|
|
|
250
232
|
function appleScriptString(value: string): string {
|
|
251
|
-
|
|
233
|
+
return JSON.stringify(value);
|
|
252
234
|
}
|
|
253
235
|
|
|
254
236
|
function sendDesktopNotification(
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
237
|
+
title: string,
|
|
238
|
+
body: string,
|
|
239
|
+
backend: Exclude<DesktopBackend, "auto">,
|
|
258
240
|
): Promise<boolean> {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
241
|
+
if (backend === "windows-toast") {
|
|
242
|
+
return runCommand("powershell.exe", [
|
|
243
|
+
"-NoProfile",
|
|
244
|
+
"-Command",
|
|
245
|
+
windowsToastScript(title, body),
|
|
246
|
+
]);
|
|
247
|
+
}
|
|
248
|
+
if (backend === "macos") {
|
|
249
|
+
return runCommand("osascript", [
|
|
250
|
+
"-e",
|
|
251
|
+
`display notification ${appleScriptString(body)} with title ${appleScriptString(title)}`,
|
|
252
|
+
]);
|
|
253
|
+
}
|
|
254
|
+
if (backend === "linux") {
|
|
255
|
+
return runCommand("notify-send", [title, body]);
|
|
256
|
+
}
|
|
257
|
+
return Promise.resolve(false);
|
|
269
258
|
}
|
|
270
259
|
|
|
271
|
-
async function playSound(
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
260
|
+
async function playSound(
|
|
261
|
+
config: NotifyConfig,
|
|
262
|
+
backend: Exclude<SoundBackend, "auto">,
|
|
263
|
+
): Promise<boolean> {
|
|
264
|
+
if (backend === "command") {
|
|
265
|
+
if (!config.sound.command.trim()) return false;
|
|
266
|
+
return runShellCommand(config.sound.command);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (backend === "windows-beep") {
|
|
270
|
+
return runCommand("powershell.exe", [
|
|
271
|
+
"-NoProfile",
|
|
272
|
+
"-Command",
|
|
273
|
+
`[console]::beep(${config.sound.frequencyHz}, ${config.sound.durationMs})`,
|
|
274
|
+
]);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (backend === "macos") {
|
|
278
|
+
return runCommand("afplay", [`/System/Library/Sounds/${config.sound.name}.aiff`]);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (backend === "linux") {
|
|
282
|
+
const soundId = config.sound.linuxSoundId;
|
|
283
|
+
const viaCanberra = await runCommand("canberra-gtk-play", ["-i", soundId]);
|
|
284
|
+
if (viaCanberra) return true;
|
|
285
|
+
return runCommand("paplay", [`/usr/share/sounds/freedesktop/stereo/${soundId}.oga`]);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return false;
|
|
297
289
|
}
|
|
298
290
|
|
|
299
291
|
export default function notifyExtension(pi: ExtensionAPI) {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
292
|
+
pi.on("agent_settled", async (_event, ctx) => {
|
|
293
|
+
const config = loadConfig(ctx);
|
|
294
|
+
if (!config.enabled) return;
|
|
295
|
+
if (config.onlyWhenInteractive && !ctx.hasUI) return;
|
|
296
|
+
|
|
297
|
+
const tasks: Array<Promise<unknown>> = [];
|
|
298
|
+
|
|
299
|
+
if (config.channels.terminal) {
|
|
300
|
+
sendTerminalNotification(
|
|
301
|
+
config.title,
|
|
302
|
+
config.body,
|
|
303
|
+
detectTerminalBackend(config),
|
|
304
|
+
shouldWrapForTmux(config),
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (config.channels.desktop) {
|
|
309
|
+
tasks.push(sendDesktopNotification(config.title, config.body, detectDesktopBackend(config)));
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (config.channels.bell) {
|
|
313
|
+
ringBell();
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (config.channels.sound) {
|
|
317
|
+
tasks.push(playSound(config, detectSoundBackend(config)));
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (tasks.length > 0) {
|
|
321
|
+
await Promise.allSettled(tasks);
|
|
322
|
+
}
|
|
323
|
+
});
|
|
332
324
|
}
|
|
@@ -1,83 +1,21 @@
|
|
|
1
1
|
# openai-fast
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Deprecated standalone leftover. This package no longer enables Codex Fast mode, registers `/fast`, or reads `openai-fast.json`. On startup it clears a leftover `openai-fast` footer status and removes `fast-mode-2026-02-01` from the current model header. It does not inject Fast fields into requests.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Fast mode lives in the unified [`fast`](../fast) extension. Install `@diegopetrucci/pi-fast`, or install the collection, which loads `extensions/fast` only.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
```json
|
|
10
|
-
{
|
|
11
|
-
"service_tier": "priority"
|
|
12
|
-
}
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
The user-facing feature is OpenAI Codex **Fast mode**. The wire value is `priority` because current Codex clients map Fast mode to the OpenAI priority service tier.
|
|
16
|
-
|
|
17
|
-
## Eligibility
|
|
18
|
-
|
|
19
|
-
Fast mode is only injected when all of these are true:
|
|
20
|
-
|
|
21
|
-
- The current provider is `openai-codex`.
|
|
22
|
-
- The current API is `openai-codex-responses`.
|
|
23
|
-
- The current model is `gpt-5.5`, `gpt-5.6-sol`, `gpt-5.6-terra`, or `gpt-5.6-luna`.
|
|
24
|
-
- The provider is using ChatGPT OAuth/subscription auth, not API-key auth.
|
|
25
|
-
- The request payload does not already include `service_tier`.
|
|
26
|
-
|
|
27
|
-
## Commands
|
|
28
|
-
|
|
29
|
-
```text
|
|
30
|
-
/fast
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Run `/fast` to toggle Fast mode on or off for the current session/runtime. The command reports the new state in chat, and the footer shows `fast` while Fast mode is active for an eligible model.
|
|
34
|
-
|
|
35
|
-
The extension defaults to off so installing the full collection does not accidentally spend Fast-mode credits.
|
|
36
|
-
|
|
37
|
-
## Config
|
|
38
|
-
|
|
39
|
-
Optional global config:
|
|
40
|
-
|
|
41
|
-
```text
|
|
42
|
-
~/<pi-config-dir>/agent/extensions/openai-fast.json
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
Optional project config:
|
|
46
|
-
|
|
47
|
-
```text
|
|
48
|
-
<project>/<pi-config-dir>/openai-fast.json
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
Here `<pi-config-dir>` is Pi's runtime config directory name (`CONFIG_DIR_NAME`; `.pi` by default). Project config overrides global config after Pi reports that the project is trusted.
|
|
52
|
-
|
|
53
|
-
```json
|
|
54
|
-
{
|
|
55
|
-
"enabled": false,
|
|
56
|
-
"showStatus": true
|
|
57
|
-
}
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
- `enabled`: default Fast-mode state when there is no session override.
|
|
61
|
-
- `showStatus`: show a compact `fast` status when Fast mode is active for the current model.
|
|
7
|
+
This package is standalone-only and is not auto-loaded by the `@diegopetrucci/pi-extensions` collection package.
|
|
62
8
|
|
|
63
9
|
## Install
|
|
64
10
|
|
|
65
|
-
### Standalone npm package
|
|
66
|
-
|
|
67
11
|
```bash
|
|
68
12
|
pi install npm:@diegopetrucci/pi-openai-fast
|
|
69
13
|
```
|
|
70
14
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
pi install npm:@diegopetrucci/pi-extensions
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### GitHub package
|
|
15
|
+
Installing this package does not enable Fast mode. For the working extension:
|
|
78
16
|
|
|
79
17
|
```bash
|
|
80
|
-
pi install
|
|
18
|
+
pi install npm:@diegopetrucci/pi-fast
|
|
81
19
|
```
|
|
82
20
|
|
|
83
21
|
Then reload pi:
|
|
@@ -85,9 +23,3 @@ Then reload pi:
|
|
|
85
23
|
```text
|
|
86
24
|
/reload
|
|
87
25
|
```
|
|
88
|
-
|
|
89
|
-
## Notes
|
|
90
|
-
|
|
91
|
-
- This extension intentionally does not affect API-key OpenAI models.
|
|
92
|
-
- Pi may only account Fast-mode cost correctly when the backend reports `service_tier: "priority"` in the streamed response. The extension does not patch usage totals to avoid double-counting.
|
|
93
|
-
- If pi adds first-class service-tier support later, this extension skips payloads that already contain `service_tier`.
|