@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,927 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * CCGram - Claude Code Smart Notification System
5
+ * Main entry point for the CLI tool
6
+ */
7
+ var __importDefault = (this && this.__importDefault) || function (mod) {
8
+ return (mod && mod.__esModule) ? mod : { "default": mod };
9
+ };
10
+ // Load environment variables from CCGram directory
11
+ const path_1 = __importDefault(require("path"));
12
+ const paths_1 = require("./src/utils/paths");
13
+ const envPath = path_1.default.join(paths_1.PROJECT_ROOT, '.env');
14
+ require('dotenv').config({ path: envPath });
15
+ const logger_1 = __importDefault(require("./src/core/logger"));
16
+ const notifier_1 = __importDefault(require("./src/core/notifier"));
17
+ const config_1 = __importDefault(require("./src/core/config"));
18
+ class ClaudeCodeRemoteCLI {
19
+ logger;
20
+ config;
21
+ notifier;
22
+ constructor() {
23
+ this.logger = new logger_1.default('CLI');
24
+ this.config = new config_1.default();
25
+ this.notifier = new notifier_1.default(this.config);
26
+ }
27
+ async init() {
28
+ // Load configuration
29
+ this.config.load();
30
+ // Initialize channels
31
+ await this.notifier.initializeChannels();
32
+ }
33
+ async run() {
34
+ const args = process.argv.slice(2);
35
+ const command = args[0];
36
+ try {
37
+ await this.init();
38
+ switch (command) {
39
+ case 'notify':
40
+ await this.handleNotify(args.slice(1));
41
+ break;
42
+ case 'test':
43
+ await this.handleTest(args.slice(1));
44
+ break;
45
+ case 'status':
46
+ await this.handleStatus(args.slice(1));
47
+ break;
48
+ case 'config':
49
+ await this.handleConfig(args.slice(1));
50
+ break;
51
+ case 'install':
52
+ await this.handleInstall(args.slice(1));
53
+ break;
54
+ case 'relay':
55
+ await this.handleRelay(args.slice(1));
56
+ break;
57
+ case 'edit-config':
58
+ await this.handleEditConfig(args.slice(1));
59
+ break;
60
+ case 'setup-email':
61
+ await this.handleSetupEmail(args.slice(1));
62
+ break;
63
+ case 'daemon':
64
+ await this.handleDaemon(args.slice(1));
65
+ break;
66
+ case 'commands':
67
+ await this.handleCommands(args.slice(1));
68
+ break;
69
+ case 'test-paste':
70
+ await this.handleTestPaste(args.slice(1));
71
+ break;
72
+ case 'test-simple':
73
+ await this.handleTestSimple(args.slice(1));
74
+ break;
75
+ case 'test-claude':
76
+ await this.handleTestClaude(args.slice(1));
77
+ break;
78
+ case 'setup-permissions':
79
+ await this.handleSetupPermissions(args.slice(1));
80
+ break;
81
+ case 'diagnose':
82
+ await this.handleDiagnose(args.slice(1));
83
+ break;
84
+ case '--help':
85
+ case '-h':
86
+ case undefined:
87
+ this.showHelp();
88
+ break;
89
+ default:
90
+ console.error(`Unknown command: ${command}`);
91
+ this.showHelp();
92
+ process.exit(1);
93
+ }
94
+ }
95
+ catch (error) {
96
+ this.logger.error('CLI error:', error.message);
97
+ process.exit(1);
98
+ }
99
+ }
100
+ async handleNotify(args) {
101
+ const typeIndex = args.findIndex(arg => arg === '--type');
102
+ if (typeIndex === -1 || typeIndex + 1 >= args.length) {
103
+ console.error('Usage: claude-remote notify --type <completed|waiting>');
104
+ process.exit(1);
105
+ }
106
+ const type = args[typeIndex + 1];
107
+ if (!['completed', 'waiting'].includes(type)) {
108
+ console.error('Invalid type. Use: completed or waiting');
109
+ process.exit(1);
110
+ }
111
+ // Automatically capture current tmux session conversation content
112
+ const metadata = await this.captureCurrentConversation();
113
+ // Handle subagent notifications
114
+ if (type === 'waiting') {
115
+ const Config = require('./src/core/config');
116
+ const config = new Config();
117
+ config.load();
118
+ const enableSubagentNotifications = config.get('enableSubagentNotifications', false);
119
+ if (!enableSubagentNotifications) {
120
+ // Instead of skipping, track the subagent activity
121
+ const SubagentTracker = require('./src/utils/subagent-tracker');
122
+ const tracker = new SubagentTracker();
123
+ // Use tmux session as the tracking key
124
+ const trackingKey = metadata.tmuxSession || 'default';
125
+ // Capture more detailed information about the subagent activity
126
+ const activityDetails = {
127
+ userQuestion: metadata.userQuestion || 'No question captured',
128
+ claudeResponse: metadata.claudeResponse || 'No response captured',
129
+ timestamp: new Date().toISOString(),
130
+ tmuxSession: metadata.tmuxSession
131
+ };
132
+ // Don't truncate the response too aggressively
133
+ if (activityDetails.claudeResponse && activityDetails.claudeResponse.length > 1000) {
134
+ activityDetails.claudeResponse = activityDetails.claudeResponse.substring(0, 1000) + '...[see full output in tmux]';
135
+ }
136
+ tracker.addActivity(trackingKey, {
137
+ type: 'SubagentStop',
138
+ description: metadata.userQuestion || 'Subagent task',
139
+ details: activityDetails
140
+ });
141
+ this.logger.info(`Subagent activity tracked for tmux session: ${trackingKey}`);
142
+ process.exit(0);
143
+ }
144
+ }
145
+ // For completed notifications, include subagent activities and execution trace
146
+ if (type === 'completed') {
147
+ const Config = require('./src/core/config');
148
+ const config = new Config();
149
+ config.load();
150
+ const showSubagentActivitiesInEmail = config.get('showSubagentActivitiesInEmail', false);
151
+ if (showSubagentActivitiesInEmail) {
152
+ const SubagentTracker = require('./src/utils/subagent-tracker');
153
+ const tracker = new SubagentTracker();
154
+ const trackingKey = metadata.tmuxSession || 'default';
155
+ // Get and format subagent activities
156
+ const subagentSummary = tracker.formatActivitiesForEmail(trackingKey);
157
+ if (subagentSummary) {
158
+ metadata.subagentActivities = subagentSummary;
159
+ }
160
+ // Clear activities after including them in the notification
161
+ tracker.clearActivities(trackingKey);
162
+ }
163
+ else {
164
+ // Always clear activities even if not showing them
165
+ const SubagentTracker = require('./src/utils/subagent-tracker');
166
+ const tracker = new SubagentTracker();
167
+ const trackingKey = metadata.tmuxSession || 'default';
168
+ tracker.clearActivities(trackingKey);
169
+ }
170
+ }
171
+ const result = await this.notifier.notify(type, metadata);
172
+ if (result.success) {
173
+ this.logger.info(`${type} notification sent successfully`);
174
+ process.exit(0);
175
+ }
176
+ else {
177
+ this.logger.error(`Failed to send ${type} notification`);
178
+ process.exit(1);
179
+ }
180
+ }
181
+ async captureCurrentConversation() {
182
+ try {
183
+ const { execSync } = require('child_process');
184
+ const TmuxMonitor = require('./src/utils/tmux-monitor');
185
+ // Get current tmux session name
186
+ let currentSession = null;
187
+ try {
188
+ currentSession = execSync('tmux display-message -p "#S"', {
189
+ encoding: 'utf8',
190
+ stdio: ['ignore', 'pipe', 'ignore']
191
+ }).trim();
192
+ }
193
+ catch (e) {
194
+ // Not running in tmux, return empty metadata
195
+ return {};
196
+ }
197
+ if (!currentSession) {
198
+ return {};
199
+ }
200
+ // Use TmuxMonitor to capture conversation
201
+ const tmuxMonitor = new TmuxMonitor();
202
+ const conversation = tmuxMonitor.getRecentConversation(currentSession);
203
+ const fullTrace = tmuxMonitor.getFullExecutionTrace(currentSession);
204
+ return {
205
+ userQuestion: conversation.userQuestion,
206
+ claudeResponse: conversation.claudeResponse,
207
+ tmuxSession: currentSession,
208
+ fullExecutionTrace: fullTrace
209
+ };
210
+ }
211
+ catch (error) {
212
+ this.logger.debug('Failed to capture conversation:', error.message);
213
+ return {};
214
+ }
215
+ }
216
+ async handleTest(args) {
217
+ console.log('Testing notification channels...\n');
218
+ const results = await this.notifier.test();
219
+ for (const [channel, result] of Object.entries(results)) {
220
+ const status = result.success ? 'āœ… PASS' : 'āŒ FAIL';
221
+ console.log(`${channel}: ${status}`);
222
+ if (result.error) {
223
+ console.log(` Error: ${result.error}`);
224
+ }
225
+ }
226
+ const passCount = Object.values(results).filter(r => r.success).length;
227
+ const totalCount = Object.keys(results).length;
228
+ console.log(`\nTest completed: ${passCount}/${totalCount} channels passed`);
229
+ if (passCount === 0) {
230
+ process.exit(1);
231
+ }
232
+ }
233
+ async handleStatus(args) {
234
+ const status = this.notifier.getStatus();
235
+ console.log('CCGram Status\n');
236
+ console.log('Configuration:');
237
+ console.log(` Enabled: ${status.enabled ? 'Yes' : 'No'}`);
238
+ console.log(` Language: ${status.config.language}`);
239
+ console.log(` Sounds: ${status.config.sound.completed} / ${status.config.sound.waiting}`);
240
+ console.log('\nChannels:');
241
+ // Display all available channels, including disabled ones
242
+ const allChannels = (this.config._channels || {});
243
+ const activeChannels = (status.channels || {});
244
+ // Merge all channel information
245
+ const channelNames = new Set([
246
+ ...Object.keys(allChannels),
247
+ ...Object.keys(activeChannels)
248
+ ]);
249
+ for (const name of channelNames) {
250
+ const channelConfig = allChannels[name] || {};
251
+ const channelStatus = activeChannels[name];
252
+ let enabled, configured, relay;
253
+ if (channelStatus) {
254
+ // Active channel, use actual status
255
+ enabled = channelStatus.enabled ? 'āœ…' : 'āŒ';
256
+ configured = channelStatus.configured ? 'āœ…' : 'āŒ';
257
+ relay = channelStatus.supportsRelay ? 'āœ…' : 'āŒ';
258
+ }
259
+ else {
260
+ // Inactive channel, use configuration status
261
+ enabled = channelConfig.enabled ? 'āœ…' : 'āŒ';
262
+ configured = this._isChannelConfigured(name, channelConfig) ? 'āœ…' : 'āŒ';
263
+ relay = this._supportsRelay(name) ? 'āœ…' : 'āŒ';
264
+ }
265
+ console.log(` ${name}:`);
266
+ console.log(` Enabled: ${enabled}`);
267
+ console.log(` Configured: ${configured}`);
268
+ console.log(` Supports Relay: ${relay}`);
269
+ }
270
+ }
271
+ _isChannelConfigured(name, config) {
272
+ switch (name) {
273
+ case 'desktop':
274
+ return true; // Desktop notifications don't need special configuration
275
+ case 'email':
276
+ return config.config &&
277
+ config.config.smtp &&
278
+ config.config.smtp.host &&
279
+ config.config.smtp.auth &&
280
+ config.config.smtp.auth.user &&
281
+ config.config.to;
282
+ default:
283
+ return false;
284
+ }
285
+ }
286
+ _supportsRelay(name) {
287
+ switch (name) {
288
+ case 'email':
289
+ return true;
290
+ case 'desktop':
291
+ default:
292
+ return false;
293
+ }
294
+ }
295
+ async handleConfig(args) {
296
+ // Launch the configuration tool
297
+ const ConfigTool = require('./src/tools/config-manager');
298
+ const configTool = new ConfigTool(this.config);
299
+ await configTool.run(args);
300
+ }
301
+ async handleInstall(args) {
302
+ // Launch the installer
303
+ const Installer = require('./src/tools/installer');
304
+ const installer = new Installer(this.config);
305
+ await installer.run(args);
306
+ }
307
+ async handleRelay(args) {
308
+ const subcommand = args[0];
309
+ switch (subcommand) {
310
+ case 'start':
311
+ await this.startRelay(args.slice(1));
312
+ break;
313
+ case 'stop':
314
+ await this.stopRelay(args.slice(1));
315
+ break;
316
+ case 'status':
317
+ await this.relayStatus(args.slice(1));
318
+ break;
319
+ case 'cleanup':
320
+ await this.cleanupRelay(args.slice(1));
321
+ break;
322
+ default:
323
+ console.error('Usage: claude-remote relay <start|stop|status|cleanup>');
324
+ console.log('');
325
+ console.log('Commands:');
326
+ console.log(' start Start email command relay service');
327
+ console.log(' stop Stop email command relay service');
328
+ console.log(' status View relay service status');
329
+ console.log(' cleanup Clean up completed command history');
330
+ process.exit(1);
331
+ }
332
+ }
333
+ async startRelay(args) {
334
+ try {
335
+ const CommandRelayService = require('./src/relay/command-relay');
336
+ const emailConfig = this.config.getChannel('email');
337
+ if (!emailConfig || !emailConfig.enabled) {
338
+ console.error('āŒ Email channel not configured or disabled');
339
+ console.log('Please run first: claude-remote config');
340
+ process.exit(1);
341
+ }
342
+ console.log('šŸš€ Starting email command relay service...');
343
+ const relayService = new CommandRelayService(emailConfig.config);
344
+ // Listen for events
345
+ relayService.on('started', () => {
346
+ console.log('āœ… Command relay service started');
347
+ console.log('šŸ“§ Listening for email replies...');
348
+ console.log('šŸ’” You can now remotely execute Claude Code commands by replying to emails');
349
+ console.log('');
350
+ console.log('Press Ctrl+C to stop the service');
351
+ });
352
+ relayService.on('commandQueued', (command) => {
353
+ console.log(`šŸ“Ø Received new command: ${command.command.substring(0, 50)}...`);
354
+ });
355
+ relayService.on('commandExecuted', (command) => {
356
+ console.log(`āœ… Command executed successfully: ${command.id}`);
357
+ });
358
+ relayService.on('commandFailed', (command, error) => {
359
+ console.log(`āŒ Command execution failed: ${command.id} - ${error.message}`);
360
+ });
361
+ // Handle graceful shutdown
362
+ process.on('SIGINT', async () => {
363
+ console.log('\nšŸ›‘ Stopping command relay service...');
364
+ await relayService.stop();
365
+ console.log('āœ… Service stopped');
366
+ process.exit(0);
367
+ });
368
+ // Start service
369
+ await relayService.start();
370
+ // Keep process running
371
+ process.stdin.resume();
372
+ }
373
+ catch (error) {
374
+ console.error('āŒ Failed to start relay service:', error.message);
375
+ process.exit(1);
376
+ }
377
+ }
378
+ async stopRelay(args) {
379
+ console.log('šŸ’” Command relay service usually stopped with Ctrl+C');
380
+ console.log('If the service is still running, please find the corresponding process and terminate it manually');
381
+ }
382
+ async relayStatus(args) {
383
+ try {
384
+ const fs = require('fs');
385
+ const stateFile = path_1.default.join(paths_1.PROJECT_ROOT, 'src/data/relay-state.json');
386
+ console.log('šŸ“Š Command relay service status\n');
387
+ // Check email configuration
388
+ const emailConfig = this.config.getChannel('email');
389
+ if (!emailConfig || !emailConfig.enabled) {
390
+ console.log('āŒ Email channel not configured');
391
+ return;
392
+ }
393
+ const emailCfg = emailConfig.config;
394
+ console.log('āœ… Email configuration enabled');
395
+ console.log(`šŸ“§ SMTP: ${emailCfg.smtp.host}:${emailCfg.smtp.port}`);
396
+ console.log(`šŸ“„ IMAP: ${emailCfg.imap.host}:${emailCfg.imap.port}`);
397
+ console.log(`šŸ“¬ Recipient: ${emailCfg.to}`);
398
+ // Check relay status
399
+ if (fs.existsSync(stateFile)) {
400
+ const state = JSON.parse(fs.readFileSync(stateFile, 'utf8'));
401
+ console.log(`\nšŸ“‹ Command queue: ${state.commandQueue?.length || 0} commands`);
402
+ if (state.commandQueue && state.commandQueue.length > 0) {
403
+ console.log('\nRecent commands:');
404
+ state.commandQueue.slice(-5).forEach((cmd) => {
405
+ const cmdStatus = cmd.status === 'completed' ? 'āœ…' :
406
+ cmd.status === 'failed' ? 'āŒ' :
407
+ cmd.status === 'executing' ? 'ā³' : 'āøļø';
408
+ console.log(` ${cmdStatus} ${cmd.id}: ${cmd.command.substring(0, 50)}...`);
409
+ });
410
+ }
411
+ }
412
+ else {
413
+ console.log('\nšŸ“‹ No command history found');
414
+ }
415
+ }
416
+ catch (error) {
417
+ console.error('āŒ Failed to get status:', error.message);
418
+ }
419
+ }
420
+ async cleanupRelay(args) {
421
+ try {
422
+ const fs = require('fs');
423
+ const stateFile = path_1.default.join(paths_1.PROJECT_ROOT, 'src/data/relay-state.json');
424
+ if (!fs.existsSync(stateFile)) {
425
+ console.log('šŸ“‹ No cleanup needed, no command history found');
426
+ return;
427
+ }
428
+ const state = JSON.parse(fs.readFileSync(stateFile, 'utf8'));
429
+ const beforeCount = state.commandQueue?.length || 0;
430
+ // Clean up completed commands (keep those within 24 hours)
431
+ const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1000);
432
+ state.commandQueue = (state.commandQueue || []).filter((cmd) => cmd.status !== 'completed' ||
433
+ new Date(cmd.completedAt || cmd.queuedAt) > cutoff);
434
+ const afterCount = state.commandQueue.length;
435
+ const removedCount = beforeCount - afterCount;
436
+ fs.writeFileSync(stateFile, JSON.stringify(state, null, 2));
437
+ console.log(`🧹 Cleanup completed: removed ${removedCount} completed commands`);
438
+ console.log(`šŸ“‹ ${afterCount} commands remaining in queue`);
439
+ }
440
+ catch (error) {
441
+ console.error('āŒ Cleanup failed:', error.message);
442
+ }
443
+ }
444
+ async handleEditConfig(args) {
445
+ const { spawn } = require('child_process');
446
+ const configType = args[0];
447
+ if (!configType) {
448
+ console.log('Available configuration files:');
449
+ console.log(' user - User personal configuration (config/user.json)');
450
+ console.log(' channels - Notification channel configuration (config/channels.json)');
451
+ console.log(' default - Default configuration template (config/default.json)');
452
+ console.log('');
453
+ console.log('Usage: claude-remote edit-config <configuration-type>');
454
+ console.log('Example: claude-remote edit-config channels');
455
+ return;
456
+ }
457
+ const configFiles = {
458
+ 'user': path_1.default.join(paths_1.PROJECT_ROOT, 'config/user.json'),
459
+ 'channels': path_1.default.join(paths_1.PROJECT_ROOT, 'config/channels.json'),
460
+ 'default': path_1.default.join(paths_1.PROJECT_ROOT, 'config/default.json')
461
+ };
462
+ const configFile = configFiles[configType];
463
+ if (!configFile) {
464
+ console.error('āŒ Invalid configuration type:', configType);
465
+ console.log('Available types: user, channels, default');
466
+ return;
467
+ }
468
+ // Check if file exists
469
+ const fs = require('fs');
470
+ if (!fs.existsSync(configFile)) {
471
+ console.error('āŒ Configuration file does not exist:', configFile);
472
+ return;
473
+ }
474
+ console.log(`šŸ“ Opening configuration file: ${configFile}`);
475
+ console.log('šŸ’” Save and close the editor after editing to take effect');
476
+ console.log('');
477
+ // Determine the editor to use
478
+ const editor = process.env.EDITOR || process.env.VISUAL || this._getDefaultEditor();
479
+ try {
480
+ const editorProcess = spawn(editor, [configFile], {
481
+ stdio: 'inherit'
482
+ });
483
+ editorProcess.on('close', (code) => {
484
+ if (code === 0) {
485
+ console.log('āœ… Configuration file saved');
486
+ console.log('šŸ’” Run "claude-remote status" to view updated configuration');
487
+ }
488
+ else {
489
+ console.log('āŒ Editor exited abnormally');
490
+ }
491
+ });
492
+ editorProcess.on('error', (error) => {
493
+ console.error('āŒ Unable to start editor:', error.message);
494
+ console.log('');
495
+ console.log('šŸ’” You can manually edit the configuration file:');
496
+ console.log(` ${configFile}`);
497
+ });
498
+ }
499
+ catch (error) {
500
+ console.error('āŒ Failed to start editor:', error.message);
501
+ console.log('');
502
+ console.log('šŸ’” You can manually edit the configuration file:');
503
+ console.log(` ${configFile}`);
504
+ }
505
+ }
506
+ _getDefaultEditor() {
507
+ // Determine default editor based on platform
508
+ if (process.platform === 'win32') {
509
+ return 'notepad';
510
+ }
511
+ else if (process.platform === 'darwin') {
512
+ return 'nano'; // Use nano on macOS as most users have it
513
+ }
514
+ else {
515
+ return 'nano'; // Linux default to nano
516
+ }
517
+ }
518
+ async handleSetupEmail(args) {
519
+ const readline = require('readline');
520
+ const fs = require('fs');
521
+ const rl = readline.createInterface({
522
+ input: process.stdin,
523
+ output: process.stdout
524
+ });
525
+ const question = (prompt) => {
526
+ return new Promise((resolve) => {
527
+ rl.question(prompt, resolve);
528
+ });
529
+ };
530
+ try {
531
+ console.log('šŸš€ CCGram Email Quick Setup Wizard\n');
532
+ // Select email provider
533
+ console.log('Please select your email provider:');
534
+ console.log('1. Gmail');
535
+ console.log('2. QQ Email');
536
+ console.log('3. 163 Email');
537
+ console.log('4. Outlook/Hotmail');
538
+ console.log('5. Custom');
539
+ const providerChoice = await question('\nPlease select (1-5): ');
540
+ let smtpHost = '', smtpPort = 587, imapHost = '', imapPort = 993, secure = false;
541
+ switch (providerChoice) {
542
+ case '1':
543
+ smtpHost = 'smtp.gmail.com';
544
+ smtpPort = 587;
545
+ imapHost = 'imap.gmail.com';
546
+ imapPort = 993;
547
+ secure = false;
548
+ console.log('\nšŸ“§ Gmail Configuration');
549
+ console.log('šŸ’” Need to enable two-factor authentication and generate app password first');
550
+ break;
551
+ case '2':
552
+ smtpHost = 'smtp.qq.com';
553
+ smtpPort = 587;
554
+ imapHost = 'imap.qq.com';
555
+ imapPort = 993;
556
+ secure = false;
557
+ console.log('\nšŸ“§ QQ Email Configuration');
558
+ break;
559
+ case '3':
560
+ smtpHost = 'smtp.163.com';
561
+ smtpPort = 587;
562
+ imapHost = 'imap.163.com';
563
+ imapPort = 993;
564
+ secure = false;
565
+ console.log('\nšŸ“§ 163 Email Configuration');
566
+ break;
567
+ case '4':
568
+ smtpHost = 'smtp.live.com';
569
+ smtpPort = 587;
570
+ imapHost = 'imap-mail.outlook.com';
571
+ imapPort = 993;
572
+ secure = false;
573
+ console.log('\nšŸ“§ Outlook Configuration');
574
+ break;
575
+ case '5':
576
+ console.log('\nšŸ“§ Custom Configuration');
577
+ smtpHost = await question('SMTP Host: ');
578
+ smtpPort = parseInt(await question('SMTP Port (default 587): ') || '587');
579
+ imapHost = await question('IMAP Host: ');
580
+ imapPort = parseInt(await question('IMAP Port (default 993): ') || '993');
581
+ const secureInput = await question('Use SSL/TLS? (y/n): ');
582
+ secure = secureInput.toLowerCase() === 'y';
583
+ break;
584
+ default:
585
+ console.log('āŒ Invalid selection');
586
+ rl.close();
587
+ return;
588
+ }
589
+ // Get email account information
590
+ console.log('\nšŸ“ Please enter email account information:');
591
+ const email = await question('Email address: ');
592
+ const password = await question('Password/App password: ');
593
+ // Build configuration
594
+ const emailConfig = {
595
+ type: "email",
596
+ enabled: true,
597
+ config: {
598
+ smtp: {
599
+ host: smtpHost,
600
+ port: smtpPort,
601
+ secure: secure,
602
+ auth: {
603
+ user: email,
604
+ pass: password
605
+ }
606
+ },
607
+ imap: {
608
+ host: imapHost,
609
+ port: imapPort,
610
+ secure: true,
611
+ auth: {
612
+ user: email,
613
+ pass: password
614
+ }
615
+ },
616
+ from: `CCGram <${email}>`,
617
+ to: email,
618
+ template: {
619
+ checkInterval: 30
620
+ }
621
+ }
622
+ };
623
+ // Read existing configuration
624
+ const channelsFile = path_1.default.join(paths_1.PROJECT_ROOT, 'config/channels.json');
625
+ let channels = {};
626
+ if (fs.existsSync(channelsFile)) {
627
+ channels = JSON.parse(fs.readFileSync(channelsFile, 'utf8'));
628
+ }
629
+ // Update email configuration
630
+ channels.email = emailConfig;
631
+ // Save configuration
632
+ fs.writeFileSync(channelsFile, JSON.stringify(channels, null, 2));
633
+ console.log('\nāœ… Email configuration saved!');
634
+ console.log('\n🧪 You can now test email functionality:');
635
+ console.log(' claude-remote test');
636
+ console.log('\nšŸš€ Start command relay service:');
637
+ console.log(' claude-remote relay start');
638
+ // Ask if user wants to test immediately
639
+ const testNow = await question('\nTest email sending now? (y/n): ');
640
+ if (testNow.toLowerCase() === 'y') {
641
+ rl.close();
642
+ // Reload configuration and test
643
+ await this.init();
644
+ await this.handleTest([]);
645
+ }
646
+ else {
647
+ rl.close();
648
+ }
649
+ }
650
+ catch (error) {
651
+ console.error('āŒ Configuration failed:', error.message);
652
+ rl.close();
653
+ }
654
+ }
655
+ async handleDaemon(args) {
656
+ const ClaudeCodeRemoteDaemon = require('./src/daemon/taskping-daemon');
657
+ const daemon = new ClaudeCodeRemoteDaemon();
658
+ const command = args[0];
659
+ switch (command) {
660
+ case 'start':
661
+ await daemon.start();
662
+ break;
663
+ case 'stop':
664
+ await daemon.stop();
665
+ break;
666
+ case 'restart':
667
+ await daemon.restart();
668
+ break;
669
+ case 'status':
670
+ daemon.showStatus();
671
+ break;
672
+ default:
673
+ console.log('Usage: claude-remote daemon <start|stop|restart|status>');
674
+ console.log('');
675
+ console.log('Commands:');
676
+ console.log(' start Start background daemon process');
677
+ console.log(' stop Stop background daemon process');
678
+ console.log(' restart Restart background daemon process');
679
+ console.log(' status View daemon process status');
680
+ break;
681
+ }
682
+ }
683
+ async handleCommands(args) {
684
+ const ClaudeCommandBridge = require('./src/relay/claude-command-bridge');
685
+ const bridge = new ClaudeCommandBridge();
686
+ const command = args[0];
687
+ switch (command) {
688
+ case 'list':
689
+ const pending = bridge.getPendingCommands();
690
+ console.log(`šŸ“‹ Pending commands: ${pending.length}\n`);
691
+ if (pending.length > 0) {
692
+ pending.forEach((cmd, index) => {
693
+ console.log(`${index + 1}. ${cmd.id}`);
694
+ console.log(` Command: ${cmd.command}`);
695
+ console.log(` Time: ${cmd.timestamp}`);
696
+ console.log(` Session: ${cmd.sessionId}`);
697
+ console.log('');
698
+ });
699
+ }
700
+ break;
701
+ case 'status':
702
+ const status = bridge.getStatus();
703
+ console.log('šŸ“Š Command bridge status\n');
704
+ console.log(`Pending commands: ${status.pendingCommands}`);
705
+ console.log(`Processed commands: ${status.processedCommands}`);
706
+ console.log(`Commands directory: ${status.commandsDir}`);
707
+ console.log(`Response directory: ${status.responseDir}`);
708
+ if (status.recentCommands.length > 0) {
709
+ console.log('\nRecent commands:');
710
+ status.recentCommands.forEach((cmd) => {
711
+ console.log(` • ${cmd.command} (${cmd.timestamp})`);
712
+ });
713
+ }
714
+ break;
715
+ case 'cleanup':
716
+ bridge.cleanup();
717
+ console.log('🧹 Old command files cleaned up');
718
+ break;
719
+ case 'clear':
720
+ const pending2 = bridge.getPendingCommands();
721
+ for (const cmd of pending2) {
722
+ bridge.markCommandProcessed(cmd.id, 'cancelled', 'Manually cancelled');
723
+ }
724
+ console.log(`šŸ—‘ļø Cleared ${pending2.length} pending commands`);
725
+ break;
726
+ default:
727
+ console.log('Usage: claude-remote commands <list|status|cleanup|clear>');
728
+ console.log('');
729
+ console.log('Commands:');
730
+ console.log(' list Show pending email commands');
731
+ console.log(' status Show command bridge status');
732
+ console.log(' cleanup Clean up old command files');
733
+ console.log(' clear Clear all pending commands');
734
+ break;
735
+ }
736
+ }
737
+ async handleTestPaste(args) {
738
+ const ClipboardAutomation = require('./src/automation/clipboard-automation');
739
+ const automation = new ClipboardAutomation();
740
+ const testCommand = args.join(' ') || 'echo "Testing email reply auto-paste functionality"';
741
+ console.log('🧪 Testing auto-paste functionality');
742
+ console.log(`šŸ“ Test command: ${testCommand}`);
743
+ console.log('\nāš ļø Please ensure Claude Code or Terminal window is open and active');
744
+ console.log('ā³ Command will be sent automatically in 3 seconds...\n');
745
+ // Countdown
746
+ for (let i = 3; i > 0; i--) {
747
+ process.stdout.write(`${i}... `);
748
+ await new Promise(resolve => setTimeout(resolve, 1000));
749
+ }
750
+ console.log('\n');
751
+ try {
752
+ const success = await automation.sendCommand(testCommand);
753
+ if (success) {
754
+ console.log('āœ… Command has been auto-pasted!');
755
+ console.log('šŸ’” If you don\'t see the effect, please check app permissions and window status');
756
+ }
757
+ else {
758
+ console.log('āŒ Auto-paste failed');
759
+ console.log('šŸ’” Please ensure automation permissions are granted and target app is open');
760
+ }
761
+ }
762
+ catch (error) {
763
+ console.error('āŒ Test failed:', error.message);
764
+ }
765
+ }
766
+ async handleSetupPermissions(args) {
767
+ const PermissionSetup = require('./setup-permissions');
768
+ const setup = new PermissionSetup();
769
+ await setup.checkAndSetup();
770
+ }
771
+ async handleTestSimple(args) {
772
+ const SimpleAutomation = require('./src/automation/simple-automation');
773
+ const automation = new SimpleAutomation();
774
+ const testCommand = args.join(' ') || 'echo "Testing simple automation functionality"';
775
+ console.log('🧪 Testing simple automation functionality');
776
+ console.log(`šŸ“ Test command: ${testCommand}`);
777
+ console.log('\nThis test will:');
778
+ console.log('1. šŸ“‹ Copy command to clipboard');
779
+ console.log('2. šŸ“„ Save command to file');
780
+ console.log('3. šŸ”” Send notification (including dialog box)');
781
+ console.log('4. šŸ¤– Attempt auto-paste (if permissions granted)');
782
+ console.log('\nā³ Starting test...\n');
783
+ try {
784
+ const success = await automation.sendCommand(testCommand, 'test-session');
785
+ if (success) {
786
+ console.log('āœ… Test successful!');
787
+ console.log('\nšŸ“‹ Next steps:');
788
+ console.log('1. Check if you received notification');
789
+ console.log('2. Check if command was copied to clipboard');
790
+ console.log('3. If you see dialog box, you can choose to open command file');
791
+ console.log('4. Manually paste to Claude Code (if auto-paste didn\'t work)');
792
+ const status = automation.getStatus();
793
+ console.log(`\nšŸ“„ Command file: ${status.commandFile}`);
794
+ if (status.commandFileExists) {
795
+ console.log('šŸ’” You can run "open -t ' + status.commandFile + '" to view command file');
796
+ }
797
+ }
798
+ else {
799
+ console.log('āŒ Test failed');
800
+ }
801
+ }
802
+ catch (error) {
803
+ console.error('āŒ Error occurred during test:', error.message);
804
+ }
805
+ }
806
+ async handleTestClaude(args) {
807
+ const ClaudeAutomation = require('./src/automation/claude-automation');
808
+ const automation = new ClaudeAutomation();
809
+ const testCommand = args.join(' ') || 'echo "This is an automated test command from email reply"';
810
+ console.log('šŸ¤– Testing Claude Code specialized automation');
811
+ console.log(`šŸ“ Test command: ${testCommand}`);
812
+ console.log('\nāš ļø Please ensure:');
813
+ console.log(' 1. Claude Code application is open');
814
+ console.log(' 2. Or Terminal/iTerm2 etc. terminal applications are open');
815
+ console.log(' 3. Necessary accessibility permissions have been granted');
816
+ console.log('\nā³ Full automation test will start in 5 seconds...\n');
817
+ // Countdown
818
+ for (let i = 5; i > 0; i--) {
819
+ process.stdout.write(`${i}... `);
820
+ await new Promise(resolve => setTimeout(resolve, 1000));
821
+ }
822
+ console.log('\nšŸš€ Starting automation...\n');
823
+ try {
824
+ // Check permissions
825
+ const hasPermission = await automation.requestPermissions();
826
+ if (!hasPermission) {
827
+ console.log('āš ļø Permission check failed, but will still attempt execution...');
828
+ }
829
+ // Execute full automation
830
+ const success = await automation.sendCommand(testCommand, 'test-session');
831
+ if (success) {
832
+ console.log('āœ… Full automation test successful!');
833
+ console.log('šŸ’” Command should have been automatically input to Claude Code and started execution');
834
+ console.log('šŸ” Please check Claude Code window to see if command was received');
835
+ }
836
+ else {
837
+ console.log('āŒ Automation test failed');
838
+ console.log('šŸ’” Possible reasons:');
839
+ console.log(' • Claude Code or terminal application not found');
840
+ console.log(' • Insufficient permissions');
841
+ console.log(' • Application not responding');
842
+ console.log('\nšŸ”§ Suggestions:');
843
+ console.log(' 1. Run "claude-remote setup-permissions" to check permissions');
844
+ console.log(' 2. Ensure Claude Code is running in foreground');
845
+ console.log(' 3. Try manually clicking input box in Claude Code first');
846
+ }
847
+ }
848
+ catch (error) {
849
+ console.error('āŒ Error occurred during test:', error.message);
850
+ }
851
+ }
852
+ async handleDiagnose(args) {
853
+ const AutomationDiagnostic = require('./diagnose-automation');
854
+ const diagnostic = new AutomationDiagnostic();
855
+ await diagnostic.runDiagnostic();
856
+ }
857
+ showHelp() {
858
+ console.log(`
859
+ CCGram - Claude Code Smart Notification System
860
+
861
+ Usage: claude-remote <command> [options]
862
+
863
+ Commands:
864
+ notify --type <type> Send a notification (completed|waiting)
865
+ test Test all notification channels
866
+ status Show system status
867
+ config Launch configuration manager
868
+ setup-email Quick email setup wizard
869
+ edit-config <type> Edit configuration files directly
870
+ install Install and configure Claude Code hooks
871
+ relay <subcommand> Manage email command relay service
872
+ daemon <subcommand> Manage background daemon service
873
+ commands <subcommand> Manage email commands and bridge
874
+ test-paste [command] Test automatic paste functionality
875
+ test-simple [command] Test simple automation (recommended)
876
+ test-claude [command] Test Claude Code full automation
877
+ setup-permissions Setup macOS permissions for automation
878
+ diagnose Diagnose automation issues
879
+
880
+ Options:
881
+ -h, --help Show this help message
882
+
883
+ Relay Subcommands:
884
+ relay start Start email command relay service
885
+ relay stop Stop email command relay service
886
+ relay status Show relay service status
887
+ relay cleanup Clean up completed command history
888
+
889
+ Daemon Subcommands:
890
+ daemon start Start background daemon service
891
+ daemon stop Stop background daemon service
892
+ daemon restart Restart background daemon service
893
+ daemon status Show daemon service status
894
+
895
+ Commands Subcommands:
896
+ commands list Show pending email commands
897
+ commands status Show command bridge status
898
+ commands cleanup Clean up old command files
899
+ commands clear Clear all pending commands
900
+
901
+ Examples:
902
+ claude-remote notify --type completed
903
+ claude-remote test
904
+ claude-remote setup-email # Quick email setup (recommended)
905
+ claude-remote edit-config channels # Edit configuration files directly
906
+ claude-remote config # Interactive configuration
907
+ claude-remote install
908
+ claude-remote daemon start # Start background service (recommended)
909
+ claude-remote daemon status # View service status
910
+ claude-remote test-claude # Test full automation (recommended)
911
+ claude-remote commands list # View pending email commands
912
+ claude-remote relay start # Run in foreground (need to keep window open)
913
+
914
+ For more information, visit: https://github.com/CCGram/CCGram
915
+ `);
916
+ }
917
+ }
918
+ // Run CLI if this file is executed directly
919
+ if (require.main === module) {
920
+ const cli = new ClaudeCodeRemoteCLI();
921
+ cli.run().catch((error) => {
922
+ console.error('Fatal error:', error.message);
923
+ process.exit(1);
924
+ });
925
+ }
926
+ module.exports = ClaudeCodeRemoteCLI;
927
+ //# sourceMappingURL=claude-remote.js.map