@urugus/slack-cli 0.1.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.
- package/.claude/settings.local.json +53 -0
- package/.eslintrc.json +25 -0
- package/.github/dependabot.yml +18 -0
- package/.github/workflows/ci.yml +70 -0
- package/.github/workflows/pr-validation.yml +51 -0
- package/.prettierignore +11 -0
- package/.prettierrc +10 -0
- package/CLAUDE.md +16 -0
- package/README.md +161 -0
- package/dist/commands/channels.d.ts +3 -0
- package/dist/commands/channels.d.ts.map +1 -0
- package/dist/commands/channels.js +50 -0
- package/dist/commands/channels.js.map +1 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +87 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/history.d.ts +3 -0
- package/dist/commands/history.d.ts.map +1 -0
- package/dist/commands/history.js +79 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/send.d.ts +3 -0
- package/dist/commands/send.d.ts.map +1 -0
- package/dist/commands/send.js +85 -0
- package/dist/commands/send.js.map +1 -0
- package/dist/commands/unread.d.ts +3 -0
- package/dist/commands/unread.d.ts.map +1 -0
- package/dist/commands/unread.js +104 -0
- package/dist/commands/unread.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/types/commands.d.ts +40 -0
- package/dist/types/commands.d.ts.map +1 -0
- package/dist/types/commands.js +3 -0
- package/dist/types/commands.js.map +1 -0
- package/dist/types/config.d.ts +18 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +3 -0
- package/dist/types/config.js.map +1 -0
- package/dist/utils/channel-formatter.d.ts +16 -0
- package/dist/utils/channel-formatter.d.ts.map +1 -0
- package/dist/utils/channel-formatter.js +77 -0
- package/dist/utils/channel-formatter.js.map +1 -0
- package/dist/utils/client-factory.d.ts +6 -0
- package/dist/utils/client-factory.d.ts.map +1 -0
- package/dist/utils/client-factory.js +13 -0
- package/dist/utils/client-factory.js.map +1 -0
- package/dist/utils/command-wrapper.d.ts +6 -0
- package/dist/utils/command-wrapper.d.ts.map +1 -0
- package/dist/utils/command-wrapper.js +27 -0
- package/dist/utils/command-wrapper.js.map +1 -0
- package/dist/utils/config-helper.d.ts +8 -0
- package/dist/utils/config-helper.d.ts.map +1 -0
- package/dist/utils/config-helper.js +19 -0
- package/dist/utils/config-helper.js.map +1 -0
- package/dist/utils/config.d.ts +10 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +94 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/constants.d.ts +32 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +42 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/date-utils.d.ts +3 -0
- package/dist/utils/date-utils.d.ts.map +1 -0
- package/dist/utils/date-utils.js +12 -0
- package/dist/utils/date-utils.js.map +1 -0
- package/dist/utils/error-utils.d.ts +2 -0
- package/dist/utils/error-utils.d.ts.map +1 -0
- package/dist/utils/error-utils.js +10 -0
- package/dist/utils/error-utils.js.map +1 -0
- package/dist/utils/errors.d.ts +17 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +40 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/profile-config.d.ts +21 -0
- package/dist/utils/profile-config.d.ts.map +1 -0
- package/dist/utils/profile-config.js +173 -0
- package/dist/utils/profile-config.js.map +1 -0
- package/dist/utils/slack-api-client.d.ts +74 -0
- package/dist/utils/slack-api-client.d.ts.map +1 -0
- package/dist/utils/slack-api-client.js +132 -0
- package/dist/utils/slack-api-client.js.map +1 -0
- package/package.json +56 -0
- package/src/commands/channels.ts +65 -0
- package/src/commands/config.ts +104 -0
- package/src/commands/history.ts +96 -0
- package/src/commands/send.ts +52 -0
- package/src/commands/unread.ts +118 -0
- package/src/index.ts +19 -0
- package/src/types/commands.ts +46 -0
- package/src/types/config.ts +20 -0
- package/src/utils/channel-formatter.ts +89 -0
- package/src/utils/client-factory.ts +10 -0
- package/src/utils/command-wrapper.ts +27 -0
- package/src/utils/config-helper.ts +21 -0
- package/src/utils/constants.ts +47 -0
- package/src/utils/date-utils.ts +8 -0
- package/src/utils/error-utils.ts +6 -0
- package/src/utils/errors.ts +37 -0
- package/src/utils/profile-config.ts +171 -0
- package/src/utils/slack-api-client.ts +218 -0
- package/tests/commands/channels.test.ts +250 -0
- package/tests/commands/config.test.ts +158 -0
- package/tests/commands/history.test.ts +250 -0
- package/tests/commands/send.test.ts +156 -0
- package/tests/commands/unread.test.ts +248 -0
- package/tests/test-utils.ts +28 -0
- package/tests/utils/config.test.ts +400 -0
- package/tests/utils/date-utils.test.ts +30 -0
- package/tests/utils/error-utils.test.ts +34 -0
- package/tests/utils/slack-api-client.test.ts +170 -0
- package/tsconfig.json +22 -0
- package/vitest.config.ts +27 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.slackApiClient = exports.SlackApiClient = void 0;
|
|
4
|
+
const web_api_1 = require("@slack/web-api");
|
|
5
|
+
class SlackApiClient {
|
|
6
|
+
constructor(token) {
|
|
7
|
+
this.client = new web_api_1.WebClient(token);
|
|
8
|
+
}
|
|
9
|
+
async sendMessage(channel, text) {
|
|
10
|
+
return await this.client.chat.postMessage({
|
|
11
|
+
channel,
|
|
12
|
+
text,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
async listChannels(options) {
|
|
16
|
+
const response = await this.client.conversations.list({
|
|
17
|
+
types: options.types,
|
|
18
|
+
exclude_archived: options.exclude_archived,
|
|
19
|
+
limit: options.limit,
|
|
20
|
+
});
|
|
21
|
+
return response.channels;
|
|
22
|
+
}
|
|
23
|
+
async getHistory(channel, options) {
|
|
24
|
+
const response = await this.client.conversations.history({
|
|
25
|
+
channel,
|
|
26
|
+
limit: options.limit,
|
|
27
|
+
oldest: options.oldest,
|
|
28
|
+
});
|
|
29
|
+
const messages = response.messages;
|
|
30
|
+
// Get unique user IDs
|
|
31
|
+
const userIds = [...new Set(messages.filter((m) => m.user).map((m) => m.user))];
|
|
32
|
+
const users = new Map();
|
|
33
|
+
// Fetch user information
|
|
34
|
+
if (userIds.length > 0) {
|
|
35
|
+
for (const userId of userIds) {
|
|
36
|
+
try {
|
|
37
|
+
const userInfo = await this.client.users.info({ user: userId });
|
|
38
|
+
if (userInfo.user?.name) {
|
|
39
|
+
users.set(userId, userInfo.user.name);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
// If we can't get user info, we'll use the ID
|
|
44
|
+
users.set(userId, userId);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return { messages, users };
|
|
49
|
+
}
|
|
50
|
+
async listUnreadChannels() {
|
|
51
|
+
// Get all conversations the user is a member of
|
|
52
|
+
const response = await this.client.conversations.list({
|
|
53
|
+
types: 'public_channel,private_channel,im,mpim',
|
|
54
|
+
exclude_archived: true,
|
|
55
|
+
limit: 1000,
|
|
56
|
+
});
|
|
57
|
+
const channels = response.channels;
|
|
58
|
+
// Get unread count for each channel
|
|
59
|
+
const channelsWithUnread = await Promise.all(channels.map(async (channel) => {
|
|
60
|
+
try {
|
|
61
|
+
const info = await this.client.conversations.info({
|
|
62
|
+
channel: channel.id,
|
|
63
|
+
include_num_members: false,
|
|
64
|
+
});
|
|
65
|
+
const channelInfo = info.channel;
|
|
66
|
+
return {
|
|
67
|
+
...channel,
|
|
68
|
+
unread_count: channelInfo.unread_count || 0,
|
|
69
|
+
unread_count_display: channelInfo.unread_count_display || 0,
|
|
70
|
+
last_read: channelInfo.last_read,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return channel;
|
|
75
|
+
}
|
|
76
|
+
}));
|
|
77
|
+
// Filter to only channels with unread messages
|
|
78
|
+
return channelsWithUnread.filter((channel) => (channel.unread_count_display || 0) > 0);
|
|
79
|
+
}
|
|
80
|
+
async getChannelUnread(channelNameOrId) {
|
|
81
|
+
// First, find the channel
|
|
82
|
+
let channelId = channelNameOrId;
|
|
83
|
+
if (!channelNameOrId.startsWith('C') &&
|
|
84
|
+
!channelNameOrId.startsWith('D') &&
|
|
85
|
+
!channelNameOrId.startsWith('G')) {
|
|
86
|
+
// It's a name, not an ID - need to find the ID
|
|
87
|
+
const channels = await this.listChannels({
|
|
88
|
+
types: 'public_channel,private_channel,im,mpim',
|
|
89
|
+
exclude_archived: true,
|
|
90
|
+
limit: 1000,
|
|
91
|
+
});
|
|
92
|
+
const channel = channels.find((c) => c.name === channelNameOrId || c.name === channelNameOrId.replace('#', ''));
|
|
93
|
+
if (!channel) {
|
|
94
|
+
throw new Error('channel_not_found');
|
|
95
|
+
}
|
|
96
|
+
channelId = channel.id;
|
|
97
|
+
}
|
|
98
|
+
// Get channel info with unread count
|
|
99
|
+
const info = await this.client.conversations.info({
|
|
100
|
+
channel: channelId,
|
|
101
|
+
});
|
|
102
|
+
const channel = info.channel;
|
|
103
|
+
// Get unread messages
|
|
104
|
+
let messages = [];
|
|
105
|
+
let users = new Map();
|
|
106
|
+
if (channel.last_read && channel.unread_count > 0) {
|
|
107
|
+
const historyResult = await this.getHistory(channelId, {
|
|
108
|
+
limit: channel.unread_count,
|
|
109
|
+
oldest: channel.last_read,
|
|
110
|
+
});
|
|
111
|
+
messages = historyResult.messages;
|
|
112
|
+
users = historyResult.users;
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
channel: {
|
|
116
|
+
...channel,
|
|
117
|
+
unread_count: channel.unread_count || 0,
|
|
118
|
+
unread_count_display: channel.unread_count_display || 0,
|
|
119
|
+
},
|
|
120
|
+
messages,
|
|
121
|
+
users,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
exports.SlackApiClient = SlackApiClient;
|
|
126
|
+
exports.slackApiClient = {
|
|
127
|
+
listChannels: async (token, options) => {
|
|
128
|
+
const client = new SlackApiClient(token);
|
|
129
|
+
return client.listChannels(options);
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
//# sourceMappingURL=slack-api-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack-api-client.js","sourceRoot":"","sources":["../../src/utils/slack-api-client.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@urugus/slack-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A command-line tool for sending messages to Slack",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"slack-cli": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"dev": "ts-node src/index.ts",
|
|
12
|
+
"start": "node dist/index.js",
|
|
13
|
+
"test": "vitest",
|
|
14
|
+
"test:watch": "vitest --watch",
|
|
15
|
+
"test:coverage": "vitest --coverage",
|
|
16
|
+
"lint": "eslint src/**/*.ts",
|
|
17
|
+
"format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json,md}\"",
|
|
18
|
+
"format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,json,md}\"",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"slack",
|
|
23
|
+
"cli",
|
|
24
|
+
"command-line",
|
|
25
|
+
"messaging",
|
|
26
|
+
"api"
|
|
27
|
+
],
|
|
28
|
+
"author": "urugus",
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@slack/web-api": "^6.9.0",
|
|
35
|
+
"commander": "^11.1.0",
|
|
36
|
+
"dotenv": "^16.3.1",
|
|
37
|
+
"chalk": "^4.1.2",
|
|
38
|
+
"inquirer": "^8.2.6"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^20.10.0",
|
|
42
|
+
"@types/inquirer": "^8.2.10",
|
|
43
|
+
"@typescript-eslint/eslint-plugin": "^6.13.0",
|
|
44
|
+
"@typescript-eslint/parser": "^6.13.0",
|
|
45
|
+
"@vitest/coverage-v8": "^1.0.4",
|
|
46
|
+
"eslint": "^8.55.0",
|
|
47
|
+
"eslint-config-prettier": "^9.1.0",
|
|
48
|
+
"prettier": "^3.1.1",
|
|
49
|
+
"ts-node": "^10.9.1",
|
|
50
|
+
"typescript": "^5.3.2",
|
|
51
|
+
"vitest": "^1.0.4"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=16.0.0"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
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 {
|
|
7
|
+
mapChannelToInfo,
|
|
8
|
+
formatChannelsAsTable,
|
|
9
|
+
formatChannelsAsSimple,
|
|
10
|
+
formatChannelsAsJson,
|
|
11
|
+
getChannelTypes,
|
|
12
|
+
} from '../utils/channel-formatter';
|
|
13
|
+
|
|
14
|
+
export function setupChannelsCommand(): Command {
|
|
15
|
+
const channelsCommand = new Command('channels');
|
|
16
|
+
|
|
17
|
+
channelsCommand
|
|
18
|
+
.description('List Slack channels')
|
|
19
|
+
.option('--type <type>', 'Channel type: public, private, im, mpim, all', 'public')
|
|
20
|
+
.option('--include-archived', 'Include archived channels', false)
|
|
21
|
+
.option('--format <format>', 'Output format: table, simple, json', 'table')
|
|
22
|
+
.option('--limit <number>', 'Maximum number of channels to list', '100')
|
|
23
|
+
.option('--profile <profile>', 'Use specific workspace profile')
|
|
24
|
+
.action(
|
|
25
|
+
wrapCommand(async (options: ChannelsOptions) => {
|
|
26
|
+
// Create Slack client
|
|
27
|
+
const client = await createSlackClient(options.profile);
|
|
28
|
+
|
|
29
|
+
// Map channel type to API types
|
|
30
|
+
const types = getChannelTypes(options.type);
|
|
31
|
+
|
|
32
|
+
// List channels
|
|
33
|
+
const channels = await client.listChannels({
|
|
34
|
+
types,
|
|
35
|
+
exclude_archived: !options.includeArchived,
|
|
36
|
+
limit: parseInt(options.limit, 10),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (channels.length === 0) {
|
|
40
|
+
console.log(ERROR_MESSAGES.NO_CHANNELS_FOUND);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Format and display channels
|
|
45
|
+
const channelInfos = channels.map(mapChannelToInfo);
|
|
46
|
+
|
|
47
|
+
switch (options.format) {
|
|
48
|
+
case 'simple':
|
|
49
|
+
formatChannelsAsSimple(channelInfos);
|
|
50
|
+
break;
|
|
51
|
+
|
|
52
|
+
case 'json':
|
|
53
|
+
formatChannelsAsJson(channelInfos);
|
|
54
|
+
break;
|
|
55
|
+
|
|
56
|
+
case 'table':
|
|
57
|
+
default:
|
|
58
|
+
formatChannelsAsTable(channelInfos);
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
return channelsCommand;
|
|
65
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { ProfileConfigManager } from '../utils/profile-config';
|
|
4
|
+
import { wrapCommand, getProfileName } from '../utils/command-wrapper';
|
|
5
|
+
import { ERROR_MESSAGES, SUCCESS_MESSAGES } from '../utils/constants';
|
|
6
|
+
|
|
7
|
+
export function setupConfigCommand(): Command {
|
|
8
|
+
const config = new Command('config').description('Manage Slack CLI configuration');
|
|
9
|
+
|
|
10
|
+
config
|
|
11
|
+
.command('set')
|
|
12
|
+
.description('Set API token')
|
|
13
|
+
.requiredOption('--token <token>', 'Slack API token')
|
|
14
|
+
.option('--profile <profile>', 'Profile name (default: "default")')
|
|
15
|
+
.action(
|
|
16
|
+
wrapCommand(async (options) => {
|
|
17
|
+
const configManager = new ProfileConfigManager();
|
|
18
|
+
const profileName = await getProfileName(configManager, options.profile);
|
|
19
|
+
await configManager.setToken(options.token, options.profile);
|
|
20
|
+
console.log(chalk.green(`✓ ${SUCCESS_MESSAGES.TOKEN_SAVED(profileName)}`));
|
|
21
|
+
})
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
config
|
|
25
|
+
.command('get')
|
|
26
|
+
.description('Show current configuration')
|
|
27
|
+
.option('--profile <profile>', 'Profile name')
|
|
28
|
+
.action(
|
|
29
|
+
wrapCommand(async (options) => {
|
|
30
|
+
const configManager = new ProfileConfigManager();
|
|
31
|
+
const profileName = await getProfileName(configManager, options.profile);
|
|
32
|
+
const currentConfig = await configManager.getConfig(options.profile);
|
|
33
|
+
|
|
34
|
+
if (!currentConfig) {
|
|
35
|
+
console.log(chalk.yellow(ERROR_MESSAGES.NO_CONFIG(profileName)));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
console.log(chalk.bold(`Configuration for profile "${profileName}":`));
|
|
40
|
+
console.log(` Token: ${chalk.cyan(configManager.maskToken(currentConfig.token))}`);
|
|
41
|
+
console.log(` Updated: ${chalk.gray(currentConfig.updatedAt)}`);
|
|
42
|
+
})
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
config
|
|
46
|
+
.command('profiles')
|
|
47
|
+
.description('List all profiles')
|
|
48
|
+
.action(
|
|
49
|
+
wrapCommand(async () => {
|
|
50
|
+
const configManager = new ProfileConfigManager();
|
|
51
|
+
const profiles = await configManager.listProfiles();
|
|
52
|
+
const currentProfile = await configManager.getCurrentProfile();
|
|
53
|
+
|
|
54
|
+
if (profiles.length === 0) {
|
|
55
|
+
console.log(chalk.yellow(ERROR_MESSAGES.NO_PROFILES_FOUND));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log(chalk.bold('Available profiles:'));
|
|
60
|
+
profiles.forEach((profile) => {
|
|
61
|
+
const marker = profile.name === currentProfile ? '*' : ' ';
|
|
62
|
+
const maskedToken = configManager.maskToken(profile.config.token);
|
|
63
|
+
console.log(` ${marker} ${chalk.cyan(profile.name)} (${maskedToken})`);
|
|
64
|
+
});
|
|
65
|
+
})
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
config
|
|
69
|
+
.command('use <profile>')
|
|
70
|
+
.description('Switch to a different profile')
|
|
71
|
+
.action(
|
|
72
|
+
wrapCommand(async (profile) => {
|
|
73
|
+
const configManager = new ProfileConfigManager();
|
|
74
|
+
await configManager.useProfile(profile);
|
|
75
|
+
console.log(chalk.green(`✓ ${SUCCESS_MESSAGES.PROFILE_SWITCHED(profile)}`));
|
|
76
|
+
})
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
config
|
|
80
|
+
.command('current')
|
|
81
|
+
.description('Show current active profile')
|
|
82
|
+
.action(
|
|
83
|
+
wrapCommand(async () => {
|
|
84
|
+
const configManager = new ProfileConfigManager();
|
|
85
|
+
const currentProfile = await configManager.getCurrentProfile();
|
|
86
|
+
console.log(chalk.bold(`Current profile: ${chalk.cyan(currentProfile)}`));
|
|
87
|
+
})
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
config
|
|
91
|
+
.command('clear')
|
|
92
|
+
.description('Clear configuration')
|
|
93
|
+
.option('--profile <profile>', 'Profile name')
|
|
94
|
+
.action(
|
|
95
|
+
wrapCommand(async (options) => {
|
|
96
|
+
const configManager = new ProfileConfigManager();
|
|
97
|
+
const profileName = await getProfileName(configManager, options.profile);
|
|
98
|
+
await configManager.clearConfig(options.profile);
|
|
99
|
+
console.log(chalk.green(`✓ ${SUCCESS_MESSAGES.PROFILE_CLEARED(profileName)}`));
|
|
100
|
+
})
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
return config;
|
|
104
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { HistoryOptions as ApiHistoryOptions, Message } from '../utils/slack-api-client';
|
|
4
|
+
import { wrapCommand } from '../utils/command-wrapper';
|
|
5
|
+
import { createSlackClient } from '../utils/client-factory';
|
|
6
|
+
import { HistoryOptions } from '../types/commands';
|
|
7
|
+
import { formatSlackTimestamp } from '../utils/date-utils';
|
|
8
|
+
import { API_LIMITS } from '../utils/constants';
|
|
9
|
+
|
|
10
|
+
export function setupHistoryCommand(): Command {
|
|
11
|
+
const historyCommand = new Command('history')
|
|
12
|
+
.description('Get message history from a Slack channel')
|
|
13
|
+
.requiredOption('-c, --channel <channel>', 'Target channel name or ID')
|
|
14
|
+
.option(
|
|
15
|
+
'-n, --number <number>',
|
|
16
|
+
'Number of messages to retrieve',
|
|
17
|
+
API_LIMITS.DEFAULT_MESSAGE_COUNT.toString()
|
|
18
|
+
)
|
|
19
|
+
.option('--since <date>', 'Get messages since specific date (YYYY-MM-DD HH:MM:SS)')
|
|
20
|
+
.option('--profile <profile>', 'Use specific workspace profile')
|
|
21
|
+
.hook('preAction', (thisCommand) => {
|
|
22
|
+
const options = thisCommand.opts();
|
|
23
|
+
|
|
24
|
+
// Validate number option
|
|
25
|
+
if (options.number) {
|
|
26
|
+
const num = parseInt(options.number, 10);
|
|
27
|
+
if (
|
|
28
|
+
isNaN(num) ||
|
|
29
|
+
num < API_LIMITS.MIN_MESSAGE_COUNT ||
|
|
30
|
+
num > API_LIMITS.MAX_MESSAGE_COUNT
|
|
31
|
+
) {
|
|
32
|
+
thisCommand.error(
|
|
33
|
+
`Error: Message count must be between ${API_LIMITS.MIN_MESSAGE_COUNT} and ${API_LIMITS.MAX_MESSAGE_COUNT}`
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Validate since option
|
|
39
|
+
if (options.since) {
|
|
40
|
+
const timestamp = Date.parse(options.since);
|
|
41
|
+
if (isNaN(timestamp)) {
|
|
42
|
+
thisCommand.error('Error: Invalid date format. Use YYYY-MM-DD HH:MM:SS');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
.action(
|
|
47
|
+
wrapCommand(async (options: HistoryOptions) => {
|
|
48
|
+
// Create Slack client
|
|
49
|
+
const client = await createSlackClient(options.profile);
|
|
50
|
+
|
|
51
|
+
// Prepare API options
|
|
52
|
+
const historyOptions: ApiHistoryOptions = {
|
|
53
|
+
limit: parseInt(options.number || API_LIMITS.DEFAULT_MESSAGE_COUNT.toString(), 10),
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
if (options.since) {
|
|
57
|
+
// Convert date to Unix timestamp (in seconds)
|
|
58
|
+
const timestamp = Math.floor(Date.parse(options.since) / 1000);
|
|
59
|
+
historyOptions.oldest = timestamp.toString();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Get message history
|
|
63
|
+
const { messages, users } = await client.getHistory(options.channel, historyOptions);
|
|
64
|
+
|
|
65
|
+
// Display results
|
|
66
|
+
if (messages.length === 0) {
|
|
67
|
+
console.log(chalk.yellow('No messages found in the specified channel.'));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log(chalk.bold(`\nMessage History for #${options.channel}:\n`));
|
|
72
|
+
|
|
73
|
+
// Display messages in reverse order (oldest first)
|
|
74
|
+
messages.reverse().forEach((message: Message) => {
|
|
75
|
+
const timestamp = formatSlackTimestamp(message.ts);
|
|
76
|
+
let author = 'Unknown';
|
|
77
|
+
|
|
78
|
+
if (message.user && users.has(message.user)) {
|
|
79
|
+
author = users.get(message.user)!;
|
|
80
|
+
} else if (message.bot_id) {
|
|
81
|
+
author = 'Bot';
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
console.log(chalk.gray(`[${timestamp}]`) + ' ' + chalk.cyan(author));
|
|
85
|
+
if (message.text) {
|
|
86
|
+
console.log(message.text);
|
|
87
|
+
}
|
|
88
|
+
console.log(''); // Empty line between messages
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
console.log(chalk.green(`✓ Displayed ${messages.length} message(s)`));
|
|
92
|
+
})
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
return historyCommand;
|
|
96
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
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 * as fs from 'fs/promises';
|
|
10
|
+
|
|
11
|
+
export function setupSendCommand(): Command {
|
|
12
|
+
const sendCommand = new Command('send')
|
|
13
|
+
.description('Send a message to a Slack channel')
|
|
14
|
+
.requiredOption('-c, --channel <channel>', 'Target channel name or ID')
|
|
15
|
+
.option('-m, --message <message>', 'Message to send')
|
|
16
|
+
.option('-f, --file <file>', 'File containing message content')
|
|
17
|
+
.option('--profile <profile>', 'Use specific workspace profile')
|
|
18
|
+
.hook('preAction', (thisCommand) => {
|
|
19
|
+
const options = thisCommand.opts();
|
|
20
|
+
if (!options.message && !options.file) {
|
|
21
|
+
thisCommand.error(`Error: ${ERROR_MESSAGES.NO_MESSAGE_OR_FILE}`);
|
|
22
|
+
}
|
|
23
|
+
if (options.message && options.file) {
|
|
24
|
+
thisCommand.error(`Error: ${ERROR_MESSAGES.BOTH_MESSAGE_AND_FILE}`);
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
.action(
|
|
28
|
+
wrapCommand(async (options: SendOptions) => {
|
|
29
|
+
// Get message content
|
|
30
|
+
let messageContent: string;
|
|
31
|
+
if (options.file) {
|
|
32
|
+
try {
|
|
33
|
+
messageContent = await fs.readFile(options.file, 'utf-8');
|
|
34
|
+
} catch (error) {
|
|
35
|
+
throw new FileError(
|
|
36
|
+
ERROR_MESSAGES.FILE_READ_ERROR(options.file, extractErrorMessage(error))
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
} else {
|
|
40
|
+
messageContent = options.message!; // This is safe because of preAction validation
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Send message
|
|
44
|
+
const client = await createSlackClient(options.profile);
|
|
45
|
+
await client.sendMessage(options.channel, messageContent);
|
|
46
|
+
|
|
47
|
+
console.log(chalk.green(`✓ ${SUCCESS_MESSAGES.MESSAGE_SENT(options.channel)}`));
|
|
48
|
+
})
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
return sendCommand;
|
|
52
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { wrapCommand } from '../utils/command-wrapper';
|
|
3
|
+
import { createSlackClient } from '../utils/client-factory';
|
|
4
|
+
import { SlackApiClient, Channel } from '../utils/slack-api-client';
|
|
5
|
+
import { UnreadOptions } from '../types/commands';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import { formatSlackTimestamp } from '../utils/date-utils';
|
|
8
|
+
import { formatChannelName } from '../utils/channel-formatter';
|
|
9
|
+
|
|
10
|
+
async function handleSpecificChannelUnread(
|
|
11
|
+
client: SlackApiClient,
|
|
12
|
+
options: UnreadOptions
|
|
13
|
+
): Promise<void> {
|
|
14
|
+
const result = await client.getChannelUnread(options.channel!);
|
|
15
|
+
const channelName = formatChannelName(result.channel.name);
|
|
16
|
+
|
|
17
|
+
console.log(chalk.bold(`${channelName}: ${result.channel.unread_count || 0} unread messages`));
|
|
18
|
+
|
|
19
|
+
if (!options.countOnly && result.messages.length > 0) {
|
|
20
|
+
console.log('');
|
|
21
|
+
result.messages.forEach((message) => {
|
|
22
|
+
const timestamp = formatSlackTimestamp(message.ts);
|
|
23
|
+
const author = message.user ? result.users.get(message.user) || message.user : 'unknown';
|
|
24
|
+
console.log(`${chalk.gray(timestamp)} ${chalk.cyan(author)}`);
|
|
25
|
+
console.log(message.text || '(no text)');
|
|
26
|
+
console.log('');
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function handleAllChannelsUnread(
|
|
32
|
+
client: SlackApiClient,
|
|
33
|
+
options: UnreadOptions
|
|
34
|
+
): Promise<void> {
|
|
35
|
+
const channels = await client.listUnreadChannels();
|
|
36
|
+
|
|
37
|
+
if (channels.length === 0) {
|
|
38
|
+
console.log(chalk.green('✓ No unread messages'));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Apply limit
|
|
43
|
+
const limit = parseInt(options.limit || '50', 10);
|
|
44
|
+
const displayChannels = channels.slice(0, limit);
|
|
45
|
+
|
|
46
|
+
if (options.countOnly) {
|
|
47
|
+
displayCountOnly(displayChannels);
|
|
48
|
+
} else if (options.format === 'json') {
|
|
49
|
+
displayAsJson(displayChannels);
|
|
50
|
+
} else if (options.format === 'simple') {
|
|
51
|
+
displayAsSimple(displayChannels);
|
|
52
|
+
} else {
|
|
53
|
+
displayAsTable(displayChannels);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function displayCountOnly(channels: Channel[]): void {
|
|
58
|
+
let totalUnread = 0;
|
|
59
|
+
channels.forEach((channel) => {
|
|
60
|
+
const count = channel.unread_count || 0;
|
|
61
|
+
totalUnread += count;
|
|
62
|
+
const channelName = formatChannelName(channel.name);
|
|
63
|
+
console.log(`${channelName}: ${count}`);
|
|
64
|
+
});
|
|
65
|
+
console.log(chalk.bold(`Total: ${totalUnread} unread messages`));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function displayAsJson(channels: Channel[]): void {
|
|
69
|
+
const output = channels.map((channel) => ({
|
|
70
|
+
channel: formatChannelName(channel.name),
|
|
71
|
+
channelId: channel.id,
|
|
72
|
+
unreadCount: channel.unread_count || 0,
|
|
73
|
+
}));
|
|
74
|
+
console.log(JSON.stringify(output, null, 2));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function displayAsSimple(channels: Channel[]): void {
|
|
78
|
+
channels.forEach((channel) => {
|
|
79
|
+
const channelName = formatChannelName(channel.name);
|
|
80
|
+
console.log(`${channelName} (${channel.unread_count || 0})`);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function displayAsTable(channels: Channel[]): void {
|
|
85
|
+
console.log(chalk.bold('Channel Unread Last Message'));
|
|
86
|
+
console.log('─'.repeat(50));
|
|
87
|
+
|
|
88
|
+
channels.forEach((channel) => {
|
|
89
|
+
const channelName = formatChannelName(channel.name);
|
|
90
|
+
const paddedName = channelName.padEnd(16);
|
|
91
|
+
const count = (channel.unread_count || 0).toString().padEnd(6);
|
|
92
|
+
const lastRead = channel.last_read ? formatSlackTimestamp(channel.last_read) : 'Unknown';
|
|
93
|
+
console.log(`${paddedName} ${count} ${lastRead}`);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function setupUnreadCommand(): Command {
|
|
98
|
+
const unreadCommand = new Command('unread')
|
|
99
|
+
.description('Show unread messages across channels')
|
|
100
|
+
.option('-c, --channel <channel>', 'Show unread for a specific channel')
|
|
101
|
+
.option('--format <format>', 'Output format: table, simple, json', 'table')
|
|
102
|
+
.option('--count-only', 'Show only unread counts', false)
|
|
103
|
+
.option('--limit <number>', 'Maximum number of channels to display', '50')
|
|
104
|
+
.option('--profile <profile>', 'Use specific workspace profile')
|
|
105
|
+
.action(
|
|
106
|
+
wrapCommand(async (options: UnreadOptions) => {
|
|
107
|
+
const client = await createSlackClient(options.profile);
|
|
108
|
+
|
|
109
|
+
if (options.channel) {
|
|
110
|
+
await handleSpecificChannelUnread(client, options);
|
|
111
|
+
} else {
|
|
112
|
+
await handleAllChannelsUnread(client, options);
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
return unreadCommand;
|
|
118
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
|
|
9
|
+
const program = new Command();
|
|
10
|
+
|
|
11
|
+
program.name('slack-cli').description('CLI tool to send messages via Slack API').version('1.0.0');
|
|
12
|
+
|
|
13
|
+
program.addCommand(setupConfigCommand());
|
|
14
|
+
program.addCommand(setupSendCommand());
|
|
15
|
+
program.addCommand(setupChannelsCommand());
|
|
16
|
+
program.addCommand(setupHistoryCommand());
|
|
17
|
+
program.addCommand(setupUnreadCommand());
|
|
18
|
+
|
|
19
|
+
program.parse();
|