@pranjalmandavkar/opencode-notifier 0.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.
package/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # @pranjalmandavkar/opencode-notifier
2
+
3
+ To install dependencies:
4
+
5
+ ```bash
6
+ bun install
7
+ ```
8
+
9
+ To run:
10
+
11
+ ```bash
12
+ bun run src/index.ts
13
+ ```
14
+
15
+ This project was created using `bun init` in bun v1.3.5. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
package/bun.lock ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "lockfileVersion": 1,
3
+ "configVersion": 1,
4
+ "workspaces": {
5
+ "": {
6
+ "name": "@pranjalmandavkar/opencode-notifier",
7
+ "dependencies": {
8
+ "node-notifier": "^10.0.1",
9
+ },
10
+ "devDependencies": {
11
+ "@opencode-ai/plugin": "^1.1.25",
12
+ "@types/bun": "latest",
13
+ "@types/node": "^25.0.9",
14
+ "@types/node-notifier": "^8.0.5",
15
+ },
16
+ "peerDependencies": {
17
+ "@opencode-ai/plugin": "^1.1.25",
18
+ },
19
+ },
20
+ },
21
+ "packages": {
22
+ "@opencode-ai/plugin": ["@opencode-ai/plugin@1.1.25", "", { "dependencies": { "@opencode-ai/sdk": "1.1.25", "zod": "4.1.8" } }, "sha512-oTUWS446H/j7z3pdzo3cOrB5N87XZ/RKdgPD8yHv/rLX92B4YQHjOqggVQ56Q+1VEnN0jxzhoqRylv/0ZEts/Q=="],
23
+
24
+ "@opencode-ai/sdk": ["@opencode-ai/sdk@1.1.25", "", {}, "sha512-mWUX489ArEF2ICg3iZsx2VQaGS3Z2j/dwAJDacao9t7dGDzjOIaacPw2weZ10zld7XmT9V9C0PM/A5lDZ52J+w=="],
25
+
26
+ "@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="],
27
+
28
+ "@types/node": ["@types/node@25.0.9", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw=="],
29
+
30
+ "@types/node-notifier": ["@types/node-notifier@8.0.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-LX7+8MtTsv6szumAp6WOy87nqMEdGhhry/Qfprjm1Ma6REjVzeF7SCyvPtp5RaF6IkXCS9V4ra8g5fwvf2ZAYg=="],
31
+
32
+ "bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="],
33
+
34
+ "growly": ["growly@1.3.0", "", {}, "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw=="],
35
+
36
+ "is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="],
37
+
38
+ "is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="],
39
+
40
+ "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
41
+
42
+ "node-notifier": ["node-notifier@10.0.1", "", { "dependencies": { "growly": "^1.3.0", "is-wsl": "^2.2.0", "semver": "^7.3.5", "shellwords": "^0.1.1", "uuid": "^8.3.2", "which": "^2.0.2" } }, "sha512-YX7TSyDukOZ0g+gmzjB6abKu+hTGvO8+8+gIFDsRCU2t8fLV/P2unmt+LGFaIa4y64aX98Qksa97rgz4vMNeLQ=="],
43
+
44
+ "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
45
+
46
+ "shellwords": ["shellwords@0.1.1", "", {}, "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww=="],
47
+
48
+ "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
49
+
50
+ "uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="],
51
+
52
+ "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
53
+
54
+ "zod": ["zod@4.1.8", "", {}, "sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ=="],
55
+ }
56
+ }
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ // src/index.ts
2
+ console.log("Hello via Bun!");
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@pranjalmandavkar/opencode-notifier",
3
+ "version": "0.1.0",
4
+ "description": "Opencode Plugin that sends system notification when permission is needed, generation is complete or error occurs in session",
5
+ "author": "MandavkarPranjal",
6
+ "license": "MIT",
7
+ "module": "src/index.ts",
8
+ "main": "dist/index.js",
9
+ "types": "dist/index.d.ts",
10
+ "type": "module",
11
+ "keywords": [
12
+ "opencode",
13
+ "opencode-plugin",
14
+ "notification",
15
+ "alerts"
16
+ ],
17
+ "scripts": {
18
+ "build": "bun build src/index.ts --outdir dist --target node",
19
+ "typecheck": "tsc --noEmit",
20
+ "release:patch": "npm run build && npm version patch && npm publish --access public",
21
+ "release:minor": "npm run build && npm version minor && npm publish --access public",
22
+ "release:major": "npm run build && npm version major && npm publish --access public"
23
+ },
24
+ "devDependencies": {
25
+ "@opencode-ai/plugin": "^1.1.25",
26
+ "@types/bun": "latest",
27
+ "@types/node": "^25.0.9",
28
+ "@types/node-notifier": "^8.0.5"
29
+ },
30
+ "peerDependencies": {
31
+ "@opencode-ai/plugin": "^1.1.25"
32
+ },
33
+ "dependencies": {
34
+ "node-notifier": "^10.0.1"
35
+ }
36
+ }
package/src/config.ts ADDED
@@ -0,0 +1,122 @@
1
+ import { readFileSync, existsSync } from "fs"
2
+ import { join } from "path"
3
+ import { homedir } from "os"
4
+
5
+ export type EventType = "permission" | "complete" | "error" | "question"
6
+
7
+ export interface EventConfig {
8
+ notification: boolean
9
+ }
10
+
11
+ export interface NotifierConfig {
12
+ notification: boolean
13
+ timeout: number
14
+ showProjectName: boolean
15
+ events: {
16
+ permission: EventConfig
17
+ complete: EventConfig
18
+ error: EventConfig
19
+ question: EventConfig
20
+ }
21
+ messages: {
22
+ permission: string
23
+ complete: string
24
+ error: string
25
+ question: string
26
+ }
27
+ }
28
+
29
+ const DEFAULT_EVENT_CONFIG: EventConfig = {
30
+ notification: true,
31
+ }
32
+
33
+ const DEFAULT_CONFIG: NotifierConfig = {
34
+ notification: true,
35
+ timeout: 5,
36
+ showProjectName: true,
37
+ events: {
38
+ permission: { ...DEFAULT_EVENT_CONFIG },
39
+ complete: { ...DEFAULT_EVENT_CONFIG },
40
+ error: { ...DEFAULT_EVENT_CONFIG },
41
+ question: { ...DEFAULT_EVENT_CONFIG },
42
+ },
43
+ messages: {
44
+ permission: "Session needs permission",
45
+ complete: "Session has finished",
46
+ error: "Session encountered an error",
47
+ question: "Session has a question",
48
+ },
49
+ }
50
+
51
+ function getConfigPath(): string {
52
+ return join(homedir(), ".config", "opencode", "opencode-notifier.json")
53
+ }
54
+
55
+ function parseEventConfig(
56
+ userEvent: boolean | { notification?: boolean } | undefined,
57
+ defaultConfig: EventConfig
58
+ ): EventConfig {
59
+ if (userEvent === undefined) {
60
+ return defaultConfig
61
+ }
62
+
63
+ if (typeof userEvent === "boolean") {
64
+ return {
65
+ notification: userEvent,
66
+ }
67
+ }
68
+
69
+ return {
70
+ notification: userEvent.notification ?? defaultConfig.notification,
71
+ }
72
+ }
73
+
74
+ export function loadConfig(): NotifierConfig {
75
+ const configPath = getConfigPath()
76
+
77
+ if (!existsSync(configPath)) {
78
+ return DEFAULT_CONFIG
79
+ }
80
+
81
+ try {
82
+ const fileContent = readFileSync(configPath, "utf-8")
83
+ const userConfig = JSON.parse(fileContent)
84
+
85
+ const globalNotification = userConfig.notification ?? DEFAULT_CONFIG.notification
86
+
87
+ const defaultWithGlobal: EventConfig = {
88
+ notification: globalNotification,
89
+ }
90
+
91
+ return {
92
+ notification: globalNotification,
93
+ timeout:
94
+ typeof userConfig.timeout === "number" && userConfig.timeout > 0
95
+ ? userConfig.timeout
96
+ : DEFAULT_CONFIG.timeout,
97
+ showProjectName: userConfig.showProjectName ?? DEFAULT_CONFIG.showProjectName,
98
+ events: {
99
+ permission: parseEventConfig(userConfig.events?.permission ?? userConfig.permission, defaultWithGlobal),
100
+ complete: parseEventConfig(userConfig.events?.complete ?? userConfig.complete, defaultWithGlobal),
101
+ error: parseEventConfig(userConfig.events?.error ?? userConfig.error, defaultWithGlobal),
102
+ question: parseEventConfig(userConfig.events?.question ?? userConfig.question, defaultWithGlobal),
103
+ },
104
+ messages: {
105
+ permission: userConfig.messages?.permission ?? DEFAULT_CONFIG.messages.permission,
106
+ complete: userConfig.messages?.complete ?? DEFAULT_CONFIG.messages.complete,
107
+ error: userConfig.messages?.error ?? DEFAULT_CONFIG.messages.error,
108
+ question: userConfig.messages?.question ?? DEFAULT_CONFIG.messages.question,
109
+ },
110
+ }
111
+ } catch {
112
+ return DEFAULT_CONFIG
113
+ }
114
+ }
115
+
116
+ export function isEventNotificationEnabled(config: NotifierConfig, event: EventType): boolean {
117
+ return config.events[event].notification
118
+ }
119
+
120
+ export function getMessage(config: NotifierConfig, event: EventType): string {
121
+ return config.messages[event]
122
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ console.log("Hello via Bun!");
package/src/notify.ts ADDED
File without changes
package/tsconfig.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "compilerOptions": {
3
+ // Environment setup & latest features
4
+ "lib": ["ESNext"],
5
+ "target": "ESNext",
6
+ "module": "Preserve",
7
+ "moduleDetection": "force",
8
+ "jsx": "react-jsx",
9
+ "allowJs": true,
10
+
11
+ // Bundler mode
12
+ "moduleResolution": "bundler",
13
+ "allowImportingTsExtensions": true,
14
+ "verbatimModuleSyntax": true,
15
+ "noEmit": true,
16
+
17
+ // Best practices
18
+ "strict": true,
19
+ "skipLibCheck": true,
20
+ "noFallthroughCasesInSwitch": true,
21
+ "noUncheckedIndexedAccess": true,
22
+ "noImplicitOverride": true,
23
+
24
+ // Some stricter flags (disabled by default)
25
+ "noUnusedLocals": false,
26
+ "noUnusedParameters": false,
27
+ "noPropertyAccessFromIndexSignature": false
28
+ }
29
+ }