@jsayubi/ccgram 1.0.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/.env.example +19 -0
- package/LICENSE +21 -0
- package/README.md +338 -0
- package/ccgram.service +24 -0
- package/config/channels.json +58 -0
- package/config/default.json +27 -0
- package/config/defaults/config.json +16 -0
- package/config/defaults/i18n.json +32 -0
- package/config/email-template.json +31 -0
- package/config/test-with-subagent.json +16 -0
- package/config/user.json +27 -0
- package/dist/claude-hook-notify.d.ts +7 -0
- package/dist/claude-hook-notify.d.ts.map +1 -0
- package/dist/claude-hook-notify.js +154 -0
- package/dist/claude-hook-notify.js.map +1 -0
- package/dist/claude-remote.d.ts +50 -0
- package/dist/claude-remote.d.ts.map +1 -0
- package/dist/claude-remote.js +927 -0
- package/dist/claude-remote.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +110 -0
- package/dist/cli.js.map +1 -0
- package/dist/enhanced-hook-notify.d.ts +16 -0
- package/dist/enhanced-hook-notify.d.ts.map +1 -0
- package/dist/enhanced-hook-notify.js +288 -0
- package/dist/enhanced-hook-notify.js.map +1 -0
- package/dist/permission-hook.d.ts +15 -0
- package/dist/permission-hook.d.ts.map +1 -0
- package/dist/permission-hook.js +357 -0
- package/dist/permission-hook.js.map +1 -0
- package/dist/prompt-bridge.d.ts +50 -0
- package/dist/prompt-bridge.d.ts.map +1 -0
- package/dist/prompt-bridge.js +173 -0
- package/dist/prompt-bridge.js.map +1 -0
- package/dist/question-notify.d.ts +16 -0
- package/dist/question-notify.d.ts.map +1 -0
- package/dist/question-notify.js +272 -0
- package/dist/question-notify.js.map +1 -0
- package/dist/setup.d.ts +10 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +649 -0
- package/dist/setup.js.map +1 -0
- package/dist/smart-monitor.d.ts +7 -0
- package/dist/smart-monitor.d.ts.map +1 -0
- package/dist/smart-monitor.js +256 -0
- package/dist/smart-monitor.js.map +1 -0
- package/dist/src/automation/claude-automation.d.ts +45 -0
- package/dist/src/automation/claude-automation.d.ts.map +1 -0
- package/dist/src/automation/claude-automation.js +367 -0
- package/dist/src/automation/claude-automation.js.map +1 -0
- package/dist/src/automation/clipboard-automation.d.ts +35 -0
- package/dist/src/automation/clipboard-automation.d.ts.map +1 -0
- package/dist/src/automation/clipboard-automation.js +242 -0
- package/dist/src/automation/clipboard-automation.js.map +1 -0
- package/dist/src/automation/simple-automation.d.ts +56 -0
- package/dist/src/automation/simple-automation.d.ts.map +1 -0
- package/dist/src/automation/simple-automation.js +283 -0
- package/dist/src/automation/simple-automation.js.map +1 -0
- package/dist/src/channels/base/channel.d.ts +60 -0
- package/dist/src/channels/base/channel.d.ts.map +1 -0
- package/dist/src/channels/base/channel.js +96 -0
- package/dist/src/channels/base/channel.js.map +1 -0
- package/dist/src/channels/email/smtp.d.ts +74 -0
- package/dist/src/channels/email/smtp.d.ts.map +1 -0
- package/dist/src/channels/email/smtp.js +605 -0
- package/dist/src/channels/email/smtp.js.map +1 -0
- package/dist/src/channels/line/line.d.ts +36 -0
- package/dist/src/channels/line/line.d.ts.map +1 -0
- package/dist/src/channels/line/line.js +180 -0
- package/dist/src/channels/line/line.js.map +1 -0
- package/dist/src/channels/line/webhook.d.ts +55 -0
- package/dist/src/channels/line/webhook.d.ts.map +1 -0
- package/dist/src/channels/line/webhook.js +191 -0
- package/dist/src/channels/line/webhook.js.map +1 -0
- package/dist/src/channels/local/desktop.d.ts +30 -0
- package/dist/src/channels/local/desktop.d.ts.map +1 -0
- package/dist/src/channels/local/desktop.js +161 -0
- package/dist/src/channels/local/desktop.js.map +1 -0
- package/dist/src/channels/telegram/telegram.d.ts +43 -0
- package/dist/src/channels/telegram/telegram.d.ts.map +1 -0
- package/dist/src/channels/telegram/telegram.js +223 -0
- package/dist/src/channels/telegram/telegram.js.map +1 -0
- package/dist/src/channels/telegram/webhook.d.ts +75 -0
- package/dist/src/channels/telegram/webhook.d.ts.map +1 -0
- package/dist/src/channels/telegram/webhook.js +278 -0
- package/dist/src/channels/telegram/webhook.js.map +1 -0
- package/dist/src/config-manager.d.ts +16 -0
- package/dist/src/config-manager.d.ts.map +1 -0
- package/dist/src/config-manager.js +152 -0
- package/dist/src/config-manager.js.map +1 -0
- package/dist/src/core/config.d.ts +28 -0
- package/dist/src/core/config.d.ts.map +1 -0
- package/dist/src/core/config.js +248 -0
- package/dist/src/core/config.js.map +1 -0
- package/dist/src/core/logger.d.ts +19 -0
- package/dist/src/core/logger.d.ts.map +1 -0
- package/dist/src/core/logger.js +47 -0
- package/dist/src/core/logger.js.map +1 -0
- package/dist/src/core/notifier.d.ts +45 -0
- package/dist/src/core/notifier.d.ts.map +1 -0
- package/dist/src/core/notifier.js +189 -0
- package/dist/src/core/notifier.js.map +1 -0
- package/dist/src/daemon/taskping-daemon.d.ts +38 -0
- package/dist/src/daemon/taskping-daemon.d.ts.map +1 -0
- package/dist/src/daemon/taskping-daemon.js +306 -0
- package/dist/src/daemon/taskping-daemon.js.map +1 -0
- package/dist/src/relay/claude-command-bridge.d.ts +57 -0
- package/dist/src/relay/claude-command-bridge.d.ts.map +1 -0
- package/dist/src/relay/claude-command-bridge.js +188 -0
- package/dist/src/relay/claude-command-bridge.js.map +1 -0
- package/dist/src/relay/command-relay.d.ts +94 -0
- package/dist/src/relay/command-relay.d.ts.map +1 -0
- package/dist/src/relay/command-relay.js +463 -0
- package/dist/src/relay/command-relay.js.map +1 -0
- package/dist/src/relay/email-listener.d.ts +65 -0
- package/dist/src/relay/email-listener.d.ts.map +1 -0
- package/dist/src/relay/email-listener.js +460 -0
- package/dist/src/relay/email-listener.js.map +1 -0
- package/dist/src/relay/relay-pty.d.ts +21 -0
- package/dist/src/relay/relay-pty.d.ts.map +1 -0
- package/dist/src/relay/relay-pty.js +696 -0
- package/dist/src/relay/relay-pty.js.map +1 -0
- package/dist/src/relay/smart-injector.d.ts +30 -0
- package/dist/src/relay/smart-injector.d.ts.map +1 -0
- package/dist/src/relay/smart-injector.js +233 -0
- package/dist/src/relay/smart-injector.js.map +1 -0
- package/dist/src/relay/tmux-injector.d.ts +46 -0
- package/dist/src/relay/tmux-injector.d.ts.map +1 -0
- package/dist/src/relay/tmux-injector.js +413 -0
- package/dist/src/relay/tmux-injector.js.map +1 -0
- package/dist/src/tools/config-manager.d.ts +33 -0
- package/dist/src/tools/config-manager.d.ts.map +1 -0
- package/dist/src/tools/config-manager.js +448 -0
- package/dist/src/tools/config-manager.js.map +1 -0
- package/dist/src/tools/installer.d.ts +38 -0
- package/dist/src/tools/installer.d.ts.map +1 -0
- package/dist/src/tools/installer.js +222 -0
- package/dist/src/tools/installer.js.map +1 -0
- package/dist/src/types/callbacks.d.ts +29 -0
- package/dist/src/types/callbacks.d.ts.map +1 -0
- package/dist/src/types/callbacks.js +7 -0
- package/dist/src/types/callbacks.js.map +1 -0
- package/dist/src/types/config.d.ts +56 -0
- package/dist/src/types/config.d.ts.map +1 -0
- package/dist/src/types/config.js +6 -0
- package/dist/src/types/config.js.map +1 -0
- package/dist/src/types/hooks.d.ts +47 -0
- package/dist/src/types/hooks.d.ts.map +1 -0
- package/dist/src/types/hooks.js +6 -0
- package/dist/src/types/hooks.js.map +1 -0
- package/dist/src/types/index.d.ts +7 -0
- package/dist/src/types/index.d.ts.map +1 -0
- package/dist/src/types/index.js +23 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/src/types/ipc.d.ts +43 -0
- package/dist/src/types/ipc.d.ts.map +1 -0
- package/dist/src/types/ipc.js +7 -0
- package/dist/src/types/ipc.js.map +1 -0
- package/dist/src/types/session.d.ts +70 -0
- package/dist/src/types/session.d.ts.map +1 -0
- package/dist/src/types/session.js +9 -0
- package/dist/src/types/session.js.map +1 -0
- package/dist/src/types/telegram.d.ts +58 -0
- package/dist/src/types/telegram.d.ts.map +1 -0
- package/dist/src/types/telegram.js +6 -0
- package/dist/src/types/telegram.js.map +1 -0
- package/dist/src/utils/active-check.d.ts +19 -0
- package/dist/src/utils/active-check.d.ts.map +1 -0
- package/dist/src/utils/active-check.js +41 -0
- package/dist/src/utils/active-check.js.map +1 -0
- package/dist/src/utils/callback-parser.d.ts +21 -0
- package/dist/src/utils/callback-parser.d.ts.map +1 -0
- package/dist/src/utils/callback-parser.js +58 -0
- package/dist/src/utils/callback-parser.js.map +1 -0
- package/dist/src/utils/controller-injector.d.ts +21 -0
- package/dist/src/utils/controller-injector.d.ts.map +1 -0
- package/dist/src/utils/controller-injector.js +108 -0
- package/dist/src/utils/controller-injector.js.map +1 -0
- package/dist/src/utils/conversation-tracker.d.ts +32 -0
- package/dist/src/utils/conversation-tracker.d.ts.map +1 -0
- package/dist/src/utils/conversation-tracker.js +119 -0
- package/dist/src/utils/conversation-tracker.js.map +1 -0
- package/dist/src/utils/http-request.d.ts +25 -0
- package/dist/src/utils/http-request.d.ts.map +1 -0
- package/dist/src/utils/http-request.js +66 -0
- package/dist/src/utils/http-request.js.map +1 -0
- package/dist/src/utils/optional-require.d.ts +13 -0
- package/dist/src/utils/optional-require.d.ts.map +1 -0
- package/dist/src/utils/optional-require.js +37 -0
- package/dist/src/utils/optional-require.js.map +1 -0
- package/dist/src/utils/paths.d.ts +11 -0
- package/dist/src/utils/paths.d.ts.map +1 -0
- package/dist/src/utils/paths.js +28 -0
- package/dist/src/utils/paths.js.map +1 -0
- package/dist/src/utils/pty-session-manager.d.ts +42 -0
- package/dist/src/utils/pty-session-manager.d.ts.map +1 -0
- package/dist/src/utils/pty-session-manager.js +182 -0
- package/dist/src/utils/pty-session-manager.js.map +1 -0
- package/dist/src/utils/subagent-tracker.d.ts +64 -0
- package/dist/src/utils/subagent-tracker.d.ts.map +1 -0
- package/dist/src/utils/subagent-tracker.js +191 -0
- package/dist/src/utils/subagent-tracker.js.map +1 -0
- package/dist/src/utils/tmux-monitor.d.ts +102 -0
- package/dist/src/utils/tmux-monitor.d.ts.map +1 -0
- package/dist/src/utils/tmux-monitor.js +642 -0
- package/dist/src/utils/tmux-monitor.js.map +1 -0
- package/dist/src/utils/trace-capture.d.ts +42 -0
- package/dist/src/utils/trace-capture.d.ts.map +1 -0
- package/dist/src/utils/trace-capture.js +102 -0
- package/dist/src/utils/trace-capture.js.map +1 -0
- package/dist/start-all-webhooks.d.ts +7 -0
- package/dist/start-all-webhooks.d.ts.map +1 -0
- package/dist/start-all-webhooks.js +98 -0
- package/dist/start-all-webhooks.js.map +1 -0
- package/dist/start-line-webhook.d.ts +7 -0
- package/dist/start-line-webhook.d.ts.map +1 -0
- package/dist/start-line-webhook.js +59 -0
- package/dist/start-line-webhook.js.map +1 -0
- package/dist/start-relay-pty.d.ts +7 -0
- package/dist/start-relay-pty.d.ts.map +1 -0
- package/dist/start-relay-pty.js +173 -0
- package/dist/start-relay-pty.js.map +1 -0
- package/dist/start-telegram-webhook.d.ts +7 -0
- package/dist/start-telegram-webhook.d.ts.map +1 -0
- package/dist/start-telegram-webhook.js +80 -0
- package/dist/start-telegram-webhook.js.map +1 -0
- package/dist/user-prompt-hook.d.ts +13 -0
- package/dist/user-prompt-hook.d.ts.map +1 -0
- package/dist/user-prompt-hook.js +45 -0
- package/dist/user-prompt-hook.js.map +1 -0
- package/dist/workspace-router.d.ts +78 -0
- package/dist/workspace-router.d.ts.map +1 -0
- package/dist/workspace-router.js +408 -0
- package/dist/workspace-router.js.map +1 -0
- package/dist/workspace-telegram-bot.d.ts +3 -0
- package/dist/workspace-telegram-bot.d.ts.map +1 -0
- package/dist/workspace-telegram-bot.js +1172 -0
- package/dist/workspace-telegram-bot.js.map +1 -0
- package/package.json +80 -0
- package/src/types/callbacks.ts +39 -0
- package/src/types/config.ts +63 -0
- package/src/types/hooks.ts +50 -0
- package/src/types/index.ts +6 -0
- package/src/types/ipc.ts +55 -0
- package/src/types/session.ts +72 -0
- package/src/types/telegram.ts +66 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* Permission Hook — Called by Claude Code's PermissionRequest hook.
|
|
5
|
+
*
|
|
6
|
+
* Blocking approach:
|
|
7
|
+
* 1. Sends a Telegram message with inline keyboard buttons
|
|
8
|
+
* 2. Polls for a response file written by the bot's callback handler
|
|
9
|
+
* 3. Outputs the permission decision via stdout
|
|
10
|
+
* 4. Exits cleanly
|
|
11
|
+
*
|
|
12
|
+
* Stdin JSON: { tool_name, tool_input, cwd, session_id, hook_event_name }
|
|
13
|
+
* Stdout JSON: { hookSpecificOutput: { hookEventName, decision: { behavior } } }
|
|
14
|
+
*/
|
|
15
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
16
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
17
|
+
};
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
const path_1 = __importDefault(require("path"));
|
|
20
|
+
const paths_1 = require("./src/utils/paths");
|
|
21
|
+
require('dotenv').config({ path: path_1.default.join(paths_1.PROJECT_ROOT, '.env'), quiet: true });
|
|
22
|
+
const fs_1 = __importDefault(require("fs"));
|
|
23
|
+
const https_1 = __importDefault(require("https"));
|
|
24
|
+
const child_process_1 = require("child_process");
|
|
25
|
+
const workspace_router_1 = require("./workspace-router");
|
|
26
|
+
const prompt_bridge_1 = require("./prompt-bridge");
|
|
27
|
+
const active_check_1 = require("./src/utils/active-check");
|
|
28
|
+
const BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN;
|
|
29
|
+
const CHAT_ID = process.env.TELEGRAM_CHAT_ID;
|
|
30
|
+
const POLL_INTERVAL_MS = 500;
|
|
31
|
+
const POLL_TIMEOUT_MS = 90000; // 90 seconds max wait
|
|
32
|
+
// Debug logging to file (since stdout is for Claude Code)
|
|
33
|
+
const LOG_FILE = path_1.default.join(paths_1.PROJECT_ROOT, 'logs', 'permission-hook-debug.log');
|
|
34
|
+
function debugLog(msg) {
|
|
35
|
+
const ts = new Date().toISOString();
|
|
36
|
+
try {
|
|
37
|
+
fs_1.default.appendFileSync(LOG_FILE, `${ts} ${msg}\n`);
|
|
38
|
+
}
|
|
39
|
+
catch { }
|
|
40
|
+
}
|
|
41
|
+
// ── Main ────────────────────────────────────────────────────────
|
|
42
|
+
async function main() {
|
|
43
|
+
const raw = await readStdin();
|
|
44
|
+
let payload;
|
|
45
|
+
try {
|
|
46
|
+
payload = JSON.parse(raw);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return; // Can't parse — exit without decision
|
|
50
|
+
}
|
|
51
|
+
const toolName = payload.tool_name || 'Unknown';
|
|
52
|
+
// AskUserQuestion: exit silently so Claude Code shows the interactive
|
|
53
|
+
// question/permission UI in the terminal. The question-notify.js PreToolUse
|
|
54
|
+
// hook sends the Telegram notification. Clicking an option injects arrow
|
|
55
|
+
// keys + Enter which both selects the answer AND grants permission.
|
|
56
|
+
if (toolName === 'AskUserQuestion') {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// If user is actively at the terminal AND this wasn't injected from Telegram,
|
|
60
|
+
// exit without a decision so Claude Code shows its own permission UI locally.
|
|
61
|
+
// Uses the same 300s (5 min) threshold as notification hooks.
|
|
62
|
+
// If user stepped away more than 5 min ago, Telegram handles the permission
|
|
63
|
+
// so Claude isn't left stuck waiting with no way to respond.
|
|
64
|
+
const typingActivePath = path_1.default.join(paths_1.PROJECT_ROOT, 'src/data', 'typing-active');
|
|
65
|
+
const isTelegramInjected = fs_1.default.existsSync(typingActivePath);
|
|
66
|
+
if (!isTelegramInjected && (0, active_check_1.isUserActiveAtTerminal)()) {
|
|
67
|
+
debugLog(`[skip] User is at terminal (within 5 min) — deferring to Claude Code's own permission UI`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const toolInput = (payload.tool_input || {});
|
|
71
|
+
const cwd = payload.cwd || process.cwd();
|
|
72
|
+
const workspace = (0, workspace_router_1.extractWorkspaceName)(cwd);
|
|
73
|
+
const promptId = (0, prompt_bridge_1.generatePromptId)();
|
|
74
|
+
const tmuxSession = detectSessionName(cwd);
|
|
75
|
+
const isPlan = toolName === 'ExitPlanMode';
|
|
76
|
+
// Build Telegram message and keyboard
|
|
77
|
+
let messageText;
|
|
78
|
+
let keyboard;
|
|
79
|
+
if (isPlan) {
|
|
80
|
+
// Plan approval — try to capture plan content from tmux
|
|
81
|
+
let planContent = '';
|
|
82
|
+
if (tmuxSession) {
|
|
83
|
+
try {
|
|
84
|
+
const paneOutput = (0, child_process_1.execSync)(`tmux capture-pane -t ${tmuxSession} -p -S -50 2>/dev/null`, { encoding: 'utf8', timeout: 3000 });
|
|
85
|
+
planContent = cleanPlanOutput(paneOutput);
|
|
86
|
+
}
|
|
87
|
+
catch { }
|
|
88
|
+
}
|
|
89
|
+
messageText = `\u{1F4CB} *Plan Approval* — ${escapeMarkdown(workspace)}`;
|
|
90
|
+
if (planContent) {
|
|
91
|
+
const truncated = planContent.length > 2500
|
|
92
|
+
? planContent.slice(0, 2497) + '...'
|
|
93
|
+
: planContent;
|
|
94
|
+
messageText += `\n\n${truncated}`;
|
|
95
|
+
}
|
|
96
|
+
keyboard = {
|
|
97
|
+
inline_keyboard: [
|
|
98
|
+
[
|
|
99
|
+
{ text: '\u2705 Approve', callback_data: `perm:${promptId}:allow` },
|
|
100
|
+
{ text: '\u274C Reject', callback_data: `perm:${promptId}:deny` },
|
|
101
|
+
],
|
|
102
|
+
],
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
// Tool permission request
|
|
107
|
+
const toolDescription = formatToolDescription(toolName, toolInput);
|
|
108
|
+
messageText = `\u{1F510} *Permission* — ${escapeMarkdown(workspace)}\n\n*Tool:* ${escapeMarkdown(toolName)}`;
|
|
109
|
+
if (toolDescription) {
|
|
110
|
+
const truncated = toolDescription.length > 2500
|
|
111
|
+
? toolDescription.slice(0, 2497) + '...'
|
|
112
|
+
: toolDescription;
|
|
113
|
+
messageText += `\n${truncated}`;
|
|
114
|
+
}
|
|
115
|
+
keyboard = {
|
|
116
|
+
inline_keyboard: [
|
|
117
|
+
[
|
|
118
|
+
{ text: '\u2705 Allow', callback_data: `perm:${promptId}:allow` },
|
|
119
|
+
{ text: '\u274C Deny', callback_data: `perm:${promptId}:deny` },
|
|
120
|
+
{ text: '\u{1F513} Always', callback_data: `perm:${promptId}:always` },
|
|
121
|
+
],
|
|
122
|
+
],
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
// Write pending file so bot callback handler can write the response
|
|
126
|
+
(0, prompt_bridge_1.writePending)(promptId, {
|
|
127
|
+
type: isPlan ? 'plan' : 'permission',
|
|
128
|
+
workspace,
|
|
129
|
+
toolName,
|
|
130
|
+
toolInput,
|
|
131
|
+
tmuxSession,
|
|
132
|
+
});
|
|
133
|
+
// Send Telegram message with inline keyboard
|
|
134
|
+
debugLog(`[${promptId}] Sending Telegram message for ${toolName}...`);
|
|
135
|
+
try {
|
|
136
|
+
const result = await sendTelegramWithKeyboard(messageText, keyboard);
|
|
137
|
+
debugLog(`[${promptId}] Telegram message sent`);
|
|
138
|
+
if (result && result.message_id) {
|
|
139
|
+
(0, workspace_router_1.trackNotificationMessage)(result.message_id, workspace, 'permission');
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
debugLog(`[${promptId}] Telegram send failed: ${err.message}`);
|
|
144
|
+
process.stderr.write(`[permission-hook] Telegram send failed: ${err.message}\n`);
|
|
145
|
+
(0, prompt_bridge_1.cleanPrompt)(promptId);
|
|
146
|
+
return; // Can't notify — exit without decision
|
|
147
|
+
}
|
|
148
|
+
// Poll for response file
|
|
149
|
+
debugLog(`[${promptId}] Starting to poll for response...`);
|
|
150
|
+
const response = await pollForResponse(promptId);
|
|
151
|
+
if (response) {
|
|
152
|
+
const action = response.action || 'allow';
|
|
153
|
+
debugLog(`[${promptId}] Got response: action=${action}`);
|
|
154
|
+
let decision;
|
|
155
|
+
if (action === 'deny') {
|
|
156
|
+
decision = 'deny';
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
decision = 'allow';
|
|
160
|
+
}
|
|
161
|
+
const output = {
|
|
162
|
+
hookSpecificOutput: {
|
|
163
|
+
hookEventName: 'PermissionRequest',
|
|
164
|
+
decision: {
|
|
165
|
+
behavior: decision,
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
systemMessage: `Decision received via Telegram: user ${decision}ed`,
|
|
169
|
+
};
|
|
170
|
+
const outputStr = JSON.stringify(output);
|
|
171
|
+
debugLog(`[${promptId}] Writing to stdout: ${outputStr}`);
|
|
172
|
+
process.stdout.write(outputStr + '\n');
|
|
173
|
+
debugLog(`[${promptId}] Stdout written`);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
debugLog(`[${promptId}] No response received (timed out or error)`);
|
|
177
|
+
}
|
|
178
|
+
// Clean up
|
|
179
|
+
(0, prompt_bridge_1.cleanPrompt)(promptId);
|
|
180
|
+
debugLog(`[${promptId}] Cleaned up, letting process exit naturally`);
|
|
181
|
+
}
|
|
182
|
+
// ── Polling ─────────────────────────────────────────────────────
|
|
183
|
+
function pollForResponse(promptId) {
|
|
184
|
+
return new Promise((resolve) => {
|
|
185
|
+
const responseFile = path_1.default.join(prompt_bridge_1.PROMPTS_DIR, `response-${promptId}.json`);
|
|
186
|
+
const startTime = Date.now();
|
|
187
|
+
const interval = setInterval(() => {
|
|
188
|
+
// Check timeout
|
|
189
|
+
if (Date.now() - startTime > POLL_TIMEOUT_MS) {
|
|
190
|
+
clearInterval(interval);
|
|
191
|
+
process.stderr.write(`[permission-hook] Timed out waiting for response\n`);
|
|
192
|
+
resolve(null);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
// Check for response file
|
|
196
|
+
try {
|
|
197
|
+
if (fs_1.default.existsSync(responseFile)) {
|
|
198
|
+
const raw = fs_1.default.readFileSync(responseFile, 'utf8');
|
|
199
|
+
const data = JSON.parse(raw);
|
|
200
|
+
clearInterval(interval);
|
|
201
|
+
resolve(data);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
// File not ready yet or parse error — keep polling
|
|
206
|
+
}
|
|
207
|
+
}, POLL_INTERVAL_MS);
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
// ── Telegram ────────────────────────────────────────────────────
|
|
211
|
+
function sendTelegramWithKeyboard(text, replyMarkup) {
|
|
212
|
+
return new Promise((resolve, reject) => {
|
|
213
|
+
const body = JSON.stringify({
|
|
214
|
+
chat_id: CHAT_ID,
|
|
215
|
+
text,
|
|
216
|
+
parse_mode: 'Markdown',
|
|
217
|
+
reply_markup: replyMarkup,
|
|
218
|
+
});
|
|
219
|
+
const options = {
|
|
220
|
+
hostname: 'api.telegram.org',
|
|
221
|
+
path: `/bot${BOT_TOKEN}/sendMessage`,
|
|
222
|
+
method: 'POST',
|
|
223
|
+
headers: {
|
|
224
|
+
'Content-Type': 'application/json',
|
|
225
|
+
'Content-Length': Buffer.byteLength(body),
|
|
226
|
+
},
|
|
227
|
+
timeout: 5000,
|
|
228
|
+
};
|
|
229
|
+
const req = https_1.default.request(options, (res) => {
|
|
230
|
+
let data = '';
|
|
231
|
+
res.on('data', (chunk) => { data += chunk; });
|
|
232
|
+
res.on('end', () => {
|
|
233
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
234
|
+
try {
|
|
235
|
+
const parsed = JSON.parse(data);
|
|
236
|
+
resolve(parsed.result || null);
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
resolve(null);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
reject(new Error(`Telegram API ${res.statusCode}: ${data}`));
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
req.on('error', reject);
|
|
248
|
+
req.on('timeout', () => {
|
|
249
|
+
req.destroy();
|
|
250
|
+
reject(new Error('Telegram request timed out'));
|
|
251
|
+
});
|
|
252
|
+
req.write(body);
|
|
253
|
+
req.end();
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
// ── Helpers ──────────────────────────────────────────────────────
|
|
257
|
+
function readStdin() {
|
|
258
|
+
return new Promise((resolve) => {
|
|
259
|
+
let data = '';
|
|
260
|
+
let resolved = false;
|
|
261
|
+
process.stdin.setEncoding('utf8');
|
|
262
|
+
process.stdin.on('data', (chunk) => { data += chunk; });
|
|
263
|
+
process.stdin.on('end', () => {
|
|
264
|
+
if (!resolved) {
|
|
265
|
+
resolved = true;
|
|
266
|
+
resolve(data);
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
setTimeout(() => {
|
|
270
|
+
if (!resolved) {
|
|
271
|
+
resolved = true;
|
|
272
|
+
process.stdin.destroy();
|
|
273
|
+
resolve(data || '{}');
|
|
274
|
+
}
|
|
275
|
+
}, 500);
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
function detectSessionName(cwd) {
|
|
279
|
+
// 1. Try tmux (existing behaviour)
|
|
280
|
+
if (process.env.TMUX) {
|
|
281
|
+
try {
|
|
282
|
+
return (0, child_process_1.execSync)('tmux display-message -p "#S"', { encoding: 'utf8' }).trim();
|
|
283
|
+
}
|
|
284
|
+
catch { }
|
|
285
|
+
}
|
|
286
|
+
// 2. Derive from CWD — apply the same sanitization /new uses for session names
|
|
287
|
+
// (dots, colons, spaces → hyphens) so the name matches the PTY handle key
|
|
288
|
+
const raw = (0, workspace_router_1.extractWorkspaceName)(cwd);
|
|
289
|
+
if (!raw)
|
|
290
|
+
return null;
|
|
291
|
+
return raw.replace(/[.:\s]/g, '-');
|
|
292
|
+
}
|
|
293
|
+
function formatToolDescription(toolName, toolInput) {
|
|
294
|
+
if (toolName === 'Bash' && toolInput.command) {
|
|
295
|
+
const cmd = toolInput.command;
|
|
296
|
+
const truncated = cmd.length > 500 ? cmd.slice(0, 497) + '...' : cmd;
|
|
297
|
+
return `*Command:* \`${escapeMarkdown(truncated)}\``;
|
|
298
|
+
}
|
|
299
|
+
if (toolName === 'Edit' && toolInput.file_path) {
|
|
300
|
+
const filePath = escapeMarkdown(toolInput.file_path);
|
|
301
|
+
if (toolInput.old_string && toolInput.new_string) {
|
|
302
|
+
const maxLines = 12;
|
|
303
|
+
const oldLines = toolInput.old_string.split('\n');
|
|
304
|
+
const newLines = toolInput.new_string.split('\n');
|
|
305
|
+
const oldTrunc = oldLines.length > maxLines;
|
|
306
|
+
const newTrunc = newLines.length > maxLines;
|
|
307
|
+
const oldStr = oldLines.slice(0, maxLines).map(l => `- ${l}`).join('\n') + (oldTrunc ? '\n ...' : '');
|
|
308
|
+
const newStr = newLines.slice(0, maxLines).map(l => `+ ${l}`).join('\n') + (newTrunc ? '\n ...' : '');
|
|
309
|
+
return `*File:* \`${filePath}\`\n\`\`\`\n${oldStr}\n${newStr}\n\`\`\``;
|
|
310
|
+
}
|
|
311
|
+
return `*File:* \`${filePath}\``;
|
|
312
|
+
}
|
|
313
|
+
if (toolName === 'Write' && toolInput.file_path) {
|
|
314
|
+
return `*File:* \`${escapeMarkdown(toolInput.file_path)}\``;
|
|
315
|
+
}
|
|
316
|
+
if (toolName === 'Read' && toolInput.file_path) {
|
|
317
|
+
return `*File:* \`${escapeMarkdown(toolInput.file_path)}\``;
|
|
318
|
+
}
|
|
319
|
+
const keys = Object.keys(toolInput);
|
|
320
|
+
if (keys.length > 0) {
|
|
321
|
+
const key = keys[0];
|
|
322
|
+
const val = String(toolInput[key]).slice(0, 200);
|
|
323
|
+
return `*${escapeMarkdown(key)}:* \`${escapeMarkdown(val)}\``;
|
|
324
|
+
}
|
|
325
|
+
return '';
|
|
326
|
+
}
|
|
327
|
+
function cleanPlanOutput(raw) {
|
|
328
|
+
let lines = raw.split('\n');
|
|
329
|
+
lines = lines.map(l => l
|
|
330
|
+
.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '')
|
|
331
|
+
.replace(/\x1B\][^\x07]*\x07/g, ''));
|
|
332
|
+
while (lines.length && !lines[lines.length - 1].trim())
|
|
333
|
+
lines.pop();
|
|
334
|
+
while (lines.length && !lines[0].trim())
|
|
335
|
+
lines.shift();
|
|
336
|
+
lines = lines.filter(l => {
|
|
337
|
+
const t = l.trim();
|
|
338
|
+
if (!t)
|
|
339
|
+
return true;
|
|
340
|
+
if (/^[\u280B\u2819\u2839\u2838\u283C\u2834\u2826\u2827\u2807\u280F]/.test(t))
|
|
341
|
+
return false;
|
|
342
|
+
if (/^(Clauding|Working|Waiting|Processing)/i.test(t))
|
|
343
|
+
return false;
|
|
344
|
+
if (/^.+\|.+\|.+\|.+\$/.test(t))
|
|
345
|
+
return false;
|
|
346
|
+
return true;
|
|
347
|
+
});
|
|
348
|
+
return lines.join('\n').trim();
|
|
349
|
+
}
|
|
350
|
+
function escapeMarkdown(text) {
|
|
351
|
+
return text.replace(/([_*`\[])/g, '\\$1');
|
|
352
|
+
}
|
|
353
|
+
// ── Run ─────────────────────────────────────────────────────────
|
|
354
|
+
main().catch((err) => {
|
|
355
|
+
process.stderr.write(`[permission-hook] Fatal: ${err.message}\n`);
|
|
356
|
+
});
|
|
357
|
+
//# sourceMappingURL=permission-hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permission-hook.js","sourceRoot":"","sources":["../permission-hook.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Prompt Bridge — File-based IPC for Claude Code interactive prompts.
|
|
4
|
+
*
|
|
5
|
+
* Manages /tmp/claude-prompts/ directory with pending/response files
|
|
6
|
+
* so that hooks (permission-hook.js, question-notify.js) can communicate
|
|
7
|
+
* with the Telegram bot's callback query handler.
|
|
8
|
+
*
|
|
9
|
+
* File format:
|
|
10
|
+
* pending-<id>.json — written by hook, read by bot callback handler
|
|
11
|
+
* response-<id>.json — written by bot callback handler, read by hook
|
|
12
|
+
*/
|
|
13
|
+
declare const PROMPTS_DIR: string;
|
|
14
|
+
/** Generate a unique 8-char prompt ID. */
|
|
15
|
+
declare function generatePromptId(): string;
|
|
16
|
+
/**
|
|
17
|
+
* Write a pending prompt file.
|
|
18
|
+
*/
|
|
19
|
+
declare function writePending(id: string, data: Record<string, unknown>): void;
|
|
20
|
+
/**
|
|
21
|
+
* Write a response file (from bot callback).
|
|
22
|
+
*/
|
|
23
|
+
declare function writeResponse(id: string, data: Record<string, unknown>): void;
|
|
24
|
+
/**
|
|
25
|
+
* Read a response file if it exists.
|
|
26
|
+
*/
|
|
27
|
+
declare function readResponse(id: string): Record<string, unknown> | null;
|
|
28
|
+
/**
|
|
29
|
+
* Read a pending prompt file.
|
|
30
|
+
*/
|
|
31
|
+
declare function readPending(id: string): Record<string, unknown> | null;
|
|
32
|
+
/**
|
|
33
|
+
* Check if there's a pending prompt for a given workspace.
|
|
34
|
+
* Used by enhanced-hook-notify.js for deduplication.
|
|
35
|
+
*/
|
|
36
|
+
declare function hasPendingForWorkspace(workspace: string): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Remove pending and response files older than EXPIRY_MS.
|
|
39
|
+
*/
|
|
40
|
+
declare function cleanExpired(): void;
|
|
41
|
+
/**
|
|
42
|
+
* Remove pending and response files for a given prompt ID.
|
|
43
|
+
*/
|
|
44
|
+
declare function cleanPrompt(id: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* Update fields on an existing pending prompt file.
|
|
47
|
+
*/
|
|
48
|
+
declare function updatePending(id: string, updates: Record<string, unknown>): void;
|
|
49
|
+
export { generatePromptId, writePending, updatePending, writeResponse, readResponse, readPending, hasPendingForWorkspace, cleanExpired, cleanPrompt, PROMPTS_DIR, };
|
|
50
|
+
//# sourceMappingURL=prompt-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-bridge.d.ts","sourceRoot":"","sources":["../prompt-bridge.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;GAUG;AAMH,QAAA,MAAM,WAAW,QAAmD,CAAC;AAUrE,0CAA0C;AAC1C,iBAAS,gBAAgB,IAAI,MAAM,CAElC;AAED;;GAEG;AACH,iBAAS,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAKrE;AAED;;GAEG;AACH,iBAAS,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAItE;AAED;;GAEG;AACH,iBAAS,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAQhE;AAED;;GAEG;AACH,iBAAS,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAQ/D;AAED;;;GAGG;AACH,iBAAS,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAyB1D;AAED;;GAEG;AACH,iBAAS,YAAY,IAAI,IAAI,CAqB5B;AAED;;GAEG;AACH,iBAAS,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAKrC;AAED;;GAEG;AACH,iBAAS,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAKzE;AAED,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,aAAa,EACb,YAAY,EACZ,WAAW,EACX,sBAAsB,EACtB,YAAY,EACZ,WAAW,EACX,WAAW,GACZ,CAAC"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* Prompt Bridge — File-based IPC for Claude Code interactive prompts.
|
|
5
|
+
*
|
|
6
|
+
* Manages /tmp/claude-prompts/ directory with pending/response files
|
|
7
|
+
* so that hooks (permission-hook.js, question-notify.js) can communicate
|
|
8
|
+
* with the Telegram bot's callback query handler.
|
|
9
|
+
*
|
|
10
|
+
* File format:
|
|
11
|
+
* pending-<id>.json — written by hook, read by bot callback handler
|
|
12
|
+
* response-<id>.json — written by bot callback handler, read by hook
|
|
13
|
+
*/
|
|
14
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
|
+
};
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.PROMPTS_DIR = void 0;
|
|
19
|
+
exports.generatePromptId = generatePromptId;
|
|
20
|
+
exports.writePending = writePending;
|
|
21
|
+
exports.updatePending = updatePending;
|
|
22
|
+
exports.writeResponse = writeResponse;
|
|
23
|
+
exports.readResponse = readResponse;
|
|
24
|
+
exports.readPending = readPending;
|
|
25
|
+
exports.hasPendingForWorkspace = hasPendingForWorkspace;
|
|
26
|
+
exports.cleanExpired = cleanExpired;
|
|
27
|
+
exports.cleanPrompt = cleanPrompt;
|
|
28
|
+
const fs_1 = __importDefault(require("fs"));
|
|
29
|
+
const path_1 = __importDefault(require("path"));
|
|
30
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
31
|
+
const PROMPTS_DIR = process.env.PROMPTS_DIR || '/tmp/claude-prompts';
|
|
32
|
+
exports.PROMPTS_DIR = PROMPTS_DIR;
|
|
33
|
+
const EXPIRY_MS = 5 * 60 * 1000; // 5 minutes
|
|
34
|
+
/** Ensure the prompts directory exists. */
|
|
35
|
+
function ensureDir() {
|
|
36
|
+
if (!fs_1.default.existsSync(PROMPTS_DIR)) {
|
|
37
|
+
fs_1.default.mkdirSync(PROMPTS_DIR, { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** Generate a unique 8-char prompt ID. */
|
|
41
|
+
function generatePromptId() {
|
|
42
|
+
return crypto_1.default.randomBytes(4).toString('hex');
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Write a pending prompt file.
|
|
46
|
+
*/
|
|
47
|
+
function writePending(id, data) {
|
|
48
|
+
ensureDir();
|
|
49
|
+
cleanExpired();
|
|
50
|
+
const filePath = path_1.default.join(PROMPTS_DIR, `pending-${id}.json`);
|
|
51
|
+
fs_1.default.writeFileSync(filePath, JSON.stringify({ ...data, createdAt: Date.now() }, null, 2));
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Write a response file (from bot callback).
|
|
55
|
+
*/
|
|
56
|
+
function writeResponse(id, data) {
|
|
57
|
+
ensureDir();
|
|
58
|
+
const filePath = path_1.default.join(PROMPTS_DIR, `response-${id}.json`);
|
|
59
|
+
fs_1.default.writeFileSync(filePath, JSON.stringify({ ...data, respondedAt: Date.now() }, null, 2));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Read a response file if it exists.
|
|
63
|
+
*/
|
|
64
|
+
function readResponse(id) {
|
|
65
|
+
const filePath = path_1.default.join(PROMPTS_DIR, `response-${id}.json`);
|
|
66
|
+
try {
|
|
67
|
+
const raw = fs_1.default.readFileSync(filePath, 'utf8');
|
|
68
|
+
return JSON.parse(raw);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Read a pending prompt file.
|
|
76
|
+
*/
|
|
77
|
+
function readPending(id) {
|
|
78
|
+
const filePath = path_1.default.join(PROMPTS_DIR, `pending-${id}.json`);
|
|
79
|
+
try {
|
|
80
|
+
const raw = fs_1.default.readFileSync(filePath, 'utf8');
|
|
81
|
+
return JSON.parse(raw);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Check if there's a pending prompt for a given workspace.
|
|
89
|
+
* Used by enhanced-hook-notify.js for deduplication.
|
|
90
|
+
*/
|
|
91
|
+
function hasPendingForWorkspace(workspace) {
|
|
92
|
+
ensureDir();
|
|
93
|
+
try {
|
|
94
|
+
const files = fs_1.default.readdirSync(PROMPTS_DIR);
|
|
95
|
+
for (const file of files) {
|
|
96
|
+
if (!file.startsWith('pending-'))
|
|
97
|
+
continue;
|
|
98
|
+
try {
|
|
99
|
+
const raw = fs_1.default.readFileSync(path_1.default.join(PROMPTS_DIR, file), 'utf8');
|
|
100
|
+
const data = JSON.parse(raw);
|
|
101
|
+
// Only count non-expired pending files
|
|
102
|
+
if (data.workspace === workspace && (Date.now() - data.createdAt) < EXPIRY_MS) {
|
|
103
|
+
// Check that no response exists for this prompt
|
|
104
|
+
const id = file.replace('pending-', '').replace('.json', '');
|
|
105
|
+
if (!readResponse(id)) {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
// Skip malformed files
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// Directory read failed
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Remove pending and response files older than EXPIRY_MS.
|
|
122
|
+
*/
|
|
123
|
+
function cleanExpired() {
|
|
124
|
+
try {
|
|
125
|
+
if (!fs_1.default.existsSync(PROMPTS_DIR))
|
|
126
|
+
return;
|
|
127
|
+
const files = fs_1.default.readdirSync(PROMPTS_DIR);
|
|
128
|
+
const now = Date.now();
|
|
129
|
+
for (const file of files) {
|
|
130
|
+
if (!file.endsWith('.json'))
|
|
131
|
+
continue;
|
|
132
|
+
const filePath = path_1.default.join(PROMPTS_DIR, file);
|
|
133
|
+
try {
|
|
134
|
+
const stat = fs_1.default.statSync(filePath);
|
|
135
|
+
if (now - stat.mtimeMs > EXPIRY_MS) {
|
|
136
|
+
fs_1.default.unlinkSync(filePath);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// Skip if file was already removed
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// Directory doesn't exist or isn't readable
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Remove pending and response files for a given prompt ID.
|
|
150
|
+
*/
|
|
151
|
+
function cleanPrompt(id) {
|
|
152
|
+
const pending = path_1.default.join(PROMPTS_DIR, `pending-${id}.json`);
|
|
153
|
+
const response = path_1.default.join(PROMPTS_DIR, `response-${id}.json`);
|
|
154
|
+
try {
|
|
155
|
+
fs_1.default.unlinkSync(pending);
|
|
156
|
+
}
|
|
157
|
+
catch { }
|
|
158
|
+
try {
|
|
159
|
+
fs_1.default.unlinkSync(response);
|
|
160
|
+
}
|
|
161
|
+
catch { }
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Update fields on an existing pending prompt file.
|
|
165
|
+
*/
|
|
166
|
+
function updatePending(id, updates) {
|
|
167
|
+
const existing = readPending(id);
|
|
168
|
+
if (!existing)
|
|
169
|
+
return;
|
|
170
|
+
const filePath = path_1.default.join(PROMPTS_DIR, `pending-${id}.json`);
|
|
171
|
+
fs_1.default.writeFileSync(filePath, JSON.stringify({ ...existing, ...updates }, null, 2));
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=prompt-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-bridge.js","sourceRoot":"","sources":["../prompt-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Question Notify — Called by Claude Code's PreToolUse hook (matcher: AskUserQuestion).
|
|
4
|
+
*
|
|
5
|
+
* Non-blocking: sends a Telegram message with option buttons, then returns
|
|
6
|
+
* without stdout output. AskUserQuestion must be in the permissions allow
|
|
7
|
+
* list (settings.json) so Claude Code handles permission automatically.
|
|
8
|
+
* The bot callback handler later injects the selected option number via tmux.
|
|
9
|
+
*
|
|
10
|
+
* Stdin JSON: { tool_name, tool_input, cwd, session_id, hook_event_name }
|
|
11
|
+
* tool_input.questions: [{ question, header, options: [{ label, description }], multiSelect }]
|
|
12
|
+
*
|
|
13
|
+
* Stdout: (none — intentionally omitted so Claude Code shows the interactive question UI)
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=question-notify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"question-notify.d.ts","sourceRoot":"","sources":["../question-notify.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;GAYG"}
|