@urugus/slack-cli 0.2.11 → 0.2.13

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 (97) hide show
  1. package/README.md +4 -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/types/commands.d.ts +1 -0
  10. package/dist/types/commands.d.ts.map +1 -1
  11. package/dist/utils/slack-api-client.d.ts +1 -0
  12. package/dist/utils/slack-api-client.d.ts.map +1 -1
  13. package/dist/utils/slack-api-client.js +3 -0
  14. package/dist/utils/slack-api-client.js.map +1 -1
  15. package/dist/utils/slack-operations/message-operations.d.ts +1 -0
  16. package/dist/utils/slack-operations/message-operations.d.ts.map +1 -1
  17. package/dist/utils/slack-operations/message-operations.js +21 -0
  18. package/dist/utils/slack-operations/message-operations.js.map +1 -1
  19. package/package.json +5 -2
  20. package/.claude/settings.local.json +0 -75
  21. package/.github/dependabot.yml +0 -18
  22. package/.github/workflows/ci.yml +0 -70
  23. package/.github/workflows/pr-validation.yml +0 -41
  24. package/.prettierignore +0 -11
  25. package/.prettierrc +0 -10
  26. package/CHANGELOG.md +0 -61
  27. package/CLAUDE.md +0 -16
  28. package/eslint.config.js +0 -38
  29. package/src/commands/channels.ts +0 -50
  30. package/src/commands/config-subcommands.ts +0 -63
  31. package/src/commands/config.ts +0 -50
  32. package/src/commands/history-display.ts +0 -19
  33. package/src/commands/history-validators.ts +0 -46
  34. package/src/commands/history.ts +0 -61
  35. package/src/commands/scheduled.ts +0 -71
  36. package/src/commands/send.ts +0 -69
  37. package/src/commands/unread.ts +0 -122
  38. package/src/index.ts +0 -27
  39. package/src/types/commands.ts +0 -58
  40. package/src/types/config.ts +0 -20
  41. package/src/utils/channel-formatter.ts +0 -45
  42. package/src/utils/channel-resolver.ts +0 -82
  43. package/src/utils/client-factory.ts +0 -10
  44. package/src/utils/command-wrapper.ts +0 -27
  45. package/src/utils/config/config-file-manager.ts +0 -56
  46. package/src/utils/config/profile-manager.ts +0 -79
  47. package/src/utils/config/token-crypto-service.ts +0 -80
  48. package/src/utils/config-helper.ts +0 -21
  49. package/src/utils/constants.ts +0 -78
  50. package/src/utils/date-utils.ts +0 -8
  51. package/src/utils/error-utils.ts +0 -6
  52. package/src/utils/errors.ts +0 -33
  53. package/src/utils/format-utils.ts +0 -9
  54. package/src/utils/formatters/base-formatter.ts +0 -34
  55. package/src/utils/formatters/channel-formatters.ts +0 -71
  56. package/src/utils/formatters/channels-list-formatters.ts +0 -55
  57. package/src/utils/formatters/history-formatters.ts +0 -123
  58. package/src/utils/formatters/message-formatters.ts +0 -85
  59. package/src/utils/mention-utils.ts +0 -47
  60. package/src/utils/option-parsers.ts +0 -100
  61. package/src/utils/profile-config.ts +0 -161
  62. package/src/utils/schedule-utils.ts +0 -41
  63. package/src/utils/slack-api-client.ts +0 -135
  64. package/src/utils/slack-operations/base-client.ts +0 -30
  65. package/src/utils/slack-operations/channel-operations.ts +0 -161
  66. package/src/utils/slack-operations/index.ts +0 -3
  67. package/src/utils/slack-operations/message-operations.ts +0 -176
  68. package/src/utils/slack-patterns.ts +0 -9
  69. package/src/utils/token-utils.ts +0 -17
  70. package/src/utils/validators.ts +0 -263
  71. package/tests/commands/channels.test.ts +0 -250
  72. package/tests/commands/config.test.ts +0 -158
  73. package/tests/commands/history.test.ts +0 -403
  74. package/tests/commands/scheduled.test.ts +0 -131
  75. package/tests/commands/send.test.ts +0 -414
  76. package/tests/commands/unread.test.ts +0 -492
  77. package/tests/index.test.ts +0 -40
  78. package/tests/test-utils.ts +0 -28
  79. package/tests/utils/channel-resolver.test.ts +0 -161
  80. package/tests/utils/config/config-file-manager.test.ts +0 -118
  81. package/tests/utils/config/profile-manager.test.ts +0 -266
  82. package/tests/utils/config/token-crypto-service.test.ts +0 -98
  83. package/tests/utils/config.test.ts +0 -400
  84. package/tests/utils/date-utils.test.ts +0 -30
  85. package/tests/utils/error-utils.test.ts +0 -34
  86. package/tests/utils/format-utils.test.ts +0 -61
  87. package/tests/utils/mention-utils.test.ts +0 -100
  88. package/tests/utils/option-parsers.test.ts +0 -173
  89. package/tests/utils/profile-config.test.ts +0 -282
  90. package/tests/utils/schedule-utils.test.ts +0 -63
  91. package/tests/utils/slack-api-client.test.ts +0 -313
  92. package/tests/utils/slack-operations/channel-operations.test.ts +0 -248
  93. package/tests/utils/slack-operations/message-operations.test.ts +0 -163
  94. package/tests/utils/token-utils.test.ts +0 -33
  95. package/tests/utils/validators.test.ts +0 -307
  96. package/tsconfig.json +0 -22
  97. 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
- });