@selucas12/cheesy 2.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.
Files changed (292) hide show
  1. package/.env.example +22 -0
  2. package/CHANGELOG.md +268 -0
  3. package/LICENSE +21 -0
  4. package/README.md +394 -0
  5. package/ccgram.service +24 -0
  6. package/config/channels.json +58 -0
  7. package/config/default.json +27 -0
  8. package/config/defaults/config.json +16 -0
  9. package/config/defaults/i18n.json +32 -0
  10. package/config/email-template.json +31 -0
  11. package/config/test-with-subagent.json +16 -0
  12. package/config/user.json +27 -0
  13. package/dist/claude-hook-notify.d.ts +7 -0
  14. package/dist/claude-hook-notify.d.ts.map +1 -0
  15. package/dist/claude-hook-notify.js +154 -0
  16. package/dist/claude-hook-notify.js.map +1 -0
  17. package/dist/claude-remote.d.ts +50 -0
  18. package/dist/claude-remote.d.ts.map +1 -0
  19. package/dist/claude-remote.js +927 -0
  20. package/dist/claude-remote.js.map +1 -0
  21. package/dist/elicitation-notify.d.ts +20 -0
  22. package/dist/elicitation-notify.d.ts.map +1 -0
  23. package/dist/elicitation-notify.js +241 -0
  24. package/dist/elicitation-notify.js.map +1 -0
  25. package/dist/enhanced-hook-notify.d.ts +23 -0
  26. package/dist/enhanced-hook-notify.d.ts.map +1 -0
  27. package/dist/enhanced-hook-notify.js +402 -0
  28. package/dist/enhanced-hook-notify.js.map +1 -0
  29. package/dist/permission-denied-notify.d.ts +11 -0
  30. package/dist/permission-denied-notify.d.ts.map +1 -0
  31. package/dist/permission-denied-notify.js +193 -0
  32. package/dist/permission-denied-notify.js.map +1 -0
  33. package/dist/permission-hook.d.ts +15 -0
  34. package/dist/permission-hook.d.ts.map +1 -0
  35. package/dist/permission-hook.js +386 -0
  36. package/dist/permission-hook.js.map +1 -0
  37. package/dist/pre-compact-notify.d.ts +13 -0
  38. package/dist/pre-compact-notify.d.ts.map +1 -0
  39. package/dist/pre-compact-notify.js +197 -0
  40. package/dist/pre-compact-notify.js.map +1 -0
  41. package/dist/prompt-bridge.d.ts +50 -0
  42. package/dist/prompt-bridge.d.ts.map +1 -0
  43. package/dist/prompt-bridge.js +173 -0
  44. package/dist/prompt-bridge.js.map +1 -0
  45. package/dist/question-notify.d.ts +17 -0
  46. package/dist/question-notify.d.ts.map +1 -0
  47. package/dist/question-notify.js +356 -0
  48. package/dist/question-notify.js.map +1 -0
  49. package/dist/setup.d.ts +10 -0
  50. package/dist/setup.d.ts.map +1 -0
  51. package/dist/setup.js +649 -0
  52. package/dist/setup.js.map +1 -0
  53. package/dist/smart-monitor.d.ts +7 -0
  54. package/dist/smart-monitor.d.ts.map +1 -0
  55. package/dist/smart-monitor.js +256 -0
  56. package/dist/smart-monitor.js.map +1 -0
  57. package/dist/src/automation/clipboard-automation.d.ts +35 -0
  58. package/dist/src/automation/clipboard-automation.d.ts.map +1 -0
  59. package/dist/src/automation/clipboard-automation.js +242 -0
  60. package/dist/src/automation/clipboard-automation.js.map +1 -0
  61. package/dist/src/channels/base/channel.d.ts +60 -0
  62. package/dist/src/channels/base/channel.d.ts.map +1 -0
  63. package/dist/src/channels/base/channel.js +96 -0
  64. package/dist/src/channels/base/channel.js.map +1 -0
  65. package/dist/src/channels/email/smtp.d.ts +74 -0
  66. package/dist/src/channels/email/smtp.d.ts.map +1 -0
  67. package/dist/src/channels/email/smtp.js +605 -0
  68. package/dist/src/channels/email/smtp.js.map +1 -0
  69. package/dist/src/channels/line/line.d.ts +36 -0
  70. package/dist/src/channels/line/line.d.ts.map +1 -0
  71. package/dist/src/channels/line/line.js +180 -0
  72. package/dist/src/channels/line/line.js.map +1 -0
  73. package/dist/src/channels/line/webhook.d.ts +55 -0
  74. package/dist/src/channels/line/webhook.d.ts.map +1 -0
  75. package/dist/src/channels/line/webhook.js +191 -0
  76. package/dist/src/channels/line/webhook.js.map +1 -0
  77. package/dist/src/channels/local/desktop.d.ts +30 -0
  78. package/dist/src/channels/local/desktop.d.ts.map +1 -0
  79. package/dist/src/channels/local/desktop.js +161 -0
  80. package/dist/src/channels/local/desktop.js.map +1 -0
  81. package/dist/src/channels/telegram/telegram.d.ts +43 -0
  82. package/dist/src/channels/telegram/telegram.d.ts.map +1 -0
  83. package/dist/src/channels/telegram/telegram.js +223 -0
  84. package/dist/src/channels/telegram/telegram.js.map +1 -0
  85. package/dist/src/channels/telegram/webhook.d.ts +75 -0
  86. package/dist/src/channels/telegram/webhook.d.ts.map +1 -0
  87. package/dist/src/channels/telegram/webhook.js +278 -0
  88. package/dist/src/channels/telegram/webhook.js.map +1 -0
  89. package/dist/src/cli.d.ts +9 -0
  90. package/dist/src/cli.d.ts.map +1 -0
  91. package/dist/src/cli.js +99 -0
  92. package/dist/src/cli.js.map +1 -0
  93. package/dist/src/commands/hooks.d.ts +10 -0
  94. package/dist/src/commands/hooks.d.ts.map +1 -0
  95. package/dist/src/commands/hooks.js +50 -0
  96. package/dist/src/commands/hooks.js.map +1 -0
  97. package/dist/src/commands/init.d.ts +20 -0
  98. package/dist/src/commands/init.d.ts.map +1 -0
  99. package/dist/src/commands/init.js +173 -0
  100. package/dist/src/commands/init.js.map +1 -0
  101. package/dist/src/commands/license.d.ts +15 -0
  102. package/dist/src/commands/license.d.ts.map +1 -0
  103. package/dist/src/commands/license.js +107 -0
  104. package/dist/src/commands/license.js.map +1 -0
  105. package/dist/src/commands/start.d.ts +17 -0
  106. package/dist/src/commands/start.d.ts.map +1 -0
  107. package/dist/src/commands/start.js +150 -0
  108. package/dist/src/commands/start.js.map +1 -0
  109. package/dist/src/commands/status.d.ts +8 -0
  110. package/dist/src/commands/status.d.ts.map +1 -0
  111. package/dist/src/commands/status.js +95 -0
  112. package/dist/src/commands/status.js.map +1 -0
  113. package/dist/src/commands/stop.d.ts +8 -0
  114. package/dist/src/commands/stop.d.ts.map +1 -0
  115. package/dist/src/commands/stop.js +64 -0
  116. package/dist/src/commands/stop.js.map +1 -0
  117. package/dist/src/config-manager.d.ts +16 -0
  118. package/dist/src/config-manager.d.ts.map +1 -0
  119. package/dist/src/config-manager.js +152 -0
  120. package/dist/src/config-manager.js.map +1 -0
  121. package/dist/src/core/config.d.ts +28 -0
  122. package/dist/src/core/config.d.ts.map +1 -0
  123. package/dist/src/core/config.js +248 -0
  124. package/dist/src/core/config.js.map +1 -0
  125. package/dist/src/core/logger.d.ts +19 -0
  126. package/dist/src/core/logger.d.ts.map +1 -0
  127. package/dist/src/core/logger.js +47 -0
  128. package/dist/src/core/logger.js.map +1 -0
  129. package/dist/src/core/notifier.d.ts +45 -0
  130. package/dist/src/core/notifier.d.ts.map +1 -0
  131. package/dist/src/core/notifier.js +189 -0
  132. package/dist/src/core/notifier.js.map +1 -0
  133. package/dist/src/lib/license-validator.d.ts +120 -0
  134. package/dist/src/lib/license-validator.d.ts.map +1 -0
  135. package/dist/src/lib/license-validator.js +294 -0
  136. package/dist/src/lib/license-validator.js.map +1 -0
  137. package/dist/src/lib/preflight.d.ts +28 -0
  138. package/dist/src/lib/preflight.d.ts.map +1 -0
  139. package/dist/src/lib/preflight.js +90 -0
  140. package/dist/src/lib/preflight.js.map +1 -0
  141. package/dist/src/relay/claude-command-bridge.d.ts +57 -0
  142. package/dist/src/relay/claude-command-bridge.d.ts.map +1 -0
  143. package/dist/src/relay/claude-command-bridge.js +188 -0
  144. package/dist/src/relay/claude-command-bridge.js.map +1 -0
  145. package/dist/src/relay/email-listener.d.ts +65 -0
  146. package/dist/src/relay/email-listener.d.ts.map +1 -0
  147. package/dist/src/relay/email-listener.js +460 -0
  148. package/dist/src/relay/email-listener.js.map +1 -0
  149. package/dist/src/relay/relay-pty.d.ts +21 -0
  150. package/dist/src/relay/relay-pty.d.ts.map +1 -0
  151. package/dist/src/relay/relay-pty.js +696 -0
  152. package/dist/src/relay/relay-pty.js.map +1 -0
  153. package/dist/src/relay/smart-injector.d.ts +30 -0
  154. package/dist/src/relay/smart-injector.d.ts.map +1 -0
  155. package/dist/src/relay/smart-injector.js +233 -0
  156. package/dist/src/relay/smart-injector.js.map +1 -0
  157. package/dist/src/relay/tmux-injector.d.ts +46 -0
  158. package/dist/src/relay/tmux-injector.d.ts.map +1 -0
  159. package/dist/src/relay/tmux-injector.js +413 -0
  160. package/dist/src/relay/tmux-injector.js.map +1 -0
  161. package/dist/src/tools/config-manager.d.ts +33 -0
  162. package/dist/src/tools/config-manager.d.ts.map +1 -0
  163. package/dist/src/tools/config-manager.js +448 -0
  164. package/dist/src/tools/config-manager.js.map +1 -0
  165. package/dist/src/tools/installer.d.ts +38 -0
  166. package/dist/src/tools/installer.d.ts.map +1 -0
  167. package/dist/src/tools/installer.js +222 -0
  168. package/dist/src/tools/installer.js.map +1 -0
  169. package/dist/src/types/callbacks.d.ts +53 -0
  170. package/dist/src/types/callbacks.d.ts.map +1 -0
  171. package/dist/src/types/callbacks.js +7 -0
  172. package/dist/src/types/callbacks.js.map +1 -0
  173. package/dist/src/types/config.d.ts +56 -0
  174. package/dist/src/types/config.d.ts.map +1 -0
  175. package/dist/src/types/config.js +6 -0
  176. package/dist/src/types/config.js.map +1 -0
  177. package/dist/src/types/hooks.d.ts +47 -0
  178. package/dist/src/types/hooks.d.ts.map +1 -0
  179. package/dist/src/types/hooks.js +6 -0
  180. package/dist/src/types/hooks.js.map +1 -0
  181. package/dist/src/types/index.d.ts +7 -0
  182. package/dist/src/types/index.d.ts.map +1 -0
  183. package/dist/src/types/index.js +23 -0
  184. package/dist/src/types/index.js.map +1 -0
  185. package/dist/src/types/ipc.d.ts +43 -0
  186. package/dist/src/types/ipc.d.ts.map +1 -0
  187. package/dist/src/types/ipc.js +7 -0
  188. package/dist/src/types/ipc.js.map +1 -0
  189. package/dist/src/types/session.d.ts +87 -0
  190. package/dist/src/types/session.d.ts.map +1 -0
  191. package/dist/src/types/session.js +9 -0
  192. package/dist/src/types/session.js.map +1 -0
  193. package/dist/src/types/telegram.d.ts +58 -0
  194. package/dist/src/types/telegram.d.ts.map +1 -0
  195. package/dist/src/types/telegram.js +6 -0
  196. package/dist/src/types/telegram.js.map +1 -0
  197. package/dist/src/utils/active-check.d.ts +20 -0
  198. package/dist/src/utils/active-check.d.ts.map +1 -0
  199. package/dist/src/utils/active-check.js +42 -0
  200. package/dist/src/utils/active-check.js.map +1 -0
  201. package/dist/src/utils/callback-parser.d.ts +23 -0
  202. package/dist/src/utils/callback-parser.d.ts.map +1 -0
  203. package/dist/src/utils/callback-parser.js +85 -0
  204. package/dist/src/utils/callback-parser.js.map +1 -0
  205. package/dist/src/utils/controller-injector.d.ts +21 -0
  206. package/dist/src/utils/controller-injector.d.ts.map +1 -0
  207. package/dist/src/utils/controller-injector.js +108 -0
  208. package/dist/src/utils/controller-injector.js.map +1 -0
  209. package/dist/src/utils/conversation-tracker.d.ts +32 -0
  210. package/dist/src/utils/conversation-tracker.d.ts.map +1 -0
  211. package/dist/src/utils/conversation-tracker.js +119 -0
  212. package/dist/src/utils/conversation-tracker.js.map +1 -0
  213. package/dist/src/utils/deep-link.d.ts +22 -0
  214. package/dist/src/utils/deep-link.d.ts.map +1 -0
  215. package/dist/src/utils/deep-link.js +43 -0
  216. package/dist/src/utils/deep-link.js.map +1 -0
  217. package/dist/src/utils/ghostty-session-manager.d.ts +81 -0
  218. package/dist/src/utils/ghostty-session-manager.d.ts.map +1 -0
  219. package/dist/src/utils/ghostty-session-manager.js +370 -0
  220. package/dist/src/utils/ghostty-session-manager.js.map +1 -0
  221. package/dist/src/utils/hook-definitions.d.ts +25 -0
  222. package/dist/src/utils/hook-definitions.d.ts.map +1 -0
  223. package/dist/src/utils/hook-definitions.js +36 -0
  224. package/dist/src/utils/hook-definitions.js.map +1 -0
  225. package/dist/src/utils/http-request.d.ts +25 -0
  226. package/dist/src/utils/http-request.d.ts.map +1 -0
  227. package/dist/src/utils/http-request.js +66 -0
  228. package/dist/src/utils/http-request.js.map +1 -0
  229. package/dist/src/utils/optional-require.d.ts +13 -0
  230. package/dist/src/utils/optional-require.d.ts.map +1 -0
  231. package/dist/src/utils/optional-require.js +37 -0
  232. package/dist/src/utils/optional-require.js.map +1 -0
  233. package/dist/src/utils/paths.d.ts +13 -0
  234. package/dist/src/utils/paths.d.ts.map +1 -0
  235. package/dist/src/utils/paths.js +30 -0
  236. package/dist/src/utils/paths.js.map +1 -0
  237. package/dist/src/utils/pty-session-manager.d.ts +43 -0
  238. package/dist/src/utils/pty-session-manager.d.ts.map +1 -0
  239. package/dist/src/utils/pty-session-manager.js +183 -0
  240. package/dist/src/utils/pty-session-manager.js.map +1 -0
  241. package/dist/src/utils/subagent-tracker.d.ts +64 -0
  242. package/dist/src/utils/subagent-tracker.d.ts.map +1 -0
  243. package/dist/src/utils/subagent-tracker.js +191 -0
  244. package/dist/src/utils/subagent-tracker.js.map +1 -0
  245. package/dist/src/utils/tmux-monitor.d.ts +102 -0
  246. package/dist/src/utils/tmux-monitor.d.ts.map +1 -0
  247. package/dist/src/utils/tmux-monitor.js +642 -0
  248. package/dist/src/utils/tmux-monitor.js.map +1 -0
  249. package/dist/src/utils/trace-capture.d.ts +42 -0
  250. package/dist/src/utils/trace-capture.d.ts.map +1 -0
  251. package/dist/src/utils/trace-capture.js +102 -0
  252. package/dist/src/utils/trace-capture.js.map +1 -0
  253. package/dist/src/utils/transcript-reader.d.ts +57 -0
  254. package/dist/src/utils/transcript-reader.d.ts.map +1 -0
  255. package/dist/src/utils/transcript-reader.js +229 -0
  256. package/dist/src/utils/transcript-reader.js.map +1 -0
  257. package/dist/start-all-webhooks.d.ts +7 -0
  258. package/dist/start-all-webhooks.d.ts.map +1 -0
  259. package/dist/start-all-webhooks.js +98 -0
  260. package/dist/start-all-webhooks.js.map +1 -0
  261. package/dist/start-line-webhook.d.ts +7 -0
  262. package/dist/start-line-webhook.d.ts.map +1 -0
  263. package/dist/start-line-webhook.js +59 -0
  264. package/dist/start-line-webhook.js.map +1 -0
  265. package/dist/start-relay-pty.d.ts +7 -0
  266. package/dist/start-relay-pty.d.ts.map +1 -0
  267. package/dist/start-relay-pty.js +173 -0
  268. package/dist/start-relay-pty.js.map +1 -0
  269. package/dist/start-telegram-webhook.d.ts +7 -0
  270. package/dist/start-telegram-webhook.d.ts.map +1 -0
  271. package/dist/start-telegram-webhook.js +80 -0
  272. package/dist/start-telegram-webhook.js.map +1 -0
  273. package/dist/user-prompt-hook.d.ts +13 -0
  274. package/dist/user-prompt-hook.d.ts.map +1 -0
  275. package/dist/user-prompt-hook.js +45 -0
  276. package/dist/user-prompt-hook.js.map +1 -0
  277. package/dist/workspace-router.d.ts +114 -0
  278. package/dist/workspace-router.d.ts.map +1 -0
  279. package/dist/workspace-router.js +572 -0
  280. package/dist/workspace-router.js.map +1 -0
  281. package/dist/workspace-telegram-bot.d.ts +3 -0
  282. package/dist/workspace-telegram-bot.d.ts.map +1 -0
  283. package/dist/workspace-telegram-bot.js +1847 -0
  284. package/dist/workspace-telegram-bot.js.map +1 -0
  285. package/package.json +85 -0
  286. package/src/types/callbacks.ts +73 -0
  287. package/src/types/config.ts +63 -0
  288. package/src/types/hooks.ts +50 -0
  289. package/src/types/index.ts +6 -0
  290. package/src/types/ipc.ts +55 -0
  291. package/src/types/session.ts +91 -0
  292. package/src/types/telegram.ts +66 -0
@@ -0,0 +1,402 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Enhanced Hook Notifier — called by Claude Code hooks.
5
+ *
6
+ * Handles: Stop (completed), Notification (waiting), SessionStart,
7
+ * SessionEnd, SubagentStop (subagent-done), StopFailure (stop-failure),
8
+ * PostCompact (post-compact), TaskCreated (task-created),
9
+ * CwdChanged (cwd-changed), InstructionsLoaded (instructions-loaded).
10
+ *
11
+ * Usage (in ~/.claude/settings.json hooks):
12
+ * node /path/to/ccgram/dist/enhanced-hook-notify.js completed
13
+ * node /path/to/ccgram/dist/enhanced-hook-notify.js waiting
14
+ * node /path/to/ccgram/dist/enhanced-hook-notify.js session-start
15
+ * node /path/to/ccgram/dist/enhanced-hook-notify.js session-end
16
+ * node /path/to/ccgram/dist/enhanced-hook-notify.js subagent-done
17
+ * node /path/to/ccgram/dist/enhanced-hook-notify.js stop-failure
18
+ * node /path/to/ccgram/dist/enhanced-hook-notify.js post-compact
19
+ * node /path/to/ccgram/dist/enhanced-hook-notify.js task-created
20
+ * node /path/to/ccgram/dist/enhanced-hook-notify.js cwd-changed
21
+ * node /path/to/ccgram/dist/enhanced-hook-notify.js instructions-loaded
22
+ */
23
+ var __importDefault = (this && this.__importDefault) || function (mod) {
24
+ return (mod && mod.__esModule) ? mod : { "default": mod };
25
+ };
26
+ Object.defineProperty(exports, "__esModule", { value: true });
27
+ const fs_1 = __importDefault(require("fs"));
28
+ const path_1 = __importDefault(require("path"));
29
+ const paths_1 = require("./src/utils/paths");
30
+ require('dotenv').config({ path: path_1.default.join(paths_1.PROJECT_ROOT, '.env'), quiet: true });
31
+ const https_1 = __importDefault(require("https"));
32
+ const logger_1 = __importDefault(require("./src/core/logger"));
33
+ const workspace_router_1 = require("./workspace-router");
34
+ const prompt_bridge_1 = require("./prompt-bridge");
35
+ const active_check_1 = require("./src/utils/active-check");
36
+ const logger = new logger_1.default('hook:enhanced');
37
+ const BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN;
38
+ const CHAT_ID = process.env.TELEGRAM_CHAT_ID;
39
+ const TELEGRAM_ENABLED = process.env.TELEGRAM_ENABLED === 'true';
40
+ const STATUS_ARG = process.argv[2] || 'completed';
41
+ const STATUS_CONFIG = {
42
+ 'completed': { icon: '\u2705', label: 'Task completed', alwaysNotify: false, upsertSession: true },
43
+ 'waiting': { icon: '\u23f3', label: 'Waiting for input', alwaysNotify: false, upsertSession: true },
44
+ 'session-start': { icon: '\u{1F7E2}', label: 'Session started', alwaysNotify: false, upsertSession: true },
45
+ 'session-end': { icon: '\u{1F534}', label: 'Session ended', alwaysNotify: false, upsertSession: false },
46
+ 'subagent-done': { icon: '\u{1F916}', label: 'Subagent finished', alwaysNotify: false, upsertSession: true },
47
+ // Phase 2 hook events
48
+ 'stop-failure': { icon: '\u26A0\uFE0F', label: 'API error', alwaysNotify: true, upsertSession: true },
49
+ 'post-compact': { icon: '\u{1F4E6}', label: 'Context compacted', alwaysNotify: false, upsertSession: true },
50
+ 'task-created': { icon: '\u{1F4CB}', label: 'Task created', alwaysNotify: false, upsertSession: true },
51
+ 'cwd-changed': { icon: '\u{1F4C2}', label: 'Directory changed', alwaysNotify: false, upsertSession: true },
52
+ 'instructions-loaded': { icon: '\u{1F4D6}', label: 'Instructions loaded', alwaysNotify: false, upsertSession: false },
53
+ };
54
+ // ── Main ────────────────────────────────────────────────────────
55
+ async function main() {
56
+ let payload;
57
+ try {
58
+ const raw = await readStdin();
59
+ payload = JSON.parse(raw);
60
+ }
61
+ catch {
62
+ payload = {};
63
+ }
64
+ const cwd = payload.cwd || process.env.CLAUDE_CWD || process.cwd();
65
+ const workspace = (0, workspace_router_1.extractWorkspaceName)(cwd);
66
+ const sessionTitle = payload.session_title || null; // v2.1.94+
67
+ const tmuxSession = detectSessionName(cwd);
68
+ const sessionId = payload.session_id || null;
69
+ const config = STATUS_CONFIG[STATUS_ARG] ?? STATUS_CONFIG['waiting'];
70
+ // Extract rate limit info from payload (Claude Code v2.1.80+)
71
+ const rateLimit = extractRateLimitInfo(payload);
72
+ // Update session map (skip for session-end — session is over)
73
+ if (config.upsertSession) {
74
+ try {
75
+ const sessionType = process.env.TMUX ? 'tmux'
76
+ : process.env.TERM_PROGRAM === 'ghostty' ? 'ghostty'
77
+ : undefined;
78
+ (0, workspace_router_1.upsertSession)({
79
+ cwd,
80
+ tmuxSession: tmuxSession || `claude-${workspace}`,
81
+ status: STATUS_ARG,
82
+ sessionId,
83
+ sessionType,
84
+ rateLimit,
85
+ });
86
+ }
87
+ catch (err) {
88
+ logger.error(`Failed to update session map: ${err.message}`);
89
+ }
90
+ }
91
+ else if (rateLimit) {
92
+ // Even for session-end, update rate limit if present
93
+ try {
94
+ (0, workspace_router_1.updateSessionRateLimit)(workspace, rateLimit);
95
+ }
96
+ catch { }
97
+ }
98
+ // If the bot injected this command from Telegram, typing-active exists — always notify
99
+ // so the response goes back to Telegram regardless of terminal activity.
100
+ const typingActivePath = path_1.default.join(paths_1.PROJECT_ROOT, 'src/data', 'typing-active');
101
+ const isTelegramInjected = fs_1.default.existsSync(typingActivePath);
102
+ // Suppress notification if user is actively at terminal AND this wasn't Telegram-injected
103
+ if (!config.alwaysNotify && !isTelegramInjected && (0, active_check_1.isUserActiveAtTerminal)()) {
104
+ try {
105
+ fs_1.default.unlinkSync(typingActivePath);
106
+ }
107
+ catch { }
108
+ return;
109
+ }
110
+ // Send Telegram notification
111
+ if (TELEGRAM_ENABLED && BOT_TOKEN && CHAT_ID) {
112
+ // Dedup: if a richer prompt (permission/question) is already pending for this
113
+ // workspace, skip the basic "Waiting for input" notification
114
+ if (STATUS_ARG === 'waiting' && (0, prompt_bridge_1.hasPendingForWorkspace)(workspace)) {
115
+ try {
116
+ fs_1.default.unlinkSync(typingActivePath);
117
+ }
118
+ catch { }
119
+ return;
120
+ }
121
+ // Include session title if available (v2.1.94+)
122
+ const titleSuffix = sessionTitle ? ` (${escapeHtml(sessionTitle)})` : '';
123
+ let message = `${config.icon} ${config.label} in <b>${escapeHtml(workspace)}</b>${titleSuffix}`;
124
+ // Status-specific message additions
125
+ if (STATUS_ARG === 'stop-failure') {
126
+ // Include error details from StopFailure hook
127
+ const errorType = payload.error_type;
128
+ const errorMessage = payload.error_message;
129
+ if (errorType || errorMessage) {
130
+ message += `\n\n<b>Error:</b> ${escapeHtml(errorType || 'Unknown')}`;
131
+ if (errorMessage) {
132
+ message += `\n${escapeHtml(errorMessage)}`;
133
+ }
134
+ }
135
+ }
136
+ else if (STATUS_ARG === 'post-compact') {
137
+ // Include compaction stats if available
138
+ const beforeTokens = payload.tokens_before;
139
+ const afterTokens = payload.tokens_after;
140
+ if (beforeTokens && afterTokens) {
141
+ const saved = beforeTokens - afterTokens;
142
+ const percent = Math.round((saved / beforeTokens) * 100);
143
+ message += `\n\n<i>${beforeTokens.toLocaleString()} → ${afterTokens.toLocaleString()} tokens (${percent}% saved)</i>`;
144
+ }
145
+ }
146
+ else if (STATUS_ARG === 'task-created') {
147
+ // Include task description
148
+ const taskDescription = payload.task_description;
149
+ const taskId = payload.task_id;
150
+ if (taskDescription) {
151
+ message += `\n\n${escapeHtml(taskDescription)}`;
152
+ }
153
+ if (taskId) {
154
+ message += `\n<i>ID: ${escapeHtml(taskId)}</i>`;
155
+ }
156
+ }
157
+ else if (STATUS_ARG === 'cwd-changed') {
158
+ // Include old and new directory
159
+ const oldCwd = payload.old_cwd;
160
+ const newCwd = payload.new_cwd;
161
+ if (oldCwd && newCwd) {
162
+ const oldWorkspace = (0, workspace_router_1.extractWorkspaceName)(oldCwd);
163
+ const newWorkspace = (0, workspace_router_1.extractWorkspaceName)(newCwd);
164
+ message += `\n\n<i>${escapeHtml(oldWorkspace || oldCwd)} → ${escapeHtml(newWorkspace || newCwd)}</i>`;
165
+ }
166
+ }
167
+ else if (STATUS_ARG === 'instructions-loaded') {
168
+ // Include instructions file path
169
+ const instructionsPath = payload.instructions_path;
170
+ if (instructionsPath) {
171
+ message += `\n\n<i>${escapeHtml(instructionsPath)}</i>`;
172
+ }
173
+ }
174
+ // Append Claude's last response text (skip for session-start and simple notifications)
175
+ const skipResponseText = ['session-start', 'post-compact', 'task-created', 'cwd-changed', 'instructions-loaded'];
176
+ if (!skipResponseText.includes(STATUS_ARG)) {
177
+ const responseText = getResponseText(payload);
178
+ if (responseText) {
179
+ const truncated = responseText.length > 3500
180
+ ? responseText.slice(0, 3497) + '...'
181
+ : responseText;
182
+ message += `\n\n${markdownToHtml(truncated)}`;
183
+ }
184
+ }
185
+ // Remove typing signal file BEFORE sending
186
+ try {
187
+ fs_1.default.unlinkSync(typingActivePath);
188
+ }
189
+ catch { }
190
+ try {
191
+ const result = await sendTelegram(message, 'HTML');
192
+ if (result && result.message_id) {
193
+ (0, workspace_router_1.trackNotificationMessage)(result.message_id, workspace, `hook-${STATUS_ARG}`);
194
+ }
195
+ }
196
+ catch {
197
+ // HTML failed — send as plain text
198
+ try {
199
+ const plain = message.replace(/<[^>]+>/g, '');
200
+ const result = await sendTelegram(plain, false);
201
+ if (result && result.message_id) {
202
+ (0, workspace_router_1.trackNotificationMessage)(result.message_id, workspace, `hook-${STATUS_ARG}`);
203
+ }
204
+ }
205
+ catch (err2) {
206
+ logger.error(`Telegram send failed: ${err2.message}`);
207
+ }
208
+ }
209
+ }
210
+ }
211
+ // ── Response text extraction ─────────────────────────────────────
212
+ /**
213
+ * Get Claude's last response text from the hook payload.
214
+ * Prefers last_assistant_message (v2.1.47+), falls back to transcript parsing.
215
+ * For SubagentStop, also tries agent_transcript_path.
216
+ */
217
+ function getResponseText(payload) {
218
+ // Direct field — available in Claude Code v2.1.47+
219
+ const direct = payload.last_assistant_message;
220
+ if (direct)
221
+ return direct;
222
+ // Transcript fallback for older Claude Code versions
223
+ const agentTranscript = payload.agent_transcript_path;
224
+ if (agentTranscript) {
225
+ try {
226
+ return extractLastResponse(agentTranscript);
227
+ }
228
+ catch { }
229
+ }
230
+ const transcript = payload.transcript_path;
231
+ if (transcript) {
232
+ try {
233
+ return extractLastResponse(transcript);
234
+ }
235
+ catch { }
236
+ }
237
+ return null;
238
+ }
239
+ // ── Telegram ────────────────────────────────────────────────────
240
+ function sendTelegram(text, parseMode = 'Markdown') {
241
+ return new Promise((resolve, reject) => {
242
+ const msgPayload = { chat_id: CHAT_ID, text };
243
+ if (parseMode)
244
+ msgPayload.parse_mode = parseMode;
245
+ const body = JSON.stringify(msgPayload);
246
+ const options = {
247
+ hostname: 'api.telegram.org',
248
+ path: `/bot${BOT_TOKEN}/sendMessage`,
249
+ method: 'POST',
250
+ headers: {
251
+ 'Content-Type': 'application/json',
252
+ 'Content-Length': Buffer.byteLength(body),
253
+ },
254
+ timeout: 5000,
255
+ };
256
+ const req = https_1.default.request(options, (res) => {
257
+ let data = '';
258
+ res.on('data', (chunk) => { data += chunk; });
259
+ res.on('end', () => {
260
+ if (res.statusCode >= 200 && res.statusCode < 300) {
261
+ try {
262
+ const parsed = JSON.parse(data);
263
+ resolve(parsed.result || null);
264
+ }
265
+ catch {
266
+ resolve(null);
267
+ }
268
+ }
269
+ else {
270
+ reject(new Error(`Telegram API ${res.statusCode}: ${data}`));
271
+ }
272
+ });
273
+ });
274
+ req.on('error', reject);
275
+ req.on('timeout', () => {
276
+ req.destroy();
277
+ reject(new Error('Telegram request timed out'));
278
+ });
279
+ req.write(body);
280
+ req.end();
281
+ });
282
+ }
283
+ // ── Helpers ──────────────────────────────────────────────────────
284
+ /**
285
+ * Extract rate limit info from hook payload (Claude Code v2.1.80+).
286
+ * Rate limits may appear in statusline data or direct payload fields.
287
+ */
288
+ function extractRateLimitInfo(payload) {
289
+ // Try direct rate_limits field
290
+ const rateLimits = payload.rate_limits;
291
+ if (rateLimits) {
292
+ return {
293
+ remaining: rateLimits.remaining,
294
+ limit: rateLimits.limit,
295
+ resetsAt: rateLimits.resets_at,
296
+ updatedAt: Date.now(),
297
+ };
298
+ }
299
+ // Try statusline object (may contain rate limit info)
300
+ const statusline = payload.statusline;
301
+ if (statusline?.rate_limits) {
302
+ const sl = statusline.rate_limits;
303
+ return {
304
+ remaining: sl.remaining,
305
+ limit: sl.limit,
306
+ resetsAt: sl.resets_at,
307
+ updatedAt: Date.now(),
308
+ };
309
+ }
310
+ return undefined;
311
+ }
312
+ function extractLastResponse(transcriptPath) {
313
+ const data = fs_1.default.readFileSync(transcriptPath, 'utf8').trimEnd();
314
+ const lines = data.split('\n');
315
+ for (let i = lines.length - 1; i >= 0; i--) {
316
+ try {
317
+ const entry = JSON.parse(lines[i]);
318
+ if (entry.type === 'assistant' && entry.message?.content) {
319
+ const texts = entry.message.content
320
+ .filter((c) => c.type === 'text')
321
+ .map((c) => c.text);
322
+ if (texts.length > 0)
323
+ return texts.join('\n\n');
324
+ }
325
+ }
326
+ catch { }
327
+ }
328
+ return null;
329
+ }
330
+ function readStdin() {
331
+ return new Promise((resolve) => {
332
+ let data = '';
333
+ let resolved = false;
334
+ process.stdin.setEncoding('utf8');
335
+ process.stdin.on('data', (chunk) => { data += chunk; });
336
+ process.stdin.on('end', () => {
337
+ if (!resolved) {
338
+ resolved = true;
339
+ resolve(data);
340
+ }
341
+ });
342
+ setTimeout(() => {
343
+ if (!resolved) {
344
+ resolved = true;
345
+ process.stdin.destroy();
346
+ resolve(data || '{}');
347
+ }
348
+ }, 500);
349
+ });
350
+ }
351
+ function detectSessionName(cwd) {
352
+ // 1. Try tmux (preferred — gives actual session name)
353
+ if (process.env.TMUX) {
354
+ try {
355
+ const { execSync } = require('child_process');
356
+ return execSync('tmux display-message -p "#S"', { encoding: 'utf8' }).trim();
357
+ }
358
+ catch { }
359
+ }
360
+ // 2. Ghostty — derive from CWD (same sanitization as tmux-less path)
361
+ if (process.env.TERM_PROGRAM === 'ghostty') {
362
+ const raw = (0, workspace_router_1.extractWorkspaceName)(cwd);
363
+ return raw ? raw.replace(/[.:\s]/g, '-') : null;
364
+ }
365
+ // 3. Derive from CWD — sanitize so it matches PTY handle key format
366
+ const raw = (0, workspace_router_1.extractWorkspaceName)(cwd);
367
+ if (!raw)
368
+ return null;
369
+ return raw.replace(/[.:\s]/g, '-');
370
+ }
371
+ function escapeHtml(text) {
372
+ return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
373
+ }
374
+ function markdownToHtml(text) {
375
+ let html = escapeHtml(text);
376
+ const placeholders = [];
377
+ // Extract code blocks/inline code first to protect them from bold/italic regexes
378
+ html = html.replace(/```(\w*)\n([\s\S]*?)```/g, (_, __, code) => {
379
+ const idx = placeholders.length;
380
+ placeholders.push(`<pre>${code.trim()}</pre>`);
381
+ return `\x00P${idx}\x00`;
382
+ });
383
+ html = html.replace(/`([^`]+)`/g, (_, code) => {
384
+ const idx = placeholders.length;
385
+ placeholders.push(`<code>${code}</code>`);
386
+ return `\x00P${idx}\x00`;
387
+ });
388
+ // Apply inline formatting only to non-code text
389
+ html = html.replace(/\*\*(.+?)\*\*/g, '<b>$1</b>');
390
+ html = html.replace(/\*(.+?)\*/g, '<i>$1</i>');
391
+ html = html.replace(/^[-*]\s+/gm, '\u2022 ');
392
+ html = html.replace(/^#{1,6}\s+/gm, '');
393
+ // Restore code placeholders
394
+ html = html.replace(/\x00P(\d+)\x00/g, (_, idx) => placeholders[parseInt(idx)]);
395
+ return html;
396
+ }
397
+ // ── Run ─────────────────────────────────────────────────────────
398
+ main().catch((err) => {
399
+ logger.error(`Fatal: ${err.message}`);
400
+ process.exit(1);
401
+ });
402
+ //# sourceMappingURL=enhanced-hook-notify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enhanced-hook-notify.js","sourceRoot":"","sources":["../enhanced-hook-notify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Permission Denied Notify — Called by Claude Code's PermissionDenied hook.
4
+ *
5
+ * Notifies user when auto mode blocks a tool. Optionally allows retry.
6
+ *
7
+ * Stdin JSON: { tool_name, tool_input, cwd, session_id, reason }
8
+ * Stdout: { hookSpecificOutput: { retry: true } } — to retry the tool
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=permission-denied-notify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permission-denied-notify.d.ts","sourceRoot":"","sources":["../permission-denied-notify.ts"],"names":[],"mappings":";AAEA;;;;;;;GAOG"}
@@ -0,0 +1,193 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Permission Denied Notify — Called by Claude Code's PermissionDenied hook.
5
+ *
6
+ * Notifies user when auto mode blocks a tool. Optionally allows retry.
7
+ *
8
+ * Stdin JSON: { tool_name, tool_input, cwd, session_id, reason }
9
+ * Stdout: { hookSpecificOutput: { retry: true } } — to retry the tool
10
+ */
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const path_1 = __importDefault(require("path"));
16
+ const paths_1 = require("./src/utils/paths");
17
+ require('dotenv').config({ path: path_1.default.join(paths_1.PROJECT_ROOT, '.env'), quiet: true });
18
+ const fs_1 = __importDefault(require("fs"));
19
+ const https_1 = __importDefault(require("https"));
20
+ const workspace_router_1 = require("./workspace-router");
21
+ const prompt_bridge_1 = require("./prompt-bridge");
22
+ const active_check_1 = require("./src/utils/active-check");
23
+ const BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN;
24
+ const CHAT_ID = process.env.TELEGRAM_CHAT_ID;
25
+ // Polling configuration
26
+ const POLL_INTERVAL_MS = 500;
27
+ const POLL_TIMEOUT_MS = 30000; // 30 seconds for permission denied (shorter than regular permission)
28
+ // ── Main ────────────────────────────────────────────────────────
29
+ async function main() {
30
+ const raw = await readStdin();
31
+ // Skip Telegram notification if user is at terminal AND this wasn't Telegram-injected
32
+ const typingActivePath = path_1.default.join(paths_1.PROJECT_ROOT, 'src/data', 'typing-active');
33
+ const isTelegramInjected = fs_1.default.existsSync(typingActivePath);
34
+ if (!isTelegramInjected && (0, active_check_1.isUserActiveAtTerminal)()) {
35
+ return;
36
+ }
37
+ let payload;
38
+ try {
39
+ payload = JSON.parse(raw);
40
+ }
41
+ catch {
42
+ return;
43
+ }
44
+ const toolName = payload.tool_name || 'Unknown tool';
45
+ const reason = payload.reason || 'No reason provided';
46
+ const cwd = payload.cwd || process.cwd();
47
+ const workspace = (0, workspace_router_1.extractWorkspaceName)(cwd);
48
+ const promptId = (0, prompt_bridge_1.generatePromptId)();
49
+ let messageText = `\u{1F6AB} *Permission Denied* — ${escapeMarkdown(workspace)}\n\n`;
50
+ messageText += `*Tool:* \`${escapeMarkdown(toolName)}\`\n`;
51
+ messageText += `*Reason:* ${escapeMarkdown(reason)}`;
52
+ // Build inline keyboard with Retry/Dismiss buttons
53
+ const keyboard = [
54
+ [
55
+ { text: '\u{1F504} Retry', callback_data: `perm-denied:${promptId}:retry` },
56
+ { text: '\u274C Dismiss', callback_data: `perm-denied:${promptId}:dismiss` },
57
+ ],
58
+ ];
59
+ // Write pending file
60
+ (0, prompt_bridge_1.writePending)(promptId, {
61
+ type: 'permission-denied',
62
+ workspace,
63
+ toolName,
64
+ reason,
65
+ });
66
+ // Send Telegram message
67
+ try {
68
+ const result = await sendTelegramWithKeyboard(messageText, { inline_keyboard: keyboard });
69
+ if (result && result.message_id) {
70
+ (0, workspace_router_1.trackNotificationMessage)(result.message_id, workspace, 'permission-denied');
71
+ }
72
+ }
73
+ catch (err) {
74
+ process.stderr.write(`[permission-denied-notify] Telegram send failed: ${err.message}\n`);
75
+ (0, prompt_bridge_1.cleanPrompt)(promptId);
76
+ return;
77
+ }
78
+ // Poll for response
79
+ const response = await pollForResponse(promptId);
80
+ (0, prompt_bridge_1.cleanPrompt)(promptId);
81
+ if (response && response.action === 'retry') {
82
+ const output = {
83
+ hookSpecificOutput: {
84
+ hookEventName: 'PermissionDenied',
85
+ retry: true,
86
+ },
87
+ };
88
+ process.stdout.write(JSON.stringify(output) + '\n');
89
+ }
90
+ // If dismiss or timeout, no output — tool stays blocked
91
+ }
92
+ // ── Polling ─────────────────────────────────────────────────────
93
+ function pollForResponse(promptId) {
94
+ return new Promise((resolve) => {
95
+ const responseFile = path_1.default.join(prompt_bridge_1.PROMPTS_DIR, `response-${promptId}.json`);
96
+ const startTime = Date.now();
97
+ const interval = setInterval(() => {
98
+ if (Date.now() - startTime > POLL_TIMEOUT_MS) {
99
+ clearInterval(interval);
100
+ process.stderr.write(`[permission-denied-notify] Timed out waiting for response\n`);
101
+ resolve(null);
102
+ return;
103
+ }
104
+ try {
105
+ if (fs_1.default.existsSync(responseFile)) {
106
+ const raw = fs_1.default.readFileSync(responseFile, 'utf8');
107
+ const data = JSON.parse(raw);
108
+ clearInterval(interval);
109
+ resolve(data);
110
+ }
111
+ }
112
+ catch {
113
+ // File not ready yet or parse error — keep polling
114
+ }
115
+ }, POLL_INTERVAL_MS);
116
+ });
117
+ }
118
+ // ── Telegram ────────────────────────────────────────────────────
119
+ function sendTelegramWithKeyboard(text, replyMarkup) {
120
+ return new Promise((resolve, reject) => {
121
+ const body = JSON.stringify({
122
+ chat_id: CHAT_ID,
123
+ text,
124
+ parse_mode: 'Markdown',
125
+ reply_markup: replyMarkup,
126
+ });
127
+ const options = {
128
+ hostname: 'api.telegram.org',
129
+ path: `/bot${BOT_TOKEN}/sendMessage`,
130
+ method: 'POST',
131
+ headers: {
132
+ 'Content-Type': 'application/json',
133
+ 'Content-Length': Buffer.byteLength(body),
134
+ },
135
+ timeout: 5000,
136
+ };
137
+ const req = https_1.default.request(options, (res) => {
138
+ let data = '';
139
+ res.on('data', (chunk) => { data += chunk; });
140
+ res.on('end', () => {
141
+ if (res.statusCode >= 200 && res.statusCode < 300) {
142
+ try {
143
+ const parsed = JSON.parse(data);
144
+ resolve(parsed.result || null);
145
+ }
146
+ catch {
147
+ resolve(null);
148
+ }
149
+ }
150
+ else {
151
+ reject(new Error(`Telegram API ${res.statusCode}: ${data}`));
152
+ }
153
+ });
154
+ });
155
+ req.on('error', reject);
156
+ req.on('timeout', () => {
157
+ req.destroy();
158
+ reject(new Error('Telegram request timed out'));
159
+ });
160
+ req.write(body);
161
+ req.end();
162
+ });
163
+ }
164
+ // ── Helpers ──────────────────────────────────────────────────────
165
+ function readStdin() {
166
+ return new Promise((resolve) => {
167
+ let data = '';
168
+ let resolved = false;
169
+ process.stdin.setEncoding('utf8');
170
+ process.stdin.on('data', (chunk) => { data += chunk; });
171
+ process.stdin.on('end', () => {
172
+ if (!resolved) {
173
+ resolved = true;
174
+ resolve(data);
175
+ }
176
+ });
177
+ setTimeout(() => {
178
+ if (!resolved) {
179
+ resolved = true;
180
+ process.stdin.destroy();
181
+ resolve(data || '{}');
182
+ }
183
+ }, 500);
184
+ });
185
+ }
186
+ function escapeMarkdown(text) {
187
+ return text.replace(/([_*`\[])/g, '\\$1');
188
+ }
189
+ // ── Run ─────────────────────────────────────────────────────────
190
+ main().catch((err) => {
191
+ process.stderr.write(`[permission-denied-notify] Fatal: ${err.message}\n`);
192
+ });
193
+ //# sourceMappingURL=permission-denied-notify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permission-denied-notify.js","sourceRoot":"","sources":["../permission-denied-notify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Permission Hook — Called by Claude Code's PermissionRequest hook.
4
+ *
5
+ * Blocking approach:
6
+ * 1. Sends a Telegram message with inline keyboard buttons
7
+ * 2. Polls for a response file written by the bot's callback handler
8
+ * 3. Outputs the permission decision via stdout
9
+ * 4. Exits cleanly
10
+ *
11
+ * Stdin JSON: { tool_name, tool_input, cwd, session_id, hook_event_name }
12
+ * Stdout JSON: { hookSpecificOutput: { hookEventName, decision: { behavior } } }
13
+ */
14
+ export {};
15
+ //# sourceMappingURL=permission-hook.d.ts.map