@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,45 @@
1
+ /**
2
+ * Cheesyboy Core Notifier
3
+ * Central notification orchestrator that manages multiple channels
4
+ */
5
+ import Logger from './logger';
6
+ import ConfigManager from './config';
7
+ import type { Notification } from '../types';
8
+ interface NotificationChannel {
9
+ enabled: boolean;
10
+ send(notification: Notification): Promise<boolean>;
11
+ test(): Promise<boolean>;
12
+ getStatus(): Record<string, unknown>;
13
+ }
14
+ interface I18nContent {
15
+ title: string;
16
+ message: string;
17
+ }
18
+ interface I18nLang {
19
+ completed: I18nContent;
20
+ waiting: I18nContent;
21
+ [type: string]: I18nContent;
22
+ }
23
+ interface I18nData {
24
+ [lang: string]: I18nLang;
25
+ }
26
+ declare class Notifier {
27
+ logger: Logger;
28
+ config: ConfigManager;
29
+ channels: Map<string, NotificationChannel>;
30
+ i18n: I18nData | null;
31
+ constructor(configManager?: ConfigManager | null);
32
+ registerChannel(name: string, channel: NotificationChannel): void;
33
+ initializeChannels(): Promise<void>;
34
+ notify(type: string, metadata?: Record<string, unknown>): Promise<Record<string, unknown>>;
35
+ _buildNotification(type: string, metadata?: Record<string, unknown>): Notification;
36
+ _getNotificationContent(type: string, lang: string): I18nContent;
37
+ _loadI18n(): void;
38
+ test(): Promise<Record<string, {
39
+ success: boolean;
40
+ error?: string;
41
+ }>>;
42
+ getStatus(): Record<string, unknown>;
43
+ }
44
+ export = Notifier;
45
+ //# sourceMappingURL=notifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifier.d.ts","sourceRoot":"","sources":["../../../src/core/notifier.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,MAAM,MAAM,UAAU,CAAC;AAC9B,OAAO,aAAa,MAAM,UAAU,CAAC;AACrC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,UAAU,mBAAmB;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IACzB,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AAED,UAAU,WAAW;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,QAAQ;IACd,SAAS,EAAE,WAAW,CAAC;IACvB,OAAO,EAAE,WAAW,CAAC;IACrB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;CAC/B;AAED,UAAU,QAAQ;IACd,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC5B;AASD,cAAM,QAAQ;IACV,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAC3C,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;gBAEV,aAAa,GAAE,aAAa,GAAG,IAAW;IAStD,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,IAAI;IAK3D,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAwCnC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAyCpG,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,YAAY;IAyBtF,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW;IAShE,SAAS,IAAI,IAAI;IAmCX,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAkB3E,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAgBvC;AAED,SAAS,QAAQ,CAAC"}
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ /**
3
+ * Cheesyboy Core Notifier
4
+ * Central notification orchestrator that manages multiple channels
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ const logger_1 = __importDefault(require("./logger"));
10
+ const config_1 = __importDefault(require("./config"));
11
+ class Notifier {
12
+ logger;
13
+ config;
14
+ channels;
15
+ i18n;
16
+ constructor(configManager = null) {
17
+ this.logger = new logger_1.default('Notifier');
18
+ this.config = configManager || new config_1.default();
19
+ this.channels = new Map();
20
+ this.i18n = null;
21
+ this._loadI18n();
22
+ }
23
+ registerChannel(name, channel) {
24
+ this.logger.debug(`Registering channel: ${name}`);
25
+ this.channels.set(name, channel);
26
+ }
27
+ async initializeChannels() {
28
+ this.logger.debug('Initializing channels...');
29
+ // Load desktop channel
30
+ const DesktopChannel = require('../channels/local/desktop');
31
+ const desktopConfig = this.config.getChannel('desktop');
32
+ if (desktopConfig && desktopConfig.enabled) {
33
+ const desktop = new DesktopChannel(desktopConfig.config || {});
34
+ desktop.config.completedSound = this.config.get('sound.completed');
35
+ desktop.config.waitingSound = this.config.get('sound.waiting');
36
+ this.registerChannel('desktop', desktop);
37
+ }
38
+ // Load email channel
39
+ const EmailChannel = require('../channels/email/smtp');
40
+ const emailConfig = this.config.getChannel('email');
41
+ if (emailConfig && emailConfig.enabled) {
42
+ const email = new EmailChannel(emailConfig.config || {});
43
+ this.registerChannel('email', email);
44
+ }
45
+ // Load LINE channel
46
+ const LINEChannel = require('../channels/line/line');
47
+ const lineConfig = this.config.getChannel('line');
48
+ if (lineConfig && lineConfig.enabled) {
49
+ const line = new LINEChannel(lineConfig.config || {});
50
+ this.registerChannel('line', line);
51
+ }
52
+ // Load Telegram channel
53
+ const TelegramChannel = require('../channels/telegram/telegram');
54
+ const telegramConfig = this.config.getChannel('telegram');
55
+ if (telegramConfig && telegramConfig.enabled) {
56
+ const telegram = new TelegramChannel(telegramConfig.config || {});
57
+ this.registerChannel('telegram', telegram);
58
+ }
59
+ this.logger.info(`Initialized ${this.channels.size} channels`);
60
+ }
61
+ async notify(type, metadata = {}) {
62
+ if (!this.config.get('enabled', true)) {
63
+ this.logger.debug('Notifications disabled');
64
+ return { success: false, reason: 'disabled' };
65
+ }
66
+ const notification = this._buildNotification(type, metadata);
67
+ this.logger.info(`Sending ${type} notification for project: ${notification.project}`);
68
+ const results = {};
69
+ const promises = [];
70
+ // Send to all channels in parallel
71
+ for (const [name, channel] of this.channels) {
72
+ if (channel.enabled) {
73
+ promises.push(channel.send(notification)
74
+ .then((success) => ({ name, success }))
75
+ .catch((error) => ({ name, success: false, error: error.message })));
76
+ }
77
+ else {
78
+ results[name] = { name, success: false, reason: 'disabled' };
79
+ }
80
+ }
81
+ // Wait for all channels to complete
82
+ const channelResults = await Promise.all(promises);
83
+ channelResults.forEach(result => {
84
+ results[result.name] = result;
85
+ });
86
+ const successCount = Object.values(results).filter(r => r.success).length;
87
+ this.logger.info(`Notification sent to ${successCount}/${this.channels.size} channels`);
88
+ return {
89
+ success: successCount > 0,
90
+ results,
91
+ notification
92
+ };
93
+ }
94
+ _buildNotification(type, metadata = {}) {
95
+ const project = metadata.project || this.config.getProjectName();
96
+ const lang = this.config.get('language', 'zh-CN');
97
+ const content = this._getNotificationContent(type, lang);
98
+ // Replace project placeholder
99
+ const message = content.message.replace('{project}', project);
100
+ // Use custom message if configured
101
+ const customMessage = this.config.get(`customMessages.${type}`);
102
+ const finalMessage = customMessage ? customMessage.replace('{project}', project) : message;
103
+ return {
104
+ type,
105
+ title: content.title,
106
+ message: finalMessage,
107
+ project,
108
+ metadata: {
109
+ timestamp: new Date().toISOString(),
110
+ language: lang,
111
+ ...metadata
112
+ }
113
+ };
114
+ }
115
+ _getNotificationContent(type, lang) {
116
+ if (!this.i18n) {
117
+ this._loadI18n();
118
+ }
119
+ const langData = this.i18n[lang] || this.i18n['en'];
120
+ return langData[type] || langData.completed;
121
+ }
122
+ _loadI18n() {
123
+ this.i18n = {
124
+ 'zh-CN': {
125
+ completed: {
126
+ title: 'Claude Code - Task Completed',
127
+ message: '[{project}] Task completed, Claude is waiting for next instruction'
128
+ },
129
+ waiting: {
130
+ title: 'Claude Code - Waiting for Input',
131
+ message: '[{project}] Claude needs your further guidance'
132
+ }
133
+ },
134
+ 'en': {
135
+ completed: {
136
+ title: 'Claude Code - Task Completed',
137
+ message: '[{project}] Task completed, Claude is waiting for next instruction'
138
+ },
139
+ waiting: {
140
+ title: 'Claude Code - Waiting for Input',
141
+ message: '[{project}] Claude needs your further guidance'
142
+ }
143
+ },
144
+ 'ja': {
145
+ completed: {
146
+ title: 'Claude Code - Task Completed',
147
+ message: '[{project}] Task completed, Claude is waiting for next instruction'
148
+ },
149
+ waiting: {
150
+ title: 'Claude Code - Waiting for Input',
151
+ message: '[{project}] Claude needs your further guidance'
152
+ }
153
+ }
154
+ };
155
+ }
156
+ async test() {
157
+ this.logger.info('Testing all channels...');
158
+ const results = {};
159
+ for (const [name, channel] of this.channels) {
160
+ try {
161
+ const success = await channel.test();
162
+ results[name] = { success };
163
+ this.logger.info(`Channel ${name}: ${success ? 'PASS' : 'FAIL'}`);
164
+ }
165
+ catch (error) {
166
+ results[name] = { success: false, error: error.message };
167
+ this.logger.error(`Channel ${name}: ERROR - ${error.message}`);
168
+ }
169
+ }
170
+ return results;
171
+ }
172
+ getStatus() {
173
+ const channels = {};
174
+ for (const [name, channel] of this.channels) {
175
+ channels[name] = channel.getStatus();
176
+ }
177
+ return {
178
+ enabled: this.config.get('enabled', true),
179
+ channels,
180
+ config: {
181
+ language: this.config.get('language'),
182
+ sound: this.config.get('sound'),
183
+ customMessages: this.config.get('customMessages')
184
+ }
185
+ };
186
+ }
187
+ }
188
+ module.exports = Notifier;
189
+ //# sourceMappingURL=notifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifier.js","sourceRoot":"","sources":["../../../src/core/notifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * LemonSqueezy License API client.
3
+ *
4
+ * The License API is a *separate* API from the main LemonSqueezy API:
5
+ * - Base URL: https://api.lemonsqueezy.com
6
+ * - Endpoints: /v1/licenses/{activate,validate,deactivate}
7
+ * - Auth: NONE — the license_key in the form-encoded body IS the auth.
8
+ * - Headers: Accept: application/json
9
+ *
10
+ * Docs (the License API page is referenced in the LS API reference;
11
+ * authoritative URL examples used by the official guides):
12
+ * https://api.lemonsqueezy.com/v1/licenses/activate
13
+ * https://api.lemonsqueezy.com/v1/licenses/validate
14
+ * https://api.lemonsqueezy.com/v1/licenses/deactivate
15
+ *
16
+ * Response invariant: status code is 200 on success AND on most "soft" errors
17
+ * (invalid key, exceeded activation limit, etc.). The booleans
18
+ * (activated|valid|deactivated) and the `error` field are the source of truth.
19
+ * Hard failures (bad request, 5xx) come back as non-200 — handled below.
20
+ */
21
+ export interface LicenseKeyObject {
22
+ id: number;
23
+ status: string;
24
+ key: string;
25
+ activation_limit: number | null;
26
+ activation_usage: number;
27
+ created_at: string;
28
+ expires_at: string | null;
29
+ }
30
+ export interface LicenseInstance {
31
+ id: string;
32
+ name: string;
33
+ created_at: string;
34
+ }
35
+ export interface LicenseMeta {
36
+ store_id: number;
37
+ order_id: number;
38
+ order_item_id: number;
39
+ product_id: number;
40
+ product_name: string;
41
+ variant_id: number;
42
+ variant_name: string;
43
+ customer_id: number;
44
+ customer_name: string;
45
+ customer_email: string;
46
+ }
47
+ export interface ActivateResponse {
48
+ activated: boolean;
49
+ error: string | null;
50
+ license_key: LicenseKeyObject;
51
+ instance: LicenseInstance;
52
+ meta: LicenseMeta;
53
+ }
54
+ export interface ValidateResponse {
55
+ valid: boolean;
56
+ error: string | null;
57
+ license_key: LicenseKeyObject;
58
+ instance: LicenseInstance | null;
59
+ meta: LicenseMeta;
60
+ }
61
+ export interface DeactivateResponse {
62
+ deactivated: boolean;
63
+ error: string | null;
64
+ license_key: LicenseKeyObject;
65
+ meta: LicenseMeta;
66
+ }
67
+ /** Stored locally at ~/.ccgram/.license.json (mode 0600). */
68
+ export interface LicenseRecord {
69
+ licenseKey: string;
70
+ instanceId: string;
71
+ instanceName: string;
72
+ activatedAt: string;
73
+ lastValidatedAt?: string;
74
+ productName?: string;
75
+ customerName?: string;
76
+ customerEmail?: string;
77
+ status?: string;
78
+ activationLimit?: number | null;
79
+ activationUsage?: number;
80
+ expiresAt?: string | null;
81
+ }
82
+ /** Discriminated union for the validator result. */
83
+ export type LicenseResult = {
84
+ kind: 'ok';
85
+ record: LicenseRecord;
86
+ } | {
87
+ kind: 'invalid';
88
+ reason: string;
89
+ } | {
90
+ kind: 'limit';
91
+ reason: string;
92
+ } | {
93
+ kind: 'network';
94
+ reason: string;
95
+ } | {
96
+ kind: 'bad-request';
97
+ reason: string;
98
+ };
99
+ export declare function activate(licenseKey: string, instanceName: string): Promise<ActivateResponse>;
100
+ export declare function validate(licenseKey: string, instanceId?: string): Promise<ValidateResponse>;
101
+ export declare function deactivate(licenseKey: string, instanceId: string): Promise<DeactivateResponse>;
102
+ /** Pick a reasonable instance name. Hostname is identifiable to the customer
103
+ * ("activated on stephens-mbp") without leaking PII. Override via env. */
104
+ export declare function defaultInstanceName(): string;
105
+ export declare function readLicenseRecord(): LicenseRecord | null;
106
+ export declare function removeLicenseRecord(): void;
107
+ export declare function isDevMode(): boolean;
108
+ export declare function writeDevMarker(): void;
109
+ export declare function removeDevMarker(): void;
110
+ /**
111
+ * Activate a license key and persist the record. Returns a discriminated
112
+ * result so the caller can render a focused error message.
113
+ */
114
+ export declare function activateAndStore(licenseKey: string): Promise<LicenseResult>;
115
+ export declare function validateStored(): Promise<LicenseResult>;
116
+ /**
117
+ * Deactivate the stored license remotely and remove the local record.
118
+ */
119
+ export declare function deactivateStored(): Promise<LicenseResult>;
120
+ //# sourceMappingURL=license-validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"license-validator.d.ts","sourceRoot":"","sources":["../../../src/lib/license-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAaH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,gBAAgB,CAAC;IAC9B,QAAQ,EAAE,eAAe,CAAC;IAC1B,IAAI,EAAE,WAAW,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,gBAAgB,CAAC;IAC9B,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IACjC,IAAI,EAAE,WAAW,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,gBAAgB,CAAC;IAC9B,IAAI,EAAE,WAAW,CAAC;CACnB;AAED,6DAA6D;AAC7D,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,oDAAoD;AACpD,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAuC5C,wBAAsB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CASlG;AAED,wBAAsB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAQjG;AAED,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CASpG;AAcD;2EAC2E;AAC3E,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAYD,wBAAgB,iBAAiB,IAAI,aAAa,GAAG,IAAI,CAOxD;AAED,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED,wBAAgB,SAAS,IAAI,OAAO,CAEnC;AAED,wBAAgB,cAAc,IAAI,IAAI,CAGrC;AAED,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAmCjF;AASD,wBAAsB,cAAc,IAAI,OAAO,CAAC,aAAa,CAAC,CAsC7D;AAED;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,aAAa,CAAC,CAoB/D"}
@@ -0,0 +1,294 @@
1
+ "use strict";
2
+ /**
3
+ * LemonSqueezy License API client.
4
+ *
5
+ * The License API is a *separate* API from the main LemonSqueezy API:
6
+ * - Base URL: https://api.lemonsqueezy.com
7
+ * - Endpoints: /v1/licenses/{activate,validate,deactivate}
8
+ * - Auth: NONE — the license_key in the form-encoded body IS the auth.
9
+ * - Headers: Accept: application/json
10
+ *
11
+ * Docs (the License API page is referenced in the LS API reference;
12
+ * authoritative URL examples used by the official guides):
13
+ * https://api.lemonsqueezy.com/v1/licenses/activate
14
+ * https://api.lemonsqueezy.com/v1/licenses/validate
15
+ * https://api.lemonsqueezy.com/v1/licenses/deactivate
16
+ *
17
+ * Response invariant: status code is 200 on success AND on most "soft" errors
18
+ * (invalid key, exceeded activation limit, etc.). The booleans
19
+ * (activated|valid|deactivated) and the `error` field are the source of truth.
20
+ * Hard failures (bad request, 5xx) come back as non-200 — handled below.
21
+ */
22
+ var __importDefault = (this && this.__importDefault) || function (mod) {
23
+ return (mod && mod.__esModule) ? mod : { "default": mod };
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.activate = activate;
27
+ exports.validate = validate;
28
+ exports.deactivate = deactivate;
29
+ exports.defaultInstanceName = defaultInstanceName;
30
+ exports.readLicenseRecord = readLicenseRecord;
31
+ exports.removeLicenseRecord = removeLicenseRecord;
32
+ exports.isDevMode = isDevMode;
33
+ exports.writeDevMarker = writeDevMarker;
34
+ exports.removeDevMarker = removeDevMarker;
35
+ exports.activateAndStore = activateAndStore;
36
+ exports.validateStored = validateStored;
37
+ exports.deactivateStored = deactivateStored;
38
+ const os_1 = __importDefault(require("os"));
39
+ const fs_1 = __importDefault(require("fs"));
40
+ const path_1 = __importDefault(require("path"));
41
+ const paths_1 = require("../utils/paths");
42
+ const LS_BASE = process.env.LEMONSQUEEZY_BASE_URL || 'https://api.lemonsqueezy.com';
43
+ const LICENSE_FILE = path_1.default.join(paths_1.CCGRAM_HOME, '.license.json');
44
+ const DEV_MARKER_FILE = path_1.default.join(paths_1.CCGRAM_HOME, '.license-dev');
45
+ /**
46
+ * POST form-encoded data to a LemonSqueezy License API endpoint.
47
+ * Uses global fetch (Node 18+).
48
+ */
49
+ async function postForm(endpoint, params) {
50
+ const url = `${LS_BASE}${endpoint}`;
51
+ const body = new URLSearchParams(params).toString();
52
+ const controller = new AbortController();
53
+ const timeout = setTimeout(() => controller.abort(), 10000);
54
+ try {
55
+ const res = await fetch(url, {
56
+ method: 'POST',
57
+ headers: {
58
+ 'Accept': 'application/json',
59
+ 'Content-Type': 'application/x-www-form-urlencoded',
60
+ },
61
+ body,
62
+ signal: controller.signal,
63
+ });
64
+ const text = await res.text();
65
+ return { status: res.status, body: text };
66
+ }
67
+ finally {
68
+ clearTimeout(timeout);
69
+ }
70
+ }
71
+ // ── Endpoint wrappers ────────────────────────────────────────────
72
+ async function activate(licenseKey, instanceName) {
73
+ const res = await postForm('/v1/licenses/activate', {
74
+ license_key: licenseKey,
75
+ instance_name: instanceName,
76
+ });
77
+ if (res.status !== 200) {
78
+ throw new HttpError(`Activate returned ${res.status}`, res.status, res.body);
79
+ }
80
+ return JSON.parse(res.body);
81
+ }
82
+ async function validate(licenseKey, instanceId) {
83
+ const params = { license_key: licenseKey };
84
+ if (instanceId)
85
+ params.instance_id = instanceId;
86
+ const res = await postForm('/v1/licenses/validate', params);
87
+ if (res.status !== 200) {
88
+ throw new HttpError(`Validate returned ${res.status}`, res.status, res.body);
89
+ }
90
+ return JSON.parse(res.body);
91
+ }
92
+ async function deactivate(licenseKey, instanceId) {
93
+ const res = await postForm('/v1/licenses/deactivate', {
94
+ license_key: licenseKey,
95
+ instance_id: instanceId,
96
+ });
97
+ if (res.status !== 200) {
98
+ throw new HttpError(`Deactivate returned ${res.status}`, res.status, res.body);
99
+ }
100
+ return JSON.parse(res.body);
101
+ }
102
+ class HttpError extends Error {
103
+ status;
104
+ body;
105
+ constructor(msg, status, body) {
106
+ super(msg);
107
+ this.status = status;
108
+ this.body = body;
109
+ }
110
+ }
111
+ // ── High-level operations ────────────────────────────────────────
112
+ /** Pick a reasonable instance name. Hostname is identifiable to the customer
113
+ * ("activated on stephens-mbp") without leaking PII. Override via env. */
114
+ function defaultInstanceName() {
115
+ return process.env.CHEESY_INSTANCE_NAME || os_1.default.hostname() || 'cheesy';
116
+ }
117
+ /** Atomically write the license record to disk with mode 0600. */
118
+ function writeLicenseRecord(rec) {
119
+ fs_1.default.mkdirSync(paths_1.CCGRAM_HOME, { recursive: true });
120
+ const tmp = LICENSE_FILE + '.tmp';
121
+ fs_1.default.writeFileSync(tmp, JSON.stringify(rec, null, 2), { mode: 0o600 });
122
+ fs_1.default.renameSync(tmp, LICENSE_FILE);
123
+ // rename preserves mode on POSIX, but just in case:
124
+ try {
125
+ fs_1.default.chmodSync(LICENSE_FILE, 0o600);
126
+ }
127
+ catch { }
128
+ }
129
+ function readLicenseRecord() {
130
+ try {
131
+ const raw = fs_1.default.readFileSync(LICENSE_FILE, 'utf8');
132
+ return JSON.parse(raw);
133
+ }
134
+ catch {
135
+ return null;
136
+ }
137
+ }
138
+ function removeLicenseRecord() {
139
+ try {
140
+ fs_1.default.unlinkSync(LICENSE_FILE);
141
+ }
142
+ catch { }
143
+ }
144
+ function isDevMode() {
145
+ return fs_1.default.existsSync(DEV_MARKER_FILE);
146
+ }
147
+ function writeDevMarker() {
148
+ fs_1.default.mkdirSync(paths_1.CCGRAM_HOME, { recursive: true });
149
+ fs_1.default.writeFileSync(DEV_MARKER_FILE, new Date().toISOString() + '\n', { mode: 0o600 });
150
+ }
151
+ function removeDevMarker() {
152
+ try {
153
+ fs_1.default.unlinkSync(DEV_MARKER_FILE);
154
+ }
155
+ catch { }
156
+ }
157
+ /**
158
+ * Activate a license key and persist the record. Returns a discriminated
159
+ * result so the caller can render a focused error message.
160
+ */
161
+ async function activateAndStore(licenseKey) {
162
+ const instanceName = defaultInstanceName();
163
+ let resp;
164
+ try {
165
+ resp = await activate(licenseKey, instanceName);
166
+ }
167
+ catch (err) {
168
+ if (err instanceof HttpError) {
169
+ return classifyHttpError(err);
170
+ }
171
+ return { kind: 'network', reason: err.message };
172
+ }
173
+ if (!resp.activated || resp.error) {
174
+ return classifySoftError(resp.error, resp.license_key);
175
+ }
176
+ const now = new Date().toISOString();
177
+ const rec = {
178
+ licenseKey,
179
+ instanceId: resp.instance.id,
180
+ instanceName: resp.instance.name,
181
+ activatedAt: now,
182
+ lastValidatedAt: now,
183
+ productName: resp.meta.product_name,
184
+ customerName: resp.meta.customer_name,
185
+ customerEmail: resp.meta.customer_email,
186
+ status: resp.license_key.status,
187
+ activationLimit: resp.license_key.activation_limit,
188
+ activationUsage: resp.license_key.activation_usage,
189
+ expiresAt: resp.license_key.expires_at,
190
+ };
191
+ writeLicenseRecord(rec);
192
+ // If they had a dev marker, drop it — they're a paying customer now.
193
+ removeDevMarker();
194
+ return { kind: 'ok', record: rec };
195
+ }
196
+ /**
197
+ * Validate the stored license remotely. On success, refreshes the cached
198
+ * record. On network failure, returns the cached record IF it was validated
199
+ * within the offline-grace window.
200
+ */
201
+ const OFFLINE_GRACE_DAYS = 7;
202
+ async function validateStored() {
203
+ const cached = readLicenseRecord();
204
+ if (!cached)
205
+ return { kind: 'invalid', reason: 'No license activated. Run: cheesy license activate <KEY>' };
206
+ let resp;
207
+ try {
208
+ resp = await validate(cached.licenseKey, cached.instanceId);
209
+ }
210
+ catch (err) {
211
+ if (err instanceof HttpError) {
212
+ return classifyHttpError(err);
213
+ }
214
+ // Network failure — fall back to cached if recent enough.
215
+ const last = cached.lastValidatedAt ? new Date(cached.lastValidatedAt).getTime() : 0;
216
+ const ageDays = (Date.now() - last) / (1000 * 60 * 60 * 24);
217
+ if (last && ageDays < OFFLINE_GRACE_DAYS) {
218
+ return { kind: 'ok', record: cached };
219
+ }
220
+ return { kind: 'network', reason: `Could not reach LemonSqueezy and the cached validation is ${Math.floor(ageDays)} days old (grace = ${OFFLINE_GRACE_DAYS}d).` };
221
+ }
222
+ if (!resp.valid || resp.error) {
223
+ return classifySoftError(resp.error, resp.license_key);
224
+ }
225
+ // Refresh cache.
226
+ const refreshed = {
227
+ ...cached,
228
+ lastValidatedAt: new Date().toISOString(),
229
+ productName: resp.meta.product_name,
230
+ customerName: resp.meta.customer_name,
231
+ customerEmail: resp.meta.customer_email,
232
+ status: resp.license_key.status,
233
+ activationLimit: resp.license_key.activation_limit,
234
+ activationUsage: resp.license_key.activation_usage,
235
+ expiresAt: resp.license_key.expires_at,
236
+ };
237
+ writeLicenseRecord(refreshed);
238
+ return { kind: 'ok', record: refreshed };
239
+ }
240
+ /**
241
+ * Deactivate the stored license remotely and remove the local record.
242
+ */
243
+ async function deactivateStored() {
244
+ const cached = readLicenseRecord();
245
+ if (!cached)
246
+ return { kind: 'invalid', reason: 'No license is currently activated on this machine.' };
247
+ try {
248
+ const resp = await deactivate(cached.licenseKey, cached.instanceId);
249
+ if (!resp.deactivated && resp.error) {
250
+ // Still remove the local file — the customer's intent is clear.
251
+ removeLicenseRecord();
252
+ return { kind: 'invalid', reason: resp.error };
253
+ }
254
+ }
255
+ catch (err) {
256
+ // If we can't reach LS, we *don't* remove the local record — better to
257
+ // leave it so the user can retry, otherwise they'd lose their instance ID.
258
+ if (err instanceof HttpError)
259
+ return classifyHttpError(err);
260
+ return { kind: 'network', reason: err.message };
261
+ }
262
+ removeLicenseRecord();
263
+ return { kind: 'ok', record: cached };
264
+ }
265
+ // ── Error classification ─────────────────────────────────────────
266
+ function classifyHttpError(err) {
267
+ // LS uses 400/404 for bad inputs.
268
+ let msg = err.message;
269
+ try {
270
+ const body = JSON.parse(err.body);
271
+ if (body.error)
272
+ msg = body.error;
273
+ }
274
+ catch { }
275
+ if (err.status >= 500) {
276
+ return { kind: 'network', reason: `LemonSqueezy server error (${err.status}). Try again in a moment.` };
277
+ }
278
+ return { kind: 'bad-request', reason: msg };
279
+ }
280
+ function classifySoftError(err, lk) {
281
+ const reason = err || 'license_key validation failed';
282
+ const lower = reason.toLowerCase();
283
+ if (lower.includes('activation') && lower.includes('limit')) {
284
+ return { kind: 'limit', reason };
285
+ }
286
+ if (lk?.status === 'expired' || lower.includes('expired')) {
287
+ return { kind: 'invalid', reason: 'License key has expired.' };
288
+ }
289
+ if (lk?.status === 'disabled' || lower.includes('disabled')) {
290
+ return { kind: 'invalid', reason: 'License key has been disabled. Contact support.' };
291
+ }
292
+ return { kind: 'invalid', reason };
293
+ }
294
+ //# sourceMappingURL=license-validator.js.map