opencode-plugin-apprise 1.1.0 → 1.2.1

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 CHANGED
@@ -5,9 +5,8 @@ OpenCode plugin for multi-service notifications via Apprise.
5
5
  ## Features
6
6
 
7
7
  - Multi-service support for 128+ notification services via Apprise.
8
- - Automatic notifications when sessions go idle.
8
+ - Automatic notifications when foreground sessions go idle (background tasks are excluded).
9
9
  - Delayed notifications for Question tool prompts (30-second grace period).
10
- - Alerts when sessions transition to idle after activity.
11
10
  - Notifications for permission requests with dual-mechanism reliability.
12
11
 
13
12
  ## Prerequisites
@@ -74,7 +73,7 @@ For complete configuration options, see: https://github.com/caronc/apprise#confi
74
73
 
75
74
  ### Idle
76
75
 
77
- Fires immediately when OpenCode emits a `session.idle` event. Includes the last user request, agent response, and todo status.
76
+ Fires when a foreground session goes idle. Only sessions where the user has sent at least one message are tracked — background agent sessions are excluded. Includes the last user request, agent response, and todo status.
78
77
 
79
78
  **Severity**: info
80
79
 
@@ -100,17 +99,6 @@ Options:
100
99
  3. cancel
101
100
  ```
102
101
 
103
- ### Background
104
-
105
- Fires when a session's status transitions to `idle` after being active. This indicates the agent has finished working and the session is waiting.
106
-
107
- **Severity**: success
108
-
109
- ```
110
- ✅ Background Task Complete
111
- Task: Session ses_abc123
112
- ```
113
-
114
102
  ### Permission
115
103
 
116
104
  Fires when a tool requires explicit user permission. Uses two mechanisms for reliability: the primary `permission.ask` hook and a fallback `permission.updated` event listener. Permissions are deduplicated by ID to prevent double notifications.
@@ -150,7 +138,6 @@ Identical notifications are suppressed for 5 minutes. Duplicates are identified
150
138
  |-------|:-------------|
151
139
  | Idle | info |
152
140
  | Question | warning |
153
- | Background | success |
154
141
  | Permission | warning |
155
142
 
156
143
  ## Troubleshooting
@@ -1,4 +1,4 @@
1
1
  import type { Hooks, PluginInput } from "@opencode-ai/plugin";
2
2
  import type { DedupChecker } from "../dedup.js";
3
3
  import type { PluginConfig } from "../types.js";
4
- export declare function createIdleHook(ctx: PluginInput, config: PluginConfig, dedup: DedupChecker): NonNullable<Hooks["event"]>;
4
+ export declare function createIdleHook(ctx: PluginInput, config: PluginConfig, dedup: DedupChecker, interactiveSessions: Set<string>): NonNullable<Hooks["event"]>;
@@ -54,7 +54,6 @@ function createDedupChecker() {
54
54
  var TYPE_MAP = {
55
55
  idle: "info",
56
56
  question: "warning",
57
- background: "success",
58
57
  permission: "warning"
59
58
  };
60
59
  var DEFAULT_TRUNCATE_LENGTH = 1500;
@@ -127,17 +126,6 @@ ${context.options.map((option, index) => ` ${index + 1}. ${option}`).join(`
127
126
  }
128
127
  body = parts.join(`
129
128
 
130
- `);
131
- break;
132
- }
133
- case "background": {
134
- const parts = [];
135
- if (context.taskName)
136
- parts.push(`Task: ${context.taskName}`);
137
- if (context.agentResponse)
138
- parts.push(`Result: ${context.agentResponse}`);
139
- body = parts.join(`
140
-
141
129
  `);
142
130
  break;
143
131
  }
@@ -220,7 +208,6 @@ var EMPTY_CONTEXT = {
220
208
  question: undefined,
221
209
  options: undefined,
222
210
  todoStatus: undefined,
223
- taskName: undefined,
224
211
  toolName: undefined,
225
212
  action: undefined
226
213
  };
@@ -243,15 +230,12 @@ async function sendHookNotification(hookName, config, dedup, payload) {
243
230
  }
244
231
 
245
232
  // src/hooks/idle.ts
246
- function extractText(message) {
247
- if (!message || typeof message !== "object") {
248
- return;
249
- }
250
- const parts = Array.isArray(message) ? message.map((p) => typeof p === "string" ? p : p.text || "") : [];
251
- return parts.join(`
233
+ function extractText(parts) {
234
+ const texts = parts.filter((p) => p.type === "text" && p.text).map((p) => p.text);
235
+ return texts.join(`
252
236
  `).trim() || undefined;
253
237
  }
254
- function createIdleHook(ctx, config, dedup) {
238
+ function createIdleHook(ctx, config, dedup, interactiveSessions) {
255
239
  return async ({ event }) => {
256
240
  if (event.type !== "session.status")
257
241
  return;
@@ -260,6 +244,8 @@ function createIdleHook(ctx, config, dedup) {
260
244
  return;
261
245
  if (!props.sessionID)
262
246
  return;
247
+ if (!interactiveSessions.has(props.sessionID))
248
+ return;
263
249
  let userRequest = undefined;
264
250
  let agentResponse = undefined;
265
251
  let todoStatus = undefined;
@@ -270,16 +256,16 @@ function createIdleHook(ctx, config, dedup) {
270
256
  const messages = messagesResponse.data ?? [];
271
257
  for (let i = messages.length - 1;i >= 0; i--) {
272
258
  const msg = messages[i];
273
- if (msg?.role === "user") {
274
- userRequest = extractText(msg.content);
259
+ if (msg?.info?.role === "user") {
260
+ userRequest = extractText(msg.parts);
275
261
  break;
276
262
  }
277
263
  }
278
264
  if (userRequest) {
279
265
  for (let i = messages.length - 1;i >= 0; i--) {
280
266
  const msg = messages[i];
281
- if (msg?.role === "assistant") {
282
- agentResponse = extractText(msg.content);
267
+ if (msg?.info?.role === "assistant") {
268
+ agentResponse = extractText(msg.parts);
283
269
  break;
284
270
  }
285
271
  }
@@ -392,7 +378,8 @@ var plugin = async (input) => {
392
378
  return {};
393
379
  }
394
380
  const dedup = createDedupChecker();
395
- const idleHook = createIdleHook(input, config, dedup);
381
+ const interactiveSessions = new Set;
382
+ const idleHook = createIdleHook(input, config, dedup, interactiveSessions);
396
383
  const questionHook = createQuestionHook(config, dedup);
397
384
  const permissionHooks = createPermissionHooks(config, dedup);
398
385
  const combinedEventHook = async ({ event }) => {
@@ -400,9 +387,13 @@ var plugin = async (input) => {
400
387
  await permissionHooks.eventFallback({ event });
401
388
  await idleHook({ event });
402
389
  };
390
+ const chatMessageHook = async (input2) => {
391
+ interactiveSessions.add(input2.sessionID);
392
+ };
403
393
  return {
404
394
  event: combinedEventHook,
405
- "permission.ask": permissionHooks.permissionAsk
395
+ "permission.ask": permissionHooks.permissionAsk,
396
+ "chat.message": chatMessageHook
406
397
  };
407
398
  };
408
399
  var src_default = plugin;
package/dist/types.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export interface PluginConfig {
2
2
  tag?: string;
3
3
  }
4
- export type HookEventType = "idle" | "question" | "background" | "permission";
4
+ export type HookEventType = "idle" | "question" | "permission";
5
5
  export type AppriseNotificationType = "info" | "warning" | "success" | "failure";
6
6
  export interface NotificationContext {
7
7
  userRequest: string | undefined;
@@ -9,7 +9,6 @@ export interface NotificationContext {
9
9
  question: string | undefined;
10
10
  options: string[] | undefined;
11
11
  todoStatus: string | undefined;
12
- taskName: string | undefined;
13
12
  toolName: string | undefined;
14
13
  action: string | undefined;
15
14
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-plugin-apprise",
3
- "version": "1.1.0",
3
+ "version": "1.2.1",
4
4
  "description": "OpenCode plugin that sends rich notifications via Apprise CLI when the agent needs your attention",
5
5
  "type": "module",
6
6
  "main": "dist/opencode-plugin-apprise.js",
@@ -1,4 +0,0 @@
1
- import type { Hooks } from "@opencode-ai/plugin";
2
- import type { DedupChecker } from "../dedup.js";
3
- import type { PluginConfig } from "../types.js";
4
- export declare function createBackgroundHook(config: PluginConfig, dedup: DedupChecker): NonNullable<Hooks["event"]>;