@pi-unipi/notify 2.1.3 → 2.2.0
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/README.md +2 -0
- package/events.ts +11 -0
- package/package.json +2 -2
- package/settings.ts +1 -0
- package/skills/configure-notify/SKILL.md +28 -1
- package/tui/gotify-setup.ts +2 -1
- package/tui/ntfy-setup.ts +2 -1
- package/tui/recap-model-selector.ts +2 -2
- package/tui/settings-overlay.ts +2 -1
- package/tui/telegram-setup.ts +2 -1
package/README.md
CHANGED
|
@@ -28,6 +28,8 @@ Notify subscribes to Pi lifecycle events and routes notifications based on your
|
|
|
28
28
|
| `agent_settled` | Off | Agent fully settles after retries, compaction, and queued continuations |
|
|
29
29
|
| `memory_consolidated` | Off | Memory auto-saved |
|
|
30
30
|
| `session_shutdown` | Off | Session ends |
|
|
31
|
+
| `ask_user_prompt` | Off | Agent asked a question and is waiting for an answer |
|
|
32
|
+
| `permission_request` | Off | A permission prompt is about to be shown (requires [`@gotgenes/pi-permission-system`](https://www.npmjs.com/package/@gotgenes/pi-permission-system)) |
|
|
31
33
|
|
|
32
34
|
Notify registers with the info-screen dashboard, showing enabled platforms and last notification time. The footer subscribes to `NOTIFICATION_SENT` events to display notification stats.
|
|
33
35
|
|
package/events.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { sendGotifyNotification } from "./platforms/gotify.js";
|
|
|
14
14
|
import { sendTelegramNotification } from "./platforms/telegram.js";
|
|
15
15
|
import { sendNtfyNotification } from "./platforms/ntfy.js";
|
|
16
16
|
import { buildAskUserPromptMessage } from "./ask-user-prompt-message.js";
|
|
17
|
+
import { buildPermissionPromptMessage } from "./permission-prompt-message.js";
|
|
17
18
|
import { summarizeLastMessage } from "./summarize.js";
|
|
18
19
|
|
|
19
20
|
// Event emitted by @juicesharp/rpiv-ask-user-question before showing its UI.
|
|
@@ -21,6 +22,13 @@ import { summarizeLastMessage } from "./summarize.js";
|
|
|
21
22
|
// `./events` contract in npm.
|
|
22
23
|
const ASK_USER_PROMPT_EVENT = "rpiv:ask-user:prompt" as const;
|
|
23
24
|
|
|
25
|
+
// Event emitted by @gotgenes/pi-permission-system immediately before the
|
|
26
|
+
// user-facing permission UI is invoked. Fires only for prompts a human must
|
|
27
|
+
// answer — policy auto-allow/deny and session approvals do not emit it.
|
|
28
|
+
// Kept as a local string (like the rpiv event above) because it belongs to a
|
|
29
|
+
// third-party package rather than the unipi event contract.
|
|
30
|
+
const PERMISSION_UI_PROMPT_EVENT = "permissions:ui_prompt" as const;
|
|
31
|
+
|
|
24
32
|
/** Stored session context for modelRegistry access */
|
|
25
33
|
let sessionCtx: ExtensionContext | null = null;
|
|
26
34
|
|
|
@@ -58,6 +66,7 @@ export const BUILTIN_EVENTS: Record<
|
|
|
58
66
|
memory_consolidated: { hook: UNIPI_EVENTS.MEMORY_CONSOLIDATED, label: "Memory Saved" },
|
|
59
67
|
session_shutdown: { hook: "session_shutdown", label: "Session End" },
|
|
60
68
|
ask_user_prompt: { hook: UNIPI_EVENTS.ASK_USER_PROMPT, label: "Question Asked" },
|
|
69
|
+
permission_request: { hook: PERMISSION_UI_PROMPT_EVENT, label: "Permission Request" },
|
|
61
70
|
};
|
|
62
71
|
|
|
63
72
|
/**
|
|
@@ -298,6 +307,8 @@ function buildEventMessage(eventKey: string, payload: unknown): string {
|
|
|
298
307
|
return "Session ending";
|
|
299
308
|
case "ask_user_prompt":
|
|
300
309
|
return buildAskUserPromptMessage(payload);
|
|
310
|
+
case "permission_request":
|
|
311
|
+
return buildPermissionPromptMessage(payload);
|
|
301
312
|
default:
|
|
302
313
|
return p.message ? String(p.message) : "Event occurred";
|
|
303
314
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/notify",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Cross-platform notification extension for Pi — native OS, Gotify, and Telegram notifications for agent lifecycle events",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"access": "public"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@pi-unipi/core": "
|
|
45
|
+
"@pi-unipi/core": "2.2.0",
|
|
46
46
|
"node-notifier": "^10.0.1"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
package/settings.ts
CHANGED
|
@@ -28,6 +28,7 @@ export const DEFAULT_CONFIG: NotifyConfig = {
|
|
|
28
28
|
memory_consolidated: { enabled: false, platforms: [] },
|
|
29
29
|
session_shutdown: { enabled: false, platforms: [] },
|
|
30
30
|
ask_user_prompt: { enabled: false, platforms: [] },
|
|
31
|
+
permission_request: { enabled: false, platforms: [] },
|
|
31
32
|
},
|
|
32
33
|
native: {
|
|
33
34
|
enabled: true,
|
|
@@ -36,7 +36,9 @@ Help users configure the `@pi-unipi/notify` notification system.
|
|
|
36
36
|
"agent_end": { "enabled": false, "platforms": [] },
|
|
37
37
|
"agent_settled": { "enabled": false, "platforms": [] },
|
|
38
38
|
"memory_consolidated": { "enabled": false, "platforms": [] },
|
|
39
|
-
"session_shutdown": { "enabled": false, "platforms": [] }
|
|
39
|
+
"session_shutdown": { "enabled": false, "platforms": [] },
|
|
40
|
+
"ask_user_prompt": { "enabled": false, "platforms": [] },
|
|
41
|
+
"permission_request": { "enabled": false, "platforms": [] }
|
|
40
42
|
},
|
|
41
43
|
"native": {
|
|
42
44
|
"enabled": true,
|
|
@@ -155,9 +157,34 @@ ntfy uses dedicated `ntfy.json` files at both global and project scope, with ful
|
|
|
155
157
|
| `agent_settled` | Off | Agent fully settles after retries, compaction, and queued continuations |
|
|
156
158
|
| `memory_consolidated` | Off | Memory auto-saved |
|
|
157
159
|
| `session_shutdown` | Off | Session ends |
|
|
160
|
+
| `ask_user_prompt` | Off | Agent asked a question and is waiting for an answer |
|
|
161
|
+
| `permission_request` | Off | A permission prompt is about to be shown |
|
|
158
162
|
|
|
159
163
|
Each event can override `platforms` — empty array means use `defaultPlatforms`.
|
|
160
164
|
|
|
165
|
+
### `permission_request`
|
|
166
|
+
|
|
167
|
+
Fires on the `permissions:ui_prompt` broadcast from
|
|
168
|
+
[`@gotgenes/pi-permission-system`](https://www.npmjs.com/package/@gotgenes/pi-permission-system),
|
|
169
|
+
emitted immediately before the user-facing permission UI is invoked. Policy
|
|
170
|
+
auto-allow, policy deny, session approvals, and infrastructure auto-allowed
|
|
171
|
+
requests do **not** emit it, so this event does not produce notification spam.
|
|
172
|
+
Forwarded subagent prompts are handled too — the parent UI session emits the
|
|
173
|
+
event right before showing the forwarded dialog, and the notification is
|
|
174
|
+
suffixed with `(forwarded)`.
|
|
175
|
+
|
|
176
|
+
The notification is formatted defensively from the payload's `agentName`,
|
|
177
|
+
`surface`, `value` and `message` fields:
|
|
178
|
+
|
|
179
|
+
```text
|
|
180
|
+
Pi — Permission Request
|
|
181
|
+
Current agent requested bash 'npm test'. Allow this command?
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Enable it when you run Pi in a background pane and don't want to miss a
|
|
185
|
+
permission prompt. If the permission system is not installed the event simply
|
|
186
|
+
never fires.
|
|
187
|
+
|
|
161
188
|
## Agent workflow
|
|
162
189
|
|
|
163
190
|
### Reading current config
|
package/tui/gotify-setup.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
|
11
11
|
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
12
12
|
import { sendGotifyNotification } from "../platforms/gotify.js";
|
|
13
13
|
import { updateConfig, loadConfig } from "../settings.js";
|
|
14
|
+
import { boxInnerWidth } from "@pi-unipi/core";
|
|
14
15
|
|
|
15
16
|
type SetupPhase =
|
|
16
17
|
| "instructions"
|
|
@@ -235,7 +236,7 @@ export class GotifySetupOverlay implements Component {
|
|
|
235
236
|
}
|
|
236
237
|
|
|
237
238
|
render(width: number): string[] {
|
|
238
|
-
const innerWidth =
|
|
239
|
+
const innerWidth = boxInnerWidth(width);
|
|
239
240
|
const lines: string[] = [];
|
|
240
241
|
|
|
241
242
|
lines.push(this.borderLine(innerWidth, "top"));
|
package/tui/ntfy-setup.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
|
11
11
|
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
12
12
|
import { sendNtfyNotification } from "../platforms/ntfy.js";
|
|
13
13
|
import { loadNtfyConfig, saveNtfyConfig, getNtfyConfigScope } from "../ntfy-config.js";
|
|
14
|
+
import { boxInnerWidth } from "@pi-unipi/core";
|
|
14
15
|
|
|
15
16
|
type SetupPhase =
|
|
16
17
|
| "instructions"
|
|
@@ -281,7 +282,7 @@ export class NtfySetupOverlay implements Component {
|
|
|
281
282
|
}
|
|
282
283
|
|
|
283
284
|
render(width: number): string[] {
|
|
284
|
-
const innerWidth =
|
|
285
|
+
const innerWidth = boxInnerWidth(width);
|
|
285
286
|
const lines: string[] = [];
|
|
286
287
|
|
|
287
288
|
lines.push(this.borderLine(innerWidth, "top"));
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import type { Component } from "@earendil-works/pi-tui";
|
|
9
9
|
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
10
10
|
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
11
|
-
import { readModelCache, type CachedModel } from "@pi-unipi/core";
|
|
11
|
+
import { readModelCache, type CachedModel, boxInnerWidth } from "@pi-unipi/core";
|
|
12
12
|
import { loadConfig, saveConfig } from "../settings.js";
|
|
13
13
|
|
|
14
14
|
const DEFAULT_MODEL = "openrouter/openai/gpt-oss-20b";
|
|
@@ -170,7 +170,7 @@ export class RecapModelSelectorOverlay implements Component {
|
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
render(width: number): string[] {
|
|
173
|
-
const innerWidth =
|
|
173
|
+
const innerWidth = boxInnerWidth(width);
|
|
174
174
|
const lines: string[] = [];
|
|
175
175
|
|
|
176
176
|
lines.push(this.borderLine(innerWidth, "top"));
|
package/tui/settings-overlay.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
} from "../settings.js";
|
|
16
16
|
import { loadNtfyConfig, saveNtfyConfig, getNtfyConfigScope } from "../ntfy-config.js";
|
|
17
17
|
import type { NotifyConfig, NtfyConfig } from "../types.js";
|
|
18
|
+
import { boxInnerWidth } from "@pi-unipi/core";
|
|
18
19
|
|
|
19
20
|
/** Section types */
|
|
20
21
|
type Section = "platforms" | "events" | "recap";
|
|
@@ -174,7 +175,7 @@ export class NotifySettingsOverlay implements Component {
|
|
|
174
175
|
}
|
|
175
176
|
|
|
176
177
|
render(width: number): string[] {
|
|
177
|
-
const innerWidth =
|
|
178
|
+
const innerWidth = boxInnerWidth(width);
|
|
178
179
|
const lines: string[] = [];
|
|
179
180
|
|
|
180
181
|
lines.push(this.borderLine(innerWidth, "top"));
|
package/tui/telegram-setup.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
|
10
10
|
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
11
11
|
import { pollForChatId } from "../platforms/telegram.js";
|
|
12
12
|
import { updateConfig } from "../settings.js";
|
|
13
|
+
import { boxInnerWidth } from "@pi-unipi/core";
|
|
13
14
|
|
|
14
15
|
type SetupPhase = "instructions" | "token" | "polling" | "success" | "error" | "timeout";
|
|
15
16
|
|
|
@@ -224,7 +225,7 @@ export class TelegramSetupOverlay implements Component {
|
|
|
224
225
|
}
|
|
225
226
|
|
|
226
227
|
render(width: number): string[] {
|
|
227
|
-
const innerWidth =
|
|
228
|
+
const innerWidth = boxInnerWidth(width);
|
|
228
229
|
const lines: string[] = [];
|
|
229
230
|
|
|
230
231
|
lines.push(this.borderLine(innerWidth, "top"));
|