@mohak34/opencode-notifier 0.1.11 → 0.1.13

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
@@ -1,6 +1,6 @@
1
1
  # opencode-notifier
2
2
 
3
- OpenCode plugin that plays sounds and sends system notifications when permission is needed, generation completes, or errors occur. Works on macOS, Linux, and Windows.
3
+ OpenCode plugin that plays sounds and sends system notifications when permission is needed, generation completes, errors occur, or the question tool is invoked. Works on macOS, Linux, and Windows.
4
4
 
5
5
  ## Installation
6
6
 
@@ -91,20 +91,24 @@ To customize the plugin, create `~/.config/opencode/opencode-notifier.json`:
91
91
  "sound": true,
92
92
  "notification": true,
93
93
  "timeout": 5,
94
+ "showProjectName": true,
94
95
  "events": {
95
96
  "permission": { "sound": true, "notification": true },
96
97
  "complete": { "sound": true, "notification": true },
97
- "error": { "sound": true, "notification": true }
98
+ "error": { "sound": true, "notification": true },
99
+ "question": { "sound": true, "notification": true }
98
100
  },
99
101
  "messages": {
100
- "permission": "OpenCode needs permission",
101
- "complete": "OpenCode has finished",
102
- "error": "OpenCode encountered an error"
102
+ "permission": "Session needs permission",
103
+ "complete": "Session has finished",
104
+ "error": "Session encountered an error",
105
+ "question": "Session has a question"
103
106
  },
104
107
  "sounds": {
105
108
  "permission": "/path/to/custom/sound.wav",
106
109
  "complete": "/path/to/custom/sound.wav",
107
- "error": "/path/to/custom/sound.wav"
110
+ "error": "/path/to/custom/sound.wav",
111
+ "question": "/path/to/custom/sound.wav"
108
112
  }
109
113
  }
110
114
  ```
@@ -116,6 +120,7 @@ To customize the plugin, create `~/.config/opencode/opencode-notifier.json`:
116
120
  | `sound` | boolean | `true` | Global toggle for all sounds |
117
121
  | `notification` | boolean | `true` | Global toggle for all notifications |
118
122
  | `timeout` | number | `5` | Notification duration in seconds (Linux only) |
123
+ | `showProjectName` | boolean | `true` | Show project folder name in notification title |
119
124
 
120
125
  ### Events
121
126
 
@@ -126,7 +131,8 @@ Control sound and notification separately for each event:
126
131
  "events": {
127
132
  "permission": { "sound": true, "notification": true },
128
133
  "complete": { "sound": false, "notification": true },
129
- "error": { "sound": true, "notification": false }
134
+ "error": { "sound": true, "notification": false },
135
+ "question": { "sound": true, "notification": true }
130
136
  }
131
137
  }
132
138
  ```
@@ -138,7 +144,8 @@ Or use a boolean to toggle both:
138
144
  "events": {
139
145
  "permission": true,
140
146
  "complete": false,
141
- "error": true
147
+ "error": true,
148
+ "question": true
142
149
  }
143
150
  }
144
151
  ```
@@ -152,7 +159,8 @@ Customize notification text:
152
159
  "messages": {
153
160
  "permission": "Action required",
154
161
  "complete": "Done!",
155
- "error": "Something went wrong"
162
+ "error": "Something went wrong",
163
+ "question": "Input needed"
156
164
  }
157
165
  }
158
166
  ```
@@ -166,7 +174,8 @@ Use your own sound files:
166
174
  "sounds": {
167
175
  "permission": "/home/user/sounds/alert.wav",
168
176
  "complete": "/home/user/sounds/done.wav",
169
- "error": "/home/user/sounds/error.wav"
177
+ "error": "/home/user/sounds/error.wav",
178
+ "question": "/home/user/sounds/question.wav"
170
179
  }
171
180
  }
172
181
  ```
package/dist/index.js CHANGED
@@ -3726,6 +3726,9 @@ var require_node_notifier = __commonJS((exports, module) => {
3726
3726
  module.exports.Growl = Growl;
3727
3727
  });
3728
3728
 
3729
+ // src/index.ts
3730
+ import { basename } from "path";
3731
+
3729
3732
  // src/config.ts
3730
3733
  import { readFileSync, existsSync } from "fs";
3731
3734
  import { join } from "path";
@@ -3738,20 +3741,24 @@ var DEFAULT_CONFIG = {
3738
3741
  sound: true,
3739
3742
  notification: true,
3740
3743
  timeout: 5,
3744
+ showProjectName: true,
3741
3745
  events: {
3742
3746
  permission: { ...DEFAULT_EVENT_CONFIG },
3743
3747
  complete: { ...DEFAULT_EVENT_CONFIG },
3744
- error: { ...DEFAULT_EVENT_CONFIG }
3748
+ error: { ...DEFAULT_EVENT_CONFIG },
3749
+ question: { ...DEFAULT_EVENT_CONFIG }
3745
3750
  },
3746
3751
  messages: {
3747
- permission: "OpenCode needs permission",
3748
- complete: "OpenCode has finished",
3749
- error: "OpenCode encountered an error"
3752
+ permission: "Session needs permission",
3753
+ complete: "Session has finished",
3754
+ error: "Session encountered an error",
3755
+ question: "Session has a question"
3750
3756
  },
3751
3757
  sounds: {
3752
3758
  permission: null,
3753
3759
  complete: null,
3754
- error: null
3760
+ error: null,
3761
+ question: null
3755
3762
  }
3756
3763
  };
3757
3764
  function getConfigPath() {
@@ -3790,20 +3797,24 @@ function loadConfig() {
3790
3797
  sound: globalSound,
3791
3798
  notification: globalNotification,
3792
3799
  timeout: typeof userConfig.timeout === "number" && userConfig.timeout > 0 ? userConfig.timeout : DEFAULT_CONFIG.timeout,
3800
+ showProjectName: userConfig.showProjectName ?? DEFAULT_CONFIG.showProjectName,
3793
3801
  events: {
3794
3802
  permission: parseEventConfig(userConfig.events?.permission ?? userConfig.permission, defaultWithGlobal),
3795
3803
  complete: parseEventConfig(userConfig.events?.complete ?? userConfig.complete, defaultWithGlobal),
3796
- error: parseEventConfig(userConfig.events?.error ?? userConfig.error, defaultWithGlobal)
3804
+ error: parseEventConfig(userConfig.events?.error ?? userConfig.error, defaultWithGlobal),
3805
+ question: parseEventConfig(userConfig.events?.question ?? userConfig.question, defaultWithGlobal)
3797
3806
  },
3798
3807
  messages: {
3799
3808
  permission: userConfig.messages?.permission ?? DEFAULT_CONFIG.messages.permission,
3800
3809
  complete: userConfig.messages?.complete ?? DEFAULT_CONFIG.messages.complete,
3801
- error: userConfig.messages?.error ?? DEFAULT_CONFIG.messages.error
3810
+ error: userConfig.messages?.error ?? DEFAULT_CONFIG.messages.error,
3811
+ question: userConfig.messages?.question ?? DEFAULT_CONFIG.messages.question
3802
3812
  },
3803
3813
  sounds: {
3804
3814
  permission: userConfig.sounds?.permission ?? DEFAULT_CONFIG.sounds.permission,
3805
3815
  complete: userConfig.sounds?.complete ?? DEFAULT_CONFIG.sounds.complete,
3806
- error: userConfig.sounds?.error ?? DEFAULT_CONFIG.sounds.error
3816
+ error: userConfig.sounds?.error ?? DEFAULT_CONFIG.sounds.error,
3817
+ question: userConfig.sounds?.question ?? DEFAULT_CONFIG.sounds.question
3807
3818
  }
3808
3819
  };
3809
3820
  } catch {
@@ -3827,7 +3838,6 @@ function getSoundPath(config, event) {
3827
3838
  var import_node_notifier = __toESM(require_node_notifier(), 1);
3828
3839
  import os from "os";
3829
3840
  import { exec } from "child_process";
3830
- var NOTIFICATION_TITLE = "OpenCode";
3831
3841
  var DEBOUNCE_MS = 1000;
3832
3842
  var platform = os.type();
3833
3843
  var platformNotifier;
@@ -3841,7 +3851,7 @@ if (platform === "Linux" || platform.match(/BSD$/)) {
3841
3851
  platformNotifier = import_node_notifier.default;
3842
3852
  }
3843
3853
  var lastNotificationTime = {};
3844
- async function sendNotification(message, timeout) {
3854
+ async function sendNotification(title, message, timeout) {
3845
3855
  const now = Date.now();
3846
3856
  if (lastNotificationTime[message] && now - lastNotificationTime[message] < DEBOUNCE_MS) {
3847
3857
  return;
@@ -3850,7 +3860,7 @@ async function sendNotification(message, timeout) {
3850
3860
  if (platform === "Darwin") {
3851
3861
  return new Promise((resolve) => {
3852
3862
  const escapedMessage = message.replace(/"/g, "\\\"");
3853
- const escapedTitle = NOTIFICATION_TITLE.replace(/"/g, "\\\"");
3863
+ const escapedTitle = title.replace(/"/g, "\\\"");
3854
3864
  exec(`osascript -e 'display notification "${escapedMessage}" with title "${escapedTitle}"'`, () => {
3855
3865
  resolve();
3856
3866
  });
@@ -3858,7 +3868,7 @@ async function sendNotification(message, timeout) {
3858
3868
  }
3859
3869
  return new Promise((resolve) => {
3860
3870
  const notificationOptions = {
3861
- title: NOTIFICATION_TITLE,
3871
+ title,
3862
3872
  message,
3863
3873
  timeout,
3864
3874
  icon: undefined
@@ -3971,11 +3981,18 @@ async function playSound(event, customPath) {
3971
3981
  }
3972
3982
 
3973
3983
  // src/index.ts
3974
- async function handleEvent(config, eventType) {
3984
+ function getNotificationTitle(config, projectName) {
3985
+ if (config.showProjectName && projectName) {
3986
+ return `OpenCode (${projectName})`;
3987
+ }
3988
+ return "OpenCode";
3989
+ }
3990
+ async function handleEvent(config, eventType, projectName) {
3975
3991
  const promises = [];
3976
3992
  if (isEventNotificationEnabled(config, eventType)) {
3993
+ const title = getNotificationTitle(config, projectName);
3977
3994
  const message = getMessage(config, eventType);
3978
- promises.push(sendNotification(message, config.timeout));
3995
+ promises.push(sendNotification(title, message, config.timeout));
3979
3996
  }
3980
3997
  if (isEventSoundEnabled(config, eventType)) {
3981
3998
  const customSoundPath = getSoundPath(config, eventType);
@@ -3983,25 +4000,31 @@ async function handleEvent(config, eventType) {
3983
4000
  }
3984
4001
  await Promise.allSettled(promises);
3985
4002
  }
3986
- var NotifierPlugin = async () => {
4003
+ var NotifierPlugin = async ({ project, client, $, directory, worktree }) => {
3987
4004
  const config = loadConfig();
4005
+ const projectName = directory ? basename(directory) : null;
3988
4006
  return {
3989
4007
  event: async ({ event }) => {
3990
4008
  if (event.type === "permission.updated") {
3991
- await handleEvent(config, "permission");
4009
+ await handleEvent(config, "permission", projectName);
3992
4010
  }
3993
4011
  if (event.type === "permission.asked") {
3994
- await handleEvent(config, "permission");
4012
+ await handleEvent(config, "permission", projectName);
3995
4013
  }
3996
4014
  if (event.type === "session.idle") {
3997
- await handleEvent(config, "complete");
4015
+ await handleEvent(config, "complete", projectName);
3998
4016
  }
3999
4017
  if (event.type === "session.error") {
4000
- await handleEvent(config, "error");
4018
+ await handleEvent(config, "error", projectName);
4001
4019
  }
4002
4020
  },
4003
4021
  "permission.ask": async () => {
4004
- await handleEvent(config, "permission");
4022
+ await handleEvent(config, "permission", projectName);
4023
+ },
4024
+ "tool.execute.before": async (input, output) => {
4025
+ if (input.tool === "question") {
4026
+ await handleEvent(config, "question", projectName);
4027
+ }
4005
4028
  }
4006
4029
  };
4007
4030
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mohak34/opencode-notifier",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "OpenCode plugin that sends system notifications and plays sounds when permission is needed, generation completes, or errors occur",
5
5
  "author": "mohak34",
6
6
  "license": "MIT",
Binary file