slack-term 1.24.0 → 1.26.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/README.md +130 -7
- package/SKILL.md +92 -8
- package/dist/cli.js +93 -90
- package/package.json +5 -2
- package/ts/cache.ts +120 -0
- package/ts/cli.ts +558 -35
- package/ts/format.ts +13 -10
- package/ts/slack.ts +42 -2
- package/ts/tail.ts +11 -7
- package/ts/todo.ts +483 -0
package/README.md
CHANGED
|
@@ -54,13 +54,23 @@ slack news --limit 5
|
|
|
54
54
|
# Recent messages across joined channels
|
|
55
55
|
slack msgs
|
|
56
56
|
|
|
57
|
+
# Channel/DM history. Thread parents are marked `[+N replies]`, so a line with
|
|
58
|
+
# replies is distinguishable from one without — open it with `slack thread`.
|
|
59
|
+
# --json adds reply_count / reply_users_count / latest_reply.
|
|
60
|
+
slack read "#general"
|
|
61
|
+
slack read "#general" --unreplied # only threads/posts whose last word isn't yours
|
|
62
|
+
|
|
57
63
|
# Search messages
|
|
58
64
|
slack search "deploy"
|
|
59
65
|
slack search "deploy" --count 50
|
|
60
66
|
|
|
61
67
|
# Send a message (two-step confirm — quote #channel)
|
|
62
68
|
slack send "#general" "Hello team"
|
|
63
|
-
# Prints
|
|
69
|
+
# Prints who you're acting as (From: @handle (Uxxxx) — Workspace) + a destination
|
|
70
|
+
# preview + confirm code; rerun with --code=<code> to actually send. Every gated write
|
|
71
|
+
# (send/edit/delete/upload/schedule/channel create/drafts) shows that From: line and
|
|
72
|
+
# binds it into the code, so a profile switch mid-flow invalidates it instead of acting
|
|
73
|
+
# as the wrong account.
|
|
64
74
|
slack send "#general" "Hello team" --code=<code>
|
|
65
75
|
|
|
66
76
|
# Reply in a thread — #chan:<thread_ts>, or just paste a message permalink
|
|
@@ -71,7 +81,7 @@ slack send "https://acme.slack.com/archives/C0123456789/p1700000000000100" "Repl
|
|
|
71
81
|
# Resolves via users.list, then the channel's members so Slack Connect guests work;
|
|
72
82
|
# any handle that can't be resolved is left as plain text. The confirm preview shows
|
|
73
83
|
# the converted message before sending. Use --no-mentions to keep @text literal.
|
|
74
|
-
slack send "#general" "thanks @t.
|
|
84
|
+
slack send "#general" "thanks @t.yamada19850101 and @alice"
|
|
75
85
|
slack send "#general" "ping @ops on call" --no-mentions # leave @ops as plain text
|
|
76
86
|
|
|
77
87
|
# Edit or delete a sent message (same confirm-code gate)
|
|
@@ -83,6 +93,14 @@ slack delete "<permalink>"
|
|
|
83
93
|
slack react "#general:1700000000.000100" white_check_mark
|
|
84
94
|
slack react "<permalink>" eyes --remove # take a reaction back
|
|
85
95
|
|
|
96
|
+
# Task tracking on top of reactions — :pushpin: marks a message as a task,
|
|
97
|
+
# a second reaction carries its progress (see "todo" below)
|
|
98
|
+
slack todo ls # my open tasks
|
|
99
|
+
slack todo ls --state untriaged --in "#general"
|
|
100
|
+
slack todo set "#general:1700000000.000100" doing
|
|
101
|
+
slack todo flag "<permalink>" blocked
|
|
102
|
+
slack todo doctor --in "#general" # find messages stuck in two states
|
|
103
|
+
|
|
86
104
|
# Bulk export channel history
|
|
87
105
|
slack dump --days 7 --filter eng
|
|
88
106
|
|
|
@@ -94,6 +112,98 @@ slack tail "#general" --me # only messages that mention you
|
|
|
94
112
|
slack tail "@bob" --exit-on-message --timeout 30m # wait for a reply, then exit
|
|
95
113
|
```
|
|
96
114
|
|
|
115
|
+
### todo — task tracking on reactions
|
|
116
|
+
|
|
117
|
+
Tasks are just messages. A **marker** reaction (📌 `:pushpin:`) says "this is a task";
|
|
118
|
+
a **progress** reaction says where it stands; **reason flags** stack on top:
|
|
119
|
+
|
|
120
|
+
| axis | reaction | meaning |
|
|
121
|
+
| --- | --- | --- |
|
|
122
|
+
| progress 1 | ✅ `white_check_mark` | done |
|
|
123
|
+
| progress 2 | 🚫 `no_entry_sign` | dropped |
|
|
124
|
+
| progress 3 | 👀 `eyes` | doing |
|
|
125
|
+
| progress 4 | ⏳ `hourglass_flowing_sand` | pending |
|
|
126
|
+
| progress 5 | *(marker only)* | undefined / untriaged |
|
|
127
|
+
| flag | ❗ `exclamation` | alert |
|
|
128
|
+
| flag | ❓ `question` | needs discussion |
|
|
129
|
+
| flag | 💬 `speech_balloon` | waiting — the other party in this conversation owes a reply |
|
|
130
|
+
| flag | 🔒 `lock` | blocked — stuck on something *outside* this conversation |
|
|
131
|
+
|
|
132
|
+
The invariant is **"at least one progress reaction, readers collapse by priority"** —
|
|
133
|
+
not "exactly one". A message carrying both ✅ and 👀 reads as *done*.
|
|
134
|
+
|
|
135
|
+
**Whose ball is it?** There are only three answers, and `pending` ⏳ already means *mine*.
|
|
136
|
+
The other two are the flags:
|
|
137
|
+
|
|
138
|
+
- 💬 **waiting** — I've done my part; someone **in this conversation** owes the next move
|
|
139
|
+
(I asked a question, I'm waiting on a review, I sent it and need a yes/no).
|
|
140
|
+
- 🔒 **blocked** — the hold-up is **outside this conversation**: another task, a third
|
|
141
|
+
party, an external dependency, a deploy window.
|
|
142
|
+
|
|
143
|
+
They stack with each other and with ❗/❓; `--state stuck` matches a task with any of them.
|
|
144
|
+
|
|
145
|
+
```sh
|
|
146
|
+
# Two listings, split by whose reactions count — the distinction is the command,
|
|
147
|
+
# not a flag, so "everyone's list" and "my list" can't be confused at a glance.
|
|
148
|
+
slack todo ls # EVERYONE's tasks (has:)
|
|
149
|
+
slack mytodo ls # only tasks YOU reacted to (hasmy:)
|
|
150
|
+
|
|
151
|
+
slack todo ls --state untriaged # marked, no progress reaction yet
|
|
152
|
+
slack todo ls --state doing --in "#eng" # scoped to a channel
|
|
153
|
+
slack mytodo ls --state stuck # my unfinished tasks carrying a reason flag
|
|
154
|
+
slack todo ls --state stuck --from "@alice" # …and it was alice who wrote it
|
|
155
|
+
slack todo ls --from me # tasks on my own messages (any reactor)
|
|
156
|
+
slack todo ls --mine # same as `slack mytodo ls`
|
|
157
|
+
slack todo set "#eng:1700000000.000100" doing
|
|
158
|
+
slack todo flag "<permalink>" waiting # their ball now
|
|
159
|
+
slack todo flag "<permalink>" needs-discussion
|
|
160
|
+
slack todo flag "<permalink>" blocked --remove
|
|
161
|
+
slack todo doctor --in "#eng" # report messages in two progress states
|
|
162
|
+
slack todo doctor --in "#eng" --fix # keep the highest-priority one
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Notes:
|
|
166
|
+
|
|
167
|
+
- **`todo ls` vs `mytodo ls`** — `todo ls` matches anyone's reactions (`has:`), `mytodo ls`
|
|
168
|
+
only your own (`hasmy:`). Everything else about them is identical. Both print a
|
|
169
|
+
`From: @handle (Uxxxx) — Workspace` line first, because `hasmy:` resolves against
|
|
170
|
+
whichever account the token belongs to — "my tasks" means nothing until you know who
|
|
171
|
+
*my* is, and a stale profile otherwise lists someone else's list without saying so.
|
|
172
|
+
(`todo ls --mine` is a one-off shortcut to the narrow view.)
|
|
173
|
+
- Both are read-only and run **exactly one** `search.messages` call — priority is expressed
|
|
174
|
+
as negated `has:`/`hasmy:` terms in the query, not as multiple searches
|
|
175
|
+
(`search.messages` is Tier 2, ~20 req/min). Slack's search index lags a little
|
|
176
|
+
behind `reactions.add`, so a just-set task may take a moment to appear.
|
|
177
|
+
- `todo set` **adds the new reaction before removing the old ones**, and removes serially.
|
|
178
|
+
The reverse order would leave a window with no progress reaction at all — a crash or a
|
|
179
|
+
429 there would drop the task out of every query with nothing left pointing at it.
|
|
180
|
+
Worst case here is a message with two progress reactions, which reads correctly and is
|
|
181
|
+
repairable with `todo doctor --fix`.
|
|
182
|
+
- `--from <@user|me>` maps to search's `from:` modifier (a missing `@` is supplied; `me`
|
|
183
|
+
passes through as-is). Reactions carry no reference to *whom* a task waits on, but the
|
|
184
|
+
sender is usually that person — so filtering by author answers most of the question for
|
|
185
|
+
free. It composes with `--in` in the same single search.
|
|
186
|
+
- **Not implemented, deliberately:** encoding the actual reference ("blocked on @alice" /
|
|
187
|
+
"blocked on task X") as a machine-readable token in a thread reply. Measured: Slack's
|
|
188
|
+
full-text index splits on punctuation, so a quoted search for `"blocked-on"` returns 0
|
|
189
|
+
hits, and `"1.91"` matches `1.91.0`. A token like `todo:v1 blocked-on=@alice` is therefore
|
|
190
|
+
unsearchable. Any future attempt needs a single alphanumeric marker word (e.g. `tdblock`)
|
|
191
|
+
plus a bare `@mention`.
|
|
192
|
+
- `todo doctor` pages history sequentially and scans at most `--limit` messages
|
|
193
|
+
(default 1000); if it hits the limit it says so rather than silently stopping.
|
|
194
|
+
- Emoji are configurable in `~/.config/slack-cli/todo.json` (same directory as
|
|
195
|
+
`profiles.json`); anything omitted falls back to the defaults above:
|
|
196
|
+
|
|
197
|
+
```json
|
|
198
|
+
{ "marker": "round_pushpin", "progress": { "doing": "construction" } }
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
- Channel-name→ID and user-ID→handle lookups are cached in
|
|
202
|
+
`~/.config/slack-cli/cache.json` for 1 hour, namespaced by workspace (`team_id`) since
|
|
203
|
+
both are workspace-scoped; `--no-cache` bypasses it. Reaction state and search results
|
|
204
|
+
are **never** cached — they are exactly the values that change, and Slack's search index
|
|
205
|
+
already lags. A corrupt or unwritable cache is ignored and the command runs uncached.
|
|
206
|
+
|
|
97
207
|
### tail — real-time message stream
|
|
98
208
|
|
|
99
209
|
`slack tail` polls a channel every 3 seconds (configurable via `--interval`) and
|
|
@@ -101,10 +211,10 @@ prints new messages as they arrive, in the same `[ts] @handle: text` format as
|
|
|
101
211
|
the `read` command.
|
|
102
212
|
|
|
103
213
|
```sh
|
|
104
|
-
slack tail "#
|
|
105
|
-
slack tail "#
|
|
106
|
-
slack tail "#
|
|
107
|
-
slack tail "#
|
|
214
|
+
slack tail "#general" # follow new messages from now
|
|
215
|
+
slack tail "#general" --since=30m # backfill 30 minutes, then stream
|
|
216
|
+
slack tail "#general" --thread=1700000000.000100 # one thread only
|
|
217
|
+
slack tail "#general" --me # only messages mentioning you
|
|
108
218
|
```
|
|
109
219
|
|
|
110
220
|
For automation, `--exit-on-message` stops as soon as the first message from
|
|
@@ -113,7 +223,7 @@ For automation, `--exit-on-message` stops as soon as the first message from
|
|
|
113
223
|
make a "wait for a reply, then act" primitive that won't hang:
|
|
114
224
|
|
|
115
225
|
```sh
|
|
116
|
-
slack tail "@
|
|
226
|
+
slack tail "@alice" --exit-on-message --timeout 30m --interval 15000
|
|
117
227
|
```
|
|
118
228
|
|
|
119
229
|
**Note:** Cross-channel mention streaming (`--me` without a target) is not yet
|
|
@@ -186,6 +296,19 @@ delivery (3-second interval). Supports `--since=<duration>` for backfill,
|
|
|
186
296
|
that mention you. Uses `conversations.history?oldest=<ts>` as a cursor so
|
|
187
297
|
already-seen messages are never re-printed, even across reconnects.
|
|
188
298
|
|
|
299
|
+
## Ecosystem
|
|
300
|
+
|
|
301
|
+
This CLI is the human-comms surface of the
|
|
302
|
+
[agent-yes](https://github.com/snomiao/agent-yes) fleet: agent-yes runs, watches and
|
|
303
|
+
delegates to AI coding agents, and `slack` is how they read and answer the humans they
|
|
304
|
+
work with. Neither depends on the other — they share a stance rather than a library:
|
|
305
|
+
file-based state over daemons, one command surface across two runtimes, gates on the
|
|
306
|
+
irreversible and warnings on the merely unwise, and no real operational data in a public
|
|
307
|
+
repo.
|
|
308
|
+
|
|
309
|
+
A write-up of the design decisions behind the confirm gate lives on the agent-yes lab:
|
|
310
|
+
[A confirm code that goes stale](https://lab.agent-yes.com/2026-08-11-slack-term-safe-writes).
|
|
311
|
+
|
|
189
312
|
## Related / prior art
|
|
190
313
|
|
|
191
314
|
- [`slkcli`](https://www.npmjs.com/package/slkcli) by
|
package/SKILL.md
CHANGED
|
@@ -8,11 +8,15 @@ description: "Terminal Slack CLI — read news/mentions/DMs/channel history, ful
|
|
|
8
8
|
A lightweight Slack CLI for quick workspace interaction from the terminal.
|
|
9
9
|
Two implementations share one command surface (parity-tested):
|
|
10
10
|
|
|
11
|
-
- **TypeScript** (bun-first), published as
|
|
11
|
+
- **TypeScript** (bun-first), published as `slack-term` on npm.
|
|
12
12
|
- **Rust** native binary, installable via `cargo install`.
|
|
13
13
|
|
|
14
14
|
Binary name: `slack` (also aliased as `sl` / invoked via `sc sl ...` in some setups).
|
|
15
15
|
|
|
16
|
+
Part of the [agent-yes](https://github.com/snomiao/agent-yes) ecosystem — this is the CLI an
|
|
17
|
+
agent uses to talk to humans. Design notes:
|
|
18
|
+
[lab.agent-yes.com](https://lab.agent-yes.com/2026-08-11-slack-term-safe-writes).
|
|
19
|
+
|
|
16
20
|
## When to use
|
|
17
21
|
|
|
18
22
|
- User wants to read Slack activity, mentions, DMs, or channel history without opening the Slack app.
|
|
@@ -25,10 +29,13 @@ Binary name: `slack` (also aliased as `sl` / invoked via `sc sl ...` in some set
|
|
|
25
29
|
TypeScript (recommended — any platform with Node 18+):
|
|
26
30
|
|
|
27
31
|
```sh
|
|
28
|
-
npm install -g
|
|
29
|
-
# or: bun add -g
|
|
32
|
+
npm install -g slack-term
|
|
33
|
+
# or: bun add -g slack-term / pnpm add -g slack-term
|
|
30
34
|
```
|
|
31
35
|
|
|
36
|
+
> Previously published as `@snomiao/slack`; that name is deprecated on npm and
|
|
37
|
+
> no longer updated. Install `slack-term`.
|
|
38
|
+
|
|
32
39
|
Rust (native binary):
|
|
33
40
|
|
|
34
41
|
```sh
|
|
@@ -55,6 +62,10 @@ slack search "deploy" --count 50
|
|
|
55
62
|
# Read a specific channel or DM (quote #channel — unquoted # is a shell comment)
|
|
56
63
|
slack read "#general"
|
|
57
64
|
slack read @username
|
|
65
|
+
# Thread parents are marked `[+N replies]` — a marked line means there is more to
|
|
66
|
+
# read inside the thread (`slack thread "#general" <ts>`); top-level output alone
|
|
67
|
+
# never shows thread replies. --json carries reply_count/reply_users_count/latest_reply.
|
|
68
|
+
slack read "#general" --unreplied # only what's still awaiting your answer
|
|
58
69
|
|
|
59
70
|
# Send a message (two-step confirm)
|
|
60
71
|
slack send "#general" "Hello team"
|
|
@@ -74,6 +85,17 @@ slack delete "<permalink>"
|
|
|
74
85
|
slack react "#general:1700000000.000100" white_check_mark
|
|
75
86
|
slack react "<permalink>" eyes --remove # take it back
|
|
76
87
|
|
|
88
|
+
# Task tracking on reactions — 📌 marks a task, a second reaction holds progress
|
|
89
|
+
slack todo ls # EVERYONE's open tasks (has:)
|
|
90
|
+
slack mytodo ls # only tasks YOU reacted to (hasmy:)
|
|
91
|
+
slack todo ls --state untriaged --in "#general" # marked but no progress yet
|
|
92
|
+
slack mytodo ls --state stuck # my unfinished tasks + a reason flag
|
|
93
|
+
slack todo set "#general:1700000000.000100" doing # pending|doing|done|dropped
|
|
94
|
+
slack todo ls --state stuck --from "@alice" # …and alice wrote it
|
|
95
|
+
slack todo flag "<permalink>" waiting # alert|needs-discussion|waiting|blocked
|
|
96
|
+
# waiting = their ball, blocked = outside
|
|
97
|
+
slack todo doctor --in "#general" [--fix] # messages stuck in two states
|
|
98
|
+
|
|
77
99
|
# Bulk export a channel's history
|
|
78
100
|
slack dump "#channel-name"
|
|
79
101
|
|
|
@@ -85,11 +107,24 @@ slack download "https://acme.slack.com/files/U1/F0123ABC/invoice.pdf"
|
|
|
85
107
|
|
|
86
108
|
Targets for `send` are `#channel`, `@user`, `#channel:<thread_ts>`, or a Slack URL —
|
|
87
109
|
a message permalink replies in that message's thread; a channel-only URL posts top-level.
|
|
88
|
-
The confirm preview prints
|
|
89
|
-
|
|
110
|
+
The confirm preview prints who it will be sent **as** (`From: @handle (Uxxxx) — Workspace`,
|
|
111
|
+
plus `[as bot]` under `--as-bot`) and the resolved destination (`→ ... — THREAD REPLY` or
|
|
112
|
+
`→ ... — NEW top-level message`); verify both before re-running with `--code`.
|
|
113
|
+
|
|
114
|
+
**Every** gated write opens its preview with that same `From:` line — `send`, `edit`,
|
|
115
|
+
`delete`, `upload`, `schedule send`, `schedule rm`, `channel create`, `drafts edit`,
|
|
116
|
+
`drafts delete` — and the identity is part of the confirm hash: switching
|
|
117
|
+
profile/token between preview and confirm invalidates the code instead of acting as
|
|
118
|
+
someone else. It matters most on `schedule send`, where the message goes out later,
|
|
119
|
+
unattended, as whoever the token was at schedule time.
|
|
120
|
+
|
|
121
|
+
`schedule send` prints its fire time in both zones —
|
|
122
|
+
`At: 2026-08-10 18:00:00 GMT+9 (local) / 2026-08-10T09:00:00.000Z (Unix: 1786352400)` —
|
|
123
|
+
because `--at` accepts both bare local times (`"2026-08-10 09:00"`) and `Z`-suffixed
|
|
124
|
+
UTC, and the two are easy to mix up. Check the side you meant before confirming.
|
|
90
125
|
|
|
91
126
|
`send` also runs a **warn-only untagged-mention lint**: if the body names a workspace
|
|
92
|
-
member in plain text (honorifics like
|
|
127
|
+
member in plain text (honorifics like `山田さん` / `王老师`, or `Hi Dave`) without a
|
|
93
128
|
matching `<@USERID>` tag, it prints `⚠ possible untagged mention: …` alongside the
|
|
94
129
|
confirm code. It never blocks — third-party/external references are expected to trip it.
|
|
95
130
|
To actually notify someone, write `@handle` (auto-converted to `<@USERID>`; see below).
|
|
@@ -103,8 +138,57 @@ and no one has replied since — `⚠ 相手はまだ返信していません…
|
|
|
103
138
|
on that message instead of piling on a new one. Reply-status based, not time-based; opt
|
|
104
139
|
out with `SLACK_UNREPLIED_WARN=0`.
|
|
105
140
|
|
|
141
|
+
### todo — tasks as reactions
|
|
142
|
+
|
|
143
|
+
A task is any message carrying the marker reaction 📌 `:pushpin:`. Progress lives in a
|
|
144
|
+
second reaction, ranked by priority — **1** ✅ `white_check_mark` done, **2** 🚫
|
|
145
|
+
`no_entry_sign` dropped, **3** 👀 `eyes` doing, **4** ⏳ `hourglass_flowing_sand` pending, **5** marker
|
|
146
|
+
only = undefined. A message may carry more than one progress reaction — readers collapse
|
|
147
|
+
to the highest priority, so ✅+👀 reads as *done*.
|
|
148
|
+
|
|
149
|
+
Reason flags stack independently of progress and of each other: ❗ `exclamation` alert,
|
|
150
|
+
❓ `question` needs-discussion, and two that say **whose ball it is** —
|
|
151
|
+
|
|
152
|
+
- 💬 `speech_balloon` **waiting** — someone **in this conversation** owes the next move
|
|
153
|
+
(asked a question, waiting on a review/approval). Their ball.
|
|
154
|
+
- 🔒 `lock` **blocked** — stuck on something **outside** it: another task, a third party,
|
|
155
|
+
an external dependency. Nobody here can unstick it by replying.
|
|
156
|
+
|
|
157
|
+
(⏳ `hourglass_flowing_sand` pending already means "my ball", which is why only these two are needed.)
|
|
158
|
+
|
|
159
|
+
- **`todo ls` = anyone's reactions (`has:`), `mytodo ls` = only yours (`hasmy:`).** Two
|
|
160
|
+
commands rather than a flag, so the two lists can't be mistaken for each other. Both
|
|
161
|
+
print `From: @handle (Uxxxx) — Workspace` first: `hasmy:` resolves against whoever the
|
|
162
|
+
token is, so "my tasks" is only meaningful once you know who *my* is. `todo ls --mine`
|
|
163
|
+
is a shortcut to the narrow view; `--shared` is accepted but is now the default.
|
|
164
|
+
- Both are read-only and issue **one** `search.messages` call; priority is encoded as
|
|
165
|
+
negated `has:`/`hasmy:` terms.
|
|
166
|
+
`search.messages` returns no reaction data, so this filtering can only happen in the
|
|
167
|
+
query. The search index lags slightly behind `reactions.add`.
|
|
168
|
+
- `todo set` adds the target reaction **first**, then removes the stale ones one at a time.
|
|
169
|
+
Never remove-then-add: an interruption in between leaves the task with no progress
|
|
170
|
+
reaction and it vanishes from every query. Two reactions is the safe failure mode, and
|
|
171
|
+
`todo doctor --fix` repairs it (also add-first).
|
|
172
|
+
- `todo ls --from <@user|me>` adds search's `from:` modifier (missing `@` supplied, `me`
|
|
173
|
+
left bare) and composes with `--in` in the same single search. Reactions can't point at
|
|
174
|
+
*who* a task waits on, but the sender usually is that person.
|
|
175
|
+
- Deliberately NOT implemented: a machine-readable token in a thread reply to carry the
|
|
176
|
+
actual reference. Measured — Slack's index splits on punctuation, so quoted `"blocked-on"`
|
|
177
|
+
gets 0 hits and `"1.91"` matches `1.91.0`; `todo:v1 blocked-on=@alice` is unsearchable.
|
|
178
|
+
A future attempt needs one alphanumeric marker word (e.g. `tdblock`) + a bare `@mention`.
|
|
179
|
+
- `todo doctor` scans at most `--limit` messages (default 1000), pages sequentially, and
|
|
180
|
+
explicitly reports when it hits the limit.
|
|
181
|
+
- Emoji overrides: `~/.config/slack-cli/todo.json`, e.g.
|
|
182
|
+
`{ "marker": "round_pushpin", "progress": { "doing": "construction" } }`.
|
|
183
|
+
- Channel/user lookups are cached for 1h in `~/.config/slack-cli/cache.json`, keyed by
|
|
184
|
+
workspace `team_id` (`--no-cache` to bypass). Reaction state and search results are never
|
|
185
|
+
cached; a broken cache is ignored. Message listings read this cache too, behind their
|
|
186
|
+
in-process map.
|
|
187
|
+
- Rate limits: `todo` commands catch Slack's 429, wait `Retry-After`, and retry up to 3
|
|
188
|
+
times before failing loudly.
|
|
189
|
+
|
|
106
190
|
**Etiquette:** prefer a `react` over a reply for simple acks (了解 → `eyes`, 完了 →
|
|
107
|
-
`white_check_mark`, 処理中 → `
|
|
191
|
+
`white_check_mark`, 処理中 → `hourglass_flowing_sand`) so threads stay short; read the thread with
|
|
108
192
|
`slack thread`/`slack read` before replying to avoid duplicates; consolidate multiple
|
|
109
193
|
points into one message.
|
|
110
194
|
|
|
@@ -177,7 +261,7 @@ slack news --limit 1
|
|
|
177
261
|
- **`xoxc-` desktop session token** — accepted by the public Slack API (send/edit/delete/react/upload/channel create+invite included) as long as its `xoxd` session cookie is attached (`slack auth chrome`/`slack auth firefox`, or `SLACK_COOKIE=...`). Without the cookie it still fails with a clear "needs its session cookie" error.
|
|
178
262
|
- **`conversations.invite` reports success but the member never shows up** — the invited user is likely a single-channel guest (`is_ultra_restricted`); Slack silently no-ops the invite since that account type can only ever belong to the one channel it was created in. `channel create --invite` now warns about this up front.
|
|
179
263
|
- **Send is rejected with "use #channel or @user"** — the CLI enforces human-readable targets. Use `#channel-name` or `@display-name`, not raw IDs.
|
|
180
|
-
- **Confirm code mismatch on
|
|
264
|
+
- **Confirm code mismatch on any gated write** — the content, target or acting identity changed between preview and confirm (a different profile/`SLACK_TOKEN`, or `--as-bot` added or dropped). Re-run without `--code` for a fresh preview, and re-check the `From:` line and the `→` destination line (THREAD REPLY vs NEW top-level message).
|
|
181
265
|
- **Enterprise Grid / admin-locked workspace** — custom app installation may need admin approval or be disabled outright.
|
|
182
266
|
|
|
183
267
|
## Safety
|