@pi-archimedes/notify 2.2.0 → 2.4.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 -1
- package/package.json +4 -2
- package/src/default-export.test.ts +25 -0
- package/src/index.ts +26 -21
package/README.md
CHANGED
|
@@ -33,11 +33,12 @@ When the agent finishes a task (`agent_end`) or a question is asked (`ASK_REQUES
|
|
|
33
33
|
|
|
34
34
|
| Setting | Type | Default | Description |
|
|
35
35
|
|---------|------|---------|-------------|
|
|
36
|
-
| `enabled` | bool | `true` | Enable desktop notifications |
|
|
37
36
|
| `notifyOnAgentEnd` | bool | `true` | Notify when agent finishes a task |
|
|
38
37
|
| `notifyOnQuestion` | bool | `true` | Notify when a question needs your answer |
|
|
39
38
|
| `delayMs` | number | `30000` | Milliseconds to wait before sending notification (default 30 seconds) |
|
|
40
39
|
|
|
40
|
+
On/off is managed by the suite: toggle via `/plugins` (`archimedes.notify.enabled`, default on).
|
|
41
|
+
|
|
41
42
|
Settings are stored in `~/.pi/agent/settings.json` under the `archimedes.notify` namespace.
|
|
42
43
|
|
|
43
44
|
## Terminal compatibility
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-archimedes/notify",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package"
|
|
@@ -14,13 +14,15 @@
|
|
|
14
14
|
".": "./src/index.ts"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@pi-archimedes/core": "2.
|
|
17
|
+
"@pi-archimedes/core": "2.4.0"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
20
|
"@earendil-works/pi-coding-agent": ">=0.1.0",
|
|
21
21
|
"@earendil-works/pi-tui": ">=0.1.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
+
"@earendil-works/pi-coding-agent": "^0.84.2",
|
|
25
|
+
"@earendil-works/pi-tui": "^0.84.2",
|
|
24
26
|
"typescript": "^6.0.0"
|
|
25
27
|
},
|
|
26
28
|
"pi": {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import defaultExport from "./index.js";
|
|
3
|
+
|
|
4
|
+
describe("notify default export (standalone factory)", () => {
|
|
5
|
+
it("is a function that registers the notify handlers (registerNotify subscribes its own session events)", () => {
|
|
6
|
+
expect(typeof defaultExport).toBe("function");
|
|
7
|
+
|
|
8
|
+
const on = vi.fn();
|
|
9
|
+
const pi = { on } as any;
|
|
10
|
+
|
|
11
|
+
defaultExport(pi);
|
|
12
|
+
|
|
13
|
+
const events = on.mock.calls.map((c: Array<unknown>) => c[0]);
|
|
14
|
+
expect(events).toEqual(
|
|
15
|
+
expect.arrayContaining([
|
|
16
|
+
"agent_end",
|
|
17
|
+
"input",
|
|
18
|
+
"before_agent_start",
|
|
19
|
+
"agent_start",
|
|
20
|
+
"session_start",
|
|
21
|
+
"session_shutdown",
|
|
22
|
+
]),
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -4,17 +4,25 @@ import { loadConfig, saveConfig } from "@pi-archimedes/core/settings-io";
|
|
|
4
4
|
import { getBus, Events } from "@pi-archimedes/core/bus";
|
|
5
5
|
import { execFile } from "node:child_process";
|
|
6
6
|
|
|
7
|
+
// ── Trigger constants ────────────────────────────────────────────────────────
|
|
8
|
+
|
|
9
|
+
const TRIGGER = {
|
|
10
|
+
AGENT_END: "agent_end",
|
|
11
|
+
ASK_REQUEST: "ask_request",
|
|
12
|
+
} as const;
|
|
13
|
+
type TriggerType = (typeof TRIGGER)[keyof typeof TRIGGER];
|
|
14
|
+
|
|
7
15
|
// ── Config ──────────────────────────────────────────────────────────────────
|
|
8
16
|
|
|
9
17
|
export interface NotifyConfig {
|
|
10
|
-
enabled
|
|
18
|
+
// suite-managed by meta's plugin gate (archimedes.notify.enabled — see ADR 0012); notify never reads this
|
|
19
|
+
enabled?: boolean;
|
|
11
20
|
notifyOnAgentEnd: boolean;
|
|
12
21
|
notifyOnQuestion: boolean;
|
|
13
22
|
delayMs: number;
|
|
14
23
|
}
|
|
15
24
|
|
|
16
25
|
export const DEFAULT_NOTIFY_CONFIG: NotifyConfig = {
|
|
17
|
-
enabled: true,
|
|
18
26
|
notifyOnAgentEnd: true,
|
|
19
27
|
notifyOnQuestion: true,
|
|
20
28
|
delayMs: 30_000,
|
|
@@ -124,7 +132,7 @@ export function notify(title: string, body: string): void {
|
|
|
124
132
|
// ── Circuit breaker state ───────────────────────────────────────────────────
|
|
125
133
|
|
|
126
134
|
let notifyTimer: ReturnType<typeof setTimeout> | null = null;
|
|
127
|
-
let pendingTrigger:
|
|
135
|
+
let pendingTrigger: TriggerType | null = null;
|
|
128
136
|
|
|
129
137
|
// ── Circuit breaker logic ───────────────────────────────────────────────────
|
|
130
138
|
|
|
@@ -138,22 +146,18 @@ export function cancelPending(): void {
|
|
|
138
146
|
}
|
|
139
147
|
|
|
140
148
|
/** Schedule a delayed notification (circuit breaker). */
|
|
141
|
-
export function scheduleNotify(trigger:
|
|
149
|
+
export function scheduleNotify(trigger: TriggerType): void {
|
|
142
150
|
// Cancel any existing timer first
|
|
143
151
|
cancelPending();
|
|
144
152
|
|
|
145
153
|
// Load config fresh on each trigger
|
|
146
154
|
const config = loadNotifyConfig();
|
|
147
155
|
|
|
148
|
-
if (!config.
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
if (trigger === "agent_end" && !config.notifyOnAgentEnd) {
|
|
156
|
+
if (trigger === TRIGGER.AGENT_END && !config.notifyOnAgentEnd) {
|
|
153
157
|
return;
|
|
154
158
|
}
|
|
155
159
|
|
|
156
|
-
if (trigger ===
|
|
160
|
+
if (trigger === TRIGGER.ASK_REQUEST && !config.notifyOnQuestion) {
|
|
157
161
|
return;
|
|
158
162
|
}
|
|
159
163
|
|
|
@@ -169,8 +173,8 @@ export function scheduleNotify(trigger: "agent_end" | "ask_request"): void {
|
|
|
169
173
|
}
|
|
170
174
|
|
|
171
175
|
/** Fire the actual notification based on the pending trigger. */
|
|
172
|
-
function fireNotification(trigger:
|
|
173
|
-
if (trigger ===
|
|
176
|
+
function fireNotification(trigger: TriggerType | null): void {
|
|
177
|
+
if (trigger === TRIGGER.AGENT_END) {
|
|
174
178
|
notify("Pi", "Task complete — waiting for input");
|
|
175
179
|
} else {
|
|
176
180
|
notify("Pi", "A question needs your answer");
|
|
@@ -181,14 +185,14 @@ function fireNotification(trigger: "agent_end" | "ask_request" | null): void {
|
|
|
181
185
|
|
|
182
186
|
/** Register the notify extension with the Pi agent. */
|
|
183
187
|
export function registerNotify(pi: ExtensionAPI): void {
|
|
184
|
-
pi.on("agent_end", () => scheduleNotify(
|
|
188
|
+
pi.on("agent_end", () => scheduleNotify(TRIGGER.AGENT_END));
|
|
185
189
|
pi.on("input", () => cancelPending());
|
|
186
190
|
pi.on("before_agent_start", () => cancelPending());
|
|
187
191
|
pi.on("agent_start", () => cancelPending());
|
|
188
192
|
|
|
189
193
|
// Listen for ask requests from the bus (ask package emits this)
|
|
190
194
|
const unsubAskRequest = getBus().on(Events.ASK_REQUEST, () =>
|
|
191
|
-
scheduleNotify(
|
|
195
|
+
scheduleNotify(TRIGGER.ASK_REQUEST),
|
|
192
196
|
);
|
|
193
197
|
|
|
194
198
|
// Listen for raw terminal keystrokes — cancel on any key press
|
|
@@ -205,18 +209,19 @@ export function registerNotify(pi: ExtensionAPI): void {
|
|
|
205
209
|
});
|
|
206
210
|
}
|
|
207
211
|
|
|
212
|
+
// ── Default export (for standalone pi.extensions loading) ─────────────────
|
|
213
|
+
|
|
214
|
+
// registerNotify subscribes its own session_start/session_shutdown (and
|
|
215
|
+
// agent/input) handlers internally, so the default factory just registers it.
|
|
216
|
+
export default function (pi: ExtensionAPI): void {
|
|
217
|
+
registerNotify(pi);
|
|
218
|
+
}
|
|
219
|
+
|
|
208
220
|
// ── Settings UI ─────────────────────────────────────────────────────────────
|
|
209
221
|
|
|
210
222
|
/** Build settings UI items for the notify package. */
|
|
211
223
|
export function getNotifySettingsItems(config: NotifyConfig): SettingItem[] {
|
|
212
224
|
return [
|
|
213
|
-
{
|
|
214
|
-
id: "enabled",
|
|
215
|
-
label: "Notifications",
|
|
216
|
-
description: "Enable desktop notifications",
|
|
217
|
-
currentValue: config.enabled ? "On" : "Off",
|
|
218
|
-
values: ["On", "Off"],
|
|
219
|
-
},
|
|
220
225
|
{
|
|
221
226
|
id: "notifyOnAgentEnd",
|
|
222
227
|
label: "Notify on task complete",
|