@nm156/opencode-notifier 0.3.1 → 0.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 +49 -22
- package/dist/bell.d.ts +2 -0
- package/dist/command.d.ts +2 -0
- package/dist/config.d.ts +109 -0
- package/dist/delivery.d.ts +4 -0
- package/dist/focus.d.ts +34 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +1705 -1783
- package/dist/notifier.d.ts +24 -0
- package/dist/notify.d.ts +19 -0
- package/dist/permission-dedupe.d.ts +3 -0
- package/dist/sound.d.ts +4 -0
- package/dist/tui.d.ts +7 -0
- package/dist/tui.js +2229 -0
- package/dist/v2.d.ts +14 -0
- package/package.json +23 -7
package/README.md
CHANGED
|
@@ -1,35 +1,50 @@
|
|
|
1
1
|
# opencode-notifier
|
|
2
2
|
|
|
3
3
|
> [!NOTE]
|
|
4
|
-
> This is a fork of [`@mohak34/opencode-notifier`](https://github.com/mohak34/opencode-notifier) that adds
|
|
5
|
-
>
|
|
6
|
-
>
|
|
4
|
+
> This is a fork of [`@mohak34/opencode-notifier`](https://github.com/mohak34/opencode-notifier) 0.4.0 that adds a
|
|
5
|
+
> `{sessionID}` custom command placeholder from
|
|
6
|
+
> [mohak34/opencode-notifier#124](https://github.com/mohak34/opencode-notifier/pull/124). Use the upstream package once
|
|
7
|
+
> it includes that change.
|
|
7
8
|
|
|
8
9
|
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.
|
|
9
10
|
|
|
10
11
|
## Quick Start
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
For OpenCode 1, add the package to `opencode.json`:
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"plugin": ["@nm156/opencode-notifier@latest"]
|
|
18
|
+
}
|
|
19
|
+
```
|
|
15
20
|
|
|
16
|
-
|
|
17
|
-
{
|
|
18
|
-
"plugin": ["@nm156/opencode-notifier@latest"]
|
|
19
|
-
}
|
|
20
|
-
```
|
|
21
|
+
For OpenCode 2, use `plugins`:
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"plugins": ["@nm156/opencode-notifier@latest"]
|
|
26
|
+
}
|
|
27
|
+
```
|
|
23
28
|
|
|
24
|
-
|
|
29
|
+
Restart OpenCode. The package contains both implementations; you do not select a version manually. V2 loads the package's terminal component automatically in the interactive CLI.
|
|
25
30
|
|
|
26
|
-
|
|
31
|
+
### OpenCode 2 delivery
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
- **OpenCode 2** loads the `setup()` entrypoint introduced with the V2 plugin API.
|
|
33
|
+
Sounds, desktop popups, terminal bells, Ghostty notifications, and focus detection run in the terminal client. Custom commands run once per event on the server, including when no terminal is open. This uses the existing `command` configuration; no external notification service is bundled.
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
With a remote server, put sound and popup settings on your local computer and custom-command settings on the server. Script paths refer to the server's filesystem. Focus suppression applies to local alerts, not server commands. Each attached terminal receives alerts for its project.
|
|
36
|
+
|
|
37
|
+
`opencode run` and Desktop/Web clients do not load this terminal component, so they receive no plugin sound, popup, or bell. Server commands still run. V1 delivery and its `enableOnDesktop` behavior are unchanged.
|
|
38
|
+
|
|
39
|
+
V2 already includes a notification plugin. To avoid duplicate built-in alerts, add `"-opencode.notifications"` to the existing `plugins` list in `~/.config/opencode/cli.json`:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"plugins": ["*", "-opencode.notifications"]
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Keep any other entries in that list. `plan_exit` remains a V1 event; V2 has no equivalent plan-ready signal, so that setting is inactive there. `client_connected` is best-effort: terminal startup for local alerts, server plugin startup for custom commands.
|
|
33
48
|
|
|
34
49
|
## What it does
|
|
35
50
|
|
|
@@ -184,7 +199,7 @@ Create `~/.config/opencode/opencode-notifier.json` with the defaults:
|
|
|
184
199
|
- `showIcon` - Show OpenCode icon, Windows/Linux only (default: true)
|
|
185
200
|
- `customIconPath` - Path to a custom icon for notifications. Useful on WSL where Windows paths are needed (default: null)
|
|
186
201
|
- `suppressWhenFocused` - Skip notifications and sounds when the terminal is the active window (default: true). See [Focus detection](#focus-detection) for platform details
|
|
187
|
-
- `enableOnDesktop` -
|
|
202
|
+
- `enableOnDesktop` - V1 only: run the plugin on Desktop and Web clients (default: false). V2 runs commands on the server and local alerts in its terminal component; this flag does not control V2 delivery.
|
|
188
203
|
- `notificationSystem` - macOS only: `"osascript"`, `"node-notifier"`, or `"ghostty"` (default: "osascript"). Use `"ghostty"` if you're running Ghostty terminal for native OSC 9 notifications
|
|
189
204
|
- `suppressGhosttySound` - macOS only: when `true` with `notificationSystem: "ghostty"`, skips the plugin's sound to avoid duplicating macOS Notification Center's default sound (default: false)
|
|
190
205
|
- `minDuration` - Suppress `complete` and `subagent_complete` notifications when session finishes faster than this many seconds (default: 0). See [Minimum duration threshold](#minimum-duration-threshold)
|
|
@@ -213,7 +228,7 @@ Control each event separately:
|
|
|
213
228
|
|
|
214
229
|
`user_cancelled` fires when you press ESC to abort a session. It's silent by default so intentional cancellations don't trigger error alerts. Set `sound` or `notification` to `true` if you want confirmation when cancelling.
|
|
215
230
|
|
|
216
|
-
`session_started` fires when a new top-level session is created. `user_message` fires when a user message is submitted in a top-level session. `client_connected` fires shortly after
|
|
231
|
+
`session_started` fires when a new top-level session is created. `user_message` fires when a user message is submitted in a top-level session. `client_connected` is best-effort. On V1 it fires shortly after plugin initialization. On V2, terminal initialization triggers local alerts and server plugin initialization triggers the custom command; it does not track every client reconnection.
|
|
217
232
|
|
|
218
233
|
The `command` property controls whether the custom command (see [Custom commands](#custom-commands)) runs for that event. Defaults to `true` for all events. Set it to `false` to suppress the command for specific events without disabling it globally.
|
|
219
234
|
|
|
@@ -318,7 +333,7 @@ Set per-event volume from `0` to `1`:
|
|
|
318
333
|
|
|
319
334
|
### Custom commands
|
|
320
335
|
|
|
321
|
-
Run your own script when something happens. Use `{event}`, `{message}`, `{sessionTitle}`, `{agentName}`, `{projectName}`, `{timestamp}`, and `{turn}` as placeholders:
|
|
336
|
+
Run your own script when something happens. Use `{event}`, `{message}`, `{sessionTitle}`, `{sessionID}`, `{agentName}`, `{projectName}`, `{timestamp}`, and `{turn}` as placeholders:
|
|
322
337
|
|
|
323
338
|
```json
|
|
324
339
|
{
|
|
@@ -333,9 +348,11 @@ Run your own script when something happens. Use `{event}`, `{message}`, `{sessio
|
|
|
333
348
|
|
|
334
349
|
- `enabled` - Turn command on/off
|
|
335
350
|
- `path` - Path to your script/executable
|
|
336
|
-
- `args` - Arguments to pass, can use `{event}`, `{message}`, `{sessionTitle}`, `{agentName}`, `{projectName}`, `{timestamp}`, and `{turn}` tokens
|
|
351
|
+
- `args` - Arguments to pass, can use `{event}`, `{message}`, `{sessionTitle}`, `{sessionID}`, `{agentName}`, `{projectName}`, `{timestamp}`, and `{turn}` tokens
|
|
337
352
|
- `minDuration` - Skip if response was quick, avoids spam (seconds)
|
|
338
353
|
|
|
354
|
+
`{sessionID}` is the ID of the session that triggered the event (e.g. `ses_0048b8aa...`), so a script can tell concurrent sessions in the same project apart. It is empty for events without a session, such as `client_connected`.
|
|
355
|
+
|
|
339
356
|
Token values are passed as argv values and are not shell-escaped for use inside
|
|
340
357
|
script source. Do not put `{message}`, `{sessionTitle}`, or other dynamic tokens
|
|
341
358
|
inside a `sh -c`, `bash -c`, `powershell -Command`, or similar script string.
|
|
@@ -663,13 +680,23 @@ This is a known Bun issue on Windows. Disable native notifications and use Power
|
|
|
663
680
|
**Plugin installed but no notifications/sounds?**
|
|
664
681
|
|
|
665
682
|
- Check `suppressWhenFocused`: when `true` (default), notifications are skipped while OpenCode terminal is focused. Set to `false` to always notify.
|
|
666
|
-
-
|
|
683
|
+
- On V1, check `enableOnDesktop`: it defaults to `false`. On V2, Desktop/Web and headless clients use server commands; local sounds and popups require the terminal component described above.
|
|
667
684
|
- Verify the package version OpenCode cached:
|
|
668
685
|
```bash
|
|
669
686
|
cat ~/.cache/opencode/packages/@nm156/opencode-notifier@latest/node_modules/@nm156/opencode-notifier/package.json | grep version
|
|
670
687
|
```
|
|
671
688
|
If you use `@beta` or a pinned version, replace `latest` in the path with `beta` or the exact version.
|
|
672
689
|
|
|
690
|
+
## TypeScript imports
|
|
691
|
+
|
|
692
|
+
Loading this plugin through OpenCode configuration does not require installing SDKs separately. If a TypeScript project imports the package directly, its declarations reference both OpenCode SDK generations. Install the optional type peers in that project:
|
|
693
|
+
|
|
694
|
+
```bash
|
|
695
|
+
bun add -d '@opencode-ai/plugin@^1.18.25' '@opencode/plugin@^2.0.18' '@opencode/client@^2.0.18'
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
These peers are optional to keep runtime-only installs lightweight. They are not automatically installed, so a V1-only TypeScript project importing the dual entrypoint also needs the V2 type peers. Adding peer metadata alone does not resolve missing type packages.
|
|
699
|
+
|
|
673
700
|
## Changelog
|
|
674
701
|
|
|
675
702
|
See [CHANGELOG.md](CHANGELOG.md)
|
package/dist/bell.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import type { EventType, NotifierConfig } from "./config";
|
|
2
|
+
export declare function runCommand(config: NotifierConfig, event: EventType, message: string, sessionTitle?: string | null, agentName?: string | null, projectName?: string | null, timestamp?: string | null, turn?: number | null, sessionID?: string | null): void;
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
export type EventType = "permission" | "complete" | "subagent_complete" | "error" | "question" | "interrupted" | "user_cancelled" | "plan_exit" | "session_started" | "user_message" | "client_connected";
|
|
2
|
+
export interface EventConfig {
|
|
3
|
+
sound: boolean;
|
|
4
|
+
notification: boolean;
|
|
5
|
+
command: boolean;
|
|
6
|
+
bell: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface CommandConfig {
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
path: string;
|
|
11
|
+
args?: string[];
|
|
12
|
+
minDuration?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface LinuxConfig {
|
|
15
|
+
grouping: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface WindowsConfig {
|
|
18
|
+
appID: string;
|
|
19
|
+
}
|
|
20
|
+
export interface MessageContext {
|
|
21
|
+
sessionTitle?: string | null;
|
|
22
|
+
agentName?: string | null;
|
|
23
|
+
projectName?: string | null;
|
|
24
|
+
timestamp?: string | null;
|
|
25
|
+
turn?: number | null;
|
|
26
|
+
}
|
|
27
|
+
export interface NotifierConfig {
|
|
28
|
+
sound: boolean;
|
|
29
|
+
notification: boolean;
|
|
30
|
+
bell: boolean;
|
|
31
|
+
timeout: number;
|
|
32
|
+
showProjectName: boolean;
|
|
33
|
+
showFullPath: boolean;
|
|
34
|
+
showSessionTitle: boolean;
|
|
35
|
+
showIcon: boolean;
|
|
36
|
+
customIconPath: string | null;
|
|
37
|
+
suppressWhenFocused: boolean;
|
|
38
|
+
enableOnDesktop: boolean;
|
|
39
|
+
notificationSystem: "osascript" | "node-notifier" | "ghostty";
|
|
40
|
+
suppressGhosttySound: boolean;
|
|
41
|
+
linux: LinuxConfig;
|
|
42
|
+
windows: WindowsConfig;
|
|
43
|
+
minDuration: number;
|
|
44
|
+
command: CommandConfig;
|
|
45
|
+
events: {
|
|
46
|
+
permission: EventConfig;
|
|
47
|
+
complete: EventConfig;
|
|
48
|
+
subagent_complete: EventConfig;
|
|
49
|
+
error: EventConfig;
|
|
50
|
+
question: EventConfig;
|
|
51
|
+
interrupted: EventConfig;
|
|
52
|
+
user_cancelled: EventConfig;
|
|
53
|
+
plan_exit: EventConfig;
|
|
54
|
+
session_started: EventConfig;
|
|
55
|
+
user_message: EventConfig;
|
|
56
|
+
client_connected: EventConfig;
|
|
57
|
+
};
|
|
58
|
+
messages: {
|
|
59
|
+
permission: string;
|
|
60
|
+
complete: string;
|
|
61
|
+
subagent_complete: string;
|
|
62
|
+
error: string;
|
|
63
|
+
question: string;
|
|
64
|
+
interrupted: string;
|
|
65
|
+
user_cancelled: string;
|
|
66
|
+
plan_exit: string;
|
|
67
|
+
session_started: string;
|
|
68
|
+
user_message: string;
|
|
69
|
+
client_connected: string;
|
|
70
|
+
};
|
|
71
|
+
sounds: {
|
|
72
|
+
permission: string | null;
|
|
73
|
+
complete: string | null;
|
|
74
|
+
subagent_complete: string | null;
|
|
75
|
+
error: string | null;
|
|
76
|
+
question: string | null;
|
|
77
|
+
interrupted: string | null;
|
|
78
|
+
user_cancelled: string | null;
|
|
79
|
+
plan_exit: string | null;
|
|
80
|
+
session_started: string | null;
|
|
81
|
+
user_message: string | null;
|
|
82
|
+
client_connected: string | null;
|
|
83
|
+
};
|
|
84
|
+
volumes: {
|
|
85
|
+
permission: number;
|
|
86
|
+
complete: number;
|
|
87
|
+
subagent_complete: number;
|
|
88
|
+
error: number;
|
|
89
|
+
question: number;
|
|
90
|
+
interrupted: number;
|
|
91
|
+
user_cancelled: number;
|
|
92
|
+
plan_exit: number;
|
|
93
|
+
session_started: number;
|
|
94
|
+
user_message: number;
|
|
95
|
+
client_connected: number;
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export declare function getConfigPath(): string;
|
|
99
|
+
export declare function getStatePath(): string;
|
|
100
|
+
export declare function loadConfig(): NotifierConfig;
|
|
101
|
+
export declare function isEventSoundEnabled(config: NotifierConfig, event: EventType): boolean;
|
|
102
|
+
export declare function isEventNotificationEnabled(config: NotifierConfig, event: EventType): boolean;
|
|
103
|
+
export declare function isEventCommandEnabled(config: NotifierConfig, event: EventType): boolean;
|
|
104
|
+
export declare function isEventBellEnabled(config: NotifierConfig, event: EventType): boolean;
|
|
105
|
+
export declare function getMessage(config: NotifierConfig, event: EventType): string;
|
|
106
|
+
export declare function getSoundPath(config: NotifierConfig, event: EventType): string | null;
|
|
107
|
+
export declare function getSoundVolume(config: NotifierConfig, event: EventType): number;
|
|
108
|
+
export declare function getIconPath(config: NotifierConfig): string | undefined;
|
|
109
|
+
export declare function interpolateMessage(message: string, context: MessageContext): string;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { EventType, NotifierConfig } from "./config";
|
|
2
|
+
export declare function extractAgentNameFromSessionTitle(sessionTitle: unknown): string;
|
|
3
|
+
export declare function shouldResolveAgentNameForEvent(config: NotifierConfig, eventType: EventType): boolean;
|
|
4
|
+
export declare function handleEvent(config: NotifierConfig, eventType: EventType, projectName: string | null, elapsedSeconds?: number | null, sessionTitle?: string | null, sessionID?: string | null, agentName?: string | null): Promise<void>;
|
package/dist/focus.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export declare function parseWezTermFocusedPaneId(output: string): string | null;
|
|
2
|
+
export declare function isGnomeLikeSession(env?: NodeJS.ProcessEnv): boolean;
|
|
3
|
+
export declare function getLinuxFocusBackendName(env?: NodeJS.ProcessEnv): string;
|
|
4
|
+
export declare function parseAtspiString(output: string | null): string | null;
|
|
5
|
+
export interface AtspiObjectRef {
|
|
6
|
+
bus: string;
|
|
7
|
+
path: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function parseAtspiObjectRefs(output: string | null): AtspiObjectRef[];
|
|
10
|
+
export declare function parseAtspiStateActive(output: string | null): boolean | null;
|
|
11
|
+
export declare function isAtspiTerminalWindow(appName: string | null, windowPath: string): boolean;
|
|
12
|
+
export declare function isAtspiWindowRoleAccepted(role: string | null): boolean;
|
|
13
|
+
export declare function getGnomeAtspiActiveWindowKey(): string | null;
|
|
14
|
+
export declare function debugFocusState(message: string): void;
|
|
15
|
+
export declare function buildOsascriptActivateAppArgs(appName: string): string[];
|
|
16
|
+
export declare function isMacTerminalAppFocused(frontmostAppName: string | null, env?: NodeJS.ProcessEnv): boolean;
|
|
17
|
+
export declare function getCachedWindowTitle(): string | null;
|
|
18
|
+
export declare function isTmuxPaneFocused(tmuxPane: string | null | undefined, probeResult: string | null): boolean;
|
|
19
|
+
export declare function isLinuxTerminalFocused(params: {
|
|
20
|
+
cachedWindowId: string | null;
|
|
21
|
+
currentWindowId: string | null;
|
|
22
|
+
wezTermPaneActive: boolean;
|
|
23
|
+
tmuxPaneActive: boolean | null;
|
|
24
|
+
}): boolean;
|
|
25
|
+
export declare function isWindowsTerminalFocused(params: {
|
|
26
|
+
className: string | null;
|
|
27
|
+
processName: string | null;
|
|
28
|
+
}): boolean;
|
|
29
|
+
export declare function isTerminalFocused(): boolean;
|
|
30
|
+
export declare function isKDEJumpBackSupported(): boolean;
|
|
31
|
+
export declare function findQdbusBinary(candidates?: readonly string[], isExecutable?: (name: string) => boolean): string | null;
|
|
32
|
+
export declare function resolveQdbusBinary(): string | null;
|
|
33
|
+
export declare function captureStartupWindowId(): void;
|
|
34
|
+
export declare function focusTerminal(): Promise<void>;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Plugin } from "@opencode-ai/plugin";
|
|
2
|
+
export { extractAgentNameFromSessionTitle } from "./delivery";
|
|
3
|
+
export { PERMISSION_PENDING_GRACE_MS } from "./notifier";
|
|
4
|
+
export declare function isCLIClient(clientEnv?: string): boolean;
|
|
5
|
+
export declare function getPermissionIDFromEvent(event: unknown): string | null;
|
|
6
|
+
export declare function isPermissionStillPending(client: unknown, permissionID: string): Promise<boolean>;
|
|
7
|
+
export declare const NotifierPlugin: Plugin;
|
|
8
|
+
declare const _default: {
|
|
9
|
+
id: string;
|
|
10
|
+
server: Plugin;
|
|
11
|
+
setup: (context: import("@opencode/plugin/promise/plugin").Context) => Promise<import("@opencode/plugin/promise/plugin").Cleanup | void> | import("@opencode/plugin/promise/plugin").Cleanup | void;
|
|
12
|
+
};
|
|
13
|
+
export default _default;
|