@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.
Files changed (247) hide show
  1. package/.env.example +19 -0
  2. package/LICENSE +21 -0
  3. package/README.md +338 -0
  4. package/ccgram.service +24 -0
  5. package/config/channels.json +58 -0
  6. package/config/default.json +27 -0
  7. package/config/defaults/config.json +16 -0
  8. package/config/defaults/i18n.json +32 -0
  9. package/config/email-template.json +31 -0
  10. package/config/test-with-subagent.json +16 -0
  11. package/config/user.json +27 -0
  12. package/dist/claude-hook-notify.d.ts +7 -0
  13. package/dist/claude-hook-notify.d.ts.map +1 -0
  14. package/dist/claude-hook-notify.js +154 -0
  15. package/dist/claude-hook-notify.js.map +1 -0
  16. package/dist/claude-remote.d.ts +50 -0
  17. package/dist/claude-remote.d.ts.map +1 -0
  18. package/dist/claude-remote.js +927 -0
  19. package/dist/claude-remote.js.map +1 -0
  20. package/dist/cli.d.ts +3 -0
  21. package/dist/cli.d.ts.map +1 -0
  22. package/dist/cli.js +110 -0
  23. package/dist/cli.js.map +1 -0
  24. package/dist/enhanced-hook-notify.d.ts +16 -0
  25. package/dist/enhanced-hook-notify.d.ts.map +1 -0
  26. package/dist/enhanced-hook-notify.js +288 -0
  27. package/dist/enhanced-hook-notify.js.map +1 -0
  28. package/dist/permission-hook.d.ts +15 -0
  29. package/dist/permission-hook.d.ts.map +1 -0
  30. package/dist/permission-hook.js +357 -0
  31. package/dist/permission-hook.js.map +1 -0
  32. package/dist/prompt-bridge.d.ts +50 -0
  33. package/dist/prompt-bridge.d.ts.map +1 -0
  34. package/dist/prompt-bridge.js +173 -0
  35. package/dist/prompt-bridge.js.map +1 -0
  36. package/dist/question-notify.d.ts +16 -0
  37. package/dist/question-notify.d.ts.map +1 -0
  38. package/dist/question-notify.js +272 -0
  39. package/dist/question-notify.js.map +1 -0
  40. package/dist/setup.d.ts +10 -0
  41. package/dist/setup.d.ts.map +1 -0
  42. package/dist/setup.js +649 -0
  43. package/dist/setup.js.map +1 -0
  44. package/dist/smart-monitor.d.ts +7 -0
  45. package/dist/smart-monitor.d.ts.map +1 -0
  46. package/dist/smart-monitor.js +256 -0
  47. package/dist/smart-monitor.js.map +1 -0
  48. package/dist/src/automation/claude-automation.d.ts +45 -0
  49. package/dist/src/automation/claude-automation.d.ts.map +1 -0
  50. package/dist/src/automation/claude-automation.js +367 -0
  51. package/dist/src/automation/claude-automation.js.map +1 -0
  52. package/dist/src/automation/clipboard-automation.d.ts +35 -0
  53. package/dist/src/automation/clipboard-automation.d.ts.map +1 -0
  54. package/dist/src/automation/clipboard-automation.js +242 -0
  55. package/dist/src/automation/clipboard-automation.js.map +1 -0
  56. package/dist/src/automation/simple-automation.d.ts +56 -0
  57. package/dist/src/automation/simple-automation.d.ts.map +1 -0
  58. package/dist/src/automation/simple-automation.js +283 -0
  59. package/dist/src/automation/simple-automation.js.map +1 -0
  60. package/dist/src/channels/base/channel.d.ts +60 -0
  61. package/dist/src/channels/base/channel.d.ts.map +1 -0
  62. package/dist/src/channels/base/channel.js +96 -0
  63. package/dist/src/channels/base/channel.js.map +1 -0
  64. package/dist/src/channels/email/smtp.d.ts +74 -0
  65. package/dist/src/channels/email/smtp.d.ts.map +1 -0
  66. package/dist/src/channels/email/smtp.js +605 -0
  67. package/dist/src/channels/email/smtp.js.map +1 -0
  68. package/dist/src/channels/line/line.d.ts +36 -0
  69. package/dist/src/channels/line/line.d.ts.map +1 -0
  70. package/dist/src/channels/line/line.js +180 -0
  71. package/dist/src/channels/line/line.js.map +1 -0
  72. package/dist/src/channels/line/webhook.d.ts +55 -0
  73. package/dist/src/channels/line/webhook.d.ts.map +1 -0
  74. package/dist/src/channels/line/webhook.js +191 -0
  75. package/dist/src/channels/line/webhook.js.map +1 -0
  76. package/dist/src/channels/local/desktop.d.ts +30 -0
  77. package/dist/src/channels/local/desktop.d.ts.map +1 -0
  78. package/dist/src/channels/local/desktop.js +161 -0
  79. package/dist/src/channels/local/desktop.js.map +1 -0
  80. package/dist/src/channels/telegram/telegram.d.ts +43 -0
  81. package/dist/src/channels/telegram/telegram.d.ts.map +1 -0
  82. package/dist/src/channels/telegram/telegram.js +223 -0
  83. package/dist/src/channels/telegram/telegram.js.map +1 -0
  84. package/dist/src/channels/telegram/webhook.d.ts +75 -0
  85. package/dist/src/channels/telegram/webhook.d.ts.map +1 -0
  86. package/dist/src/channels/telegram/webhook.js +278 -0
  87. package/dist/src/channels/telegram/webhook.js.map +1 -0
  88. package/dist/src/config-manager.d.ts +16 -0
  89. package/dist/src/config-manager.d.ts.map +1 -0
  90. package/dist/src/config-manager.js +152 -0
  91. package/dist/src/config-manager.js.map +1 -0
  92. package/dist/src/core/config.d.ts +28 -0
  93. package/dist/src/core/config.d.ts.map +1 -0
  94. package/dist/src/core/config.js +248 -0
  95. package/dist/src/core/config.js.map +1 -0
  96. package/dist/src/core/logger.d.ts +19 -0
  97. package/dist/src/core/logger.d.ts.map +1 -0
  98. package/dist/src/core/logger.js +47 -0
  99. package/dist/src/core/logger.js.map +1 -0
  100. package/dist/src/core/notifier.d.ts +45 -0
  101. package/dist/src/core/notifier.d.ts.map +1 -0
  102. package/dist/src/core/notifier.js +189 -0
  103. package/dist/src/core/notifier.js.map +1 -0
  104. package/dist/src/daemon/taskping-daemon.d.ts +38 -0
  105. package/dist/src/daemon/taskping-daemon.d.ts.map +1 -0
  106. package/dist/src/daemon/taskping-daemon.js +306 -0
  107. package/dist/src/daemon/taskping-daemon.js.map +1 -0
  108. package/dist/src/relay/claude-command-bridge.d.ts +57 -0
  109. package/dist/src/relay/claude-command-bridge.d.ts.map +1 -0
  110. package/dist/src/relay/claude-command-bridge.js +188 -0
  111. package/dist/src/relay/claude-command-bridge.js.map +1 -0
  112. package/dist/src/relay/command-relay.d.ts +94 -0
  113. package/dist/src/relay/command-relay.d.ts.map +1 -0
  114. package/dist/src/relay/command-relay.js +463 -0
  115. package/dist/src/relay/command-relay.js.map +1 -0
  116. package/dist/src/relay/email-listener.d.ts +65 -0
  117. package/dist/src/relay/email-listener.d.ts.map +1 -0
  118. package/dist/src/relay/email-listener.js +460 -0
  119. package/dist/src/relay/email-listener.js.map +1 -0
  120. package/dist/src/relay/relay-pty.d.ts +21 -0
  121. package/dist/src/relay/relay-pty.d.ts.map +1 -0
  122. package/dist/src/relay/relay-pty.js +696 -0
  123. package/dist/src/relay/relay-pty.js.map +1 -0
  124. package/dist/src/relay/smart-injector.d.ts +30 -0
  125. package/dist/src/relay/smart-injector.d.ts.map +1 -0
  126. package/dist/src/relay/smart-injector.js +233 -0
  127. package/dist/src/relay/smart-injector.js.map +1 -0
  128. package/dist/src/relay/tmux-injector.d.ts +46 -0
  129. package/dist/src/relay/tmux-injector.d.ts.map +1 -0
  130. package/dist/src/relay/tmux-injector.js +413 -0
  131. package/dist/src/relay/tmux-injector.js.map +1 -0
  132. package/dist/src/tools/config-manager.d.ts +33 -0
  133. package/dist/src/tools/config-manager.d.ts.map +1 -0
  134. package/dist/src/tools/config-manager.js +448 -0
  135. package/dist/src/tools/config-manager.js.map +1 -0
  136. package/dist/src/tools/installer.d.ts +38 -0
  137. package/dist/src/tools/installer.d.ts.map +1 -0
  138. package/dist/src/tools/installer.js +222 -0
  139. package/dist/src/tools/installer.js.map +1 -0
  140. package/dist/src/types/callbacks.d.ts +29 -0
  141. package/dist/src/types/callbacks.d.ts.map +1 -0
  142. package/dist/src/types/callbacks.js +7 -0
  143. package/dist/src/types/callbacks.js.map +1 -0
  144. package/dist/src/types/config.d.ts +56 -0
  145. package/dist/src/types/config.d.ts.map +1 -0
  146. package/dist/src/types/config.js +6 -0
  147. package/dist/src/types/config.js.map +1 -0
  148. package/dist/src/types/hooks.d.ts +47 -0
  149. package/dist/src/types/hooks.d.ts.map +1 -0
  150. package/dist/src/types/hooks.js +6 -0
  151. package/dist/src/types/hooks.js.map +1 -0
  152. package/dist/src/types/index.d.ts +7 -0
  153. package/dist/src/types/index.d.ts.map +1 -0
  154. package/dist/src/types/index.js +23 -0
  155. package/dist/src/types/index.js.map +1 -0
  156. package/dist/src/types/ipc.d.ts +43 -0
  157. package/dist/src/types/ipc.d.ts.map +1 -0
  158. package/dist/src/types/ipc.js +7 -0
  159. package/dist/src/types/ipc.js.map +1 -0
  160. package/dist/src/types/session.d.ts +70 -0
  161. package/dist/src/types/session.d.ts.map +1 -0
  162. package/dist/src/types/session.js +9 -0
  163. package/dist/src/types/session.js.map +1 -0
  164. package/dist/src/types/telegram.d.ts +58 -0
  165. package/dist/src/types/telegram.d.ts.map +1 -0
  166. package/dist/src/types/telegram.js +6 -0
  167. package/dist/src/types/telegram.js.map +1 -0
  168. package/dist/src/utils/active-check.d.ts +19 -0
  169. package/dist/src/utils/active-check.d.ts.map +1 -0
  170. package/dist/src/utils/active-check.js +41 -0
  171. package/dist/src/utils/active-check.js.map +1 -0
  172. package/dist/src/utils/callback-parser.d.ts +21 -0
  173. package/dist/src/utils/callback-parser.d.ts.map +1 -0
  174. package/dist/src/utils/callback-parser.js +58 -0
  175. package/dist/src/utils/callback-parser.js.map +1 -0
  176. package/dist/src/utils/controller-injector.d.ts +21 -0
  177. package/dist/src/utils/controller-injector.d.ts.map +1 -0
  178. package/dist/src/utils/controller-injector.js +108 -0
  179. package/dist/src/utils/controller-injector.js.map +1 -0
  180. package/dist/src/utils/conversation-tracker.d.ts +32 -0
  181. package/dist/src/utils/conversation-tracker.d.ts.map +1 -0
  182. package/dist/src/utils/conversation-tracker.js +119 -0
  183. package/dist/src/utils/conversation-tracker.js.map +1 -0
  184. package/dist/src/utils/http-request.d.ts +25 -0
  185. package/dist/src/utils/http-request.d.ts.map +1 -0
  186. package/dist/src/utils/http-request.js +66 -0
  187. package/dist/src/utils/http-request.js.map +1 -0
  188. package/dist/src/utils/optional-require.d.ts +13 -0
  189. package/dist/src/utils/optional-require.d.ts.map +1 -0
  190. package/dist/src/utils/optional-require.js +37 -0
  191. package/dist/src/utils/optional-require.js.map +1 -0
  192. package/dist/src/utils/paths.d.ts +11 -0
  193. package/dist/src/utils/paths.d.ts.map +1 -0
  194. package/dist/src/utils/paths.js +28 -0
  195. package/dist/src/utils/paths.js.map +1 -0
  196. package/dist/src/utils/pty-session-manager.d.ts +42 -0
  197. package/dist/src/utils/pty-session-manager.d.ts.map +1 -0
  198. package/dist/src/utils/pty-session-manager.js +182 -0
  199. package/dist/src/utils/pty-session-manager.js.map +1 -0
  200. package/dist/src/utils/subagent-tracker.d.ts +64 -0
  201. package/dist/src/utils/subagent-tracker.d.ts.map +1 -0
  202. package/dist/src/utils/subagent-tracker.js +191 -0
  203. package/dist/src/utils/subagent-tracker.js.map +1 -0
  204. package/dist/src/utils/tmux-monitor.d.ts +102 -0
  205. package/dist/src/utils/tmux-monitor.d.ts.map +1 -0
  206. package/dist/src/utils/tmux-monitor.js +642 -0
  207. package/dist/src/utils/tmux-monitor.js.map +1 -0
  208. package/dist/src/utils/trace-capture.d.ts +42 -0
  209. package/dist/src/utils/trace-capture.d.ts.map +1 -0
  210. package/dist/src/utils/trace-capture.js +102 -0
  211. package/dist/src/utils/trace-capture.js.map +1 -0
  212. package/dist/start-all-webhooks.d.ts +7 -0
  213. package/dist/start-all-webhooks.d.ts.map +1 -0
  214. package/dist/start-all-webhooks.js +98 -0
  215. package/dist/start-all-webhooks.js.map +1 -0
  216. package/dist/start-line-webhook.d.ts +7 -0
  217. package/dist/start-line-webhook.d.ts.map +1 -0
  218. package/dist/start-line-webhook.js +59 -0
  219. package/dist/start-line-webhook.js.map +1 -0
  220. package/dist/start-relay-pty.d.ts +7 -0
  221. package/dist/start-relay-pty.d.ts.map +1 -0
  222. package/dist/start-relay-pty.js +173 -0
  223. package/dist/start-relay-pty.js.map +1 -0
  224. package/dist/start-telegram-webhook.d.ts +7 -0
  225. package/dist/start-telegram-webhook.d.ts.map +1 -0
  226. package/dist/start-telegram-webhook.js +80 -0
  227. package/dist/start-telegram-webhook.js.map +1 -0
  228. package/dist/user-prompt-hook.d.ts +13 -0
  229. package/dist/user-prompt-hook.d.ts.map +1 -0
  230. package/dist/user-prompt-hook.js +45 -0
  231. package/dist/user-prompt-hook.js.map +1 -0
  232. package/dist/workspace-router.d.ts +78 -0
  233. package/dist/workspace-router.d.ts.map +1 -0
  234. package/dist/workspace-router.js +408 -0
  235. package/dist/workspace-router.js.map +1 -0
  236. package/dist/workspace-telegram-bot.d.ts +3 -0
  237. package/dist/workspace-telegram-bot.d.ts.map +1 -0
  238. package/dist/workspace-telegram-bot.js +1172 -0
  239. package/dist/workspace-telegram-bot.js.map +1 -0
  240. package/package.json +80 -0
  241. package/src/types/callbacks.ts +39 -0
  242. package/src/types/config.ts +63 -0
  243. package/src/types/hooks.ts +50 -0
  244. package/src/types/index.ts +6 -0
  245. package/src/types/ipc.ts +55 -0
  246. package/src/types/session.ts +72 -0
  247. package/src/types/telegram.ts +66 -0
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Telegram Bot API types (subset used by ccgram).
3
+ */
4
+ export interface TelegramUser {
5
+ id: number;
6
+ is_bot: boolean;
7
+ first_name: string;
8
+ last_name?: string;
9
+ username?: string;
10
+ }
11
+ export interface TelegramChat {
12
+ id: number;
13
+ type: string;
14
+ title?: string;
15
+ username?: string;
16
+ first_name?: string;
17
+ last_name?: string;
18
+ }
19
+ export interface TelegramMessage {
20
+ message_id: number;
21
+ from?: TelegramUser;
22
+ chat: TelegramChat;
23
+ date: number;
24
+ text?: string;
25
+ reply_to_message?: TelegramMessage;
26
+ }
27
+ export interface TelegramCallbackQuery {
28
+ id: string;
29
+ from: TelegramUser;
30
+ message?: TelegramMessage;
31
+ data?: string;
32
+ }
33
+ export interface TelegramUpdate {
34
+ update_id: number;
35
+ message?: TelegramMessage;
36
+ callback_query?: TelegramCallbackQuery;
37
+ }
38
+ export interface InlineKeyboardButton {
39
+ text: string;
40
+ callback_data?: string;
41
+ url?: string;
42
+ }
43
+ export interface InlineKeyboardMarkup {
44
+ inline_keyboard: InlineKeyboardButton[][];
45
+ }
46
+ export interface SendMessageRequest {
47
+ chat_id: string | number;
48
+ text: string;
49
+ parse_mode?: 'Markdown' | 'HTML' | 'MarkdownV2';
50
+ reply_markup?: InlineKeyboardMarkup;
51
+ }
52
+ export interface TelegramApiResponse<T = unknown> {
53
+ ok: boolean;
54
+ result?: T;
55
+ description?: string;
56
+ error_code?: number;
57
+ }
58
+ //# sourceMappingURL=telegram.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram.d.ts","sourceRoot":"","sources":["../../../src/types/telegram.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,eAAe,CAAC;CACpC;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,cAAc,CAAC,EAAE,qBAAqB,CAAC;CACxC;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,eAAe,EAAE,oBAAoB,EAAE,EAAE,CAAC;CAC3C;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,UAAU,GAAG,MAAM,GAAG,YAAY,CAAC;IAChD,YAAY,CAAC,EAAE,oBAAoB,CAAC;CACrC;AAED,MAAM,WAAW,mBAAmB,CAAC,CAAC,GAAG,OAAO;IAC9C,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,CAAC,CAAC;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * Telegram Bot API types (subset used by ccgram).
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ //# sourceMappingURL=telegram.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram.js","sourceRoot":"","sources":["../../../src/types/telegram.ts"],"names":[],"mappings":";AAAA;;GAEG"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * active-check.ts — Detects whether the user is actively working at the terminal.
3
+ *
4
+ * Reads /tmp/claude_last_msg_time (written by the UserPromptSubmit hook in
5
+ * ~/.claude/settings.json) to determine when the user last sent a message to Claude.
6
+ *
7
+ * If the gap is below ACTIVE_THRESHOLD_SECONDS (default: 300 = 5 min), the user
8
+ * is considered active at the terminal and Telegram notifications should be
9
+ * suppressed (they can see the output directly).
10
+ *
11
+ * Applied to: enhanced-hook-notify (Stop/Notification), permission-hook (PermissionRequest).
12
+ * Skipped when: typing-active file exists (command was Telegram-injected).
13
+ */
14
+ /**
15
+ * Returns true if the user sent a Claude message within the active threshold.
16
+ * @param thresholdSeconds - seconds since last message to consider user "active" (default 300)
17
+ */
18
+ export declare function isUserActiveAtTerminal(thresholdSeconds?: number): boolean;
19
+ //# sourceMappingURL=active-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"active-check.d.ts","sourceRoot":"","sources":["../../../src/utils/active-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,gBAAgB,GAAE,MAAsF,GACvG,OAAO,CAWT"}
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ /**
3
+ * active-check.ts — Detects whether the user is actively working at the terminal.
4
+ *
5
+ * Reads /tmp/claude_last_msg_time (written by the UserPromptSubmit hook in
6
+ * ~/.claude/settings.json) to determine when the user last sent a message to Claude.
7
+ *
8
+ * If the gap is below ACTIVE_THRESHOLD_SECONDS (default: 300 = 5 min), the user
9
+ * is considered active at the terminal and Telegram notifications should be
10
+ * suppressed (they can see the output directly).
11
+ *
12
+ * Applied to: enhanced-hook-notify (Stop/Notification), permission-hook (PermissionRequest).
13
+ * Skipped when: typing-active file exists (command was Telegram-injected).
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
+ exports.isUserActiveAtTerminal = isUserActiveAtTerminal;
20
+ const fs_1 = __importDefault(require("fs"));
21
+ const LAST_MSG_FILE = '/tmp/claude_last_msg_time';
22
+ const DEFAULT_THRESHOLD = 300; // 5 minutes
23
+ /**
24
+ * Returns true if the user sent a Claude message within the active threshold.
25
+ * @param thresholdSeconds - seconds since last message to consider user "active" (default 300)
26
+ */
27
+ function isUserActiveAtTerminal(thresholdSeconds = parseInt(process.env.ACTIVE_THRESHOLD_SECONDS || '', 10) || DEFAULT_THRESHOLD) {
28
+ try {
29
+ const raw = fs_1.default.readFileSync(LAST_MSG_FILE, 'utf8').trim();
30
+ const lastMsg = parseInt(raw, 10);
31
+ if (!lastMsg || isNaN(lastMsg))
32
+ return false;
33
+ const nowSeconds = Math.floor(Date.now() / 1000);
34
+ return (nowSeconds - lastMsg) < thresholdSeconds;
35
+ }
36
+ catch {
37
+ // File doesn't exist — no session info, assume not active
38
+ return false;
39
+ }
40
+ }
41
+ //# sourceMappingURL=active-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"active-check.js","sourceRoot":"","sources":["../../../src/utils/active-check.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;;;;AAWH,wDAaC;AAtBD,4CAAoB;AAEpB,MAAM,aAAa,GAAG,2BAA2B,CAAC;AAClD,MAAM,iBAAiB,GAAG,GAAG,CAAC,CAAC,YAAY;AAE3C;;;GAGG;AACH,SAAgB,sBAAsB,CACpC,mBAA2B,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,iBAAiB;IAExG,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAE,CAAC,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QAC1D,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAClC,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC;YAAE,OAAO,KAAK,CAAC;QAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QACjD,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC,GAAG,gBAAgB,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,0DAA0D;QAC1D,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Callback Data Parser
3
+ *
4
+ * Parses Telegram inline keyboard callback_data strings into
5
+ * structured objects. Format: "type:promptId:action"
6
+ *
7
+ * Extracted from workspace-telegram-bot.js for testability.
8
+ */
9
+ import type { ParsedCallback } from '../types';
10
+ /**
11
+ * Parse a callback_data string into a structured object.
12
+ *
13
+ * Return shapes:
14
+ * { type: 'new', projectName: string }
15
+ * { type: 'perm', promptId: string, action: string }
16
+ * { type: 'opt', promptId: string, optionIndex: number }
17
+ * { type: 'opt-submit', promptId: string }
18
+ * { type: 'qperm', promptId: string, optionIndex: number }
19
+ */
20
+ export declare function parseCallbackData(data: string | null | undefined): ParsedCallback | null;
21
+ //# sourceMappingURL=callback-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callback-parser.d.ts","sourceRoot":"","sources":["../../../src/utils/callback-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,cAAc,GAAG,IAAI,CAqCxF"}
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ /**
3
+ * Callback Data Parser
4
+ *
5
+ * Parses Telegram inline keyboard callback_data strings into
6
+ * structured objects. Format: "type:promptId:action"
7
+ *
8
+ * Extracted from workspace-telegram-bot.js for testability.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.parseCallbackData = parseCallbackData;
12
+ /**
13
+ * Parse a callback_data string into a structured object.
14
+ *
15
+ * Return shapes:
16
+ * { type: 'new', projectName: string }
17
+ * { type: 'perm', promptId: string, action: string }
18
+ * { type: 'opt', promptId: string, optionIndex: number }
19
+ * { type: 'opt-submit', promptId: string }
20
+ * { type: 'qperm', promptId: string, optionIndex: number }
21
+ */
22
+ function parseCallbackData(data) {
23
+ if (!data)
24
+ return null;
25
+ const parts = data.split(':');
26
+ const type = parts[0];
27
+ // new:<projectName> (rejoin in case name has colons)
28
+ if (type === 'new') {
29
+ const projectName = parts.slice(1).join(':');
30
+ if (!projectName)
31
+ return null;
32
+ return { type: 'new', projectName };
33
+ }
34
+ // opt-submit:<promptId> (only 2 parts)
35
+ if (type === 'opt-submit') {
36
+ if (parts.length < 2 || !parts[1])
37
+ return null;
38
+ return { type: 'opt-submit', promptId: parts[1] };
39
+ }
40
+ // All other types need at least 3 parts: type:promptId:action
41
+ if (parts.length < 3)
42
+ return null;
43
+ const promptId = parts[1];
44
+ const action = parts[2];
45
+ if (!promptId)
46
+ return null;
47
+ switch (type) {
48
+ case 'perm':
49
+ return { type: 'perm', promptId, action };
50
+ case 'opt':
51
+ return { type: 'opt', promptId, optionIndex: parseInt(action, 10) };
52
+ case 'qperm':
53
+ return { type: 'qperm', promptId, optionIndex: parseInt(action, 10) };
54
+ default:
55
+ return null;
56
+ }
57
+ }
58
+ //# sourceMappingURL=callback-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callback-parser.js","sourceRoot":"","sources":["../../../src/utils/callback-parser.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;AAcH,8CAqCC;AA/CD;;;;;;;;;GASG;AACH,SAAgB,iBAAiB,CAAC,IAA+B;IAC/D,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAEtB,qDAAqD;IACrD,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnB,MAAM,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7C,IAAI,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC;QAC9B,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;IACtC,CAAC;IAED,uCAAuC;IACvC,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;QAC1B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QAC/C,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACpD,CAAC;IAED,8DAA8D;IAC9D,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAElC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC1B,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAExB,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAE3B,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,MAAM;YACT,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;QAC5C,KAAK,KAAK;YACR,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;QACtE,KAAK,OAAO;YACV,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;QACxE;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Controller Injector
3
+ * Injects commands into tmux sessions or PTY
4
+ */
5
+ import Logger from '../core/logger';
6
+ interface ControllerInjectorConfig {
7
+ mode?: string;
8
+ defaultSession?: string;
9
+ }
10
+ declare class ControllerInjector {
11
+ logger: Logger;
12
+ mode: string;
13
+ defaultSession: string;
14
+ constructor(config?: ControllerInjectorConfig);
15
+ injectCommand(command: string, sessionName?: string | null): Promise<boolean>;
16
+ _injectTmux(command: string, sessionName: string): boolean;
17
+ _injectPty(command: string, sessionName: string): boolean;
18
+ listSessions(): string[];
19
+ }
20
+ export = ControllerInjector;
21
+ //# sourceMappingURL=controller-injector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller-injector.d.ts","sourceRoot":"","sources":["../../../src/utils/controller-injector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,MAAM,MAAM,gBAAgB,CAAC;AAGpC,UAAU,wBAAwB;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B;AAWD,cAAM,kBAAkB;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;gBAEX,MAAM,GAAE,wBAA6B;IAM3C,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,GAAE,MAAM,GAAG,IAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAUzF,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO;IAyB1D,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO;IA4BzD,YAAY,IAAI,MAAM,EAAE;CA2B3B;AAED,SAAS,kBAAkB,CAAC"}
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ /**
3
+ * Controller Injector
4
+ * Injects commands into tmux sessions or PTY
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ const child_process_1 = require("child_process");
10
+ const path_1 = __importDefault(require("path"));
11
+ const fs_1 = __importDefault(require("fs"));
12
+ const logger_1 = __importDefault(require("../core/logger"));
13
+ const paths_1 = require("./paths");
14
+ class ControllerInjector {
15
+ logger;
16
+ mode;
17
+ defaultSession;
18
+ constructor(config = {}) {
19
+ this.logger = new logger_1.default('ControllerInjector');
20
+ this.mode = config.mode || process.env.INJECTION_MODE || 'pty';
21
+ this.defaultSession = config.defaultSession || process.env.TMUX_SESSION || 'claude-code';
22
+ }
23
+ async injectCommand(command, sessionName = null) {
24
+ const session = sessionName || this.defaultSession;
25
+ if (this.mode === 'tmux') {
26
+ return this._injectTmux(command, session);
27
+ }
28
+ else {
29
+ return this._injectPty(command, session);
30
+ }
31
+ }
32
+ _injectTmux(command, sessionName) {
33
+ try {
34
+ // Check if tmux session exists
35
+ try {
36
+ (0, child_process_1.execSync)(`tmux has-session -t ${sessionName}`, { stdio: 'ignore' });
37
+ }
38
+ catch (error) {
39
+ throw new Error(`Tmux session '${sessionName}' not found`);
40
+ }
41
+ // Send command to tmux session and execute it
42
+ const escapedCommand = command.replace(/'/g, "'\\''");
43
+ // Send command first
44
+ (0, child_process_1.execSync)(`tmux send-keys -t ${sessionName} '${escapedCommand}'`);
45
+ // Then send Enter as separate command
46
+ (0, child_process_1.execSync)(`tmux send-keys -t ${sessionName} Enter`);
47
+ this.logger.info(`Command injected to tmux session '${sessionName}'`);
48
+ return true;
49
+ }
50
+ catch (error) {
51
+ this.logger.error('Failed to inject command via tmux:', error.message);
52
+ throw error;
53
+ }
54
+ }
55
+ _injectPty(command, sessionName) {
56
+ try {
57
+ // Find PTY session file
58
+ const sessionMapPath = process.env.SESSION_MAP_PATH ||
59
+ path_1.default.join(paths_1.PROJECT_ROOT, 'src/data/session-map.json');
60
+ if (!fs_1.default.existsSync(sessionMapPath)) {
61
+ throw new Error('Session map file not found');
62
+ }
63
+ const sessionMap = JSON.parse(fs_1.default.readFileSync(sessionMapPath, 'utf8'));
64
+ const sessionInfo = sessionMap[sessionName];
65
+ if (!sessionInfo || !sessionInfo.ptyPath) {
66
+ throw new Error(`PTY session '${sessionName}' not found`);
67
+ }
68
+ // Write command to PTY
69
+ fs_1.default.writeFileSync(sessionInfo.ptyPath, command + '\n');
70
+ this.logger.info(`Command injected to PTY session '${sessionName}'`);
71
+ return true;
72
+ }
73
+ catch (error) {
74
+ this.logger.error('Failed to inject command via PTY:', error.message);
75
+ throw error;
76
+ }
77
+ }
78
+ listSessions() {
79
+ if (this.mode === 'tmux') {
80
+ try {
81
+ const output = (0, child_process_1.execSync)('tmux list-sessions -F "#{session_name}"', {
82
+ encoding: 'utf8',
83
+ stdio: ['ignore', 'pipe', 'ignore']
84
+ });
85
+ return output.trim().split('\n').filter(Boolean);
86
+ }
87
+ catch (error) {
88
+ return [];
89
+ }
90
+ }
91
+ else {
92
+ try {
93
+ const sessionMapPath = process.env.SESSION_MAP_PATH ||
94
+ path_1.default.join(paths_1.PROJECT_ROOT, 'src/data/session-map.json');
95
+ if (!fs_1.default.existsSync(sessionMapPath)) {
96
+ return [];
97
+ }
98
+ const sessionMap = JSON.parse(fs_1.default.readFileSync(sessionMapPath, 'utf8'));
99
+ return Object.keys(sessionMap);
100
+ }
101
+ catch (error) {
102
+ return [];
103
+ }
104
+ }
105
+ }
106
+ }
107
+ module.exports = ControllerInjector;
108
+ //# sourceMappingURL=controller-injector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller-injector.js","sourceRoot":"","sources":["../../../src/utils/controller-injector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Conversation Tracker - Used to capture user questions and Claude responses
3
+ */
4
+ interface ConversationMessage {
5
+ type: 'user' | 'claude';
6
+ content: string;
7
+ timestamp: string;
8
+ }
9
+ interface ConversationSession {
10
+ created: string;
11
+ messages: ConversationMessage[];
12
+ }
13
+ interface ConversationMap {
14
+ [sessionId: string]: ConversationSession;
15
+ }
16
+ interface RecentConversation {
17
+ userQuestion: string;
18
+ claudeResponse: string;
19
+ }
20
+ declare class ConversationTracker {
21
+ conversationPath: string;
22
+ constructor();
23
+ ensureDataDir(): void;
24
+ recordUserMessage(sessionId: string, message: string): void;
25
+ recordClaudeResponse(sessionId: string, response: string): void;
26
+ getRecentConversation(sessionId: string, limit?: number): RecentConversation;
27
+ cleanupOldConversations(): number;
28
+ loadConversations(): ConversationMap;
29
+ saveConversations(conversations: ConversationMap): void;
30
+ }
31
+ export = ConversationTracker;
32
+ //# sourceMappingURL=conversation-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-tracker.d.ts","sourceRoot":"","sources":["../../../src/utils/conversation-tracker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,UAAU,mBAAmB;IACzB,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,mBAAmB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;CACnC;AAED,UAAU,eAAe;IACrB,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,CAAC;CAC5C;AAED,UAAU,kBAAkB;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;CAC1B;AAED,cAAM,mBAAmB;IACrB,gBAAgB,EAAE,MAAM,CAAC;;IAOzB,aAAa,IAAI,IAAI;IAQrB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAmB3D,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAmB/D,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,GAAG,kBAAkB;IA+B/E,uBAAuB,IAAI,MAAM;IAiBjC,iBAAiB,IAAI,eAAe;IAapC,iBAAiB,CAAC,aAAa,EAAE,eAAe,GAAG,IAAI;CAO1D;AAED,SAAS,mBAAmB,CAAC"}
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ /**
3
+ * Conversation Tracker - Used to capture user questions and Claude responses
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const paths_1 = require("./paths");
11
+ class ConversationTracker {
12
+ conversationPath;
13
+ constructor() {
14
+ this.conversationPath = path_1.default.join(paths_1.PROJECT_ROOT, 'src/data/conversations.json');
15
+ this.ensureDataDir();
16
+ }
17
+ ensureDataDir() {
18
+ const dir = path_1.default.dirname(this.conversationPath);
19
+ if (!fs_1.default.existsSync(dir)) {
20
+ fs_1.default.mkdirSync(dir, { recursive: true });
21
+ }
22
+ }
23
+ // Record user question
24
+ recordUserMessage(sessionId, message) {
25
+ const conversations = this.loadConversations();
26
+ if (!conversations[sessionId]) {
27
+ conversations[sessionId] = {
28
+ created: new Date().toISOString(),
29
+ messages: []
30
+ };
31
+ }
32
+ conversations[sessionId].messages.push({
33
+ type: 'user',
34
+ content: message,
35
+ timestamp: new Date().toISOString()
36
+ });
37
+ this.saveConversations(conversations);
38
+ }
39
+ // Record Claude response
40
+ recordClaudeResponse(sessionId, response) {
41
+ const conversations = this.loadConversations();
42
+ if (!conversations[sessionId]) {
43
+ conversations[sessionId] = {
44
+ created: new Date().toISOString(),
45
+ messages: []
46
+ };
47
+ }
48
+ conversations[sessionId].messages.push({
49
+ type: 'claude',
50
+ content: response,
51
+ timestamp: new Date().toISOString()
52
+ });
53
+ this.saveConversations(conversations);
54
+ }
55
+ // Get recent conversation content
56
+ getRecentConversation(sessionId, limit = 2) {
57
+ const conversations = this.loadConversations();
58
+ const session = conversations[sessionId];
59
+ if (!session || !session.messages.length) {
60
+ return { userQuestion: '', claudeResponse: '' };
61
+ }
62
+ const messages = session.messages.slice(-limit * 2); // Get recent user-Claude conversation
63
+ let userQuestion = '';
64
+ let claudeResponse = '';
65
+ // Find most recent user question and Claude response from back to front
66
+ for (let i = messages.length - 1; i >= 0; i--) {
67
+ const msg = messages[i];
68
+ if (msg.type === 'claude' && !claudeResponse) {
69
+ claudeResponse = msg.content;
70
+ }
71
+ else if (msg.type === 'user' && !userQuestion) {
72
+ userQuestion = msg.content;
73
+ }
74
+ if (userQuestion && claudeResponse)
75
+ break;
76
+ }
77
+ return {
78
+ userQuestion: userQuestion || 'Unrecorded user question',
79
+ claudeResponse: claudeResponse || 'Unrecorded Claude response'
80
+ };
81
+ }
82
+ // Clean up expired conversations (older than 7 days)
83
+ cleanupOldConversations() {
84
+ const conversations = this.loadConversations();
85
+ const now = new Date();
86
+ const sevenDaysAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
87
+ const cleaned = {};
88
+ for (const [sessionId, session] of Object.entries(conversations)) {
89
+ const created = new Date(session.created);
90
+ if (created > sevenDaysAgo) {
91
+ cleaned[sessionId] = session;
92
+ }
93
+ }
94
+ this.saveConversations(cleaned);
95
+ return Object.keys(conversations).length - Object.keys(cleaned).length;
96
+ }
97
+ loadConversations() {
98
+ if (!fs_1.default.existsSync(this.conversationPath)) {
99
+ return {};
100
+ }
101
+ try {
102
+ return JSON.parse(fs_1.default.readFileSync(this.conversationPath, 'utf8'));
103
+ }
104
+ catch (error) {
105
+ console.error('Failed to load conversations:', error);
106
+ return {};
107
+ }
108
+ }
109
+ saveConversations(conversations) {
110
+ try {
111
+ fs_1.default.writeFileSync(this.conversationPath, JSON.stringify(conversations, null, 2));
112
+ }
113
+ catch (error) {
114
+ console.error('Failed to save conversations:', error);
115
+ }
116
+ }
117
+ }
118
+ module.exports = ConversationTracker;
119
+ //# sourceMappingURL=conversation-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-tracker.js","sourceRoot":"","sources":["../../../src/utils/conversation-tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Lightweight HTTP/JSON helper using Node's built-in https module.
3
+ * Replaces axios for simple GET/POST JSON requests.
4
+ *
5
+ * Supports: IPv4 forcing (family: 4), custom headers, timeout.
6
+ */
7
+ interface HttpOptions {
8
+ headers?: Record<string, string>;
9
+ family?: 4 | 6;
10
+ timeout?: number;
11
+ }
12
+ interface HttpResponse {
13
+ status: number | undefined;
14
+ data: unknown;
15
+ }
16
+ /**
17
+ * Make an HTTPS JSON request.
18
+ */
19
+ declare function httpJSON(method: string, url: string, body: unknown | null, opts?: HttpOptions): Promise<HttpResponse>;
20
+ declare namespace httpJSON {
21
+ var get: (url: string, opts?: HttpOptions) => Promise<HttpResponse>;
22
+ var post: (url: string, body: unknown, opts?: HttpOptions) => Promise<HttpResponse>;
23
+ }
24
+ export = httpJSON;
25
+ //# sourceMappingURL=http-request.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-request.d.ts","sourceRoot":"","sources":["../../../src/utils/http-request.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,UAAU,WAAW;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,YAAY;IACpB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,IAAI,EAAE,OAAO,CAAC;CACf;AAED;;GAEG;AACH,iBAAS,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,YAAY,CAAC,CAkDlH;kBAlDQ,QAAQ;mBAqDI,MAAM,SAAS,WAAW,KAAG,OAAO,CAAC,YAAY,CAAC;oBAGjD,MAAM,QAAQ,OAAO,SAAS,WAAW,KAAG,OAAO,CAAC,YAAY,CAAC;;AAEvF,SAAS,QAAQ,CAAC"}
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ /**
3
+ * Lightweight HTTP/JSON helper using Node's built-in https module.
4
+ * Replaces axios for simple GET/POST JSON requests.
5
+ *
6
+ * Supports: IPv4 forcing (family: 4), custom headers, timeout.
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ const https_1 = __importDefault(require("https"));
12
+ const url_1 = require("url");
13
+ /**
14
+ * Make an HTTPS JSON request.
15
+ */
16
+ function httpJSON(method, url, body, opts = {}) {
17
+ return new Promise((resolve, reject) => {
18
+ const parsed = new url_1.URL(url);
19
+ const payload = body ? JSON.stringify(body) : null;
20
+ const headers = { ...opts.headers };
21
+ const options = {
22
+ hostname: parsed.hostname,
23
+ port: parsed.port || 443,
24
+ path: parsed.pathname + parsed.search,
25
+ method,
26
+ headers,
27
+ timeout: opts.timeout || 10000,
28
+ };
29
+ if (opts.family) {
30
+ options.family = opts.family;
31
+ }
32
+ if (payload) {
33
+ headers['Content-Type'] = headers['Content-Type'] || 'application/json';
34
+ headers['Content-Length'] = Buffer.byteLength(payload);
35
+ }
36
+ const req = https_1.default.request(options, (res) => {
37
+ let data = '';
38
+ res.on('data', (chunk) => { data += chunk; });
39
+ res.on('end', () => {
40
+ let parsedData;
41
+ try {
42
+ parsedData = JSON.parse(data);
43
+ }
44
+ catch {
45
+ parsedData = data;
46
+ }
47
+ resolve({ status: res.statusCode, data: parsedData });
48
+ });
49
+ });
50
+ req.on('error', reject);
51
+ req.on('timeout', () => {
52
+ req.destroy();
53
+ reject(new Error('Request timed out'));
54
+ });
55
+ if (payload) {
56
+ req.write(payload);
57
+ }
58
+ req.end();
59
+ });
60
+ }
61
+ /** Convenience: GET request */
62
+ httpJSON.get = (url, opts) => httpJSON('GET', url, null, opts);
63
+ /** Convenience: POST request */
64
+ httpJSON.post = (url, body, opts) => httpJSON('POST', url, body, opts);
65
+ module.exports = httpJSON;
66
+ //# sourceMappingURL=http-request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-request.js","sourceRoot":"","sources":["../../../src/utils/http-request.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;AAEH,kDAA0B;AAC1B,6BAA0B;AAa1B;;GAEG;AACH,SAAS,QAAQ,CAAC,MAAc,EAAE,GAAW,EAAE,IAAoB,EAAE,OAAoB,EAAE;IACvF,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACnC,MAAM,MAAM,GAAG,IAAI,SAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAEnD,MAAM,OAAO,GAAoC,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAErE,MAAM,OAAO,GAAyB;YAClC,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,GAAG;YACxB,IAAI,EAAE,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,MAAM;YACrC,MAAM;YACN,OAAO;YACP,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,KAAK;SACjC,CAAC;QAEF,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YACd,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QACjC,CAAC;QAED,IAAI,OAAO,EAAE,CAAC;YACV,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC,IAAI,kBAAkB,CAAC;YACxE,OAAO,CAAC,gBAAgB,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC3D,CAAC;QAED,MAAM,GAAG,GAAG,eAAK,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACvC,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,GAAG,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACtD,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;gBACf,IAAI,UAAmB,CAAC;gBACxB,IAAI,CAAC;oBACD,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAClC,CAAC;gBAAC,MAAM,CAAC;oBACL,UAAU,GAAG,IAAI,CAAC;gBACtB,CAAC;gBACD,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;YAC1D,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACxB,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;YACnB,GAAG,CAAC,OAAO,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,IAAI,OAAO,EAAE,CAAC;YACV,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACvB,CAAC;QACD,GAAG,CAAC,GAAG,EAAE,CAAC;IACd,CAAC,CAAC,CAAC;AACP,CAAC;AAED,+BAA+B;AAC/B,QAAQ,CAAC,GAAG,GAAG,CAAC,GAAW,EAAE,IAAkB,EAAyB,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAE5G,gCAAgC;AAChC,QAAQ,CAAC,IAAI,GAAG,CAAC,GAAW,EAAE,IAAa,EAAE,IAAkB,EAAyB,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAE7H,iBAAS,QAAQ,CAAC"}