@urugus/slack-cli 0.2.12 → 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,50 +0,0 @@
1
- import { Command } from 'commander';
2
- import { wrapCommand } from '../utils/command-wrapper';
3
- import { createSlackClient } from '../utils/client-factory';
4
- import { ERROR_MESSAGES } from '../utils/constants';
5
- import { ChannelsOptions } from '../types/commands';
6
- import { mapChannelToInfo, getChannelTypes } from '../utils/channel-formatter';
7
- import { createChannelsListFormatter } from '../utils/formatters/channels-list-formatters';
8
- import { parseFormat, parseLimit, parseBoolean } from '../utils/option-parsers';
9
-
10
- export function setupChannelsCommand(): Command {
11
- const channelsCommand = new Command('channels');
12
-
13
- channelsCommand
14
- .description('List Slack channels')
15
- .option('--type <type>', 'Channel type: public, private, im, mpim, all', 'public')
16
- .option('--include-archived', 'Include archived channels', false)
17
- .option('--format <format>', 'Output format: table, simple, json', 'table')
18
- .option('--limit <number>', 'Maximum number of channels to list', '100')
19
- .option('--profile <profile>', 'Use specific workspace profile')
20
- .action(
21
- wrapCommand(async (options: ChannelsOptions) => {
22
- // Create Slack client
23
- const client = await createSlackClient(options.profile);
24
-
25
- // Map channel type to API types
26
- const types = getChannelTypes(options.type);
27
-
28
- // List channels
29
- const limit = parseLimit(options.limit, 100);
30
- const channels = await client.listChannels({
31
- types,
32
- exclude_archived: !parseBoolean(options.includeArchived),
33
- limit: limit,
34
- });
35
-
36
- if (channels.length === 0) {
37
- console.log(ERROR_MESSAGES.NO_CHANNELS_FOUND);
38
- return;
39
- }
40
-
41
- // Format and display channels
42
- const channelInfos = channels.map(mapChannelToInfo);
43
- const format = parseFormat(options.format);
44
- const formatter = createChannelsListFormatter(format);
45
- formatter.format({ channels: channelInfos });
46
- })
47
- );
48
-
49
- return channelsCommand;
50
- }
@@ -1,63 +0,0 @@
1
- import chalk from 'chalk';
2
- import { ProfileConfigManager } from '../utils/profile-config';
3
- import { getProfileName } from '../utils/command-wrapper';
4
- import { ERROR_MESSAGES, SUCCESS_MESSAGES } from '../utils/constants';
5
-
6
- export async function handleSetToken(options: { token: string; profile?: string }): Promise<void> {
7
- const configManager = new ProfileConfigManager();
8
- const profileName = await getProfileName(configManager, options.profile);
9
- await configManager.setToken(options.token, options.profile);
10
- console.log(chalk.green(`✓ ${SUCCESS_MESSAGES.TOKEN_SAVED(profileName)}`));
11
- }
12
-
13
- export async function handleGetConfig(options: { profile?: string }): Promise<void> {
14
- const configManager = new ProfileConfigManager();
15
- const profileName = await getProfileName(configManager, options.profile);
16
- const currentConfig = await configManager.getConfig(options.profile);
17
-
18
- if (!currentConfig) {
19
- console.log(chalk.yellow(ERROR_MESSAGES.NO_CONFIG(profileName)));
20
- return;
21
- }
22
-
23
- console.log(chalk.bold(`Configuration for profile "${profileName}":`));
24
- console.log(` Token: ${chalk.cyan(configManager.maskToken(currentConfig.token))}`);
25
- console.log(` Updated: ${chalk.gray(currentConfig.updatedAt)}`);
26
- }
27
-
28
- export async function handleListProfiles(): Promise<void> {
29
- const configManager = new ProfileConfigManager();
30
- const profiles = await configManager.listProfiles();
31
- const currentProfile = await configManager.getCurrentProfile();
32
-
33
- if (profiles.length === 0) {
34
- console.log(chalk.yellow(ERROR_MESSAGES.NO_PROFILES_FOUND));
35
- return;
36
- }
37
-
38
- console.log(chalk.bold('Available profiles:'));
39
- profiles.forEach((profile) => {
40
- const marker = profile.name === currentProfile ? '*' : ' ';
41
- const maskedToken = configManager.maskToken(profile.config.token);
42
- console.log(` ${marker} ${chalk.cyan(profile.name)} (${maskedToken})`);
43
- });
44
- }
45
-
46
- export async function handleUseProfile(profile: string): Promise<void> {
47
- const configManager = new ProfileConfigManager();
48
- await configManager.useProfile(profile);
49
- console.log(chalk.green(`✓ ${SUCCESS_MESSAGES.PROFILE_SWITCHED(profile)}`));
50
- }
51
-
52
- export async function handleShowCurrentProfile(): Promise<void> {
53
- const configManager = new ProfileConfigManager();
54
- const currentProfile = await configManager.getCurrentProfile();
55
- console.log(chalk.bold(`Current profile: ${chalk.cyan(currentProfile)}`));
56
- }
57
-
58
- export async function handleClearConfig(options: { profile?: string }): Promise<void> {
59
- const configManager = new ProfileConfigManager();
60
- const profileName = await getProfileName(configManager, options.profile);
61
- await configManager.clearConfig(options.profile);
62
- console.log(chalk.green(`✓ ${SUCCESS_MESSAGES.PROFILE_CLEARED(profileName)}`));
63
- }
@@ -1,50 +0,0 @@
1
- import { Command } from 'commander';
2
- import { wrapCommand } from '../utils/command-wrapper';
3
- import {
4
- handleSetToken,
5
- handleGetConfig,
6
- handleListProfiles,
7
- handleUseProfile,
8
- handleShowCurrentProfile,
9
- handleClearConfig,
10
- } from './config-subcommands';
11
-
12
- export function setupConfigCommand(): Command {
13
- const config = new Command('config').description('Manage Slack CLI configuration');
14
-
15
- config
16
- .command('set')
17
- .description('Set API token')
18
- .requiredOption('--token <token>', 'Slack API token')
19
- .option('--profile <profile>', 'Profile name (default: "default")')
20
- .action(wrapCommand(handleSetToken));
21
-
22
- config
23
- .command('get')
24
- .description('Show current configuration')
25
- .option('--profile <profile>', 'Profile name')
26
- .action(wrapCommand(handleGetConfig));
27
-
28
- config
29
- .command('profiles')
30
- .description('List all profiles')
31
- .action(wrapCommand(handleListProfiles));
32
-
33
- config
34
- .command('use <profile>')
35
- .description('Switch to a different profile')
36
- .action(wrapCommand(handleUseProfile));
37
-
38
- config
39
- .command('current')
40
- .description('Show current active profile')
41
- .action(wrapCommand(handleShowCurrentProfile));
42
-
43
- config
44
- .command('clear')
45
- .description('Clear configuration')
46
- .option('--profile <profile>', 'Profile name')
47
- .action(wrapCommand(handleClearConfig));
48
-
49
- return config;
50
- }
@@ -1,19 +0,0 @@
1
- import { Message } from '../utils/slack-api-client';
2
- import { createHistoryFormatter } from '../utils/formatters/history-formatters';
3
-
4
- export function displayHistoryResults(
5
- messages: Message[],
6
- users: Map<string, string>,
7
- channelName: string,
8
- format = 'table'
9
- ): void {
10
- // Display messages in reverse order (oldest first)
11
- const orderedMessages = [...messages].reverse();
12
-
13
- const formatter = createHistoryFormatter(format);
14
- formatter.format({
15
- channelName,
16
- messages: orderedMessages,
17
- users,
18
- });
19
- }
@@ -1,46 +0,0 @@
1
- import { Command } from 'commander';
2
- import { API_LIMITS } from '../utils/constants';
3
-
4
- export function validateMessageCount(
5
- value: string | undefined,
6
- command: Command
7
- ): number | undefined {
8
- if (!value) {
9
- return undefined;
10
- }
11
-
12
- const num = parseInt(value, 10);
13
- if (isNaN(num) || num < API_LIMITS.MIN_MESSAGE_COUNT || num > API_LIMITS.MAX_MESSAGE_COUNT) {
14
- command.error(
15
- `Error: Message count must be between ${API_LIMITS.MIN_MESSAGE_COUNT} and ${API_LIMITS.MAX_MESSAGE_COUNT}`
16
- );
17
- }
18
-
19
- return num;
20
- }
21
-
22
- export function validateDateFormat(
23
- value: string | undefined,
24
- command: Command
25
- ): string | undefined {
26
- if (!value) {
27
- return undefined;
28
- }
29
-
30
- const timestamp = Date.parse(value);
31
- if (isNaN(timestamp)) {
32
- command.error('Error: Invalid date format. Use YYYY-MM-DD HH:MM:SS');
33
- }
34
-
35
- return value;
36
- }
37
-
38
- export function prepareSinceTimestamp(since: string | undefined): string | undefined {
39
- if (!since) {
40
- return undefined;
41
- }
42
-
43
- // Convert date to Unix timestamp (in seconds)
44
- const timestamp = Math.floor(Date.parse(since) / 1000);
45
- return timestamp.toString();
46
- }
@@ -1,61 +0,0 @@
1
- import { Command } from 'commander';
2
- import { HistoryOptions as ApiHistoryOptions } from '../utils/slack-api-client';
3
- import { wrapCommand } from '../utils/command-wrapper';
4
- import { createSlackClient } from '../utils/client-factory';
5
- import { HistoryOptions } from '../types/commands';
6
- import { API_LIMITS } from '../utils/constants';
7
- import { parseCount, parseProfile } from '../utils/option-parsers';
8
- import { createValidationHook, optionValidators } from '../utils/validators';
9
- import { parseFormat } from '../utils/option-parsers';
10
- import { prepareSinceTimestamp } from './history-validators';
11
- import { displayHistoryResults } from './history-display';
12
-
13
- export function setupHistoryCommand(): Command {
14
- const historyCommand = new Command('history')
15
- .description('Get message history from a Slack channel')
16
- .requiredOption('-c, --channel <channel>', 'Target channel name or ID')
17
- .option(
18
- '-n, --number <number>',
19
- 'Number of messages to retrieve',
20
- API_LIMITS.DEFAULT_MESSAGE_COUNT.toString()
21
- )
22
- .option('--since <date>', 'Get messages since specific date (YYYY-MM-DD HH:MM:SS)')
23
- .option('--format <format>', 'Output format: table, simple, json', 'table')
24
- .option('--profile <profile>', 'Use specific workspace profile')
25
- .hook(
26
- 'preAction',
27
- createValidationHook([
28
- optionValidators.messageCount,
29
- optionValidators.sinceDate,
30
- optionValidators.format,
31
- ])
32
- )
33
- .action(
34
- wrapCommand(async (options: HistoryOptions) => {
35
- const profile = parseProfile(options.profile);
36
- const client = await createSlackClient(profile);
37
-
38
- const limit = parseCount(
39
- options.number,
40
- API_LIMITS.DEFAULT_MESSAGE_COUNT,
41
- API_LIMITS.MIN_MESSAGE_COUNT,
42
- API_LIMITS.MAX_MESSAGE_COUNT
43
- );
44
-
45
- const historyOptions: ApiHistoryOptions = {
46
- limit,
47
- };
48
-
49
- const oldest = prepareSinceTimestamp(options.since);
50
- if (oldest) {
51
- historyOptions.oldest = oldest;
52
- }
53
-
54
- const { messages, users } = await client.getHistory(options.channel, historyOptions);
55
- const format = parseFormat(options.format);
56
- displayHistoryResults(messages, users, options.channel, format);
57
- })
58
- );
59
-
60
- return historyCommand;
61
- }
@@ -1,71 +0,0 @@
1
- import { Command } from 'commander';
2
- import { wrapCommand } from '../utils/command-wrapper';
3
- import { createSlackClient } from '../utils/client-factory';
4
- import { ScheduledOptions } from '../types/commands';
5
- import { parseFormat, parseLimit } from '../utils/option-parsers';
6
- import { createValidationHook, optionValidators } from '../utils/validators';
7
-
8
- function formatPostAt(postAt: number): string {
9
- return new Date(postAt * 1000).toISOString();
10
- }
11
-
12
- function renderTable(
13
- messages: Array<{ id: string; channel_id: string; post_at: number; text?: string }>
14
- ) {
15
- const rows = messages.map((message) => ({
16
- id: message.id,
17
- channel: message.channel_id,
18
- post_at: formatPostAt(message.post_at),
19
- text: message.text || '',
20
- }));
21
-
22
- console.table(rows);
23
- }
24
-
25
- function renderSimple(
26
- messages: Array<{ id: string; channel_id: string; post_at: number; text?: string }>
27
- ) {
28
- for (const message of messages) {
29
- console.log(
30
- `${formatPostAt(message.post_at)} ${message.channel_id} ${message.id} ${message.text || ''}`
31
- );
32
- }
33
- }
34
-
35
- export function setupScheduledCommand(): Command {
36
- const scheduledCommand = new Command('scheduled')
37
- .description('List scheduled messages')
38
- .option('-c, --channel <channel>', 'Filter by channel name or ID')
39
- .option('--limit <number>', 'Maximum number of scheduled messages to list', '50')
40
- .option('--format <format>', 'Output format: table, simple, json', 'table')
41
- .option('--profile <profile>', 'Use specific workspace profile')
42
- .hook('preAction', createValidationHook([optionValidators.format]))
43
- .action(
44
- wrapCommand(async (options: ScheduledOptions) => {
45
- const client = await createSlackClient(options.profile);
46
- const limit = parseLimit(options.limit, 50);
47
- const messages = await client.listScheduledMessages(options.channel, limit);
48
-
49
- if (messages.length === 0) {
50
- console.log('No scheduled messages found');
51
- return;
52
- }
53
-
54
- const format = parseFormat(options.format);
55
-
56
- if (format === 'json') {
57
- console.log(JSON.stringify(messages, null, 2));
58
- return;
59
- }
60
-
61
- if (format === 'simple') {
62
- renderSimple(messages);
63
- return;
64
- }
65
-
66
- renderTable(messages);
67
- })
68
- );
69
-
70
- return scheduledCommand;
71
- }
@@ -1,69 +0,0 @@
1
- import { Command } from 'commander';
2
- import chalk from 'chalk';
3
- import { wrapCommand } from '../utils/command-wrapper';
4
- import { ERROR_MESSAGES, SUCCESS_MESSAGES } from '../utils/constants';
5
- import { createSlackClient } from '../utils/client-factory';
6
- import { FileError } from '../utils/errors';
7
- import { SendOptions } from '../types/commands';
8
- import { extractErrorMessage } from '../utils/error-utils';
9
- import { parseProfile } from '../utils/option-parsers';
10
- import { createValidationHook, optionValidators } from '../utils/validators';
11
- import { resolvePostAt } from '../utils/schedule-utils';
12
- import * as fs from 'fs/promises';
13
-
14
- export function setupSendCommand(): Command {
15
- const sendCommand = new Command('send')
16
- .description('Send or schedule a message to a Slack channel')
17
- .requiredOption('-c, --channel <channel>', 'Target channel name or ID')
18
- .option('-m, --message <message>', 'Message to send')
19
- .option('-f, --file <file>', 'File containing message content')
20
- .option('-t, --thread <thread>', 'Thread timestamp to reply to')
21
- .option('--at <time>', 'Schedule time (Unix timestamp in seconds or ISO 8601)')
22
- .option('--after <minutes>', 'Schedule message after N minutes')
23
- .option('--profile <profile>', 'Use specific workspace profile')
24
- .hook(
25
- 'preAction',
26
- createValidationHook([
27
- optionValidators.messageOrFile,
28
- optionValidators.threadTimestamp,
29
- optionValidators.scheduleTiming,
30
- ])
31
- )
32
- .action(
33
- wrapCommand(async (options: SendOptions) => {
34
- // Get message content
35
- let messageContent: string;
36
- if (options.file) {
37
- try {
38
- messageContent = await fs.readFile(options.file, 'utf-8');
39
- } catch (error) {
40
- throw new FileError(
41
- ERROR_MESSAGES.FILE_READ_ERROR(options.file, extractErrorMessage(error))
42
- );
43
- }
44
- } else {
45
- messageContent = options.message!; // This is safe because of preAction validation
46
- }
47
-
48
- const postAt = resolvePostAt(options.at, options.after);
49
-
50
- // Send message
51
- const profile = parseProfile(options.profile);
52
- const client = await createSlackClient(profile);
53
-
54
- if (postAt !== null) {
55
- await client.scheduleMessage(options.channel, messageContent, postAt, options.thread);
56
- const postAtIso = new Date(postAt * 1000).toISOString();
57
- console.log(
58
- chalk.green(`✓ ${SUCCESS_MESSAGES.MESSAGE_SCHEDULED(options.channel, postAtIso)}`)
59
- );
60
- return;
61
- }
62
-
63
- await client.sendMessage(options.channel, messageContent, options.thread);
64
- console.log(chalk.green(`✓ ${SUCCESS_MESSAGES.MESSAGE_SENT(options.channel)}`));
65
- })
66
- );
67
-
68
- return sendCommand;
69
- }
@@ -1,122 +0,0 @@
1
- import { Command } from 'commander';
2
- import { wrapCommand } from '../utils/command-wrapper';
3
- import { createSlackClient } from '../utils/client-factory';
4
- import { SlackApiClient, ChannelUnreadResult, Channel } from '../utils/slack-api-client';
5
- import { UnreadOptions } from '../types/commands';
6
- import chalk from 'chalk';
7
- import { createChannelFormatter } from '../utils/formatters/channel-formatters';
8
- import { createMessageFormatter } from '../utils/formatters/message-formatters';
9
- import { DEFAULTS } from '../utils/constants';
10
- import { parseLimit, parseFormat, parseBoolean } from '../utils/option-parsers';
11
-
12
- async function fetchChannelUnreadData(client: SlackApiClient, channelName: string) {
13
- return await client.getChannelUnread(channelName);
14
- }
15
-
16
- function formatChannelUnreadOutput(
17
- result: ChannelUnreadResult,
18
- format: string,
19
- countOnly: boolean
20
- ): void {
21
- const formatter = createMessageFormatter(format);
22
- formatter.format({
23
- channel: result.channel,
24
- messages: result.messages,
25
- users: result.users,
26
- countOnly: countOnly,
27
- format: format,
28
- });
29
- }
30
-
31
- async function markChannelAsRead(client: SlackApiClient, channel: Channel): Promise<void> {
32
- await client.markAsRead(channel.id);
33
- console.log(chalk.green(`✓ Marked messages in #${channel.name} as read`));
34
- }
35
-
36
- async function handleSpecificChannelUnread(
37
- client: SlackApiClient,
38
- options: UnreadOptions
39
- ): Promise<void> {
40
- const result = await fetchChannelUnreadData(client, options.channel!);
41
-
42
- const format = parseFormat(options.format);
43
- const countOnly = parseBoolean(options.countOnly);
44
-
45
- formatChannelUnreadOutput(result, format, countOnly);
46
-
47
- if (parseBoolean(options.markRead)) {
48
- await markChannelAsRead(client, result.channel);
49
- }
50
- }
51
-
52
- async function fetchAllUnreadChannels(client: SlackApiClient) {
53
- return await client.listUnreadChannels();
54
- }
55
-
56
- function formatAllChannelsOutput(
57
- channels: Channel[],
58
- format: string,
59
- countOnly: boolean,
60
- limit: number
61
- ): void {
62
- const displayChannels = channels.slice(0, limit);
63
- const formatter = createChannelFormatter(format, countOnly);
64
- formatter.format({ channels: displayChannels, countOnly: countOnly });
65
- }
66
-
67
- async function markAllChannelsAsRead(client: SlackApiClient, channels: Channel[]): Promise<void> {
68
- for (const channel of channels) {
69
- await client.markAsRead(channel.id);
70
- }
71
- console.log(chalk.green('✓ Marked all messages as read'));
72
- }
73
-
74
- async function handleAllChannelsUnread(
75
- client: SlackApiClient,
76
- options: UnreadOptions
77
- ): Promise<void> {
78
- const channels = await fetchAllUnreadChannels(client);
79
-
80
- if (channels.length === 0) {
81
- console.log(chalk.green('✓ No unread messages'));
82
- return;
83
- }
84
-
85
- const limit = parseLimit(options.limit, DEFAULTS.UNREAD_DISPLAY_LIMIT);
86
- const format = parseFormat(options.format);
87
- const countOnly = parseBoolean(options.countOnly);
88
-
89
- formatAllChannelsOutput(channels, format, countOnly, limit);
90
-
91
- if (parseBoolean(options.markRead)) {
92
- await markAllChannelsAsRead(client, channels);
93
- }
94
- }
95
-
96
- export function setupUnreadCommand(): Command {
97
- const unreadCommand = new Command('unread')
98
- .description('Show unread messages across channels')
99
- .option('-c, --channel <channel>', 'Show unread for a specific channel')
100
- .option('--format <format>', 'Output format: table, simple, json', 'table')
101
- .option('--count-only', 'Show only unread counts', false)
102
- .option(
103
- '--limit <number>',
104
- 'Maximum number of channels to display',
105
- DEFAULTS.UNREAD_DISPLAY_LIMIT.toString()
106
- )
107
- .option('--mark-read', 'Mark messages as read after fetching', false)
108
- .option('--profile <profile>', 'Use specific workspace profile')
109
- .action(
110
- wrapCommand(async (options: UnreadOptions) => {
111
- const client = await createSlackClient(options.profile);
112
-
113
- if (options.channel) {
114
- await handleSpecificChannelUnread(client, options);
115
- } else {
116
- await handleAllChannelsUnread(client, options);
117
- }
118
- })
119
- );
120
-
121
- return unreadCommand;
122
- }
package/src/index.ts DELETED
@@ -1,27 +0,0 @@
1
- #!/usr/bin/env node
2
- import { Command } from 'commander';
3
- import { setupConfigCommand } from './commands/config';
4
- import { setupSendCommand } from './commands/send';
5
- import { setupChannelsCommand } from './commands/channels';
6
- import { setupHistoryCommand } from './commands/history';
7
- import { setupUnreadCommand } from './commands/unread';
8
- import { setupScheduledCommand } from './commands/scheduled';
9
- import { readFileSync } from 'fs';
10
- import { join } from 'path';
11
-
12
- const program = new Command();
13
-
14
- // Read version from package.json
15
- const packageJson = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
16
- const version = packageJson.version;
17
-
18
- program.name('slack-cli').description('CLI tool to send messages via Slack API').version(version);
19
-
20
- program.addCommand(setupConfigCommand());
21
- program.addCommand(setupSendCommand());
22
- program.addCommand(setupChannelsCommand());
23
- program.addCommand(setupHistoryCommand());
24
- program.addCommand(setupUnreadCommand());
25
- program.addCommand(setupScheduledCommand());
26
-
27
- program.parse();
@@ -1,58 +0,0 @@
1
- export interface ConfigSetOptions {
2
- token: string;
3
- profile?: string;
4
- }
5
-
6
- export interface ConfigGetOptions {
7
- profile?: string;
8
- }
9
-
10
- export interface ConfigUseOptions {
11
- profile: string;
12
- }
13
-
14
- export interface ConfigClearOptions {
15
- profile?: string;
16
- }
17
-
18
- export interface SendOptions {
19
- channel: string;
20
- message?: string;
21
- file?: string;
22
- thread?: string;
23
- at?: string;
24
- after?: string;
25
- profile?: string;
26
- }
27
-
28
- export interface ScheduledOptions {
29
- channel?: string;
30
- limit?: string;
31
- format?: 'table' | 'simple' | 'json';
32
- profile?: string;
33
- }
34
-
35
- export interface ChannelsOptions {
36
- type: 'public' | 'private' | 'im' | 'mpim' | 'all';
37
- includeArchived: boolean;
38
- format: 'table' | 'simple' | 'json';
39
- limit: string;
40
- profile?: string;
41
- }
42
-
43
- export interface HistoryOptions {
44
- channel: string;
45
- number?: string;
46
- since?: string;
47
- format?: 'table' | 'simple' | 'json';
48
- profile?: string;
49
- }
50
-
51
- export interface UnreadOptions {
52
- channel?: string;
53
- format?: 'table' | 'simple' | 'json';
54
- countOnly?: boolean;
55
- limit?: string;
56
- markRead?: boolean;
57
- profile?: string;
58
- }
@@ -1,20 +0,0 @@
1
- export interface Config {
2
- token: string;
3
- updatedAt: string;
4
- }
5
-
6
- export interface Profile {
7
- name: string;
8
- config: Config;
9
- isDefault?: boolean;
10
- }
11
-
12
- export interface ConfigStore {
13
- profiles: Record<string, Config>;
14
- defaultProfile?: string;
15
- }
16
-
17
- export interface ConfigOptions {
18
- configDir?: string;
19
- profile?: string;
20
- }