opencode-termux-notify 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.
Files changed (60) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/LICENSE +21 -0
  3. package/README.md +132 -0
  4. package/assets/audio/bip-bop-01.mp3 +0 -0
  5. package/assets/audio/bip-bop-03.mp3 +0 -0
  6. package/assets/audio/nope-03.mp3 +0 -0
  7. package/assets/audio/staplebops-06.mp3 +0 -0
  8. package/assets/audio/yup-01.mp3 +0 -0
  9. package/dist/audio.d.ts +4 -0
  10. package/dist/audio.d.ts.map +1 -0
  11. package/dist/audio.js +55 -0
  12. package/dist/audio.js.map +1 -0
  13. package/dist/config.d.ts +6 -0
  14. package/dist/config.d.ts.map +1 -0
  15. package/dist/config.js +47 -0
  16. package/dist/config.js.map +1 -0
  17. package/dist/constants.d.ts +17 -0
  18. package/dist/constants.d.ts.map +1 -0
  19. package/dist/constants.js +40 -0
  20. package/dist/constants.js.map +1 -0
  21. package/dist/dedup.d.ts +3 -0
  22. package/dist/dedup.d.ts.map +1 -0
  23. package/dist/dedup.js +57 -0
  24. package/dist/dedup.js.map +1 -0
  25. package/dist/env.d.ts +2 -0
  26. package/dist/env.d.ts.map +1 -0
  27. package/dist/env.js +4 -0
  28. package/dist/env.js.map +1 -0
  29. package/dist/events.d.ts +9 -0
  30. package/dist/events.d.ts.map +1 -0
  31. package/dist/events.js +52 -0
  32. package/dist/events.js.map +1 -0
  33. package/dist/index.d.ts +19 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +119 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/notify.d.ts +3 -0
  38. package/dist/notify.d.ts.map +1 -0
  39. package/dist/notify.js +23 -0
  40. package/dist/notify.js.map +1 -0
  41. package/dist/types.d.ts +37 -0
  42. package/dist/types.d.ts.map +1 -0
  43. package/dist/types.js +2 -0
  44. package/dist/types.js.map +1 -0
  45. package/dist/v1.d.ts +21 -0
  46. package/dist/v1.d.ts.map +1 -0
  47. package/dist/v1.js +133 -0
  48. package/dist/v1.js.map +1 -0
  49. package/index.js +4 -0
  50. package/package.json +80 -0
  51. package/src/audio.ts +50 -0
  52. package/src/config.ts +50 -0
  53. package/src/constants.ts +43 -0
  54. package/src/dedup.ts +58 -0
  55. package/src/env.ts +3 -0
  56. package/src/events.ts +58 -0
  57. package/src/index.ts +127 -0
  58. package/src/notify.ts +25 -0
  59. package/src/types.ts +39 -0
  60. package/src/v1.ts +140 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,28 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2026-09-04
9
+
10
+ ### Added
11
+ - Initial npm release, extracted from `~/.config/opencode/plugins/termux-notify`
12
+ - `Plugin.define` entrypoint using `@opencode-ai/plugin` (`^1.18.27`, `v2/promise`)
13
+ - Cross-instance deduplication via shared JSON file + stable `termux-notification --id`
14
+ - Per-session cooldown (5s), global throttle (1s), `event.id` TTL (60s) + `active`/`errored` tracking (mirrors `packages/tui/src/feature-plugins/system/notifications.ts:59-86`)
15
+ - Session-aware titles via `ctx.session.get` + `parentID` check for `subagent_done`
16
+ - 6 wired attention sounds (from `packages/tui/src/attention.ts:19-60` + `packages/ui/src/assets/audio/`):
17
+ - `default` → `bip-bop-01.mp3` (400,200,400)
18
+ - `question` → `bip-bop-03.mp3` (500,250,500) on `question.asked`/`v2`
19
+ - `permission` → `staplebops-06.mp3` (600,200,600) on `permission.asked`/`v2`
20
+ - `error` → `nope-03.mp3` (800,300,800,300,800)
21
+ - `done` → `bip-bop-01.mp3` (400,200,400)
22
+ - `subagent_done` → `yup-01.mp3` (200,100,200) — obeys `notifySubagents` (default true, `false` = sound-only like TUI)
23
+ - Bundled mp3 assets at `assets/audio/*.mp3` + playback via `termux-media-player play` (`termux-notification --sound` is boolean only — see `termux-notification -h`)
24
+ - Configurable via `opencode.json` `options`: `bin`, `mediaBin`, `sharedPath`, `seenTTL`, `sessionCooldown`, `globalCooldown`, `sound`, `playSound`, `vibrate`, `priority`, `requireTermux`, `kinds` (6), `notifySubagents`, `title_<kind>`/`content_<kind>`
25
+ - TypeScript source (`src/index.ts`) + runtime JS (`src/index.js`) + types (`src/index.d.ts`)
26
+ - Professional package scaffolding: README, LICENSE (MIT), CHANGELOG, `.gitignore`, `tsconfig.json`
27
+
28
+ [0.1.0]: https://github.com/Victozee26/opencode-termux-notify/releases/tag/v0.1.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 opencode-termux-notify contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,132 @@
1
+ # opencode-termux-notify
2
+
3
+ Termux notification plugin for [OpenCode](https://opencode.ai) on Android. Routes OpenCode attention events to `termux-notification` and `termux-media-player`. **Default is V1 (`opencode`), V2 (`opencode2`) via `opencode-termux-notify/v2`.**
4
+
5
+ [![npm version](https://img.shields.io/npm/v/opencode-termux-notify)](https://www.npmjs.com/package/opencode-termux-notify)
6
+ [![license](https://img.shields.io/npm/l/opencode-termux-notify)](./LICENSE)
7
+
8
+ ## Features
9
+
10
+ - 6 notification kinds (default, question, permission, error, done, subagent_done) with distinct vibration and audio via `termux-media-player` from Opencode
11
+ - Cross-instance deduplication via shared JSON file and stable notification IDs
12
+ - Spam prevention via event TTL (60s), per-session cooldown (5s), and global throttle (1s)
13
+ - Session-aware titles resolved from OpenCode session metadata
14
+ - Fully configurable: binaries, vibration, priority, cooldowns, kinds, and subagent handling
15
+
16
+ ## Requirements
17
+
18
+ - Android + Termux with `termux-api` (`pkg install termux-api` and install Termux:API app)
19
+ - Node >= 20, OpenCode >= 1.18.27
20
+
21
+ ## Install
22
+
23
+ **V1 (default) — `opencode` (1.18.27+):**
24
+
25
+ ```bash
26
+ opencode plugin opencode-termux-notify # latest
27
+ opencode plugin opencode-termux-notify -g # install globally instead of per-project
28
+ ```
29
+
30
+ Add to `opencode.json`:
31
+
32
+ ```jsonc
33
+ // ~/.config/opencode/opencode.json (V1: singular "plugin")
34
+ {
35
+ "$schema": "https://opencode.ai/config.json",
36
+ "plugin": ["opencode-termux-notify"]
37
+ }
38
+ ```
39
+
40
+ **V2 — `opencode2` (beta):**
41
+
42
+ ```bash
43
+ opencode2 plugin add opencode-termux-notify/v2
44
+ ```
45
+
46
+ Add to `opencode.jsonc` (`opencode.json(c)`):
47
+
48
+ ```jsonc
49
+ // ~/.config/opencode/opencode.jsonc (V2: plural "plugins")
50
+ {
51
+ "$schema": "https://opencode.ai/config.json",
52
+ "plugins": ["opencode-termux-notify/v2"]
53
+ }
54
+ ```
55
+
56
+ Local path (this repo) for V2 — must be a directory (`opencode.jsonc`):
57
+
58
+ ```jsonc
59
+ // opencode.jsonc
60
+ {
61
+ "plugins": ["/data/data/com.termux/files/home/opencode-termux-notify/v2"]
62
+ }
63
+ ```
64
+
65
+ ## Usage
66
+
67
+ With options (same for V1/V2, note `plugin` vs `plugins` and `opencode.json` vs `opencode.jsonc`):
68
+
69
+ ```jsonc
70
+ // V1 — opencode.json
71
+ {
72
+ "plugin": [["opencode-termux-notify", {
73
+ "kinds": ["question", "permission", "error", "done", "subagent_done"],
74
+ "notifySubagents": true,
75
+ "priority": "high"
76
+ }]]
77
+ }
78
+ // V2 — opencode.jsonc
79
+ {
80
+ "plugins": [{
81
+ "package": "opencode-termux-notify/v2",
82
+ "options": {
83
+ "kinds": ["question", "permission", "error", "done", "subagent_done"],
84
+ "notifySubagents": true,
85
+ "priority": "high"
86
+ }
87
+ }]
88
+ }
89
+ ```
90
+
91
+ Restart the opencode after editing config:
92
+
93
+ ```bash
94
+ opencode2 service restart
95
+ ```
96
+
97
+ Grant notification permission on Android 13+ under Settings > Apps > Termux > Notifications. Verify with:
98
+
99
+ ```bash
100
+ termux-notification --title test --content test --priority high --vibrate "400,200,400" --sound --id test
101
+ ```
102
+
103
+ ## Configuration
104
+
105
+ | Option | Type | Default | Description |
106
+ |---|---|---|---|
107
+ | `bin` | `string` | `/data/data/com.termux/files/usr/bin/termux-notification` | Notification binary |
108
+ | `mediaBin` | `string` | `/data/data/com.termux/files/usr/bin/termux-media-player` | Audio player binary |
109
+ | `sharedPath` | `string` | `os.tmpdir()/termux-notify-shared.json` | Deduplication file |
110
+ | `seenTTL` | `number` | `60000` | Event ID TTL (ms) |
111
+ | `sessionCooldown` | `number` | `5000` | Per-session debounce (ms) |
112
+ | `globalCooldown` | `number` | `1000` | Global throttle (ms) |
113
+ | `priority` | `string` | per-kind | Notification priority |
114
+ | `sound` | `boolean` | `true` | Enable sound |
115
+ | `playSound` | `boolean` | `true` | Play bundled mp3 |
116
+ | `vibrate` | `boolean` | `true` | Enable vibration |
117
+ | `requireTermux` | `boolean` | `true` | Warn if not in Termux |
118
+ | `kinds` | `string[]` | all kinds | Enabled event kinds |
119
+ | `notifySubagents` | `boolean` | `true` | Notify for subagents (false = sound only) |
120
+ | `title_<kind>` / `content_<kind>` | `string` | per-kind | Title/content override |
121
+
122
+ ## Development
123
+
124
+ ```bash
125
+ npm install
126
+ npm run typecheck
127
+ npm run build
128
+ ```
129
+
130
+ ## License
131
+
132
+ [MIT](./LICENSE)
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,4 @@
1
+ import type { ResolvedOpts } from "./types.js";
2
+ export declare function resolveAudioPath(file: string): string;
3
+ export declare function playAudio(soundName: string, opts: ResolvedOpts): Promise<void>;
4
+ //# sourceMappingURL=audio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgBrD;AAED,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBpF"}
package/dist/audio.js ADDED
@@ -0,0 +1,55 @@
1
+ import { existsSync } from "node:fs";
2
+ import { spawn } from "node:child_process";
3
+ import { join, dirname } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { SOUND_FILES } from "./constants.js";
6
+ export function resolveAudioPath(file) {
7
+ try {
8
+ const here = dirname(fileURLToPath(import.meta.url));
9
+ const candidates = [
10
+ join(here, "../assets/audio", file),
11
+ join(here, "assets/audio", file),
12
+ join(here, "../../assets/audio", file),
13
+ join(here, "../src/assets/audio", file),
14
+ join(process.cwd(), "assets/audio", file),
15
+ join(process.cwd(), "src/assets/audio", file),
16
+ ];
17
+ for (const p of candidates)
18
+ if (existsSync(p))
19
+ return p;
20
+ return candidates[0];
21
+ }
22
+ catch {
23
+ return file;
24
+ }
25
+ }
26
+ export async function playAudio(soundName, opts) {
27
+ if (!opts.playSound)
28
+ return;
29
+ const file = SOUND_FILES[soundName];
30
+ if (!file)
31
+ return;
32
+ const path = resolveAudioPath(file);
33
+ if (!existsSync(path)) {
34
+ console.warn(`[termux-notify] audio file not found: ${path} for ${soundName}`);
35
+ return;
36
+ }
37
+ const bin = existsSync(opts.mediaBin) ? opts.mediaBin : "termux-media-player";
38
+ await new Promise((resolve) => {
39
+ const p = spawn(bin, ["play", path], { stdio: "ignore" });
40
+ p.on("error", (err) => {
41
+ console.error(`[termux-notify] media play failed for ${soundName}:`, err.message);
42
+ resolve();
43
+ });
44
+ p.on("close", () => resolve());
45
+ setTimeout(() => {
46
+ try {
47
+ ;
48
+ p.unref?.();
49
+ }
50
+ catch { }
51
+ resolve();
52
+ }, 3000);
53
+ });
54
+ }
55
+ //# sourceMappingURL=audio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio.js","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAC1C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAG5C,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;QACpD,MAAM,UAAU,GAAG;YACjB,IAAI,CAAC,IAAI,EAAE,iBAAiB,EAAE,IAAI,CAAC;YACnC,IAAI,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,CAAC;YAChC,IAAI,CAAC,IAAI,EAAE,oBAAoB,EAAE,IAAI,CAAC;YACtC,IAAI,CAAC,IAAI,EAAE,qBAAqB,EAAE,IAAI,CAAC;YACvC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,IAAI,CAAC;YACzC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,kBAAkB,EAAE,IAAI,CAAC;SAC9C,CAAA;QACD,KAAK,MAAM,CAAC,IAAI,UAAU;YAAE,IAAI,UAAU,CAAC,CAAC,CAAC;gBAAE,OAAO,CAAC,CAAA;QACvD,OAAO,UAAU,CAAC,CAAC,CAAE,CAAA;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,SAAiB,EAAE,IAAkB;IACnE,IAAI,CAAC,IAAI,CAAC,SAAS;QAAE,OAAM;IAC3B,MAAM,IAAI,GAAG,WAAW,CAAC,SAAS,CAAC,CAAA;IACnC,IAAI,CAAC,IAAI;QAAE,OAAM;IACjB,MAAM,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAA;IACnC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,IAAI,CAAC,yCAAyC,IAAI,QAAQ,SAAS,EAAE,CAAC,CAAA;QAC9E,OAAM;IACR,CAAC;IACD,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,qBAAqB,CAAA;IAC7E,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAClC,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;QACzD,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACpB,OAAO,CAAC,KAAK,CAAC,yCAAyC,SAAS,GAAG,EAAG,GAAa,CAAC,OAAO,CAAC,CAAA;YAC5F,OAAO,EAAE,CAAA;QACX,CAAC,CAAC,CAAA;QACF,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAA;QAC9B,UAAU,CAAC,GAAG,EAAE;YACd,IAAI,CAAC;gBACH,CAAC;gBAAC,CAAS,CAAC,KAAK,EAAE,EAAE,CAAA;YACvB,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;YACV,OAAO,EAAE,CAAA;QACX,CAAC,EAAE,IAAI,CAAC,CAAA;IACV,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { ResolvedOpts, TermuxNotifyOptions } from "./types.js";
2
+ export declare function resolveOpts(userOpts: TermuxNotifyOptions): ResolvedOpts;
3
+ export declare function getEnabledKinds(userOpts: TermuxNotifyOptions): Set<string>;
4
+ export declare function getTitle(kind: string, sessionName: string, userOpts: TermuxNotifyOptions): string;
5
+ export declare function getContent(kind: string, userOpts: TermuxNotifyOptions): string;
6
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAEnE,wBAAgB,WAAW,CAAC,QAAQ,EAAE,mBAAmB,GAAG,YAAY,CAMvE;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,mBAAmB,GAAG,GAAG,CAAC,MAAM,CAAC,CAY1E;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,mBAAmB,GAAG,MAAM,CAWjG;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,mBAAmB,GAAG,MAAM,CAW9E"}
package/dist/config.js ADDED
@@ -0,0 +1,47 @@
1
+ import { DEFAULTS } from "./constants.js";
2
+ export function resolveOpts(userOpts) {
3
+ const opts = { ...DEFAULTS, ...userOpts };
4
+ if (typeof userOpts.sharedPath === "string" && userOpts.sharedPath.trim())
5
+ opts.sharedPath = userOpts.sharedPath;
6
+ if (typeof userOpts.bin === "string" && userOpts.bin.trim())
7
+ opts.bin = userOpts.bin;
8
+ if (typeof userOpts.mediaBin === "string" && userOpts.mediaBin.trim())
9
+ opts.mediaBin = userOpts.mediaBin;
10
+ return opts;
11
+ }
12
+ export function getEnabledKinds(userOpts) {
13
+ const enabledKinds = new Set(Array.isArray(userOpts.kinds) && userOpts.kinds.length
14
+ ? userOpts.kinds
15
+ : ["default", "question", "permission", "error", "done", "subagent_done"]);
16
+ if (enabledKinds.has("idle")) {
17
+ enabledKinds.delete("idle");
18
+ enabledKinds.add("done");
19
+ enabledKinds.add("default");
20
+ }
21
+ return enabledKinds;
22
+ }
23
+ export function getTitle(kind, sessionName, userOpts) {
24
+ const titles = {
25
+ default: `OpenCode — ${sessionName}`,
26
+ done: `OpenCode — ${sessionName}`,
27
+ subagent_done: `OpenCode (subagent) — ${sessionName}`,
28
+ question: `OpenCode question — ${sessionName}`,
29
+ permission: `OpenCode permission — ${sessionName}`,
30
+ error: `OpenCode error — ${sessionName}`,
31
+ };
32
+ const key = `title_${kind}`;
33
+ return typeof userOpts[key] === "string" ? userOpts[key] : titles[kind] || titles.default;
34
+ }
35
+ export function getContent(kind, userOpts) {
36
+ const contents = {
37
+ default: "Session finished",
38
+ done: "Session done",
39
+ subagent_done: "Subagent done",
40
+ question: "Question needs input",
41
+ permission: "Permission needs input",
42
+ error: "Session errored",
43
+ };
44
+ const key = `content_${kind}`;
45
+ return typeof userOpts[key] === "string" ? userOpts[key] : contents[kind] || contents.default;
46
+ }
47
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAGzC,MAAM,UAAU,WAAW,CAAC,QAA6B;IACvD,MAAM,IAAI,GAAiB,EAAE,GAAG,QAAQ,EAAE,GAAG,QAAQ,EAAkB,CAAA;IACvE,IAAI,OAAO,QAAQ,CAAC,UAAU,KAAK,QAAQ,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE;QAAE,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAA;IAChH,IAAI,OAAQ,QAAgB,CAAC,GAAG,KAAK,QAAQ,IAAK,QAAgB,CAAC,GAAG,CAAC,IAAI,EAAE;QAAE,IAAI,CAAC,GAAG,GAAI,QAAgB,CAAC,GAAG,CAAA;IAC/G,IAAI,OAAO,QAAQ,CAAC,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE;QAAE,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAA;IACxG,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAA6B;IAC3D,MAAM,YAAY,GAAG,IAAI,GAAG,CAC1B,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM;QACpD,CAAC,CAAE,QAAQ,CAAC,KAAkB;QAC9B,CAAC,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,eAAe,CAAC,CAC5E,CAAA;IACD,IAAI,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;QAC3B,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QACxB,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IAC7B,CAAC;IACD,OAAO,YAAY,CAAA;AACrB,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,WAAmB,EAAE,QAA6B;IACvF,MAAM,MAAM,GAA2B;QACrC,OAAO,EAAE,cAAc,WAAW,EAAE;QACpC,IAAI,EAAE,cAAc,WAAW,EAAE;QACjC,aAAa,EAAE,yBAAyB,WAAW,EAAE;QACrD,QAAQ,EAAE,uBAAuB,WAAW,EAAE;QAC9C,UAAU,EAAE,yBAAyB,WAAW,EAAE;QAClD,KAAK,EAAE,oBAAoB,WAAW,EAAE;KACzC,CAAA;IACD,MAAM,GAAG,GAAG,SAAS,IAAI,EAA+B,CAAA;IACxD,OAAO,OAAQ,QAAgB,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,QAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,OAAQ,CAAA;AAC9G,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,QAA6B;IACpE,MAAM,QAAQ,GAA2B;QACvC,OAAO,EAAE,kBAAkB;QAC3B,IAAI,EAAE,cAAc;QACpB,aAAa,EAAE,eAAe;QAC9B,QAAQ,EAAE,sBAAsB;QAChC,UAAU,EAAE,wBAAwB;QACpC,KAAK,EAAE,iBAAiB;KACzB,CAAA;IACD,MAAM,GAAG,GAAG,WAAW,IAAI,EAA+B,CAAA;IAC1D,OAAO,OAAQ,QAAgB,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,QAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,OAAQ,CAAA;AAClH,CAAC"}
@@ -0,0 +1,17 @@
1
+ export declare const SOUND_FILES: Record<string, string>;
2
+ export declare const VIBRATE_PATTERNS: Record<string, string>;
3
+ export declare const PRIORITY_BY_KIND: Record<string, string>;
4
+ export declare const DEFAULTS: {
5
+ bin: string;
6
+ mediaBin: string;
7
+ sharedPath: string;
8
+ seenTTL: number;
9
+ sessionCooldown: number;
10
+ globalCooldown: number;
11
+ sound: boolean;
12
+ playSound: boolean;
13
+ vibrate: boolean;
14
+ requireTermux: boolean;
15
+ priority: string | undefined;
16
+ };
17
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAO9C,CAAA;AAED,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAOnD,CAAA;AAED,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAOnD,CAAA;AAED,eAAO,MAAM,QAAQ;IACnB,GAAG;IACH,QAAQ;IACR,UAAU;IACV,OAAO;IACP,eAAe;IACf,cAAc;IACd,KAAK;IACL,SAAS;IACT,OAAO;IACP,aAAa;IACb,QAAQ,EAAe,MAAM,GAAG,SAAS;CAC1C,CAAA"}
@@ -0,0 +1,40 @@
1
+ import { tmpdir } from "node:os";
2
+ import { join } from "node:path";
3
+ export const SOUND_FILES = {
4
+ default: "bip-bop-01.mp3",
5
+ question: "bip-bop-03.mp3",
6
+ permission: "staplebops-06.mp3",
7
+ error: "nope-03.mp3",
8
+ done: "bip-bop-01.mp3",
9
+ subagent_done: "yup-01.mp3",
10
+ };
11
+ export const VIBRATE_PATTERNS = {
12
+ default: "400,200,400",
13
+ done: "400,200,400",
14
+ subagent_done: "200,100,200",
15
+ question: "500,250,500",
16
+ permission: "600,200,600",
17
+ error: "800,300,800,300,800",
18
+ };
19
+ export const PRIORITY_BY_KIND = {
20
+ default: "high",
21
+ done: "high",
22
+ subagent_done: "default",
23
+ question: "high",
24
+ permission: "high",
25
+ error: "high",
26
+ };
27
+ export const DEFAULTS = {
28
+ bin: "/data/data/com.termux/files/usr/bin/termux-notification",
29
+ mediaBin: "/data/data/com.termux/files/usr/bin/termux-media-player",
30
+ sharedPath: join(tmpdir(), "termux-notify-shared.json"),
31
+ seenTTL: 60_000,
32
+ sessionCooldown: 5_000,
33
+ globalCooldown: 1_000,
34
+ sound: true,
35
+ playSound: true,
36
+ vibrate: true,
37
+ requireTermux: true,
38
+ priority: undefined,
39
+ };
40
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,MAAM,CAAC,MAAM,WAAW,GAA2B;IACjD,OAAO,EAAE,gBAAgB;IACzB,QAAQ,EAAE,gBAAgB;IAC1B,UAAU,EAAE,mBAAmB;IAC/B,KAAK,EAAE,aAAa;IACpB,IAAI,EAAE,gBAAgB;IACtB,aAAa,EAAE,YAAY;CAC5B,CAAA;AAED,MAAM,CAAC,MAAM,gBAAgB,GAA2B;IACtD,OAAO,EAAE,aAAa;IACtB,IAAI,EAAE,aAAa;IACnB,aAAa,EAAE,aAAa;IAC5B,QAAQ,EAAE,aAAa;IACvB,UAAU,EAAE,aAAa;IACzB,KAAK,EAAE,qBAAqB;CAC7B,CAAA;AAED,MAAM,CAAC,MAAM,gBAAgB,GAA2B;IACtD,OAAO,EAAE,MAAM;IACf,IAAI,EAAE,MAAM;IACZ,aAAa,EAAE,SAAS;IACxB,QAAQ,EAAE,MAAM;IAChB,UAAU,EAAE,MAAM;IAClB,KAAK,EAAE,MAAM;CACd,CAAA;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,GAAG,EAAE,yDAAyD;IAC9D,QAAQ,EAAE,yDAAyD;IACnE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,2BAA2B,CAAC;IACvD,OAAO,EAAE,MAAM;IACf,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,KAAK;IACrB,KAAK,EAAE,IAAI;IACX,SAAS,EAAE,IAAI;IACf,OAAO,EAAE,IAAI;IACb,aAAa,EAAE,IAAI;IACnB,QAAQ,EAAE,SAA+B;CAC1C,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { ResolvedOpts } from "./types.js";
2
+ export declare function shouldNotifyShared(evtId: string, sessionKey: string, opts: ResolvedOpts): Promise<boolean>;
3
+ //# sourceMappingURL=dedup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dedup.d.ts","sourceRoot":"","sources":["../src/dedup.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAQ9C,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAgDhH"}
package/dist/dedup.js ADDED
@@ -0,0 +1,57 @@
1
+ import { readFile, writeFile, rename } from "node:fs/promises";
2
+ export async function shouldNotifyShared(evtId, sessionKey, opts) {
3
+ const now = Date.now();
4
+ let state = {
5
+ seen: {},
6
+ lastBySession: {},
7
+ lastGlobal: 0,
8
+ };
9
+ try {
10
+ const raw = await readFile(opts.sharedPath, "utf8");
11
+ state = JSON.parse(raw);
12
+ for (const [k, exp] of Object.entries(state.seen || {})) {
13
+ if (now > exp)
14
+ delete state.seen[k];
15
+ }
16
+ }
17
+ catch { }
18
+ state.seen ??= {};
19
+ state.lastBySession ??= {};
20
+ if (evtId && state.seen[evtId] && now < state.seen[evtId])
21
+ return false;
22
+ const lastForKey = state.lastBySession[sessionKey] || 0;
23
+ if (now - lastForKey < opts.sessionCooldown)
24
+ return false;
25
+ if (now - (state.lastGlobal || 0) < opts.globalCooldown)
26
+ return false;
27
+ if (evtId)
28
+ state.seen[evtId] = now + opts.seenTTL;
29
+ state.lastBySession[sessionKey] = now;
30
+ state.lastGlobal = now;
31
+ const seenKeys = Object.keys(state.seen);
32
+ if (seenKeys.length > 300) {
33
+ const sorted = seenKeys.sort((a, b) => state.seen[b] - state.seen[a]);
34
+ const keep = new Set(sorted.slice(0, 200));
35
+ for (const k of seenKeys)
36
+ if (!keep.has(k))
37
+ delete state.seen[k];
38
+ }
39
+ const sessionKeys = Object.keys(state.lastBySession);
40
+ if (sessionKeys.length > 200) {
41
+ const cutoff = now - opts.sessionCooldown * 4;
42
+ for (const k of sessionKeys)
43
+ if (state.lastBySession[k] < cutoff)
44
+ delete state.lastBySession[k];
45
+ }
46
+ try {
47
+ const tmp = opts.sharedPath + ".tmp." + process.pid;
48
+ await writeFile(tmp, JSON.stringify(state), "utf8");
49
+ await rename(tmp, opts.sharedPath);
50
+ }
51
+ catch (e) {
52
+ const msg = e instanceof Error ? e.message : String(e);
53
+ console.error("[termux-notify] shared state write failed:", msg);
54
+ }
55
+ return true;
56
+ }
57
+ //# sourceMappingURL=dedup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dedup.js","sourceRoot":"","sources":["../src/dedup.ts"],"names":[],"mappings":"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"}
package/dist/env.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function isTermuxEnvironment(): boolean;
2
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C"}
package/dist/env.js ADDED
@@ -0,0 +1,4 @@
1
+ export function isTermuxEnvironment() {
2
+ return Boolean(process.env.TERMUX_VERSION || process.env.PREFIX?.includes("com.termux"));
3
+ }
4
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,mBAAmB;IACjC,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAA;AAC1F,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { NotifyKind } from "./types.js";
2
+ export declare function classifyEvent(event: any, ctx: any): Promise<{
3
+ kind: NotifyKind;
4
+ sound: string;
5
+ sessionID: string;
6
+ evtId: string;
7
+ isSubagent: boolean;
8
+ } | null>;
9
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE5C,wBAAsB,aAAa,CACjC,KAAK,EAAE,GAAG,EACV,GAAG,EAAE,GAAG,GACP,OAAO,CAAC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAAC,CAoD5G"}
package/dist/events.js ADDED
@@ -0,0 +1,52 @@
1
+ export async function classifyEvent(event, ctx) {
2
+ const t = event?.type;
3
+ if (!t)
4
+ return null;
5
+ const sessionID = event.properties?.sessionID || event.data?.sessionID || event.sessionID || event.properties?.id || "global";
6
+ const evtId = event.id || event.eventID || `${t}:${sessionID}:${event.created || ""}:${event.properties?.id || event.properties?.requestID || ""}`;
7
+ if (t === "question.asked" || t === "question.v2.asked" || t === "question.updated" || t.startsWith("question")) {
8
+ return { kind: "question", sound: "question", sessionID, evtId, isSubagent: false };
9
+ }
10
+ if (t === "permission.asked" || t === "permission.v2.asked" || t.startsWith("permission")) {
11
+ return { kind: "permission", sound: "permission", sessionID, evtId, isSubagent: false };
12
+ }
13
+ if (t === "session.error" ||
14
+ t === "session.execution.failed" ||
15
+ t === "session.step.failed" ||
16
+ t === "error" ||
17
+ t.endsWith(".error")) {
18
+ return { kind: "error", sound: "error", sessionID, evtId, isSubagent: false };
19
+ }
20
+ if (t === "session.status" && event.properties?.status?.type === "idle") {
21
+ let isSubagent = false;
22
+ try {
23
+ if (ctx?.session?.get) {
24
+ const info = await ctx.session.get({ sessionID });
25
+ const raw = info?.info || info?.data || info;
26
+ isSubagent = Boolean(raw?.parentID || raw?.parentId || raw?.parent);
27
+ }
28
+ }
29
+ catch { }
30
+ if (!isSubagent && event.properties?.parentID)
31
+ isSubagent = true;
32
+ const sound = isSubagent ? "subagent_done" : "done";
33
+ const kind = isSubagent ? "subagent_done" : "done";
34
+ return { kind, sound, sessionID, evtId, isSubagent };
35
+ }
36
+ if (t === "session.idle" || t === "session.execution.succeeded") {
37
+ let isSubagent = false;
38
+ try {
39
+ if (ctx?.session?.get) {
40
+ const info = await ctx.session.get({ sessionID });
41
+ const raw = info?.info || info?.data || info;
42
+ isSubagent = Boolean(raw?.parentID || raw?.parentId);
43
+ }
44
+ }
45
+ catch { }
46
+ const sound = isSubagent ? "subagent_done" : "done";
47
+ const kind = isSubagent ? "subagent_done" : "done";
48
+ return { kind, sound, sessionID, evtId, isSubagent };
49
+ }
50
+ return null;
51
+ }
52
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * opencode-termux-notify — Termux-native notifications for OpenCode (V2)
3
+ *
4
+ * 6 builtin attention sounds:
5
+ * default → bip-bop-01.mp3
6
+ * question → bip-bop-03.mp3
7
+ * permission → staplebops-06.mp3
8
+ * error → nope-03.mp3
9
+ * done → bip-bop-01.mp3
10
+ * subagent_done → yup-01.mp3
11
+ *
12
+ * Audio bundled at assets/audio/*.mp3, played via `termux-media-player play <file>`
13
+ * (termux-notification --sound is boolean only — no file arg)
14
+ */
15
+ export type { TermuxNotifyOptions } from "./types.js";
16
+ export { DEFAULTS, PRIORITY_BY_KIND, SOUND_FILES, VIBRATE_PATTERNS } from "./constants.js";
17
+ declare const _default: import("@opencode-ai/plugin/v2/promise").Plugin;
18
+ export default _default;
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAWH,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AACrD,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA"}