claude-pager 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/LICENSE +21 -0
- package/README.md +207 -0
- package/dist/channels/channel.d.ts +27 -0
- package/dist/channels/channel.d.ts.map +1 -0
- package/dist/channels/channel.js +3 -0
- package/dist/channels/channel.js.map +1 -0
- package/dist/channels/factory.d.ts +4 -0
- package/dist/channels/factory.d.ts.map +1 -0
- package/dist/channels/factory.js +22 -0
- package/dist/channels/factory.js.map +1 -0
- package/dist/channels/ntfy/__tests__/provider.test.d.ts +2 -0
- package/dist/channels/ntfy/__tests__/provider.test.d.ts.map +1 -0
- package/dist/channels/ntfy/__tests__/provider.test.js +29 -0
- package/dist/channels/ntfy/__tests__/provider.test.js.map +1 -0
- package/dist/channels/ntfy/provider.d.ts +17 -0
- package/dist/channels/ntfy/provider.d.ts.map +1 -0
- package/dist/channels/ntfy/provider.js +142 -0
- package/dist/channels/ntfy/provider.js.map +1 -0
- package/dist/channels/telegram/provider.d.ts +27 -0
- package/dist/channels/telegram/provider.d.ts.map +1 -0
- package/dist/channels/telegram/provider.js +312 -0
- package/dist/channels/telegram/provider.js.map +1 -0
- package/dist/channels/telegram/voice-handler.d.ts +22 -0
- package/dist/channels/telegram/voice-handler.d.ts.map +1 -0
- package/dist/channels/telegram/voice-handler.js +68 -0
- package/dist/channels/telegram/voice-handler.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +99 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/recover.d.ts +2 -0
- package/dist/cli/recover.d.ts.map +1 -0
- package/dist/cli/recover.js +45 -0
- package/dist/cli/recover.js.map +1 -0
- package/dist/cli/run.d.ts +2 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +32 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/cli/setup.d.ts +8 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +238 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/config/index.d.ts +6 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +40 -0
- package/dist/config/index.js.map +1 -0
- package/dist/daemon/__tests__/handlers.test.d.ts +2 -0
- package/dist/daemon/__tests__/handlers.test.d.ts.map +1 -0
- package/dist/daemon/__tests__/handlers.test.js +99 -0
- package/dist/daemon/__tests__/handlers.test.js.map +1 -0
- package/dist/daemon/__tests__/server.test.d.ts +2 -0
- package/dist/daemon/__tests__/server.test.d.ts.map +1 -0
- package/dist/daemon/__tests__/server.test.js +118 -0
- package/dist/daemon/__tests__/server.test.js.map +1 -0
- package/dist/daemon/handlers.d.ts +4 -0
- package/dist/daemon/handlers.d.ts.map +1 -0
- package/dist/daemon/handlers.js +153 -0
- package/dist/daemon/handlers.js.map +1 -0
- package/dist/daemon/index.d.ts +7 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +83 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/server.d.ts +11 -0
- package/dist/daemon/server.d.ts.map +1 -0
- package/dist/daemon/server.js +115 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +172 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/injectors/__tests__/tmux.test.d.ts +2 -0
- package/dist/injectors/__tests__/tmux.test.d.ts.map +1 -0
- package/dist/injectors/__tests__/tmux.test.js +38 -0
- package/dist/injectors/__tests__/tmux.test.js.map +1 -0
- package/dist/injectors/factory.d.ts +3 -0
- package/dist/injectors/factory.d.ts.map +1 -0
- package/dist/injectors/factory.js +22 -0
- package/dist/injectors/factory.js.map +1 -0
- package/dist/injectors/injector.d.ts +7 -0
- package/dist/injectors/injector.d.ts.map +1 -0
- package/dist/injectors/injector.js +3 -0
- package/dist/injectors/injector.js.map +1 -0
- package/dist/injectors/tmux/injector.d.ts +9 -0
- package/dist/injectors/tmux/injector.d.ts.map +1 -0
- package/dist/injectors/tmux/injector.js +55 -0
- package/dist/injectors/tmux/injector.js.map +1 -0
- package/dist/injectors/xdotool/injector.d.ts +9 -0
- package/dist/injectors/xdotool/injector.d.ts.map +1 -0
- package/dist/injectors/xdotool/injector.js +59 -0
- package/dist/injectors/xdotool/injector.js.map +1 -0
- package/dist/sessions/__tests__/events.test.d.ts +2 -0
- package/dist/sessions/__tests__/events.test.d.ts.map +1 -0
- package/dist/sessions/__tests__/events.test.js +103 -0
- package/dist/sessions/__tests__/events.test.js.map +1 -0
- package/dist/sessions/__tests__/tracker.test.d.ts +2 -0
- package/dist/sessions/__tests__/tracker.test.d.ts.map +1 -0
- package/dist/sessions/__tests__/tracker.test.js +24 -0
- package/dist/sessions/__tests__/tracker.test.js.map +1 -0
- package/dist/sessions/events.d.ts +11 -0
- package/dist/sessions/events.d.ts.map +1 -0
- package/dist/sessions/events.js +73 -0
- package/dist/sessions/events.js.map +1 -0
- package/dist/sessions/tracker.d.ts +7 -0
- package/dist/sessions/tracker.d.ts.map +1 -0
- package/dist/sessions/tracker.js +83 -0
- package/dist/sessions/tracker.js.map +1 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/__tests__/html.test.d.ts +2 -0
- package/dist/utils/__tests__/html.test.d.ts.map +1 -0
- package/dist/utils/__tests__/html.test.js +42 -0
- package/dist/utils/__tests__/html.test.js.map +1 -0
- package/dist/utils/__tests__/json.test.d.ts +2 -0
- package/dist/utils/__tests__/json.test.d.ts.map +1 -0
- package/dist/utils/__tests__/json.test.js +27 -0
- package/dist/utils/__tests__/json.test.js.map +1 -0
- package/dist/utils/__tests__/validation.test.d.ts +2 -0
- package/dist/utils/__tests__/validation.test.d.ts.map +1 -0
- package/dist/utils/__tests__/validation.test.js +38 -0
- package/dist/utils/__tests__/validation.test.js.map +1 -0
- package/dist/utils/html.d.ts +3 -0
- package/dist/utils/html.d.ts.map +1 -0
- package/dist/utils/html.js +43 -0
- package/dist/utils/html.js.map +1 -0
- package/dist/utils/json.d.ts +2 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/json.js +13 -0
- package/dist/utils/json.js.map +1 -0
- package/dist/utils/validation.d.ts +4 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +16 -0
- package/dist/utils/validation.js.map +1 -0
- package/dist/voice/transcribe.d.ts +7 -0
- package/dist/voice/transcribe.d.ts.map +1 -0
- package/dist/voice/transcribe.js +66 -0
- package/dist/voice/transcribe.js.map +1 -0
- package/package.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Seb Bassompierre / KASEI LABS
|
|
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,207 @@
|
|
|
1
|
+
# claude-pager
|
|
2
|
+
|
|
3
|
+
Relay notifications and responses between Claude Code CLI sessions and your phone. When Claude needs your input (permission prompt, idle question) and you're away from the terminal, `claude-pager` sends a notification to your phone and types your response back into the correct tmux pane.
|
|
4
|
+
|
|
5
|
+
## How it works
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
┌─────────────┐ hook → HTTP ┌──────────────┐ Telegram / ntfy ┌──────────┐
|
|
9
|
+
│ Claude Code │ ────────────────► │ claude-pager │ ──────────────────► │ Phone │
|
|
10
|
+
│ (N instances)│ │ daemon │ ◄────────────────── │ (reply) │
|
|
11
|
+
└─────────────┘ └──────┬───────┘ └──────────┘
|
|
12
|
+
│ tmux send-keys
|
|
13
|
+
▼
|
|
14
|
+
┌──────────────┐
|
|
15
|
+
│ Right terminal│
|
|
16
|
+
└──────────────┘
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
1. Claude Code hooks fire when an instance needs user input
|
|
20
|
+
2. The hook enriches the event (tool name, last assistant message) and sends it to the daemon
|
|
21
|
+
3. The daemon dispatches a notification to your phone via Telegram or ntfy
|
|
22
|
+
4. You respond — tap Allow/Deny, type a message, or send a voice note
|
|
23
|
+
5. The daemon matches the response to the right session and injects it via `tmux send-keys`
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- **Multi-session** — run N Claude Code instances in tmux, responses route to the correct pane
|
|
28
|
+
- **Telegram** — inline keyboards (Allow/Deny), reply-to-message routing, voice transcription (Whisper)
|
|
29
|
+
- **ntfy** — self-hosted or ntfy.sh, mobile push notifications
|
|
30
|
+
- **Session recovery** — `claude-pager recover` detects existing Claude sessions in tmux
|
|
31
|
+
- **Smart routing** — `#id response` for explicit targeting, auto-route for single session, session picker for ambiguous cases
|
|
32
|
+
- **Fallback by project** — if a session UUID is no longer registered, matches by `cwd` (project directory)
|
|
33
|
+
|
|
34
|
+
## Requirements
|
|
35
|
+
|
|
36
|
+
- Node.js >= 20
|
|
37
|
+
- tmux
|
|
38
|
+
- Linux (macOS support planned)
|
|
39
|
+
- A Telegram bot or ntfy server for notifications
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install -g claude-pager
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Setup
|
|
48
|
+
|
|
49
|
+
Interactive configuration — creates `~/.claude-pager/config.json` and installs Claude Code hooks in `~/.claude/settings.json`:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
claude-pager setup
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The setup wizard lets you choose between **Telegram** and **ntfy** as notification channel, and verifies the connection.
|
|
56
|
+
|
|
57
|
+
### Telegram
|
|
58
|
+
|
|
59
|
+
You need a Telegram bot token (from [@BotFather](https://t.me/BotFather)) and a chat ID. The setup command walks you through obtaining both.
|
|
60
|
+
|
|
61
|
+
### ntfy
|
|
62
|
+
|
|
63
|
+
Point to your ntfy server (self-hosted or `https://ntfy.sh`) with a topic and optional authentication (user/password or token).
|
|
64
|
+
|
|
65
|
+
## Usage
|
|
66
|
+
|
|
67
|
+
### Start the daemon
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Foreground (for testing)
|
|
71
|
+
claude-pager start
|
|
72
|
+
|
|
73
|
+
# As a systemd user service (recommended)
|
|
74
|
+
cat > ~/.config/systemd/user/claude-pager.service << 'EOF'
|
|
75
|
+
[Unit]
|
|
76
|
+
Description=Claude Code Relay Daemon
|
|
77
|
+
After=network-online.target
|
|
78
|
+
Wants=network-online.target
|
|
79
|
+
|
|
80
|
+
[Service]
|
|
81
|
+
Type=simple
|
|
82
|
+
ExecStart=%h/.local/bin/claude-pager start
|
|
83
|
+
ExecStop=%h/.local/bin/claude-pager stop
|
|
84
|
+
Restart=on-failure
|
|
85
|
+
RestartSec=5
|
|
86
|
+
Environment=NODE_ENV=production
|
|
87
|
+
|
|
88
|
+
[Install]
|
|
89
|
+
WantedBy=default.target
|
|
90
|
+
EOF
|
|
91
|
+
# If claude-pager is installed via nvm, adjust ExecStart path:
|
|
92
|
+
# ExecStart=/home/you/.nvm/versions/node/v22.x.x/bin/claude-pager start
|
|
93
|
+
systemctl --user daemon-reload
|
|
94
|
+
systemctl --user enable --now claude-pager
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Launch Claude Code in tmux
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
claude-pager run # opens a new tmux session with claude
|
|
101
|
+
claude-pager run --resume # pass args through to claude
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Or just run `claude` directly inside tmux — the `SessionStart` hook registers the session automatically.
|
|
105
|
+
|
|
106
|
+
### Recover existing sessions
|
|
107
|
+
|
|
108
|
+
If you already have Claude Code running in tmux panes:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
claude-pager recover
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Other commands
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
claude-pager status # daemon status + health check
|
|
118
|
+
claude-pager pending # list pending questions
|
|
119
|
+
claude-pager stop # stop the daemon
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Responding to notifications
|
|
123
|
+
|
|
124
|
+
### Telegram
|
|
125
|
+
|
|
126
|
+
- **Permission prompts** — tap the inline **Allow** or **Deny** button
|
|
127
|
+
- **Idle prompts** — reply to the notification message with your answer
|
|
128
|
+
- **Voice** — send a voice message, it gets transcribed and injected
|
|
129
|
+
- **Free messages** — send a message without replying; if one session is active it goes there, otherwise a session picker appears
|
|
130
|
+
|
|
131
|
+
### ntfy
|
|
132
|
+
|
|
133
|
+
- Reply with `#<id> <response>` to target a specific notification
|
|
134
|
+
- If only one question is pending, any reply routes to it
|
|
135
|
+
- `allow` / `deny` auto-route to the most recent permission prompt
|
|
136
|
+
|
|
137
|
+
## Configuration
|
|
138
|
+
|
|
139
|
+
`~/.claude-pager/config.json`:
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"port": 17380,
|
|
144
|
+
"channel": {
|
|
145
|
+
"type": "telegram",
|
|
146
|
+
"telegram": {
|
|
147
|
+
"botToken": "123456:ABC...",
|
|
148
|
+
"chatId": 12345678
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
"injector": "auto"
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
| Key | Default | Description |
|
|
156
|
+
|-----|---------|-------------|
|
|
157
|
+
| `port` | `17380` | Daemon HTTP port (localhost only) |
|
|
158
|
+
| `channel.type` | `"ntfy"` | `"ntfy"` or `"telegram"` |
|
|
159
|
+
| `injector` | `"auto"` | `"auto"`, `"tmux"`, or `"xdotool"` |
|
|
160
|
+
|
|
161
|
+
The hook port can be overridden with `CLAUDE_PAGER_PORT` environment variable.
|
|
162
|
+
|
|
163
|
+
## Architecture
|
|
164
|
+
|
|
165
|
+
Strategy + Factory pattern for pluggable components:
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
src/
|
|
169
|
+
├── channels/ # Notification channels (ntfy, telegram)
|
|
170
|
+
│ ├── channel.ts # ChannelProvider interface
|
|
171
|
+
│ └── factory.ts
|
|
172
|
+
├── injectors/ # Terminal input injection (tmux, xdotool)
|
|
173
|
+
│ ├── injector.ts # InputInjector interface
|
|
174
|
+
│ └── factory.ts
|
|
175
|
+
├── daemon/ # HTTP server + response routing
|
|
176
|
+
│ ├── server.ts # Fastify routes with JSON Schema validation
|
|
177
|
+
│ └── handlers.ts # Channel listener logic (routing, picker)
|
|
178
|
+
├── sessions/ # Session tracking + pending question store
|
|
179
|
+
├── hooks/ # Claude Code hook entry point
|
|
180
|
+
├── utils/ # Shared utilities (html, json, validation)
|
|
181
|
+
├── cli/ # Commander CLI
|
|
182
|
+
└── voice/ # Telegram voice transcription (Whisper)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
See `docs/ARCHITECTURE.md` for the detailed flow.
|
|
186
|
+
|
|
187
|
+
## Security
|
|
188
|
+
|
|
189
|
+
- HTTP API binds to `127.0.0.1` only — no network exposure
|
|
190
|
+
- Input validation with Fastify JSON Schema + custom validators (`isValidEventType`, `isValidSessionId`)
|
|
191
|
+
- No shell injection — all child processes use `execFileSync` with argument arrays
|
|
192
|
+
- No code content in notifications — only tool names, project names, and question types
|
|
193
|
+
- Memory-bounded maps (capped at 500-1000 entries)
|
|
194
|
+
- Safe JSON parsing with fallbacks for corrupted files
|
|
195
|
+
|
|
196
|
+
## Development
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
npm run build # TypeScript compilation
|
|
200
|
+
npm test # Run all tests (node:test)
|
|
201
|
+
npm run lint # ESLint with typescript-eslint
|
|
202
|
+
npm run dev # Dev mode (tsx watch)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## License
|
|
206
|
+
|
|
207
|
+
MIT
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { RelayEvent } from '../types.js';
|
|
2
|
+
export interface NotificationResult {
|
|
3
|
+
messageId?: string;
|
|
4
|
+
success: boolean;
|
|
5
|
+
error?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface FreeMessage {
|
|
8
|
+
text: string;
|
|
9
|
+
sessionId?: string;
|
|
10
|
+
replyCallback: (text: string) => Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export interface ChannelListeners {
|
|
13
|
+
onResponse: (rawText: string) => void | Promise<void>;
|
|
14
|
+
onFreeMessage?: (msg: FreeMessage) => void | Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export interface ChannelProvider {
|
|
17
|
+
readonly name: string;
|
|
18
|
+
send(event: RelayEvent, shortId: string): Promise<NotificationResult>;
|
|
19
|
+
sendRaw?(text: string): Promise<void>;
|
|
20
|
+
sendSessionPicker?(text: string, sessions: Array<{
|
|
21
|
+
id: string;
|
|
22
|
+
label: string;
|
|
23
|
+
}>): Promise<number | undefined>;
|
|
24
|
+
startListening(listeners: ChannelListeners): void;
|
|
25
|
+
stopListening(): void;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=channel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../src/channels/channel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAEtE,OAAO,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtC,iBAAiB,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAE9G,cAAc,CAAC,SAAS,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAElD,aAAa,IAAI,IAAI,CAAC;CACvB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.js","sourceRoot":"","sources":["../../src/channels/channel.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/channels/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAIpD,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,eAAe,CAepE"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createChannel = createChannel;
|
|
4
|
+
const provider_js_1 = require("./ntfy/provider.js");
|
|
5
|
+
const provider_js_2 = require("./telegram/provider.js");
|
|
6
|
+
function createChannel(config) {
|
|
7
|
+
switch (config.type) {
|
|
8
|
+
case 'ntfy':
|
|
9
|
+
if (!config.ntfy) {
|
|
10
|
+
throw new Error('ntfy configuration is required when channel type is "ntfy"');
|
|
11
|
+
}
|
|
12
|
+
return new provider_js_1.NtfyProvider(config.ntfy);
|
|
13
|
+
case 'telegram':
|
|
14
|
+
if (!config.telegram) {
|
|
15
|
+
throw new Error('telegram configuration is required when channel type is "telegram"');
|
|
16
|
+
}
|
|
17
|
+
return new provider_js_2.TelegramProvider(config.telegram);
|
|
18
|
+
default:
|
|
19
|
+
throw new Error(`Unknown channel type: ${config.type}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/channels/factory.ts"],"names":[],"mappings":";;AAKA,sCAeC;AAlBD,oDAAkD;AAClD,wDAA0D;AAE1D,SAAgB,aAAa,CAAC,MAAqB;IACjD,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,MAAM;YACT,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;YAChF,CAAC;YACD,OAAO,IAAI,0BAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACvC,KAAK,UAAU;YACb,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;gBACrB,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAC;YACxF,CAAC;YACD,OAAO,IAAI,8BAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC/C;YACE,MAAM,IAAI,KAAK,CAAC,yBAAyB,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.test.d.ts","sourceRoot":"","sources":["../../../../src/channels/ntfy/__tests__/provider.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_test_1 = require("node:test");
|
|
7
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
8
|
+
const provider_js_1 = require("../provider.js");
|
|
9
|
+
(0, node_test_1.describe)('NtfyProvider', () => {
|
|
10
|
+
(0, node_test_1.describe)('send', () => {
|
|
11
|
+
(0, node_test_1.it)('should report error when server is unreachable', async () => {
|
|
12
|
+
const provider = new provider_js_1.NtfyProvider({
|
|
13
|
+
server: 'http://127.0.0.1:19999',
|
|
14
|
+
topic: 'test',
|
|
15
|
+
});
|
|
16
|
+
const result = await provider.send({
|
|
17
|
+
id: 'evt-1',
|
|
18
|
+
sessionId: 'sess-1',
|
|
19
|
+
type: 'permission_prompt',
|
|
20
|
+
message: 'Allow Bash(git status)?',
|
|
21
|
+
project: '/home/user/dev/myproject',
|
|
22
|
+
timestamp: Date.now(),
|
|
23
|
+
}, '1');
|
|
24
|
+
strict_1.default.equal(result.success, false);
|
|
25
|
+
strict_1.default.ok(result.error);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
//# sourceMappingURL=provider.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.test.js","sourceRoot":"","sources":["../../../../src/channels/ntfy/__tests__/provider.test.ts"],"names":[],"mappings":";;;;;AAAA,yCAAyC;AACzC,gEAAwC;AACxC,gDAA8C;AAE9C,IAAA,oBAAQ,EAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,IAAA,oBAAQ,EAAC,MAAM,EAAE,GAAG,EAAE;QACpB,IAAA,cAAE,EAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;YAC9D,MAAM,QAAQ,GAAG,IAAI,0BAAY,CAAC;gBAChC,MAAM,EAAE,wBAAwB;gBAChC,KAAK,EAAE,MAAM;aACd,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAChC;gBACE,EAAE,EAAE,OAAO;gBACX,SAAS,EAAE,QAAQ;gBACnB,IAAI,EAAE,mBAAmB;gBACzB,OAAO,EAAE,yBAAyB;gBAClC,OAAO,EAAE,0BAA0B;gBACnC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;aACtB,EACD,GAAG,CACJ,CAAC;YAEF,gBAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACpC,gBAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ChannelProvider, ChannelListeners, NotificationResult } from '../channel.js';
|
|
2
|
+
import type { NtfyConfig, RelayEvent } from '../../types.js';
|
|
3
|
+
export declare class NtfyProvider implements ChannelProvider {
|
|
4
|
+
readonly name = "ntfy";
|
|
5
|
+
private abortController;
|
|
6
|
+
private readonly config;
|
|
7
|
+
private processedIds;
|
|
8
|
+
constructor(config: NtfyConfig);
|
|
9
|
+
private get topicUrl();
|
|
10
|
+
private authHeaders;
|
|
11
|
+
send(event: RelayEvent, shortId: string): Promise<NotificationResult>;
|
|
12
|
+
startListening(listeners: ChannelListeners): void;
|
|
13
|
+
private poll;
|
|
14
|
+
private capSet;
|
|
15
|
+
stopListening(): void;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../src/channels/ntfy/provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC3F,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE7D,qBAAa,YAAa,YAAW,eAAe;IAClD,QAAQ,CAAC,IAAI,UAAU;IACvB,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,OAAO,CAAC,YAAY,CAAqB;gBAE7B,MAAM,EAAE,UAAU;IAI9B,OAAO,KAAK,QAAQ,GAEnB;IAED,OAAO,CAAC,WAAW;IAWb,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAiD3E,cAAc,CAAC,SAAS,EAAE,gBAAgB,GAAG,IAAI;YAMnC,IAAI;IAsDlB,OAAO,CAAC,MAAM;IAOd,aAAa,IAAI,IAAI;CAItB"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NtfyProvider = void 0;
|
|
4
|
+
class NtfyProvider {
|
|
5
|
+
name = 'ntfy';
|
|
6
|
+
abortController = null;
|
|
7
|
+
config;
|
|
8
|
+
processedIds = new Set();
|
|
9
|
+
constructor(config) {
|
|
10
|
+
this.config = config;
|
|
11
|
+
}
|
|
12
|
+
get topicUrl() {
|
|
13
|
+
return `${this.config.server}/${this.config.topic}`;
|
|
14
|
+
}
|
|
15
|
+
authHeaders() {
|
|
16
|
+
if (this.config.token) {
|
|
17
|
+
return { Authorization: `Bearer ${this.config.token}` };
|
|
18
|
+
}
|
|
19
|
+
if (this.config.user && this.config.password) {
|
|
20
|
+
const encoded = Buffer.from(`${this.config.user}:${this.config.password}`).toString('base64');
|
|
21
|
+
return { Authorization: `Basic ${encoded}` };
|
|
22
|
+
}
|
|
23
|
+
return {};
|
|
24
|
+
}
|
|
25
|
+
async send(event, shortId) {
|
|
26
|
+
const projectName = event.project.split('/').pop() || event.project;
|
|
27
|
+
const title = `Claude Code - ${projectName}`;
|
|
28
|
+
const isPermission = event.type === 'permission_prompt';
|
|
29
|
+
const tag = isPermission ? 'robot,lock' : 'robot,question';
|
|
30
|
+
const hint = isPermission ? 'Reply: allow / deny' : 'Reply with your answer';
|
|
31
|
+
const headers = {
|
|
32
|
+
'Content-Type': 'text/plain',
|
|
33
|
+
Title: title,
|
|
34
|
+
Priority: isPermission ? 'high' : 'default',
|
|
35
|
+
Tags: tag,
|
|
36
|
+
...this.authHeaders(),
|
|
37
|
+
};
|
|
38
|
+
let body = `#${shortId} ${event.message}`;
|
|
39
|
+
if (event.toolName) {
|
|
40
|
+
body += `\n${event.toolName}`;
|
|
41
|
+
if (event.toolInput) {
|
|
42
|
+
const input = event.toolInput.length > 200 ? event.toolInput.slice(0, 200) + '...' : event.toolInput;
|
|
43
|
+
body += `(${input})`;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
body += `\n\n${hint}`;
|
|
47
|
+
try {
|
|
48
|
+
const res = await fetch(this.topicUrl, {
|
|
49
|
+
method: 'POST',
|
|
50
|
+
headers,
|
|
51
|
+
body,
|
|
52
|
+
});
|
|
53
|
+
if (!res.ok) {
|
|
54
|
+
const text = await res.text();
|
|
55
|
+
return { success: false, error: `ntfy responded ${res.status}: ${text}` };
|
|
56
|
+
}
|
|
57
|
+
const data = (await res.json());
|
|
58
|
+
if (data.id) {
|
|
59
|
+
this.capSet(this.processedIds, 1000);
|
|
60
|
+
this.processedIds.add(data.id);
|
|
61
|
+
}
|
|
62
|
+
return { success: true, messageId: data.id };
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
return { success: false, error: String(err) };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
startListening(listeners) {
|
|
69
|
+
this.stopListening();
|
|
70
|
+
this.abortController = new AbortController();
|
|
71
|
+
this.poll(listeners.onResponse);
|
|
72
|
+
}
|
|
73
|
+
async poll(onResponse) {
|
|
74
|
+
const signal = this.abortController.signal;
|
|
75
|
+
let pollCount = 0;
|
|
76
|
+
while (!signal.aborted) {
|
|
77
|
+
try {
|
|
78
|
+
pollCount++;
|
|
79
|
+
if (pollCount % 2 === 0)
|
|
80
|
+
console.log(`[ntfy] poll #${pollCount}`);
|
|
81
|
+
const url = `${this.topicUrl}/json?poll=1&since=30s`;
|
|
82
|
+
const res = await fetch(url, {
|
|
83
|
+
headers: this.authHeaders(),
|
|
84
|
+
signal,
|
|
85
|
+
});
|
|
86
|
+
if (res.ok) {
|
|
87
|
+
const text = await res.text();
|
|
88
|
+
for (const line of text.split('\n').filter(Boolean)) {
|
|
89
|
+
try {
|
|
90
|
+
const msg = JSON.parse(line);
|
|
91
|
+
if (msg.event !== 'message' || !msg.message)
|
|
92
|
+
continue;
|
|
93
|
+
if (msg.id && this.processedIds.has(msg.id))
|
|
94
|
+
continue;
|
|
95
|
+
if (msg.id) {
|
|
96
|
+
this.capSet(this.processedIds, 1000);
|
|
97
|
+
this.processedIds.add(msg.id);
|
|
98
|
+
}
|
|
99
|
+
if (/^#\d+ .+\n\nReply[ :]/.test(msg.message))
|
|
100
|
+
continue;
|
|
101
|
+
console.log(`[ntfy] received response: "${msg.message}"`);
|
|
102
|
+
try {
|
|
103
|
+
await Promise.resolve(onResponse(msg.message));
|
|
104
|
+
}
|
|
105
|
+
catch (cbErr) {
|
|
106
|
+
console.error('[ntfy] callback error:', cbErr);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
console.debug('[ntfy] skipping malformed line:', line.slice(0, 80));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
if (signal.aborted)
|
|
117
|
+
return;
|
|
118
|
+
console.error('[ntfy] poll error:', err);
|
|
119
|
+
}
|
|
120
|
+
// Simple sleep that resolves on abort instead of rejecting
|
|
121
|
+
if (signal.aborted)
|
|
122
|
+
return;
|
|
123
|
+
await new Promise(resolve => {
|
|
124
|
+
const timer = setTimeout(resolve, 5000);
|
|
125
|
+
signal.addEventListener('abort', () => { clearTimeout(timer); resolve(); }, { once: true });
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
capSet(set, max) {
|
|
130
|
+
if (set.size >= max) {
|
|
131
|
+
const first = set.values().next().value;
|
|
132
|
+
if (first !== undefined)
|
|
133
|
+
set.delete(first);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
stopListening() {
|
|
137
|
+
this.abortController?.abort();
|
|
138
|
+
this.abortController = null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
exports.NtfyProvider = NtfyProvider;
|
|
142
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../../src/channels/ntfy/provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ChannelProvider, ChannelListeners, NotificationResult } from '../channel.js';
|
|
2
|
+
import type { TelegramConfig, RelayEvent } from '../../types.js';
|
|
3
|
+
export declare class TelegramProvider implements ChannelProvider {
|
|
4
|
+
readonly name = "telegram";
|
|
5
|
+
private abortController;
|
|
6
|
+
private readonly config;
|
|
7
|
+
private lastUpdateId;
|
|
8
|
+
private messageToEvent;
|
|
9
|
+
private messageToSession;
|
|
10
|
+
constructor(config: TelegramConfig);
|
|
11
|
+
private apiUrl;
|
|
12
|
+
send(event: RelayEvent, shortId: string): Promise<NotificationResult>;
|
|
13
|
+
sendRaw(text: string): Promise<void>;
|
|
14
|
+
sendSessionPicker(text: string, sessions: Array<{
|
|
15
|
+
id: string;
|
|
16
|
+
label: string;
|
|
17
|
+
}>): Promise<number | undefined>;
|
|
18
|
+
startListening(listeners: ChannelListeners): void;
|
|
19
|
+
private poll;
|
|
20
|
+
private handleCallback;
|
|
21
|
+
private handleVoice;
|
|
22
|
+
private handleFreeMessage;
|
|
23
|
+
private handleReply;
|
|
24
|
+
private capMap;
|
|
25
|
+
stopListening(): void;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../src/channels/telegram/provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,kBAAkB,EAAe,MAAM,eAAe,CAAC;AACxG,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AA2BjE,qBAAa,gBAAiB,YAAW,eAAe;IACtD,QAAQ,CAAC,IAAI,cAAc;IAC3B,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,YAAY,CAAK;IAEzB,OAAO,CAAC,cAAc,CAA6B;IAEnD,OAAO,CAAC,gBAAgB,CAA6B;gBAEzC,MAAM,EAAE,cAAc;IAIlC,OAAO,CAAC,MAAM;IAIR,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA8DrE,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAapC,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IA0BlH,cAAc,CAAC,SAAS,EAAE,gBAAgB,GAAG,IAAI;YAMnC,IAAI;YA6CJ,cAAc;YAwEd,WAAW;YAYX,iBAAiB;YAmBjB,WAAW;IA2CzB,OAAO,CAAC,MAAM;IAOd,aAAa,IAAI,IAAI;CAItB"}
|