@urugus/slack-cli 0.2.12 → 0.3.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 (123) hide show
  1. package/README.md +45 -0
  2. package/dist/commands/history-display.d.ts +5 -1
  3. package/dist/commands/history-display.d.ts.map +1 -1
  4. package/dist/commands/history-display.js +3 -3
  5. package/dist/commands/history-display.js.map +1 -1
  6. package/dist/commands/history.d.ts.map +1 -1
  7. package/dist/commands/history.js +28 -11
  8. package/dist/commands/history.js.map +1 -1
  9. package/dist/commands/search.d.ts +3 -0
  10. package/dist/commands/search.d.ts.map +1 -0
  11. package/dist/commands/search.js +51 -0
  12. package/dist/commands/search.js.map +1 -0
  13. package/dist/index.js +2 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/types/commands.d.ts +10 -0
  16. package/dist/types/commands.d.ts.map +1 -1
  17. package/dist/utils/constants.d.ts +5 -0
  18. package/dist/utils/constants.d.ts.map +1 -1
  19. package/dist/utils/constants.js +5 -0
  20. package/dist/utils/constants.js.map +1 -1
  21. package/dist/utils/formatters/search-formatters.d.ts +10 -0
  22. package/dist/utils/formatters/search-formatters.d.ts.map +1 -0
  23. package/dist/utils/formatters/search-formatters.js +91 -0
  24. package/dist/utils/formatters/search-formatters.js.map +1 -0
  25. package/dist/utils/slack-api-client.d.ts +5 -0
  26. package/dist/utils/slack-api-client.d.ts.map +1 -1
  27. package/dist/utils/slack-api-client.js +8 -0
  28. package/dist/utils/slack-api-client.js.map +1 -1
  29. package/dist/utils/slack-operations/index.d.ts +1 -0
  30. package/dist/utils/slack-operations/index.d.ts.map +1 -1
  31. package/dist/utils/slack-operations/index.js +3 -1
  32. package/dist/utils/slack-operations/index.js.map +1 -1
  33. package/dist/utils/slack-operations/message-operations.d.ts +1 -0
  34. package/dist/utils/slack-operations/message-operations.d.ts.map +1 -1
  35. package/dist/utils/slack-operations/message-operations.js +21 -0
  36. package/dist/utils/slack-operations/message-operations.js.map +1 -1
  37. package/dist/utils/slack-operations/search-operations.d.ts +29 -0
  38. package/dist/utils/slack-operations/search-operations.d.ts.map +1 -0
  39. package/dist/utils/slack-operations/search-operations.js +37 -0
  40. package/dist/utils/slack-operations/search-operations.js.map +1 -0
  41. package/dist/utils/validators.d.ts +16 -0
  42. package/dist/utils/validators.d.ts.map +1 -1
  43. package/dist/utils/validators.js +50 -0
  44. package/dist/utils/validators.js.map +1 -1
  45. package/package.json +5 -2
  46. package/.claude/settings.local.json +0 -75
  47. package/.github/dependabot.yml +0 -18
  48. package/.github/workflows/ci.yml +0 -70
  49. package/.github/workflows/pr-validation.yml +0 -41
  50. package/.prettierignore +0 -11
  51. package/.prettierrc +0 -10
  52. package/CHANGELOG.md +0 -61
  53. package/CLAUDE.md +0 -16
  54. package/eslint.config.js +0 -38
  55. package/src/commands/channels.ts +0 -50
  56. package/src/commands/config-subcommands.ts +0 -63
  57. package/src/commands/config.ts +0 -50
  58. package/src/commands/history-display.ts +0 -19
  59. package/src/commands/history-validators.ts +0 -46
  60. package/src/commands/history.ts +0 -61
  61. package/src/commands/scheduled.ts +0 -71
  62. package/src/commands/send.ts +0 -69
  63. package/src/commands/unread.ts +0 -122
  64. package/src/index.ts +0 -27
  65. package/src/types/commands.ts +0 -58
  66. package/src/types/config.ts +0 -20
  67. package/src/utils/channel-formatter.ts +0 -45
  68. package/src/utils/channel-resolver.ts +0 -82
  69. package/src/utils/client-factory.ts +0 -10
  70. package/src/utils/command-wrapper.ts +0 -27
  71. package/src/utils/config/config-file-manager.ts +0 -56
  72. package/src/utils/config/profile-manager.ts +0 -79
  73. package/src/utils/config/token-crypto-service.ts +0 -80
  74. package/src/utils/config-helper.ts +0 -21
  75. package/src/utils/constants.ts +0 -78
  76. package/src/utils/date-utils.ts +0 -8
  77. package/src/utils/error-utils.ts +0 -6
  78. package/src/utils/errors.ts +0 -33
  79. package/src/utils/format-utils.ts +0 -9
  80. package/src/utils/formatters/base-formatter.ts +0 -34
  81. package/src/utils/formatters/channel-formatters.ts +0 -71
  82. package/src/utils/formatters/channels-list-formatters.ts +0 -55
  83. package/src/utils/formatters/history-formatters.ts +0 -123
  84. package/src/utils/formatters/message-formatters.ts +0 -85
  85. package/src/utils/mention-utils.ts +0 -47
  86. package/src/utils/option-parsers.ts +0 -100
  87. package/src/utils/profile-config.ts +0 -161
  88. package/src/utils/schedule-utils.ts +0 -41
  89. package/src/utils/slack-api-client.ts +0 -135
  90. package/src/utils/slack-operations/base-client.ts +0 -30
  91. package/src/utils/slack-operations/channel-operations.ts +0 -161
  92. package/src/utils/slack-operations/index.ts +0 -3
  93. package/src/utils/slack-operations/message-operations.ts +0 -176
  94. package/src/utils/slack-patterns.ts +0 -9
  95. package/src/utils/token-utils.ts +0 -17
  96. package/src/utils/validators.ts +0 -263
  97. package/tests/commands/channels.test.ts +0 -250
  98. package/tests/commands/config.test.ts +0 -158
  99. package/tests/commands/history.test.ts +0 -403
  100. package/tests/commands/scheduled.test.ts +0 -131
  101. package/tests/commands/send.test.ts +0 -414
  102. package/tests/commands/unread.test.ts +0 -492
  103. package/tests/index.test.ts +0 -40
  104. package/tests/test-utils.ts +0 -28
  105. package/tests/utils/channel-resolver.test.ts +0 -161
  106. package/tests/utils/config/config-file-manager.test.ts +0 -118
  107. package/tests/utils/config/profile-manager.test.ts +0 -266
  108. package/tests/utils/config/token-crypto-service.test.ts +0 -98
  109. package/tests/utils/config.test.ts +0 -400
  110. package/tests/utils/date-utils.test.ts +0 -30
  111. package/tests/utils/error-utils.test.ts +0 -34
  112. package/tests/utils/format-utils.test.ts +0 -61
  113. package/tests/utils/mention-utils.test.ts +0 -100
  114. package/tests/utils/option-parsers.test.ts +0 -173
  115. package/tests/utils/profile-config.test.ts +0 -282
  116. package/tests/utils/schedule-utils.test.ts +0 -63
  117. package/tests/utils/slack-api-client.test.ts +0 -313
  118. package/tests/utils/slack-operations/channel-operations.test.ts +0 -248
  119. package/tests/utils/slack-operations/message-operations.test.ts +0 -163
  120. package/tests/utils/token-utils.test.ts +0 -33
  121. package/tests/utils/validators.test.ts +0 -307
  122. package/tsconfig.json +0 -22
  123. package/vitest.config.ts +0 -27
@@ -1,414 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
- import { setupSendCommand } from '../../src/commands/send';
3
- import { SlackApiClient } from '../../src/utils/slack-api-client';
4
- import { ProfileConfigManager } from '../../src/utils/profile-config';
5
- import { setupMockConsole, createTestProgram, restoreMocks } from '../test-utils';
6
- import { ERROR_MESSAGES, SUCCESS_MESSAGES } from '../../src/utils/constants';
7
- import * as fs from 'fs/promises';
8
-
9
- vi.mock('../../src/utils/slack-api-client');
10
- vi.mock('../../src/utils/profile-config');
11
- vi.mock('fs/promises');
12
-
13
- describe('send command', () => {
14
- let program: any;
15
- let mockSlackClient: SlackApiClient;
16
- let mockConfigManager: ProfileConfigManager;
17
- let mockConsole: any;
18
-
19
- beforeEach(() => {
20
- vi.clearAllMocks();
21
-
22
- mockConfigManager = new ProfileConfigManager();
23
- vi.mocked(ProfileConfigManager).mockReturnValue(mockConfigManager);
24
-
25
- mockSlackClient = new SlackApiClient('test-token');
26
- vi.mocked(SlackApiClient).mockReturnValue(mockSlackClient);
27
-
28
- mockConsole = setupMockConsole();
29
- program = createTestProgram();
30
- program.addCommand(setupSendCommand());
31
- });
32
-
33
- afterEach(() => {
34
- restoreMocks();
35
- });
36
-
37
- describe('send message with -m option', () => {
38
- it('should send a message to specified channel', async () => {
39
- vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
40
- token: 'test-token',
41
- updatedAt: new Date().toISOString(),
42
- });
43
- vi.mocked(mockSlackClient.sendMessage).mockResolvedValue({
44
- ok: true,
45
- ts: '1234567890.123456',
46
- });
47
-
48
- await program.parseAsync(['node', 'slack-cli', 'send', '-c', 'general', '-m', 'Hello, World!']);
49
-
50
- expect(mockSlackClient.sendMessage).toHaveBeenCalledWith('general', 'Hello, World!', undefined);
51
- expect(mockConsole.logSpy).toHaveBeenCalledWith(
52
- expect.stringContaining(SUCCESS_MESSAGES.MESSAGE_SENT('general'))
53
- );
54
- });
55
-
56
- it('should use specified profile', async () => {
57
- vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
58
- token: 'work-token',
59
- updatedAt: new Date().toISOString(),
60
- });
61
- vi.mocked(mockSlackClient.sendMessage).mockResolvedValue({
62
- ok: true,
63
- ts: '1234567890.123456',
64
- });
65
-
66
- await program.parseAsync([
67
- 'node',
68
- 'slack-cli',
69
- 'send',
70
- '-c',
71
- 'general',
72
- '-m',
73
- 'Hello',
74
- '--profile',
75
- 'work',
76
- ]);
77
-
78
- expect(mockConfigManager.getConfig).toHaveBeenCalledWith('work');
79
- expect(SlackApiClient).toHaveBeenCalledWith('work-token');
80
- });
81
- });
82
-
83
- describe('send message with -f option', () => {
84
- it('should send message from file', async () => {
85
- const fileContent = 'Message from file\nLine 2';
86
- vi.mocked(fs.readFile).mockResolvedValue(fileContent);
87
- vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
88
- token: 'test-token',
89
- updatedAt: new Date().toISOString(),
90
- });
91
- vi.mocked(mockSlackClient.sendMessage).mockResolvedValue({
92
- ok: true,
93
- ts: '1234567890.123456',
94
- });
95
-
96
- await program.parseAsync(['node', 'slack-cli', 'send', '-c', 'general', '-f', 'message.txt']);
97
-
98
- expect(fs.readFile).toHaveBeenCalledWith('message.txt', 'utf-8');
99
- expect(mockSlackClient.sendMessage).toHaveBeenCalledWith('general', fileContent, undefined);
100
- });
101
- });
102
-
103
- describe('send reply to thread', () => {
104
- it('should send a reply to a thread with --thread option', async () => {
105
- vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
106
- token: 'test-token',
107
- updatedAt: new Date().toISOString(),
108
- });
109
- vi.mocked(mockSlackClient.sendMessage).mockResolvedValue({
110
- ok: true,
111
- ts: '1234567890.123456',
112
- });
113
-
114
- await program.parseAsync([
115
- 'node',
116
- 'slack-cli',
117
- 'send',
118
- '-c',
119
- 'general',
120
- '-m',
121
- 'Reply to thread',
122
- '--thread',
123
- '1719207629.000100',
124
- ]);
125
-
126
- expect(mockSlackClient.sendMessage).toHaveBeenCalledWith(
127
- 'general',
128
- 'Reply to thread',
129
- '1719207629.000100'
130
- );
131
- expect(mockConsole.logSpy).toHaveBeenCalledWith(
132
- expect.stringContaining(SUCCESS_MESSAGES.MESSAGE_SENT('general'))
133
- );
134
- });
135
-
136
- it('should send a reply to a thread with -t option', async () => {
137
- vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
138
- token: 'test-token',
139
- updatedAt: new Date().toISOString(),
140
- });
141
- vi.mocked(mockSlackClient.sendMessage).mockResolvedValue({
142
- ok: true,
143
- ts: '1234567890.123456',
144
- });
145
-
146
- await program.parseAsync([
147
- 'node',
148
- 'slack-cli',
149
- 'send',
150
- '-c',
151
- 'general',
152
- '-m',
153
- 'Reply to thread',
154
- '-t',
155
- '1719207629.000100',
156
- ]);
157
-
158
- expect(mockSlackClient.sendMessage).toHaveBeenCalledWith(
159
- 'general',
160
- 'Reply to thread',
161
- '1719207629.000100'
162
- );
163
- expect(mockConsole.logSpy).toHaveBeenCalledWith(
164
- expect.stringContaining(SUCCESS_MESSAGES.MESSAGE_SENT('general'))
165
- );
166
- });
167
-
168
- it('should validate thread timestamp format', async () => {
169
- vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
170
- token: 'test-token',
171
- updatedAt: new Date().toISOString(),
172
- });
173
-
174
- const sendCommand = setupSendCommand();
175
- sendCommand.exitOverride();
176
-
177
- await expect(
178
- sendCommand.parseAsync(['-c', 'general', '-m', 'Reply', '-t', 'invalid-timestamp'], {
179
- from: 'user',
180
- })
181
- ).rejects.toThrow(ERROR_MESSAGES.INVALID_THREAD_TIMESTAMP);
182
- });
183
-
184
- it('should send a reply to a thread with file content', async () => {
185
- const fileContent = 'Reply from file\nLine 2';
186
- vi.mocked(fs.readFile).mockResolvedValue(fileContent);
187
- vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
188
- token: 'test-token',
189
- updatedAt: new Date().toISOString(),
190
- });
191
- vi.mocked(mockSlackClient.sendMessage).mockResolvedValue({
192
- ok: true,
193
- ts: '1234567890.123456',
194
- });
195
-
196
- await program.parseAsync([
197
- 'node',
198
- 'slack-cli',
199
- 'send',
200
- '-c',
201
- 'general',
202
- '-f',
203
- 'reply.txt',
204
- '-t',
205
- '1719207629.000100',
206
- ]);
207
-
208
- expect(fs.readFile).toHaveBeenCalledWith('reply.txt', 'utf-8');
209
- expect(mockSlackClient.sendMessage).toHaveBeenCalledWith(
210
- 'general',
211
- fileContent,
212
- '1719207629.000100'
213
- );
214
- expect(mockConsole.logSpy).toHaveBeenCalledWith(
215
- expect.stringContaining(SUCCESS_MESSAGES.MESSAGE_SENT('general'))
216
- );
217
- });
218
- });
219
-
220
- describe('schedule message', () => {
221
- it('should schedule message with --at', async () => {
222
- vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
223
- token: 'test-token',
224
- updatedAt: new Date().toISOString(),
225
- });
226
- vi.mocked(mockSlackClient.scheduleMessage).mockResolvedValue({
227
- ok: true,
228
- scheduled_message_id: 'Q1298393284',
229
- post_at: 2051258400,
230
- } as any);
231
-
232
- await program.parseAsync([
233
- 'node',
234
- 'slack-cli',
235
- 'send',
236
- '-c',
237
- 'general',
238
- '-m',
239
- 'Future message',
240
- '--at',
241
- '2035-01-01T10:00:00Z',
242
- ]);
243
-
244
- expect(mockSlackClient.scheduleMessage).toHaveBeenCalledWith(
245
- 'general',
246
- 'Future message',
247
- 2051258400,
248
- undefined
249
- );
250
- expect(mockSlackClient.sendMessage).not.toHaveBeenCalled();
251
- expect(mockConsole.logSpy).toHaveBeenCalledWith(
252
- expect.stringContaining('Message scheduled to #general')
253
- );
254
- });
255
-
256
- it('should schedule message with --after', async () => {
257
- vi.useFakeTimers();
258
- vi.setSystemTime(new Date('2026-02-12T00:00:00Z'));
259
-
260
- vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
261
- token: 'test-token',
262
- updatedAt: new Date().toISOString(),
263
- });
264
- vi.mocked(mockSlackClient.scheduleMessage).mockResolvedValue({
265
- ok: true,
266
- scheduled_message_id: 'Q1298393284',
267
- post_at: 1770868800,
268
- } as any);
269
-
270
- await program.parseAsync([
271
- 'node',
272
- 'slack-cli',
273
- 'send',
274
- '-c',
275
- 'general',
276
- '-m',
277
- 'Future message',
278
- '--after',
279
- '10',
280
- ]);
281
-
282
- expect(mockSlackClient.scheduleMessage).toHaveBeenCalledWith(
283
- 'general',
284
- 'Future message',
285
- 1770855000,
286
- undefined
287
- );
288
-
289
- vi.useRealTimers();
290
- });
291
- });
292
-
293
- describe('validation', () => {
294
- it('should fail when no message or file is provided', async () => {
295
- const sendCommand = setupSendCommand();
296
- sendCommand.exitOverride();
297
-
298
- await expect(sendCommand.parseAsync(['-c', 'general'], { from: 'user' })).rejects.toThrow(
299
- `Error: ${ERROR_MESSAGES.NO_MESSAGE_OR_FILE}`
300
- );
301
- });
302
-
303
- it('should fail when both message and file are provided', async () => {
304
- const sendCommand = setupSendCommand();
305
- sendCommand.exitOverride();
306
-
307
- await expect(
308
- sendCommand.parseAsync(['-c', 'general', '-m', 'Hello', '-f', 'file.txt'], {
309
- from: 'user',
310
- })
311
- ).rejects.toThrow(`Error: ${ERROR_MESSAGES.BOTH_MESSAGE_AND_FILE}`);
312
- });
313
-
314
- it('should fail when both --at and --after are provided', async () => {
315
- const sendCommand = setupSendCommand();
316
- sendCommand.exitOverride();
317
-
318
- await expect(
319
- sendCommand.parseAsync(
320
- ['-c', 'general', '-m', 'Hello', '--at', '2030-01-01T10:00:00Z', '--after', '10'],
321
- {
322
- from: 'user',
323
- }
324
- )
325
- ).rejects.toThrow(`Error: ${ERROR_MESSAGES.BOTH_SCHEDULE_OPTIONS}`);
326
- });
327
-
328
- it('should fail with invalid --at', async () => {
329
- const sendCommand = setupSendCommand();
330
- sendCommand.exitOverride();
331
-
332
- await expect(
333
- sendCommand.parseAsync(['-c', 'general', '-m', 'Hello', '--at', 'invalid-date'], {
334
- from: 'user',
335
- })
336
- ).rejects.toThrow(`Error: ${ERROR_MESSAGES.INVALID_SCHEDULE_AT}`);
337
- });
338
-
339
- it('should fail with past --at', async () => {
340
- const sendCommand = setupSendCommand();
341
- sendCommand.exitOverride();
342
-
343
- await expect(
344
- sendCommand.parseAsync(['-c', 'general', '-m', 'Hello', '--at', '1'], {
345
- from: 'user',
346
- })
347
- ).rejects.toThrow(`Error: ${ERROR_MESSAGES.SCHEDULE_TIME_IN_PAST}`);
348
- });
349
-
350
- it('should fail with invalid --after', async () => {
351
- const sendCommand = setupSendCommand();
352
- sendCommand.exitOverride();
353
-
354
- await expect(
355
- sendCommand.parseAsync(['-c', 'general', '-m', 'Hello', '--after', '0'], {
356
- from: 'user',
357
- })
358
- ).rejects.toThrow(`Error: ${ERROR_MESSAGES.INVALID_SCHEDULE_AFTER}`);
359
- });
360
-
361
- it('should fail when no channel is provided', async () => {
362
- const sendCommand = setupSendCommand();
363
- sendCommand.exitOverride();
364
-
365
- await expect(sendCommand.parseAsync(['-m', 'Hello'], { from: 'user' })).rejects.toThrow();
366
- });
367
- });
368
-
369
- describe('error handling', () => {
370
- it('should handle missing configuration', async () => {
371
- vi.mocked(mockConfigManager.getConfig).mockResolvedValue(null);
372
-
373
- await program.parseAsync(['node', 'slack-cli', 'send', '-c', 'general', '-m', 'Hello']);
374
-
375
- expect(mockConsole.errorSpy).toHaveBeenCalledWith(
376
- expect.stringContaining('Error:'),
377
- expect.any(String)
378
- );
379
- expect(mockConsole.exitSpy).toHaveBeenCalledWith(1);
380
- });
381
-
382
- it('should handle Slack API errors', async () => {
383
- vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
384
- token: 'test-token',
385
- updatedAt: new Date().toISOString(),
386
- });
387
- vi.mocked(mockSlackClient.sendMessage).mockRejectedValue(new Error('channel_not_found'));
388
-
389
- await program.parseAsync(['node', 'slack-cli', 'send', '-c', 'nonexistent', '-m', 'Hello']);
390
-
391
- expect(mockConsole.errorSpy).toHaveBeenCalledWith(
392
- expect.stringContaining('Error:'),
393
- expect.any(String)
394
- );
395
- expect(mockConsole.exitSpy).toHaveBeenCalledWith(1);
396
- });
397
-
398
- it('should handle file read errors', async () => {
399
- vi.mocked(fs.readFile).mockRejectedValue(new Error('ENOENT: no such file'));
400
- vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
401
- token: 'test-token',
402
- updatedAt: new Date().toISOString(),
403
- });
404
-
405
- await program.parseAsync(['node', 'slack-cli', 'send', '-c', 'general', '-f', 'nonexistent.txt']);
406
-
407
- expect(mockConsole.errorSpy).toHaveBeenCalledWith(
408
- expect.stringContaining('Error:'),
409
- expect.any(String)
410
- );
411
- expect(mockConsole.exitSpy).toHaveBeenCalledWith(1);
412
- });
413
- });
414
- });