@urugus/slack-cli 0.2.4 → 0.2.6
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 +8 -1
- package/.github/workflows/pr-validation.yml +0 -10
- package/README.md +93 -19
- package/dist/commands/send.d.ts.map +1 -1
- package/dist/commands/send.js +10 -1
- package/dist/commands/send.js.map +1 -1
- package/dist/commands/unread.d.ts.map +1 -1
- package/dist/commands/unread.js +12 -0
- package/dist/commands/unread.js.map +1 -1
- package/dist/types/commands.d.ts +2 -0
- package/dist/types/commands.d.ts.map +1 -1
- package/dist/utils/constants.d.ts +1 -0
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +1 -0
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/slack-api-client.d.ts +2 -1
- package/dist/utils/slack-api-client.d.ts.map +1 -1
- package/dist/utils/slack-api-client.js +5 -2
- package/dist/utils/slack-api-client.js.map +1 -1
- package/dist/utils/slack-operations/message-operations.d.ts +2 -1
- package/dist/utils/slack-operations/message-operations.d.ts.map +1 -1
- package/dist/utils/slack-operations/message-operations.js +13 -3
- package/dist/utils/slack-operations/message-operations.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/send.ts +11 -1
- package/src/commands/unread.ts +14 -0
- package/src/types/commands.ts +2 -0
- package/src/utils/constants.ts +1 -0
- package/src/utils/slack-api-client.ts +10 -2
- package/src/utils/slack-operations/message-operations.ts +21 -4
- package/tests/commands/send.test.ts +69 -2
- package/tests/commands/unread.test.ts +60 -0
- package/tests/index.test.ts +4 -4
|
@@ -57,7 +57,14 @@
|
|
|
57
57
|
"Bash(npx tsx:*)",
|
|
58
58
|
"Bash(gh workflow view:*)",
|
|
59
59
|
"Bash(git tag:*)",
|
|
60
|
-
"Bash(./bin/dev:*)"
|
|
60
|
+
"Bash(./bin/dev:*)",
|
|
61
|
+
"Bash(git checkout:*)",
|
|
62
|
+
"Bash(gh pr create:*)",
|
|
63
|
+
"Bash(gh pr checks:*)",
|
|
64
|
+
"Bash(gh pr view:*)",
|
|
65
|
+
"Bash(gh pr merge:*)",
|
|
66
|
+
"Bash(git pull:*)",
|
|
67
|
+
"Bash(gh api graphql:*)"
|
|
61
68
|
],
|
|
62
69
|
"deny": []
|
|
63
70
|
}
|
|
@@ -28,16 +28,6 @@ jobs:
|
|
|
28
28
|
|
|
29
29
|
- name: Run tests with coverage
|
|
30
30
|
run: npm run test:coverage
|
|
31
|
-
|
|
32
|
-
- name: Comment PR with coverage
|
|
33
|
-
uses: ArtiomTr/jest-coverage-report-action@v2
|
|
34
|
-
if: github.event_name == 'pull_request'
|
|
35
|
-
with:
|
|
36
|
-
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
37
|
-
test-script: npm run test:coverage
|
|
38
|
-
skip-step: all
|
|
39
|
-
coverage-file: ./coverage/coverage-final.json
|
|
40
|
-
base-coverage-file: ./coverage/coverage-final.json
|
|
41
31
|
|
|
42
32
|
- name: Check build
|
|
43
33
|
run: npm run build
|
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ npm install -g @urugus/slack-cli
|
|
|
13
13
|
You need to configure your Slack API token on first use:
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
slack-cli config --token YOUR_SLACK_API_TOKEN
|
|
16
|
+
slack-cli config set --token YOUR_SLACK_API_TOKEN
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
## Usage
|
|
@@ -58,6 +58,12 @@ slack-cli send -c general -m "Line 1\nLine 2\nLine 3"
|
|
|
58
58
|
|
|
59
59
|
# Send message from file
|
|
60
60
|
slack-cli send -c random -f message.txt
|
|
61
|
+
|
|
62
|
+
# Reply to a thread
|
|
63
|
+
slack-cli send -c channel-name -m "Reply message" --thread 1719207629.000100
|
|
64
|
+
|
|
65
|
+
# Reply to a thread (short option)
|
|
66
|
+
slack-cli send -c channel-name -m "Reply message" -t 1719207629.000100
|
|
61
67
|
```
|
|
62
68
|
|
|
63
69
|
### List Channels
|
|
@@ -70,16 +76,29 @@ slack-cli channels
|
|
|
70
76
|
slack-cli channels --profile work
|
|
71
77
|
|
|
72
78
|
# List public channels only
|
|
73
|
-
slack-cli channels --public
|
|
79
|
+
slack-cli channels --type public
|
|
74
80
|
|
|
75
81
|
# List private channels only
|
|
76
|
-
slack-cli channels --private
|
|
82
|
+
slack-cli channels --type private
|
|
83
|
+
|
|
84
|
+
# List all channel types including IMs and MPIMs
|
|
85
|
+
slack-cli channels --type all
|
|
86
|
+
|
|
87
|
+
# Include archived channels
|
|
88
|
+
slack-cli channels --include-archived
|
|
89
|
+
|
|
90
|
+
# Limit number of channels displayed
|
|
91
|
+
slack-cli channels --limit 20
|
|
92
|
+
|
|
93
|
+
# Output in different formats
|
|
94
|
+
slack-cli channels --format json
|
|
95
|
+
slack-cli channels --format simple
|
|
77
96
|
```
|
|
78
97
|
|
|
79
98
|
### View Message History
|
|
80
99
|
|
|
81
100
|
```bash
|
|
82
|
-
# Get latest 10 messages
|
|
101
|
+
# Get latest 10 messages (default)
|
|
83
102
|
slack-cli history -c general
|
|
84
103
|
|
|
85
104
|
# Specify number of messages
|
|
@@ -87,6 +106,9 @@ slack-cli history -c general -n 20
|
|
|
87
106
|
|
|
88
107
|
# Get messages since specific date
|
|
89
108
|
slack-cli history -c general --since "2024-01-01 00:00:00"
|
|
109
|
+
|
|
110
|
+
# Use specific profile
|
|
111
|
+
slack-cli history -c general --profile work
|
|
90
112
|
```
|
|
91
113
|
|
|
92
114
|
### Get Unread Messages
|
|
@@ -98,14 +120,21 @@ slack-cli unread
|
|
|
98
120
|
# Get unread messages from specific channel
|
|
99
121
|
slack-cli unread -c general
|
|
100
122
|
|
|
101
|
-
#
|
|
102
|
-
slack-cli unread --
|
|
123
|
+
# Show only unread counts (no message content)
|
|
124
|
+
slack-cli unread --count-only
|
|
103
125
|
|
|
104
126
|
# Mark messages as read after fetching
|
|
105
127
|
slack-cli unread --mark-read
|
|
106
128
|
|
|
107
|
-
#
|
|
108
|
-
slack-cli unread -c general
|
|
129
|
+
# Mark messages as read for specific channel
|
|
130
|
+
slack-cli unread -c general --mark-read
|
|
131
|
+
|
|
132
|
+
# Limit number of channels displayed
|
|
133
|
+
slack-cli unread --limit 10
|
|
134
|
+
|
|
135
|
+
# Output in different formats
|
|
136
|
+
slack-cli unread --format json
|
|
137
|
+
slack-cli unread --format simple
|
|
109
138
|
```
|
|
110
139
|
|
|
111
140
|
### Other Commands
|
|
@@ -126,23 +155,43 @@ slack-cli config set --token NEW_TOKEN
|
|
|
126
155
|
|
|
127
156
|
## Options
|
|
128
157
|
|
|
158
|
+
### Global Options
|
|
159
|
+
| Option | Short | Description |
|
|
160
|
+
|--------|-------|-------------|
|
|
161
|
+
| --profile | -p | Use specific workspace profile |
|
|
162
|
+
|
|
163
|
+
### send command
|
|
129
164
|
| Option | Short | Description |
|
|
130
165
|
|--------|-------|-------------|
|
|
131
|
-
| --channel | -c | Target channel name or ID |
|
|
166
|
+
| --channel | -c | Target channel name or ID (required) |
|
|
132
167
|
| --message | -m | Message to send |
|
|
133
168
|
| --file | -f | File containing message content |
|
|
134
|
-
| --
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
|
138
|
-
|
|
139
|
-
| --
|
|
169
|
+
| --thread | -t | Thread timestamp to reply to |
|
|
170
|
+
|
|
171
|
+
### channels command
|
|
172
|
+
| Option | Short | Description |
|
|
173
|
+
|--------|-------|-------------|
|
|
174
|
+
| --type | | Channel type: public, private, im, mpim, all (default: public) |
|
|
175
|
+
| --include-archived | | Include archived channels |
|
|
176
|
+
| --format | | Output format: table, simple, json (default: table) |
|
|
177
|
+
| --limit | | Maximum number of channels to list (default: 100) |
|
|
178
|
+
|
|
179
|
+
### history command
|
|
180
|
+
| Option | Short | Description |
|
|
181
|
+
|--------|-------|-------------|
|
|
182
|
+
| --channel | -c | Target channel name or ID (required) |
|
|
183
|
+
| --number | -n | Number of messages to retrieve (default: 10) |
|
|
184
|
+
| --since | | Get messages since specific date (YYYY-MM-DD HH:MM:SS) |
|
|
140
185
|
|
|
141
|
-
|
|
186
|
+
### unread command
|
|
187
|
+
| Option | Short | Description |
|
|
188
|
+
|--------|-------|-------------|
|
|
189
|
+
| --channel | -c | Get unread for specific channel |
|
|
190
|
+
| --format | | Output format: table, simple, json (default: table) |
|
|
191
|
+
| --count-only | | Show only unread counts |
|
|
192
|
+
| --limit | | Maximum number of channels to display (default: 50) |
|
|
193
|
+
| --mark-read | | Mark messages as read after fetching |
|
|
142
194
|
|
|
143
|
-
- `SLACK_API_TOKEN`: Default API token (used when no profile is configured)
|
|
144
|
-
- `SLACK_DEFAULT_CHANNEL`: Default target channel
|
|
145
|
-
- `SLACK_DEFAULT_PROFILE`: Default profile to use
|
|
146
195
|
|
|
147
196
|
## Required Permissions
|
|
148
197
|
|
|
@@ -156,6 +205,31 @@ Your Slack API token needs the following scopes:
|
|
|
156
205
|
- `im:history` - Read direct message history
|
|
157
206
|
- `users:read` - Access user information for unread counts
|
|
158
207
|
|
|
208
|
+
## Advanced Features
|
|
209
|
+
|
|
210
|
+
### Rate Limiting
|
|
211
|
+
The CLI includes built-in rate limiting to handle Slack API limits:
|
|
212
|
+
- Concurrent requests: 3
|
|
213
|
+
- Automatic retry with exponential backoff (max 3 retries)
|
|
214
|
+
- Graceful error handling for rate limit errors
|
|
215
|
+
|
|
216
|
+
### Output Formats
|
|
217
|
+
Most commands support multiple output formats:
|
|
218
|
+
- `table` (default) - Human-readable table format
|
|
219
|
+
- `simple` - Simplified text output
|
|
220
|
+
- `json` - Machine-readable JSON format
|
|
221
|
+
|
|
222
|
+
### Markdown Support
|
|
223
|
+
Messages sent via the `send` command automatically support Slack's mrkdwn formatting:
|
|
224
|
+
- `*bold*` for bold text
|
|
225
|
+
- `_italic_` for italic text
|
|
226
|
+
- `~strikethrough~` for strikethrough
|
|
227
|
+
- `` `code` `` for inline code
|
|
228
|
+
- ` ```code blocks``` ` for multiline code
|
|
229
|
+
- Links are automatically hyperlinked
|
|
230
|
+
- User mentions: `<@USER_ID>`
|
|
231
|
+
- Channel mentions: `<#CHANNEL_ID>`
|
|
232
|
+
|
|
159
233
|
## License
|
|
160
234
|
|
|
161
235
|
MIT
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"send.d.ts","sourceRoot":"","sources":["../../src/commands/send.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"send.d.ts","sourceRoot":"","sources":["../../src/commands/send.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBpC,wBAAgB,gBAAgB,IAAI,OAAO,CA6C1C"}
|
package/dist/commands/send.js
CHANGED
|
@@ -45,12 +45,18 @@ const client_factory_1 = require("../utils/client-factory");
|
|
|
45
45
|
const errors_1 = require("../utils/errors");
|
|
46
46
|
const error_utils_1 = require("../utils/error-utils");
|
|
47
47
|
const fs = __importStar(require("fs/promises"));
|
|
48
|
+
function isValidThreadTimestamp(timestamp) {
|
|
49
|
+
// Slack timestamp format: 1234567890.123456
|
|
50
|
+
const timestampRegex = /^\d{10}\.\d{6}$/;
|
|
51
|
+
return timestampRegex.test(timestamp);
|
|
52
|
+
}
|
|
48
53
|
function setupSendCommand() {
|
|
49
54
|
const sendCommand = new commander_1.Command('send')
|
|
50
55
|
.description('Send a message to a Slack channel')
|
|
51
56
|
.requiredOption('-c, --channel <channel>', 'Target channel name or ID')
|
|
52
57
|
.option('-m, --message <message>', 'Message to send')
|
|
53
58
|
.option('-f, --file <file>', 'File containing message content')
|
|
59
|
+
.option('-t, --thread <thread>', 'Thread timestamp to reply to')
|
|
54
60
|
.option('--profile <profile>', 'Use specific workspace profile')
|
|
55
61
|
.hook('preAction', (thisCommand) => {
|
|
56
62
|
const options = thisCommand.opts();
|
|
@@ -60,6 +66,9 @@ function setupSendCommand() {
|
|
|
60
66
|
if (options.message && options.file) {
|
|
61
67
|
thisCommand.error(`Error: ${constants_1.ERROR_MESSAGES.BOTH_MESSAGE_AND_FILE}`);
|
|
62
68
|
}
|
|
69
|
+
if (options.thread && !isValidThreadTimestamp(options.thread)) {
|
|
70
|
+
thisCommand.error(`Error: ${constants_1.ERROR_MESSAGES.INVALID_THREAD_TIMESTAMP}`);
|
|
71
|
+
}
|
|
63
72
|
})
|
|
64
73
|
.action((0, command_wrapper_1.wrapCommand)(async (options) => {
|
|
65
74
|
// Get message content
|
|
@@ -77,7 +86,7 @@ function setupSendCommand() {
|
|
|
77
86
|
}
|
|
78
87
|
// Send message
|
|
79
88
|
const client = await (0, client_factory_1.createSlackClient)(options.profile);
|
|
80
|
-
await client.sendMessage(options.channel, messageContent);
|
|
89
|
+
await client.sendMessage(options.channel, messageContent, options.thread);
|
|
81
90
|
console.log(chalk_1.default.green(`✓ ${constants_1.SUCCESS_MESSAGES.MESSAGE_SENT(options.channel)}`));
|
|
82
91
|
}));
|
|
83
92
|
return sendCommand;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"send.js","sourceRoot":"","sources":["../../src/commands/send.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"send.js","sourceRoot":"","sources":["../../src/commands/send.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgBA,4CA6CC;AA7DD,yCAAoC;AACpC,kDAA0B;AAC1B,8DAAuD;AACvD,kDAAsE;AACtE,4DAA4D;AAC5D,4CAA4C;AAE5C,sDAA2D;AAC3D,gDAAkC;AAElC,SAAS,sBAAsB,CAAC,SAAiB;IAC/C,4CAA4C;IAC5C,MAAM,cAAc,GAAG,iBAAiB,CAAC;IACzC,OAAO,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AACxC,CAAC;AAED,SAAgB,gBAAgB;IAC9B,MAAM,WAAW,GAAG,IAAI,mBAAO,CAAC,MAAM,CAAC;SACpC,WAAW,CAAC,mCAAmC,CAAC;SAChD,cAAc,CAAC,yBAAyB,EAAE,2BAA2B,CAAC;SACtE,MAAM,CAAC,yBAAyB,EAAE,iBAAiB,CAAC;SACpD,MAAM,CAAC,mBAAmB,EAAE,iCAAiC,CAAC;SAC9D,MAAM,CAAC,uBAAuB,EAAE,8BAA8B,CAAC;SAC/D,MAAM,CAAC,qBAAqB,EAAE,gCAAgC,CAAC;SAC/D,IAAI,CAAC,WAAW,EAAE,CAAC,WAAW,EAAE,EAAE;QACjC,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YACtC,WAAW,CAAC,KAAK,CAAC,UAAU,0BAAc,CAAC,kBAAkB,EAAE,CAAC,CAAC;QACnE,CAAC;QACD,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACpC,WAAW,CAAC,KAAK,CAAC,UAAU,0BAAc,CAAC,qBAAqB,EAAE,CAAC,CAAC;QACtE,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9D,WAAW,CAAC,KAAK,CAAC,UAAU,0BAAc,CAAC,wBAAwB,EAAE,CAAC,CAAC;QACzE,CAAC;IACH,CAAC,CAAC;SACD,MAAM,CACL,IAAA,6BAAW,EAAC,KAAK,EAAE,OAAoB,EAAE,EAAE;QACzC,sBAAsB;QACtB,IAAI,cAAsB,CAAC;QAC3B,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,IAAI,CAAC;gBACH,cAAc,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC5D,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,kBAAS,CACjB,0BAAc,CAAC,eAAe,CAAC,OAAO,CAAC,IAAI,EAAE,IAAA,iCAAmB,EAAC,KAAK,CAAC,CAAC,CACzE,CAAC;YACJ,CAAC;QACH,CAAC;aAAM,CAAC;YACN,cAAc,GAAG,OAAO,CAAC,OAAQ,CAAC,CAAC,+CAA+C;QACpF,CAAC;QAED,eAAe;QACf,MAAM,MAAM,GAAG,MAAM,IAAA,kCAAiB,EAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACxD,MAAM,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAE1E,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,KAAK,4BAAgB,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;IAClF,CAAC,CAAC,CACH,CAAC;IAEJ,OAAO,WAAW,CAAC;AACrB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unread.d.ts","sourceRoot":"","sources":["../../src/commands/unread.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"unread.d.ts","sourceRoot":"","sources":["../../src/commands/unread.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiEpC,wBAAgB,kBAAkB,IAAI,OAAO,CA0B5C"}
|
package/dist/commands/unread.js
CHANGED
|
@@ -24,6 +24,10 @@ async function handleSpecificChannelUnread(client, options) {
|
|
|
24
24
|
countOnly: countOnly,
|
|
25
25
|
format: format,
|
|
26
26
|
});
|
|
27
|
+
if ((0, option_parsers_1.parseBoolean)(options.markRead)) {
|
|
28
|
+
await client.markAsRead(result.channel.id);
|
|
29
|
+
console.log(chalk_1.default.green(`✓ Marked messages in #${result.channel.name} as read`));
|
|
30
|
+
}
|
|
27
31
|
}
|
|
28
32
|
async function handleAllChannelsUnread(client, options) {
|
|
29
33
|
const channels = await client.listUnreadChannels();
|
|
@@ -38,6 +42,13 @@ async function handleAllChannelsUnread(client, options) {
|
|
|
38
42
|
const countOnly = (0, option_parsers_1.parseBoolean)(options.countOnly);
|
|
39
43
|
const formatter = (0, channel_formatters_1.createChannelFormatter)(format, countOnly);
|
|
40
44
|
formatter.format({ channels: displayChannels, countOnly: countOnly });
|
|
45
|
+
if ((0, option_parsers_1.parseBoolean)(options.markRead)) {
|
|
46
|
+
// Mark all unread channels as read
|
|
47
|
+
for (const channel of channels) {
|
|
48
|
+
await client.markAsRead(channel.id);
|
|
49
|
+
}
|
|
50
|
+
console.log(chalk_1.default.green('✓ Marked all messages as read'));
|
|
51
|
+
}
|
|
41
52
|
}
|
|
42
53
|
function setupUnreadCommand() {
|
|
43
54
|
const unreadCommand = new commander_1.Command('unread')
|
|
@@ -46,6 +57,7 @@ function setupUnreadCommand() {
|
|
|
46
57
|
.option('--format <format>', 'Output format: table, simple, json', 'table')
|
|
47
58
|
.option('--count-only', 'Show only unread counts', false)
|
|
48
59
|
.option('--limit <number>', 'Maximum number of channels to display', constants_1.DEFAULTS.UNREAD_DISPLAY_LIMIT.toString())
|
|
60
|
+
.option('--mark-read', 'Mark messages as read after fetching', false)
|
|
49
61
|
.option('--profile <profile>', 'Use specific workspace profile')
|
|
50
62
|
.action((0, command_wrapper_1.wrapCommand)(async (options) => {
|
|
51
63
|
const client = await (0, client_factory_1.createSlackClient)(options.profile);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unread.js","sourceRoot":"","sources":["../../src/commands/unread.ts"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"unread.js","sourceRoot":"","sources":["../../src/commands/unread.ts"],"names":[],"mappings":"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"}
|
package/dist/types/commands.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export interface SendOptions {
|
|
|
15
15
|
channel: string;
|
|
16
16
|
message?: string;
|
|
17
17
|
file?: string;
|
|
18
|
+
thread?: string;
|
|
18
19
|
profile?: string;
|
|
19
20
|
}
|
|
20
21
|
export interface ChannelsOptions {
|
|
@@ -35,6 +36,7 @@ export interface UnreadOptions {
|
|
|
35
36
|
format?: 'table' | 'simple' | 'json';
|
|
36
37
|
countOnly?: boolean;
|
|
37
38
|
limit?: string;
|
|
39
|
+
markRead?: boolean;
|
|
38
40
|
profile?: string;
|
|
39
41
|
}
|
|
40
42
|
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/types/commands.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,KAAK,CAAC;IACnD,eAAe,EAAE,OAAO,CAAC;IACzB,MAAM,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/types/commands.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,KAAK,CAAC;IACnD,eAAe,EAAE,OAAO,CAAC;IACzB,MAAM,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
|
|
@@ -8,6 +8,7 @@ export declare const ERROR_MESSAGES: {
|
|
|
8
8
|
readonly INVALID_CONFIG_FORMAT: "Invalid config file format";
|
|
9
9
|
readonly NO_MESSAGE_OR_FILE: "You must specify either --message or --file";
|
|
10
10
|
readonly BOTH_MESSAGE_AND_FILE: "Cannot use both --message and --file";
|
|
11
|
+
readonly INVALID_THREAD_TIMESTAMP: "Invalid thread timestamp format";
|
|
11
12
|
readonly API_ERROR: (error: string) => string;
|
|
12
13
|
readonly CHANNEL_NOT_FOUND: (channel: string) => string;
|
|
13
14
|
readonly FILE_READ_ERROR: (file: string, error: string) => string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/utils/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,IAAI,CAAC;AACnC,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAClC,eAAO,MAAM,oBAAoB,YAAY,CAAC;AAE9C,eAAO,MAAM,cAAc;sCAEA,MAAM;8CAEE,MAAM
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/utils/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,IAAI,CAAC;AACnC,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAClC,eAAO,MAAM,oBAAoB,YAAY,CAAC;AAE9C,eAAO,MAAM,cAAc;sCAEA,MAAM;8CAEE,MAAM;;;;;;gCAUpB,MAAM;0CACI,MAAM;qCAGX,MAAM,SAAS,MAAM;oCACtB,MAAM;;6CAIG,MAAM;CAC9B,CAAC;AAEX,eAAO,MAAM,gBAAgB;wCACA,MAAM;6CACD,MAAM;4CACP,MAAM;qCACb,MAAM;CACtB,CAAC;AAGX,eAAO,MAAM,gBAAgB;;CAE5B,CAAC;AAGF,eAAO,MAAM,UAAU;;;;CAItB,CAAC;AAGF,eAAO,MAAM,UAAU;;;;;;;;;;CAUtB,CAAC;AAGF,eAAO,MAAM,QAAQ;;;;CAIpB,CAAC;AAGF,eAAO,MAAM,WAAW,wBAAwB,CAAC"}
|
package/dist/utils/constants.js
CHANGED
|
@@ -13,6 +13,7 @@ exports.ERROR_MESSAGES = {
|
|
|
13
13
|
// Validation errors
|
|
14
14
|
NO_MESSAGE_OR_FILE: 'You must specify either --message or --file',
|
|
15
15
|
BOTH_MESSAGE_AND_FILE: 'Cannot use both --message and --file',
|
|
16
|
+
INVALID_THREAD_TIMESTAMP: 'Invalid thread timestamp format',
|
|
16
17
|
// API errors
|
|
17
18
|
API_ERROR: (error) => `API Error: ${error}`,
|
|
18
19
|
CHANNEL_NOT_FOUND: (channel) => `Channel not found: ${channel}`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/utils/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,iBAAiB,GAAG,CAAC,CAAC;AACtB,QAAA,gBAAgB,GAAG,CAAC,CAAC;AACrB,QAAA,oBAAoB,GAAG,SAAS,CAAC;AAEjC,QAAA,cAAc,GAAG;IAC5B,uBAAuB;IACvB,SAAS,EAAE,CAAC,WAAmB,EAAE,EAAE,CACjC,uCAAuC,WAAW,0DAA0D,WAAW,cAAc;IACvI,iBAAiB,EAAE,CAAC,WAAmB,EAAE,EAAE,CAAC,YAAY,WAAW,aAAa;IAChF,iBAAiB,EAAE,8EAA8E;IACjG,qBAAqB,EAAE,4BAA4B;IAEnD,oBAAoB;IACpB,kBAAkB,EAAE,6CAA6C;IACjE,qBAAqB,EAAE,sCAAsC;
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/utils/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,iBAAiB,GAAG,CAAC,CAAC;AACtB,QAAA,gBAAgB,GAAG,CAAC,CAAC;AACrB,QAAA,oBAAoB,GAAG,SAAS,CAAC;AAEjC,QAAA,cAAc,GAAG;IAC5B,uBAAuB;IACvB,SAAS,EAAE,CAAC,WAAmB,EAAE,EAAE,CACjC,uCAAuC,WAAW,0DAA0D,WAAW,cAAc;IACvI,iBAAiB,EAAE,CAAC,WAAmB,EAAE,EAAE,CAAC,YAAY,WAAW,aAAa;IAChF,iBAAiB,EAAE,8EAA8E;IACjG,qBAAqB,EAAE,4BAA4B;IAEnD,oBAAoB;IACpB,kBAAkB,EAAE,6CAA6C;IACjE,qBAAqB,EAAE,sCAAsC;IAC7D,wBAAwB,EAAE,iCAAiC;IAE3D,aAAa;IACb,SAAS,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,cAAc,KAAK,EAAE;IACnD,iBAAiB,EAAE,CAAC,OAAe,EAAE,EAAE,CAAC,sBAAsB,OAAO,EAAE;IAEvE,cAAc;IACd,eAAe,EAAE,CAAC,IAAY,EAAE,KAAa,EAAE,EAAE,CAAC,sBAAsB,IAAI,KAAK,KAAK,EAAE;IACxF,cAAc,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,mBAAmB,IAAI,EAAE;IAE3D,0BAA0B;IAC1B,iBAAiB,EAAE,mBAAmB;IACtC,sBAAsB,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,2BAA2B,KAAK,EAAE;CACrE,CAAC;AAEE,QAAA,gBAAgB,GAAG;IAC9B,WAAW,EAAE,CAAC,WAAmB,EAAE,EAAE,CAAC,yCAAyC,WAAW,GAAG;IAC7F,gBAAgB,EAAE,CAAC,WAAmB,EAAE,EAAE,CAAC,wBAAwB,WAAW,GAAG;IACjF,eAAe,EAAE,CAAC,WAAmB,EAAE,EAAE,CAAC,YAAY,WAAW,wBAAwB;IACzF,YAAY,EAAE,CAAC,OAAe,EAAE,EAAE,CAAC,iCAAiC,OAAO,EAAE;CACrE,CAAC;AAEX,4BAA4B;AACf,QAAA,gBAAgB,GAAG;IAC9B,WAAW,EAAE,KAAK,EAAE,4BAA4B;CACjD,CAAC;AAEF,aAAa;AACA,QAAA,UAAU,GAAG;IACxB,iBAAiB,EAAE,IAAI;IACvB,iBAAiB,EAAE,CAAC;IACpB,qBAAqB,EAAE,EAAE;CAC1B,CAAC;AAEF,kCAAkC;AACrB,QAAA,UAAU,GAAG;IACxB,mBAAmB,EAAE,CAAC;IACtB,UAAU,EAAE,EAAE;IACd,cAAc,EAAE,IAAI;IACpB,YAAY,EAAE;QACZ,OAAO,EAAE,CAAC;QACV,MAAM,EAAE,CAAC;QACT,UAAU,EAAE,IAAI;QAChB,UAAU,EAAE,KAAK;KAClB;CACF,CAAC;AAEF,iBAAiB;AACJ,QAAA,QAAQ,GAAG;IACtB,aAAa,EAAE,EAAE;IACjB,cAAc,EAAE,IAAI;IACpB,oBAAoB,EAAE,EAAE;CACzB,CAAC;AAEF,eAAe;AACF,QAAA,WAAW,GAAG,qBAAqB,CAAC"}
|
|
@@ -63,11 +63,12 @@ export declare class SlackApiClient {
|
|
|
63
63
|
private channelOps;
|
|
64
64
|
private messageOps;
|
|
65
65
|
constructor(token: string);
|
|
66
|
-
sendMessage(channel: string, text: string): Promise<ChatPostMessageResponse>;
|
|
66
|
+
sendMessage(channel: string, text: string, thread_ts?: string): Promise<ChatPostMessageResponse>;
|
|
67
67
|
listChannels(options: ListChannelsOptions): Promise<Channel[]>;
|
|
68
68
|
getHistory(channel: string, options: HistoryOptions): Promise<HistoryResult>;
|
|
69
69
|
listUnreadChannels(): Promise<Channel[]>;
|
|
70
70
|
getChannelUnread(channelNameOrId: string): Promise<ChannelUnreadResult>;
|
|
71
|
+
markAsRead(channelId: string): Promise<void>;
|
|
71
72
|
}
|
|
72
73
|
export declare const slackApiClient: {
|
|
73
74
|
listChannels: (token: string, options: ListChannelsOptions) => Promise<Channel[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack-api-client.d.ts","sourceRoot":"","sources":["../../src/utils/slack-api-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAIzD,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE;QACN,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,OAAO,CAAC,EAAE;QACR,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,OAAO,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5B;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,UAAU,CAAoB;gBAE1B,KAAK,EAAE,MAAM;IAKnB,WAAW,
|
|
1
|
+
{"version":3,"file":"slack-api-client.d.ts","sourceRoot":"","sources":["../../src/utils/slack-api-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAIzD,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE;QACN,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,OAAO,CAAC,EAAE;QACR,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,OAAO,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5B;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,UAAU,CAAoB;gBAE1B,KAAK,EAAE,MAAM;IAKnB,WAAW,CACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,uBAAuB,CAAC;IAI7B,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAI9D,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAI5E,kBAAkB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAIxC,gBAAgB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAIvE,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGnD;AAED,eAAO,MAAM,cAAc;0BACG,MAAM,WAAW,mBAAmB,KAAG,OAAO,CAAC,OAAO,EAAE,CAAC;CAItF,CAAC"}
|
|
@@ -8,8 +8,8 @@ class SlackApiClient {
|
|
|
8
8
|
this.channelOps = new channel_operations_1.ChannelOperations(token);
|
|
9
9
|
this.messageOps = new message_operations_1.MessageOperations(token);
|
|
10
10
|
}
|
|
11
|
-
async sendMessage(channel, text) {
|
|
12
|
-
return this.messageOps.sendMessage(channel, text);
|
|
11
|
+
async sendMessage(channel, text, thread_ts) {
|
|
12
|
+
return this.messageOps.sendMessage(channel, text, thread_ts);
|
|
13
13
|
}
|
|
14
14
|
async listChannels(options) {
|
|
15
15
|
return this.channelOps.listChannels(options);
|
|
@@ -23,6 +23,9 @@ class SlackApiClient {
|
|
|
23
23
|
async getChannelUnread(channelNameOrId) {
|
|
24
24
|
return this.messageOps.getChannelUnread(channelNameOrId);
|
|
25
25
|
}
|
|
26
|
+
async markAsRead(channelId) {
|
|
27
|
+
return this.messageOps.markAsRead(channelId);
|
|
28
|
+
}
|
|
26
29
|
}
|
|
27
30
|
exports.SlackApiClient = SlackApiClient;
|
|
28
31
|
exports.slackApiClient = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack-api-client.js","sourceRoot":"","sources":["../../src/utils/slack-api-client.ts"],"names":[],"mappings":";;;AACA,8EAA0E;AAC1E,8EAA0E;AAoE1E,MAAa,cAAc;IAIzB,YAAY,KAAa;QACvB,IAAI,CAAC,UAAU,GAAG,IAAI,sCAAiB,CAAC,KAAK,CAAC,CAAC;QAC/C,IAAI,CAAC,UAAU,GAAG,IAAI,sCAAiB,CAAC,KAAK,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,WAAW,
|
|
1
|
+
{"version":3,"file":"slack-api-client.js","sourceRoot":"","sources":["../../src/utils/slack-api-client.ts"],"names":[],"mappings":";;;AACA,8EAA0E;AAC1E,8EAA0E;AAoE1E,MAAa,cAAc;IAIzB,YAAY,KAAa;QACvB,IAAI,CAAC,UAAU,GAAG,IAAI,sCAAiB,CAAC,KAAK,CAAC,CAAC;QAC/C,IAAI,CAAC,UAAU,GAAG,IAAI,sCAAiB,CAAC,KAAK,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,WAAW,CACf,OAAe,EACf,IAAY,EACZ,SAAkB;QAElB,OAAO,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;IAC/D,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAA4B;QAC7C,OAAO,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,OAAe,EAAE,OAAuB;QACvD,OAAO,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,kBAAkB;QACtB,OAAO,IAAI,CAAC,UAAU,CAAC,kBAAkB,EAAE,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,eAAuB;QAC5C,OAAO,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAC;IAC3D,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,SAAiB;QAChC,OAAO,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IAC/C,CAAC;CACF;AApCD,wCAoCC;AAEY,QAAA,cAAc,GAAG;IAC5B,YAAY,EAAE,KAAK,EAAE,KAAa,EAAE,OAA4B,EAAsB,EAAE;QACtF,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,KAAK,CAAC,CAAC;QACzC,OAAO,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;CACF,CAAC"}
|
|
@@ -4,9 +4,10 @@ import { HistoryOptions, HistoryResult, ChannelUnreadResult } from '../slack-api
|
|
|
4
4
|
export declare class MessageOperations extends BaseSlackClient {
|
|
5
5
|
private channelOps;
|
|
6
6
|
constructor(token: string);
|
|
7
|
-
sendMessage(channel: string, text: string): Promise<ChatPostMessageResponse>;
|
|
7
|
+
sendMessage(channel: string, text: string, thread_ts?: string): Promise<ChatPostMessageResponse>;
|
|
8
8
|
getHistory(channel: string, options: HistoryOptions): Promise<HistoryResult>;
|
|
9
9
|
getChannelUnread(channelNameOrId: string): Promise<ChannelUnreadResult>;
|
|
10
10
|
private fetchUserInfo;
|
|
11
|
+
markAsRead(channelId: string): Promise<void>;
|
|
11
12
|
}
|
|
12
13
|
//# sourceMappingURL=message-operations.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-operations.d.ts","sourceRoot":"","sources":["../../../src/utils/slack-operations/message-operations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,
|
|
1
|
+
{"version":3,"file":"message-operations.d.ts","sourceRoot":"","sources":["../../../src/utils/slack-operations/message-operations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAA4B,MAAM,gBAAgB,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,EAAW,cAAc,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAIlG,qBAAa,iBAAkB,SAAQ,eAAe;IACpD,OAAO,CAAC,UAAU,CAAoB;gBAE1B,KAAK,EAAE,MAAM;IAKnB,WAAW,CACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,uBAAuB,CAAC;IAa7B,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAyB5E,gBAAgB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;YAsC/D,aAAa;IAoBrB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAMnD"}
|
|
@@ -11,11 +11,15 @@ class MessageOperations extends base_client_1.BaseSlackClient {
|
|
|
11
11
|
super(token);
|
|
12
12
|
this.channelOps = new channel_operations_1.ChannelOperations(token);
|
|
13
13
|
}
|
|
14
|
-
async sendMessage(channel, text) {
|
|
15
|
-
|
|
14
|
+
async sendMessage(channel, text, thread_ts) {
|
|
15
|
+
const params = {
|
|
16
16
|
channel,
|
|
17
17
|
text,
|
|
18
|
-
}
|
|
18
|
+
};
|
|
19
|
+
if (thread_ts) {
|
|
20
|
+
params.thread_ts = thread_ts;
|
|
21
|
+
}
|
|
22
|
+
return await this.client.chat.postMessage(params);
|
|
19
23
|
}
|
|
20
24
|
async getHistory(channel, options) {
|
|
21
25
|
// Resolve channel name to ID if needed
|
|
@@ -88,6 +92,12 @@ class MessageOperations extends base_client_1.BaseSlackClient {
|
|
|
88
92
|
}
|
|
89
93
|
return users;
|
|
90
94
|
}
|
|
95
|
+
async markAsRead(channelId) {
|
|
96
|
+
await this.client.conversations.mark({
|
|
97
|
+
channel: channelId,
|
|
98
|
+
ts: Date.now() / 1000 + '',
|
|
99
|
+
});
|
|
100
|
+
}
|
|
91
101
|
}
|
|
92
102
|
exports.MessageOperations = MessageOperations;
|
|
93
103
|
//# sourceMappingURL=message-operations.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-operations.js","sourceRoot":"","sources":["../../../src/utils/slack-operations/message-operations.ts"],"names":[],"mappings":";;;AACA,+CAAgD;AAChD,0DAAsD;AACtD,4CAAwC;AAExC,6DAAyD;AACzD,oDAAqD;AAErD,MAAa,iBAAkB,SAAQ,6BAAe;IAGpD,YAAY,KAAa;QACvB,KAAK,CAAC,KAAK,CAAC,CAAC;QACb,IAAI,CAAC,UAAU,GAAG,IAAI,sCAAiB,CAAC,KAAK,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,WAAW,
|
|
1
|
+
{"version":3,"file":"message-operations.js","sourceRoot":"","sources":["../../../src/utils/slack-operations/message-operations.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/commands/send.ts
CHANGED
|
@@ -8,12 +8,19 @@ import { SendOptions } from '../types/commands';
|
|
|
8
8
|
import { extractErrorMessage } from '../utils/error-utils';
|
|
9
9
|
import * as fs from 'fs/promises';
|
|
10
10
|
|
|
11
|
+
function isValidThreadTimestamp(timestamp: string): boolean {
|
|
12
|
+
// Slack timestamp format: 1234567890.123456
|
|
13
|
+
const timestampRegex = /^\d{10}\.\d{6}$/;
|
|
14
|
+
return timestampRegex.test(timestamp);
|
|
15
|
+
}
|
|
16
|
+
|
|
11
17
|
export function setupSendCommand(): Command {
|
|
12
18
|
const sendCommand = new Command('send')
|
|
13
19
|
.description('Send a message to a Slack channel')
|
|
14
20
|
.requiredOption('-c, --channel <channel>', 'Target channel name or ID')
|
|
15
21
|
.option('-m, --message <message>', 'Message to send')
|
|
16
22
|
.option('-f, --file <file>', 'File containing message content')
|
|
23
|
+
.option('-t, --thread <thread>', 'Thread timestamp to reply to')
|
|
17
24
|
.option('--profile <profile>', 'Use specific workspace profile')
|
|
18
25
|
.hook('preAction', (thisCommand) => {
|
|
19
26
|
const options = thisCommand.opts();
|
|
@@ -23,6 +30,9 @@ export function setupSendCommand(): Command {
|
|
|
23
30
|
if (options.message && options.file) {
|
|
24
31
|
thisCommand.error(`Error: ${ERROR_MESSAGES.BOTH_MESSAGE_AND_FILE}`);
|
|
25
32
|
}
|
|
33
|
+
if (options.thread && !isValidThreadTimestamp(options.thread)) {
|
|
34
|
+
thisCommand.error(`Error: ${ERROR_MESSAGES.INVALID_THREAD_TIMESTAMP}`);
|
|
35
|
+
}
|
|
26
36
|
})
|
|
27
37
|
.action(
|
|
28
38
|
wrapCommand(async (options: SendOptions) => {
|
|
@@ -42,7 +52,7 @@ export function setupSendCommand(): Command {
|
|
|
42
52
|
|
|
43
53
|
// Send message
|
|
44
54
|
const client = await createSlackClient(options.profile);
|
|
45
|
-
await client.sendMessage(options.channel, messageContent);
|
|
55
|
+
await client.sendMessage(options.channel, messageContent, options.thread);
|
|
46
56
|
|
|
47
57
|
console.log(chalk.green(`✓ ${SUCCESS_MESSAGES.MESSAGE_SENT(options.channel)}`));
|
|
48
58
|
})
|
package/src/commands/unread.ts
CHANGED
|
@@ -26,6 +26,11 @@ async function handleSpecificChannelUnread(
|
|
|
26
26
|
countOnly: countOnly,
|
|
27
27
|
format: format,
|
|
28
28
|
});
|
|
29
|
+
|
|
30
|
+
if (parseBoolean(options.markRead)) {
|
|
31
|
+
await client.markAsRead(result.channel.id);
|
|
32
|
+
console.log(chalk.green(`✓ Marked messages in #${result.channel.name} as read`));
|
|
33
|
+
}
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
async function handleAllChannelsUnread(
|
|
@@ -48,6 +53,14 @@ async function handleAllChannelsUnread(
|
|
|
48
53
|
|
|
49
54
|
const formatter = createChannelFormatter(format, countOnly);
|
|
50
55
|
formatter.format({ channels: displayChannels, countOnly: countOnly });
|
|
56
|
+
|
|
57
|
+
if (parseBoolean(options.markRead)) {
|
|
58
|
+
// Mark all unread channels as read
|
|
59
|
+
for (const channel of channels) {
|
|
60
|
+
await client.markAsRead(channel.id);
|
|
61
|
+
}
|
|
62
|
+
console.log(chalk.green('✓ Marked all messages as read'));
|
|
63
|
+
}
|
|
51
64
|
}
|
|
52
65
|
|
|
53
66
|
export function setupUnreadCommand(): Command {
|
|
@@ -61,6 +74,7 @@ export function setupUnreadCommand(): Command {
|
|
|
61
74
|
'Maximum number of channels to display',
|
|
62
75
|
DEFAULTS.UNREAD_DISPLAY_LIMIT.toString()
|
|
63
76
|
)
|
|
77
|
+
.option('--mark-read', 'Mark messages as read after fetching', false)
|
|
64
78
|
.option('--profile <profile>', 'Use specific workspace profile')
|
|
65
79
|
.action(
|
|
66
80
|
wrapCommand(async (options: UnreadOptions) => {
|
package/src/types/commands.ts
CHANGED
|
@@ -19,6 +19,7 @@ export interface SendOptions {
|
|
|
19
19
|
channel: string;
|
|
20
20
|
message?: string;
|
|
21
21
|
file?: string;
|
|
22
|
+
thread?: string;
|
|
22
23
|
profile?: string;
|
|
23
24
|
}
|
|
24
25
|
|
|
@@ -42,5 +43,6 @@ export interface UnreadOptions {
|
|
|
42
43
|
format?: 'table' | 'simple' | 'json';
|
|
43
44
|
countOnly?: boolean;
|
|
44
45
|
limit?: string;
|
|
46
|
+
markRead?: boolean;
|
|
45
47
|
profile?: string;
|
|
46
48
|
}
|
package/src/utils/constants.ts
CHANGED
|
@@ -13,6 +13,7 @@ export const ERROR_MESSAGES = {
|
|
|
13
13
|
// Validation errors
|
|
14
14
|
NO_MESSAGE_OR_FILE: 'You must specify either --message or --file',
|
|
15
15
|
BOTH_MESSAGE_AND_FILE: 'Cannot use both --message and --file',
|
|
16
|
+
INVALID_THREAD_TIMESTAMP: 'Invalid thread timestamp format',
|
|
16
17
|
|
|
17
18
|
// API errors
|
|
18
19
|
API_ERROR: (error: string) => `API Error: ${error}`,
|
|
@@ -77,8 +77,12 @@ export class SlackApiClient {
|
|
|
77
77
|
this.messageOps = new MessageOperations(token);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
async sendMessage(
|
|
81
|
-
|
|
80
|
+
async sendMessage(
|
|
81
|
+
channel: string,
|
|
82
|
+
text: string,
|
|
83
|
+
thread_ts?: string
|
|
84
|
+
): Promise<ChatPostMessageResponse> {
|
|
85
|
+
return this.messageOps.sendMessage(channel, text, thread_ts);
|
|
82
86
|
}
|
|
83
87
|
|
|
84
88
|
async listChannels(options: ListChannelsOptions): Promise<Channel[]> {
|
|
@@ -96,6 +100,10 @@ export class SlackApiClient {
|
|
|
96
100
|
async getChannelUnread(channelNameOrId: string): Promise<ChannelUnreadResult> {
|
|
97
101
|
return this.messageOps.getChannelUnread(channelNameOrId);
|
|
98
102
|
}
|
|
103
|
+
|
|
104
|
+
async markAsRead(channelId: string): Promise<void> {
|
|
105
|
+
return this.messageOps.markAsRead(channelId);
|
|
106
|
+
}
|
|
99
107
|
}
|
|
100
108
|
|
|
101
109
|
export const slackApiClient = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ChatPostMessageResponse } from '@slack/web-api';
|
|
1
|
+
import { ChatPostMessageResponse, ChatPostMessageArguments } from '@slack/web-api';
|
|
2
2
|
import { BaseSlackClient } from './base-client';
|
|
3
3
|
import { channelResolver } from '../channel-resolver';
|
|
4
4
|
import { DEFAULTS } from '../constants';
|
|
@@ -14,11 +14,21 @@ export class MessageOperations extends BaseSlackClient {
|
|
|
14
14
|
this.channelOps = new ChannelOperations(token);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
async sendMessage(
|
|
18
|
-
|
|
17
|
+
async sendMessage(
|
|
18
|
+
channel: string,
|
|
19
|
+
text: string,
|
|
20
|
+
thread_ts?: string
|
|
21
|
+
): Promise<ChatPostMessageResponse> {
|
|
22
|
+
const params: ChatPostMessageArguments = {
|
|
19
23
|
channel,
|
|
20
24
|
text,
|
|
21
|
-
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
if (thread_ts) {
|
|
28
|
+
params.thread_ts = thread_ts;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return await this.client.chat.postMessage(params);
|
|
22
32
|
}
|
|
23
33
|
|
|
24
34
|
async getHistory(channel: string, options: HistoryOptions): Promise<HistoryResult> {
|
|
@@ -103,4 +113,11 @@ export class MessageOperations extends BaseSlackClient {
|
|
|
103
113
|
|
|
104
114
|
return users;
|
|
105
115
|
}
|
|
116
|
+
|
|
117
|
+
async markAsRead(channelId: string): Promise<void> {
|
|
118
|
+
await this.client.conversations.mark({
|
|
119
|
+
channel: channelId,
|
|
120
|
+
ts: Date.now() / 1000 + '',
|
|
121
|
+
});
|
|
122
|
+
}
|
|
106
123
|
}
|
|
@@ -47,7 +47,7 @@ describe('send command', () => {
|
|
|
47
47
|
|
|
48
48
|
await program.parseAsync(['node', 'slack-cli', 'send', '-c', 'general', '-m', 'Hello, World!']);
|
|
49
49
|
|
|
50
|
-
expect(mockSlackClient.sendMessage).toHaveBeenCalledWith('general', 'Hello, World!');
|
|
50
|
+
expect(mockSlackClient.sendMessage).toHaveBeenCalledWith('general', 'Hello, World!', undefined);
|
|
51
51
|
expect(mockConsole.logSpy).toHaveBeenCalledWith(expect.stringContaining(SUCCESS_MESSAGES.MESSAGE_SENT('general')));
|
|
52
52
|
});
|
|
53
53
|
|
|
@@ -84,7 +84,74 @@ describe('send command', () => {
|
|
|
84
84
|
await program.parseAsync(['node', 'slack-cli', 'send', '-c', 'general', '-f', 'message.txt']);
|
|
85
85
|
|
|
86
86
|
expect(fs.readFile).toHaveBeenCalledWith('message.txt', 'utf-8');
|
|
87
|
-
expect(mockSlackClient.sendMessage).toHaveBeenCalledWith('general', fileContent);
|
|
87
|
+
expect(mockSlackClient.sendMessage).toHaveBeenCalledWith('general', fileContent, undefined);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe('send reply to thread', () => {
|
|
92
|
+
it('should send a reply to a thread with --thread option', async () => {
|
|
93
|
+
vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
|
|
94
|
+
token: 'test-token',
|
|
95
|
+
updatedAt: new Date().toISOString()
|
|
96
|
+
});
|
|
97
|
+
vi.mocked(mockSlackClient.sendMessage).mockResolvedValue({
|
|
98
|
+
ok: true,
|
|
99
|
+
ts: '1234567890.123456'
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
await program.parseAsync(['node', 'slack-cli', 'send', '-c', 'general', '-m', 'Reply to thread', '--thread', '1719207629.000100']);
|
|
103
|
+
|
|
104
|
+
expect(mockSlackClient.sendMessage).toHaveBeenCalledWith('general', 'Reply to thread', '1719207629.000100');
|
|
105
|
+
expect(mockConsole.logSpy).toHaveBeenCalledWith(expect.stringContaining(SUCCESS_MESSAGES.MESSAGE_SENT('general')));
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should send a reply to a thread with -t option', async () => {
|
|
109
|
+
vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
|
|
110
|
+
token: 'test-token',
|
|
111
|
+
updatedAt: new Date().toISOString()
|
|
112
|
+
});
|
|
113
|
+
vi.mocked(mockSlackClient.sendMessage).mockResolvedValue({
|
|
114
|
+
ok: true,
|
|
115
|
+
ts: '1234567890.123456'
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
await program.parseAsync(['node', 'slack-cli', 'send', '-c', 'general', '-m', 'Reply to thread', '-t', '1719207629.000100']);
|
|
119
|
+
|
|
120
|
+
expect(mockSlackClient.sendMessage).toHaveBeenCalledWith('general', 'Reply to thread', '1719207629.000100');
|
|
121
|
+
expect(mockConsole.logSpy).toHaveBeenCalledWith(expect.stringContaining(SUCCESS_MESSAGES.MESSAGE_SENT('general')));
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should validate thread timestamp format', async () => {
|
|
125
|
+
vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
|
|
126
|
+
token: 'test-token',
|
|
127
|
+
updatedAt: new Date().toISOString()
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const sendCommand = setupSendCommand();
|
|
131
|
+
sendCommand.exitOverride();
|
|
132
|
+
|
|
133
|
+
await expect(
|
|
134
|
+
sendCommand.parseAsync(['-c', 'general', '-m', 'Reply', '-t', 'invalid-timestamp'], { from: 'user' })
|
|
135
|
+
).rejects.toThrow(ERROR_MESSAGES.INVALID_THREAD_TIMESTAMP);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should send a reply to a thread with file content', async () => {
|
|
139
|
+
const fileContent = 'Reply from file\nLine 2';
|
|
140
|
+
vi.mocked(fs.readFile).mockResolvedValue(fileContent);
|
|
141
|
+
vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
|
|
142
|
+
token: 'test-token',
|
|
143
|
+
updatedAt: new Date().toISOString()
|
|
144
|
+
});
|
|
145
|
+
vi.mocked(mockSlackClient.sendMessage).mockResolvedValue({
|
|
146
|
+
ok: true,
|
|
147
|
+
ts: '1234567890.123456'
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
await program.parseAsync(['node', 'slack-cli', 'send', '-c', 'general', '-f', 'reply.txt', '-t', '1719207629.000100']);
|
|
151
|
+
|
|
152
|
+
expect(fs.readFile).toHaveBeenCalledWith('reply.txt', 'utf-8');
|
|
153
|
+
expect(mockSlackClient.sendMessage).toHaveBeenCalledWith('general', fileContent, '1719207629.000100');
|
|
154
|
+
expect(mockConsole.logSpy).toHaveBeenCalledWith(expect.stringContaining(SUCCESS_MESSAGES.MESSAGE_SENT('general')));
|
|
88
155
|
});
|
|
89
156
|
});
|
|
90
157
|
|
|
@@ -429,4 +429,64 @@ describe('unread command', () => {
|
|
|
429
429
|
expect(mockConsole.logSpy).toHaveBeenCalledWith(expect.stringContaining('transitioned ES-4359'));
|
|
430
430
|
});
|
|
431
431
|
});
|
|
432
|
+
|
|
433
|
+
describe('mark-read functionality', () => {
|
|
434
|
+
it('should mark messages as read when --mark-read is specified', async () => {
|
|
435
|
+
vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
|
|
436
|
+
token: 'test-token',
|
|
437
|
+
updatedAt: new Date().toISOString()
|
|
438
|
+
});
|
|
439
|
+
vi.mocked(mockSlackClient.listUnreadChannels).mockResolvedValue(
|
|
440
|
+
mockChannelsWithUnread.filter(ch => (ch.unread_count_display || 0) > 0)
|
|
441
|
+
);
|
|
442
|
+
vi.mocked(mockSlackClient.markAsRead).mockResolvedValue(undefined);
|
|
443
|
+
|
|
444
|
+
await program.parseAsync(['node', 'slack-cli', 'unread', '--mark-read']);
|
|
445
|
+
|
|
446
|
+
expect(mockSlackClient.listUnreadChannels).toHaveBeenCalled();
|
|
447
|
+
expect(mockSlackClient.markAsRead).toHaveBeenCalledWith('C123');
|
|
448
|
+
expect(mockSlackClient.markAsRead).toHaveBeenCalledWith('C456');
|
|
449
|
+
expect(mockConsole.logSpy).toHaveBeenCalledWith(chalk.green('✓ Marked all messages as read'));
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
it('should mark messages as read for specific channel when --channel and --mark-read are specified', async () => {
|
|
453
|
+
vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
|
|
454
|
+
token: 'test-token',
|
|
455
|
+
updatedAt: new Date().toISOString()
|
|
456
|
+
});
|
|
457
|
+
vi.mocked(mockSlackClient.getChannelUnread).mockResolvedValue({
|
|
458
|
+
channel: mockChannelsWithUnread[0],
|
|
459
|
+
messages: mockUnreadMessages,
|
|
460
|
+
users: new Map([
|
|
461
|
+
['U123', 'john.doe'],
|
|
462
|
+
['U456', 'jane.smith']
|
|
463
|
+
])
|
|
464
|
+
});
|
|
465
|
+
vi.mocked(mockSlackClient.markAsRead).mockResolvedValue(undefined);
|
|
466
|
+
|
|
467
|
+
await program.parseAsync(['node', 'slack-cli', 'unread', '--channel', 'general', '--mark-read']);
|
|
468
|
+
|
|
469
|
+
expect(mockSlackClient.getChannelUnread).toHaveBeenCalledWith('general');
|
|
470
|
+
expect(mockSlackClient.markAsRead).toHaveBeenCalledWith('C123');
|
|
471
|
+
expect(mockConsole.logSpy).toHaveBeenCalledWith(chalk.green('✓ Marked messages in #general as read'));
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
it('should handle mark as read errors gracefully', async () => {
|
|
475
|
+
vi.mocked(mockConfigManager.getConfig).mockResolvedValue({
|
|
476
|
+
token: 'test-token',
|
|
477
|
+
updatedAt: new Date().toISOString()
|
|
478
|
+
});
|
|
479
|
+
vi.mocked(mockSlackClient.listUnreadChannels).mockResolvedValue(
|
|
480
|
+
mockChannelsWithUnread.filter(ch => (ch.unread_count_display || 0) > 0)
|
|
481
|
+
);
|
|
482
|
+
vi.mocked(mockSlackClient.markAsRead).mockRejectedValue(
|
|
483
|
+
new Error('channel_not_found')
|
|
484
|
+
);
|
|
485
|
+
|
|
486
|
+
await program.parseAsync(['node', 'slack-cli', 'unread', '--mark-read']);
|
|
487
|
+
|
|
488
|
+
expect(mockConsole.errorSpy).toHaveBeenCalledWith(expect.stringContaining('Error:'), expect.any(String));
|
|
489
|
+
expect(mockConsole.exitSpy).toHaveBeenCalledWith(1);
|
|
490
|
+
});
|
|
491
|
+
});
|
|
432
492
|
});
|
package/tests/index.test.ts
CHANGED
|
@@ -11,8 +11,8 @@ describe('slack-cli version', () => {
|
|
|
11
11
|
);
|
|
12
12
|
const expectedVersion = packageJson.version;
|
|
13
13
|
|
|
14
|
-
// Execute the CLI command to get version
|
|
15
|
-
const output = execSync('node
|
|
14
|
+
// Execute the CLI command to get version using ts-node
|
|
15
|
+
const output = execSync('npx ts-node src/index.ts --version', {
|
|
16
16
|
encoding: 'utf-8',
|
|
17
17
|
cwd: join(__dirname, '..')
|
|
18
18
|
}).trim();
|
|
@@ -28,8 +28,8 @@ describe('slack-cli version', () => {
|
|
|
28
28
|
);
|
|
29
29
|
const expectedVersion = packageJson.version;
|
|
30
30
|
|
|
31
|
-
// Execute the CLI command with -V flag
|
|
32
|
-
const output = execSync('node
|
|
31
|
+
// Execute the CLI command with -V flag using ts-node
|
|
32
|
+
const output = execSync('npx ts-node src/index.ts -V', {
|
|
33
33
|
encoding: 'utf-8',
|
|
34
34
|
cwd: join(__dirname, '..')
|
|
35
35
|
}).trim();
|