opencode-plugin-apprise 1.0.0 → 1.1.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.
@@ -4,7 +4,7 @@ import type { PluginConfig } from "../types.js";
4
4
  export interface PermissionHooks {
5
5
  /** Primary: permission.ask hook */
6
6
  permissionAsk: NonNullable<Hooks["permission.ask"]>;
7
- /** Fallback: event hook watching permission.updated */
7
+ /** Fallback: event hook watching permission.asked */
8
8
  eventFallback: NonNullable<Hooks["event"]>;
9
9
  }
10
10
  export declare function createPermissionHooks(config: PluginConfig, dedup: DedupChecker): PermissionHooks;
@@ -1,8 +1,4 @@
1
1
  import type { Hooks } from "@opencode-ai/plugin";
2
2
  import type { DedupChecker } from "../dedup.js";
3
3
  import type { PluginConfig } from "../types.js";
4
- export interface QuestionHooks {
5
- before: NonNullable<Hooks["tool.execute.before"]>;
6
- after: NonNullable<Hooks["tool.execute.after"]>;
7
- }
8
- export declare function createQuestionHooks(config: PluginConfig, dedup: DedupChecker, delayMs?: number): QuestionHooks;
4
+ export declare function createQuestionHook(config: PluginConfig, dedup: DedupChecker, delayMs?: number): NonNullable<Hooks["event"]>;
@@ -242,21 +242,6 @@ async function sendHookNotification(hookName, config, dedup, payload) {
242
242
  }
243
243
  }
244
244
 
245
- // src/hooks/background.ts
246
- function createBackgroundHook(config, dedup) {
247
- return async ({ event }) => {
248
- if (event.type !== "session.status")
249
- return;
250
- const props = event.properties;
251
- if (props.status.type !== "idle")
252
- return;
253
- const payload = createPayload("background", "✅ Background Task Complete", {
254
- taskName: `Session ${props.sessionID}`
255
- });
256
- await sendHookNotification("background", config, dedup, payload);
257
- };
258
- }
259
-
260
245
  // src/hooks/idle.ts
261
246
  function extractText(message) {
262
247
  if (!message || typeof message !== "object") {
@@ -268,9 +253,11 @@ function extractText(message) {
268
253
  }
269
254
  function createIdleHook(ctx, config, dedup) {
270
255
  return async ({ event }) => {
271
- if (event.type !== "session.idle")
256
+ if (event.type !== "session.status")
272
257
  return;
273
258
  const props = event.properties;
259
+ if (props.status.type !== "idle")
260
+ return;
274
261
  if (!props.sessionID)
275
262
  return;
276
263
  let userRequest = undefined;
@@ -320,65 +307,71 @@ function createIdleHook(ctx, config, dedup) {
320
307
  // src/hooks/permission.ts
321
308
  function createPermissionHooks(config, dedup) {
322
309
  const notifiedPermissions = new Set;
323
- async function notifyPermission(permission) {
324
- const permId = permission.id ?? "unknown";
310
+ const permissionAsk = async (input, _output) => {
311
+ const permId = input.id ?? "unknown";
325
312
  if (notifiedPermissions.has(permId))
326
313
  return;
327
314
  notifiedPermissions.add(permId);
328
- const toolName = permission.toolName ?? "Unknown Tool";
329
- const action = permission.action ?? "Unknown Action";
315
+ const title = input.title ?? "Unknown";
316
+ const pattern = input.pattern;
317
+ const action = Array.isArray(pattern) ? pattern.join(", ") : pattern ?? "Unknown";
330
318
  const payload = createPayload("permission", "\uD83D\uDD10 OpenCode Permission Required", {
331
- toolName,
319
+ toolName: title,
332
320
  action
333
321
  });
334
322
  await sendHookNotification("permission", config, dedup, payload);
335
- }
336
- const permissionAsk = async (input, _output) => {
337
- await notifyPermission(input);
338
323
  };
339
324
  const eventFallback = async ({ event }) => {
340
- if (event.type !== "permission.updated")
325
+ const eventType = event.type;
326
+ if (eventType !== "permission.asked")
327
+ return;
328
+ const props = event.properties;
329
+ const permId = props.id ?? "unknown";
330
+ if (notifiedPermissions.has(permId))
341
331
  return;
342
- const permission = event.properties;
343
- await notifyPermission(permission);
332
+ notifiedPermissions.add(permId);
333
+ const payload = createPayload("permission", "\uD83D\uDD10 OpenCode Permission Required", {
334
+ toolName: props.permission ?? "Unknown",
335
+ action: props.patterns?.join(", ") ?? "Unknown"
336
+ });
337
+ await sendHookNotification("permission", config, dedup, payload);
344
338
  };
345
339
  return { permissionAsk, eventFallback };
346
340
  }
347
341
 
348
342
  // src/hooks/question.ts
349
- function createQuestionHooks(config, dedup, delayMs = 30000) {
343
+ function createQuestionHook(config, dedup, delayMs = 30000) {
350
344
  const timers = new Map;
351
- const before = async ({ tool, callID }, input) => {
352
- if (tool.toLowerCase() !== "question")
345
+ return async ({ event }) => {
346
+ const eventType = event.type;
347
+ if (eventType === "question.replied" || eventType === "question.rejected") {
348
+ const props2 = event.properties;
349
+ const timer2 = timers.get(props2.requestID);
350
+ if (timer2) {
351
+ clearTimeout(timer2);
352
+ timers.delete(props2.requestID);
353
+ }
353
354
  return;
354
- const args = input?.args;
355
- const question = typeof args?.question === "string" ? args.question : undefined;
356
- const options = Array.isArray(args?.options) ? args.options.filter((option) => typeof option === "string") : undefined;
355
+ }
356
+ if (eventType !== "question.asked")
357
+ return;
358
+ const props = event.properties;
359
+ const firstQuestion = props.questions[0];
360
+ if (!firstQuestion)
361
+ return;
362
+ const question = firstQuestion.question;
363
+ const options = firstQuestion.options.map((opt) => opt.label);
364
+ const requestId = props.id;
357
365
  const timer = setTimeout(async () => {
358
- if (!question)
359
- return;
366
+ timers.delete(requestId);
360
367
  const payload = createPayload("question", "❓ OpenCode Question", {
361
368
  question,
362
- options,
363
- toolName: "Question"
369
+ options: options.length > 0 ? options : undefined
364
370
  });
365
371
  await sendHookNotification("question", config, dedup, payload);
366
372
  }, delayMs);
367
- timers.set(callID, timer);
368
- };
369
- const after = async ({
370
- tool,
371
- callID
372
- }) => {
373
- if (tool.toLowerCase() !== "question")
374
- return;
375
- const timer = timers.get(callID);
376
- if (timer) {
377
- clearTimeout(timer);
378
- timers.delete(callID);
379
- }
373
+ timers.set(requestId, timer);
380
374
  };
381
- return { before, after };
382
375
  }
383
376
 
384
377
  // src/index.ts
@@ -400,18 +393,15 @@ var plugin = async (input) => {
400
393
  }
401
394
  const dedup = createDedupChecker();
402
395
  const idleHook = createIdleHook(input, config, dedup);
403
- const questionHooks = createQuestionHooks(config, dedup);
404
- const backgroundHook = createBackgroundHook(config, dedup);
396
+ const questionHook = createQuestionHook(config, dedup);
405
397
  const permissionHooks = createPermissionHooks(config, dedup);
406
398
  const combinedEventHook = async ({ event }) => {
407
- await idleHook({ event });
408
- await backgroundHook({ event });
399
+ await questionHook({ event });
409
400
  await permissionHooks.eventFallback({ event });
401
+ await idleHook({ event });
410
402
  };
411
403
  return {
412
404
  event: combinedEventHook,
413
- "tool.execute.before": questionHooks.before,
414
- "tool.execute.after": questionHooks.after,
415
405
  "permission.ask": permissionHooks.permissionAsk
416
406
  };
417
407
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-plugin-apprise",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
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",