slack-term 1.35.0 → 1.37.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 +35 -3
- package/SKILL.md +27 -9
- package/dist/cli.js +277 -141
- package/package.json +1 -1
- package/ts/ask.ts +14 -3
- package/ts/auth.ts +383 -54
- package/ts/chromeCookieWin.ts +230 -0
- package/ts/cli.ts +252 -42
- package/ts/leveldb.ts +154 -0
- package/ts/profiles.ts +73 -19
- package/ts/sentlog.ts +356 -0
- package/ts/slack-app.ts +287 -185
- package/ts/slack.ts +31 -5
package/README.md
CHANGED
|
@@ -126,7 +126,9 @@ slack react "<permalink>" eyes --remove # take a reaction back
|
|
|
126
126
|
slack ask "@bob" "本番に出してよい?" "出してよい" "待って"
|
|
127
127
|
# --wait blocks until answered and prints ONLY the answer on stdout, so it composes:
|
|
128
128
|
ANS=$(slack ask "@bob" "本番に出してよい?" "出してよい" "待って" --code=<code> --wait)
|
|
129
|
-
# exit 0 = answered, 2 = timed out (--timeout, default 3600s), 3 = transport failure
|
|
129
|
+
# exit 0 = answered, 2 = timed out (--timeout, default 3600s), 3 = transport failure,
|
|
130
|
+
# 4 = a reply matched several choices, 5 = a free-text reply that picked NO choice —
|
|
131
|
+
# the reply text is on stdout, it is not a decision, and the question stays open.
|
|
130
132
|
#
|
|
131
133
|
# The question must say WHO may answer — only their reaction/reply is taken as the
|
|
132
134
|
# answer, so a bystander can't decide it for them. `ask` refuses to post otherwise.
|
|
@@ -144,14 +146,26 @@ RESUME=$(slack ask "@bob" "本番に出してよい?" "出してよい" "待っ
|
|
|
144
146
|
# -> slack ask --waitFor='https://acme.slack.com/archives/C00000001/p1700000000000100'
|
|
145
147
|
# Run it whenever you like: it re-reads the question from Slack, so nothing is
|
|
146
148
|
# stored locally and any machine holding the link can collect. Same stdout/exit
|
|
147
|
-
# contract as --wait, plus --timeout 0 = check once (exit 2 while still open,
|
|
148
|
-
# somebody
|
|
149
|
+
# contract as --wait, plus --timeout 0 = check once (exit 2 while still open, 5 with
|
|
150
|
+
# the reply on stdout if somebody wrote free text instead of choosing; re-wait past
|
|
151
|
+
# it with --after=<reply ts>),
|
|
149
152
|
# which is what a periodic monitor should use instead of parking on --wait.
|
|
150
153
|
eval "$RESUME --timeout 0" && echo answered
|
|
151
154
|
# A pressed pill is invisible to `slack tail` (it only sees `type: "message"`
|
|
152
155
|
# events and drops `message_changed`), so this is the only way to hear about an
|
|
153
156
|
# answer to a question you did not block on.
|
|
154
157
|
|
|
158
|
+
# Who sent what: every send/ask/poll/edit is logged locally with its sender —
|
|
159
|
+
# pid, cwd, git branch, agent CLI and session id — and the same attribution rides
|
|
160
|
+
# along as invisible Slack message metadata (event_type `slack_term_sent`).
|
|
161
|
+
slack sent # newest first, sender on its own line
|
|
162
|
+
slack sent "deploy" --since 2h --kind ask # substring of the text
|
|
163
|
+
slack sent --session 4f1c --cwd ~/ws/app --json
|
|
164
|
+
# Log: ~/.config/slack-cli/sent.sqlite (SLACK_TERM_SENT_DB overrides).
|
|
165
|
+
# Opt out of both with SLACK_TERM_ATTRIBUTION=off. Agent CLIs other than Claude
|
|
166
|
+
# Code are found by process name; set SLACK_TERM_AGENT_SESSION / _CLI / _PID to
|
|
167
|
+
# name the session explicitly.
|
|
168
|
+
|
|
155
169
|
# Task tracking on top of reactions — :pushpin: marks a message as a task,
|
|
156
170
|
# a second reaction carries its progress (see "todo" below)
|
|
157
171
|
slack todo ls # my open tasks
|
|
@@ -321,6 +335,24 @@ Or place it in `~/.config/slack-cli/.env` or a local `.env` file.
|
|
|
321
335
|
|
|
322
336
|
See [`SKILL.md`](SKILL.md) for a full token-acquisition walkthrough.
|
|
323
337
|
|
|
338
|
+
### Ubuntu desktop session
|
|
339
|
+
|
|
340
|
+
Sign in to Slack in Chrome or Slack Desktop. `--from-chrome` reads a browser `xoxc-` token and cookie from the same Chrome profile; desktop import reads `xoxc-` tokens from native, Snap, or Flatpak data directories. Browser profiles contain sensitive cookies, so the CLI asks `Read local browser profiles and Slack session cookies? [y/N]` before scanning. Enter `y` to allow a scan; the default is no.
|
|
341
|
+
|
|
342
|
+
```sh
|
|
343
|
+
slack auth login --from-desktop # desktop token only
|
|
344
|
+
slack auth login --from-chrome # Chrome token + Chrome cookie
|
|
345
|
+
slack auth login --from-firefox # desktop token + Firefox cookie
|
|
346
|
+
slack auth login --from-all # desktop and browser sources
|
|
347
|
+
slack auth login --from-chrome --yes # bypass the browser-read prompt
|
|
348
|
+
slack auth tokens # print active credentials in .env format
|
|
349
|
+
slack auth save --envfile=./.env.local # export active token + cookie
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
`--from-all` attaches a cookie only when exactly one browser session is found. If several are found, the desktop token is saved without a cookie; use `slack auth chrome -w <name>` or `slack auth firefox -w <name>` to select the matching profile. These commands also ask before reading browser profiles, and accept `--yes` for scripts. Select the saved workspace with `slack auth use -g <name>`. `auth tokens` prints the active `SLACK_TOKEN`, optional `SLACK_COOKIE`, and optional `SLACK_BOT_TOKEN` to stdout; treat its output as secret. `auth save` requires a cookie, writes `SLACK_TOKEN` and `SLACK_COOKIE`, and makes the env file owner-readable only on Unix. `--workspace <name>` selects a specific profile.
|
|
353
|
+
|
|
354
|
+
Chrome supports Linux `v10` cookies and `v11` cookies when `secret-tool` can read the unlocked GNOME keyring. Other Linux keyring backends are not yet supported. Firefox discovery covers native, Snap, and Flatpak profiles. If browser session access is unavailable, use `slack auth token` to add a user token from a Slack app. Treat desktop tokens and browser cookies as credentials; keep profile files and local env files private.
|
|
355
|
+
|
|
324
356
|
## Development
|
|
325
357
|
|
|
326
358
|
```sh
|
package/SKILL.md
CHANGED
|
@@ -162,15 +162,17 @@ without losing clicks. A reaction is durable state anyone can read back later.
|
|
|
162
162
|
- **Two pills pressed = no answer.** Changing your mind leaves both reactions in place, so
|
|
163
163
|
`ask` says so in the thread once and keeps waiting rather than guessing.
|
|
164
164
|
- **Exit codes** are the contract: `0` answered (the answer alone on stdout), `2` nobody
|
|
165
|
-
replied, `3` transport/config failure, `4`
|
|
166
|
-
|
|
165
|
+
replied, `3` transport/config failure, `4` a reply matched several choices (stdout
|
|
166
|
+
empty), `5` a **free-text reply** that picked none of the offered choices — the reply
|
|
167
|
+
text is on stdout. Everything human-facing goes to stderr, so
|
|
167
168
|
`ANS=$(slack ask … --wait)` is safe.
|
|
168
|
-
- **A reply that chooses nothing is not
|
|
169
|
-
reaction, the choice text, or its number
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
169
|
+
- **A reply that chooses nothing is delivered, but is not a decision.** When choices were
|
|
170
|
+
offered, only a reaction, the choice text, or its number is a decision (`0`). A reply
|
|
171
|
+
like 「背景を教えて」 or 「3 でなく X にして」 exits `5` at once with the text on stdout
|
|
172
|
+
— read it and act on it; do not treat it as a chosen option (measured 2026-09-04, a
|
|
173
|
+
question back returned as `rc=0` was stored as the decision). The question stays open,
|
|
174
|
+
so a pill pressed later still decides it: re-wait past the delivered reply with
|
|
175
|
+
`slack ask --waitFor='<permalink>' --after=<reply ts>` (stderr prints this line).
|
|
174
176
|
|
|
175
177
|
**Collecting an answer you did not block on.** Without `--wait`, stdout is a runnable
|
|
176
178
|
`slack ask --waitFor='<permalink>'`. Run it any time — it re-reads the question from Slack
|
|
@@ -184,6 +186,22 @@ This path is not optional convenience — **a pressed pill is invisible to `slac
|
|
|
184
186
|
which only sees `type: "message"` events and drops `message_changed`. Without `--waitFor`
|
|
185
187
|
an answer can be pressed and nobody ever hears about it.
|
|
186
188
|
|
|
189
|
+
### sent — what did I post, and which session posted it
|
|
190
|
+
|
|
191
|
+
Every `send`/`ask`/`poll`/`edit` is logged locally (`~/.config/slack-cli/sent.sqlite`)
|
|
192
|
+
with its sender: agent pid, cwd, git branch, agent CLI and session id. The same
|
|
193
|
+
attribution is attached as Slack message `metadata` (event_type `slack_term_sent`) —
|
|
194
|
+
invisible in the client, readable through the API from any machine.
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
slack sent "deploy" --since 2h # text substring, newest first
|
|
198
|
+
slack sent --kind ask --session <id-prefix> # this session's questions
|
|
199
|
+
slack sent --cwd . --json # everything posted from this repo, every field
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Read-only and token-free. `SLACK_TERM_ATTRIBUTION=off` disables both the log and the
|
|
203
|
+
metadata; `SLACK_TERM_AGENT_SESSION` / `_CLI` / `_PID` override what is detected.
|
|
204
|
+
|
|
187
205
|
### todo — tasks as reactions
|
|
188
206
|
|
|
189
207
|
A task is any message carrying the marker reaction 📌 `:pushpin:`. Progress lives in a
|
|
@@ -304,7 +322,7 @@ slack news --limit 1
|
|
|
304
322
|
- **`missing_scope`** — add the scope from the error, then click **Reinstall to Workspace** (scope changes require reinstall).
|
|
305
323
|
- **`token_revoked`** — app uninstalled; reinstall from the app page.
|
|
306
324
|
- **Token starts with `xoxb-`** — that's a Bot Token. Add scopes under **User Token Scopes** instead, reinstall, and copy the **User OAuth Token**.
|
|
307
|
-
- **`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
|
|
325
|
+
- **`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 firefox` on Ubuntu, `slack auth chrome` on macOS/Linux, or `SLACK_COOKIE=...`). Without the cookie it still fails with a clear "needs its session cookie" error.
|
|
308
326
|
- **`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.
|
|
309
327
|
- **Send is rejected with "use #channel or @user"** — the CLI enforces human-readable targets. Use `#channel-name` or `@display-name`, not raw IDs.
|
|
310
328
|
- **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).
|