@diegopetrucci/pi-brrr 0.1.4 → 0.1.7

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.
@@ -1 +1 @@
1
- 0.79.10
1
+ 0.80.6
package/README.md CHANGED
@@ -32,10 +32,10 @@ Then reload pi:
32
32
 
33
33
  Config files are merged, with project config overriding global config:
34
34
 
35
- - `~/.pi/agent/extensions/brrr.json`
36
- - `<project>/.pi/brrr.json`
35
+ - `~/<pi-config-dir>/agent/extensions/brrr.json`
36
+ - `<project>/<pi-config-dir>/brrr.json`
37
37
 
38
- Project config is only read after Pi reports that the project is trusted.
38
+ Here `<pi-config-dir>` is Pi's runtime config directory name (`CONFIG_DIR_NAME`; `.pi` by default). Project config is only read after Pi reports that the project is trusted.
39
39
 
40
40
  The default config expects your webhook in `BRRR_WEBHOOK_URL`:
41
41
 
package/index.ts CHANGED
@@ -5,18 +5,17 @@
5
5
  * for more input.
6
6
  *
7
7
  * Config files (project overrides global):
8
- * - ~/.pi/agent/extensions/brrr.json
9
- * - <cwd>/.pi/brrr.json, when the project is trusted
8
+ * - ~/<pi-config-dir>/agent/extensions/brrr.json
9
+ * - <cwd>/<pi-config-dir>/brrr.json, when the project is trusted
10
10
  */
11
11
 
12
12
  import { execFile } from "node:child_process";
13
13
  import { existsSync, readFileSync } from "node:fs";
14
14
  import { basename, join } from "node:path";
15
15
  import { promisify } from "node:util";
16
- import { getAgentDir, type ExtensionAPI, type ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
16
+ import { CONFIG_DIR_NAME, getAgentDir, type ExtensionAPI, type ExtensionCommandContext, type SessionEntry } from "@earendil-works/pi-coding-agent";
17
17
 
18
18
  const execFileAsync = promisify(execFile);
19
- const CONFIG_DIR_NAME = ".pi";
20
19
 
21
20
  interface BrrrConfig {
22
21
  enabled: boolean;
@@ -159,8 +158,9 @@ function extractTextContent(content: unknown): string {
159
158
  }
160
159
  if (typeof part !== "object" || part === null) continue;
161
160
 
162
- const maybeText = (part as { text?: unknown }).text;
163
- if (typeof maybeText === "string") parts.push(maybeText);
161
+ const typedPart = part as { type?: unknown; text?: unknown };
162
+ if (typedPart.type !== undefined && typedPart.type !== "text") continue;
163
+ if (typeof typedPart.text === "string") parts.push(typedPart.text);
164
164
  }
165
165
 
166
166
  return parts.join("\n");
@@ -173,12 +173,31 @@ function lastAssistantMessage(messages: readonly unknown[]): string | undefined
173
173
  if ((message as { role?: unknown }).role !== "assistant") continue;
174
174
 
175
175
  const text = extractTextContent((message as { content?: unknown }).content).trim();
176
- if (text) return text;
176
+ return text || undefined;
177
177
  }
178
178
 
179
179
  return undefined;
180
180
  }
181
181
 
182
+ type SessionMessageSource = {
183
+ buildContextEntries(): SessionEntry[];
184
+ };
185
+
186
+ function sessionMessages(sessionManager: SessionMessageSource | undefined): readonly unknown[] {
187
+ if (!sessionManager) return [];
188
+
189
+ return sessionManager
190
+ .buildContextEntries()
191
+ .flatMap((entry: SessionEntry) => (entry.type === "message" ? [entry.message] : []));
192
+ }
193
+
194
+ function resolveAssistantMessage(
195
+ sessionManager: SessionMessageSource | undefined,
196
+ fallbackMessages: readonly unknown[],
197
+ ): string | undefined {
198
+ return lastAssistantMessage(sessionMessages(sessionManager)) ?? lastAssistantMessage(fallbackMessages);
199
+ }
200
+
182
201
  function truncateMessage(value: string): string {
183
202
  const trimmed = value.trim();
184
203
  if (trimmed.length <= 800) return trimmed;
@@ -236,7 +255,7 @@ export default function brrrExtension(pi: ExtensionAPI) {
236
255
  },
237
256
  });
238
257
 
239
- pi.on("agent_end", async (event, ctx) => {
258
+ pi.on("agent_settled", async (event, ctx) => {
240
259
  const config = loadConfig(ctx);
241
260
  if (!config.enabled) return;
242
261
  if (config.onlyWhenInteractive && !ctx.hasUI) return;
@@ -245,7 +264,9 @@ export default function brrrExtension(pi: ExtensionAPI) {
245
264
  if (!webhook || !isBrrrWebhookUrl(webhook)) return;
246
265
  if (await shouldSkipForIdleThreshold(config.idleSeconds)) return;
247
266
 
248
- const assistantMessage = config.includeLastAssistantMessage ? lastAssistantMessage(event.messages as readonly unknown[]) : undefined;
267
+ const assistantMessage = config.includeLastAssistantMessage
268
+ ? resolveAssistantMessage(ctx.sessionManager, (event as { messages?: readonly unknown[] }).messages ?? [])
269
+ : undefined;
249
270
  const message = truncateMessage(assistantMessage || formatTemplate(config.message, ctx.cwd));
250
271
  const result = await sendBrrr(webhook, {
251
272
  title: formatTemplate(config.title, ctx.cwd),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-brrr",
3
- "version": "0.1.4",
3
+ "version": "0.1.7",
4
4
  "description": "A pi extension that sends brrr push notifications when pi is ready for input.",
5
5
  "keywords": [
6
6
  "pi-package",