slack-term 1.39.2 → 1.41.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 +20 -4
- package/SKILL.md +66 -2
- package/dist/cli.js +227 -185
- package/package.json +1 -1
- package/ts/ask.ts +377 -45
- package/ts/cli.ts +1197 -38
- package/ts/slack.ts +68 -11
- package/ts/slackTodos.ts +85 -0
- package/ts/urlGuard.ts +162 -10
package/README.md
CHANGED
|
@@ -91,7 +91,7 @@ slack search "deploy" --count 50
|
|
|
91
91
|
slack send "#general" "Hello team"
|
|
92
92
|
# Prints who you're acting as (From: @handle (Uxxxx) — Workspace) + a destination
|
|
93
93
|
# preview + confirm code; rerun with --code=<code> to actually send. Every gated write
|
|
94
|
-
# (send/edit/delete/upload/schedule/channel create/lists/drafts) shows that From: line and
|
|
94
|
+
# (send/edit/delete/upload/schedule/channel create/rename/lists/drafts) shows that From: line and
|
|
95
95
|
# binds it into the code, so a profile switch mid-flow invalidates it instead of acting
|
|
96
96
|
# as the wrong account.
|
|
97
97
|
slack send "#general" "Hello team" --code=<code>
|
|
@@ -123,11 +123,15 @@ slack react "<permalink>" eyes --remove # take a reaction back
|
|
|
123
123
|
|
|
124
124
|
# Ask a question with its choices pre-seeded as 1️⃣..🔟 reactions — answering is
|
|
125
125
|
# one tap on an existing pill, no emoji picker. Same two-step confirm gate as send.
|
|
126
|
+
# A ❓ "その他 (other)" pill always follows the choices: pressing it means "none of
|
|
127
|
+
# these" and the answer comes as a reply (exit 5), not as the ❓ itself.
|
|
128
|
+
# The instructions are posted in ja or en: --lang / SLACK_TERM_LANG, else the
|
|
129
|
+
# answerers' Slack locale, else the question's own language, else $LANG, else ja.
|
|
126
130
|
slack ask "@bob" "本番に出してよい?" "出してよい" "待って"
|
|
127
131
|
# --wait blocks until answered and prints ONLY the answer on stdout, so it composes:
|
|
128
132
|
ANS=$(slack ask "@bob" "本番に出してよい?" "出してよい" "待って" --code=<code> --wait)
|
|
129
133
|
# 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 —
|
|
134
|
+
# 4 = a reply matched several choices, 6 = the question was voided, 5 = a free-text reply that picked NO choice —
|
|
131
135
|
# the reply text is on stdout, it is not a decision, and the question stays open.
|
|
132
136
|
#
|
|
133
137
|
# The question must say WHO may answer — only their reaction/reply is taken as the
|
|
@@ -138,8 +142,20 @@ slack ask "#eng" "@here 誰か見れる?" "見る" "あとで" # anyo
|
|
|
138
142
|
#
|
|
139
143
|
# With no choices the question asks for a free-text reply and the reply is the answer.
|
|
140
144
|
# In a DM a plain reply counts; in a channel only reactions and thread replies do.
|
|
141
|
-
# Once answered, the question is edited to "✅ …回答済み > <answer>"
|
|
142
|
-
#
|
|
145
|
+
# Once answered, the question is edited to "✅ …回答済み > <answer>" — the body/background
|
|
146
|
+
# and the CHOSEN option line stay; the other options, ❓ line and instructions go. The
|
|
147
|
+
# unpressed seeds are removed, leaving the chosen pill visible.
|
|
148
|
+
#
|
|
149
|
+
# Thread notes (audience replies that are not the answer, even after ✅) go to
|
|
150
|
+
# stderr; --json puts {answer, notes[], cursor} on stdout. Feed cursor back as --after:
|
|
151
|
+
# slack ask --waitFor='<permalink>' --timeout 0 --json --after=<cursor>
|
|
152
|
+
#
|
|
153
|
+
# Retire a question that expired / stopped meaning anything (無効化) — waits on it exit 6:
|
|
154
|
+
# slack ask --void='<permalink>' --reason 'head moved' --superseded-by '<new permalink>'
|
|
155
|
+
# Change one: slack ask --edit='<permalink>' ["new question" [choices…]] [--body …]
|
|
156
|
+
# (options only while unanswered; after that: --void='<permalink>' --reask …)
|
|
157
|
+
# List mine with live state: slack ask --ls [--stale 24h] [--state all] [--json]
|
|
158
|
+
# (`slack edit` refuses an edit that would break an ask/poll; --force overrides.)
|
|
143
159
|
#
|
|
144
160
|
# WITHOUT --wait, stdout is the command that collects the answer later:
|
|
145
161
|
RESUME=$(slack ask "@bob" "本番に出してよい?" "出してよい" "待って" --code=<code>)
|
package/SKILL.md
CHANGED
|
@@ -120,7 +120,7 @@ plus `[as bot]` under `--as-bot`) and the resolved destination (`→ ... — THR
|
|
|
120
120
|
`→ ... — NEW top-level message`); verify both before re-running with `--code`.
|
|
121
121
|
|
|
122
122
|
**Every** gated write opens its preview with that same `From:` line — `send`, `edit`,
|
|
123
|
-
`delete`, `upload`, `schedule send`, `schedule rm`, `channel create`, `lists create/add/set/share`, `drafts edit`,
|
|
123
|
+
`delete`, `upload`, `schedule send`, `schedule rm`, `channel create`, `channel rename`, `lists create/add/set/share`, `drafts edit`,
|
|
124
124
|
`drafts delete` — and the identity is part of the confirm hash: switching
|
|
125
125
|
profile/token between preview and confirm invalidates the code instead of acting as
|
|
126
126
|
someone else. It matters most on `schedule send`, where the message goes out later,
|
|
@@ -162,11 +162,19 @@ without losing clicks. A reaction is durable state anyone can read back later.
|
|
|
162
162
|
the other party counts automatically.
|
|
163
163
|
- **Answer paths**: a pill, or free text. In a DM a plain reply counts; in a channel only
|
|
164
164
|
reactions and thread replies do (a channel carries unrelated traffic).
|
|
165
|
+
- **❓ is the standing "other" choice.** Every question with choices lists it last
|
|
166
|
+
(`1️⃣ … 2️⃣ … 3️⃣ … ❓ その他 — スレッドで返信`) and seeds it after the keycaps. Pressing it
|
|
167
|
+
is not an answer — `--wait` notes it on stderr and keeps waiting for the reply, which
|
|
168
|
+
arrives as free text (exit `5`).
|
|
169
|
+
- **The instructions are posted in `ja` or `en`.** `--lang` (or `SLACK_TERM_LANG`) decides;
|
|
170
|
+
otherwise the answerers' Slack locale when they all share one, else the language the
|
|
171
|
+
question is written in, else the system locale, else `ja`. The confirm gate prints the
|
|
172
|
+
choice and why (`Language: en (answerers' Slack locale; …)`). `--waitFor` reads either.
|
|
165
173
|
- **Two pills pressed = no answer.** Changing your mind leaves both reactions in place, so
|
|
166
174
|
`ask` says so in the thread once and keeps waiting rather than guessing.
|
|
167
175
|
- **Exit codes** are the contract: `0` answered (the answer alone on stdout), `2` nobody
|
|
168
176
|
replied, `3` transport/config failure, `4` a reply matched several choices (stdout
|
|
169
|
-
empty), `5` a **free-text reply** that picked none of the offered choices — the reply
|
|
177
|
+
empty), `6` the question was **voided** (stop waiting), `5` a **free-text reply** that picked none of the offered choices — the reply
|
|
170
178
|
text is on stdout. Everything human-facing goes to stderr, so
|
|
171
179
|
`ANS=$(slack ask … --wait)` is safe.
|
|
172
180
|
- **A reply that chooses nothing is delivered, but is not a decision.** When choices were
|
|
@@ -177,6 +185,46 @@ without losing clicks. A reaction is durable state anyone can read back later.
|
|
|
177
185
|
so a pill pressed later still decides it: re-wait past the delivered reply with
|
|
178
186
|
`slack ask --waitFor='<permalink>' --after=<reply ts>` (stderr prints this line).
|
|
179
187
|
|
|
188
|
+
**Thread notes ride along with the answer.** A reply from the audience that is not the
|
|
189
|
+
answer (「あと cswap ls も見て」 next to a pressed pill) is a *note*. Notes are read even when
|
|
190
|
+
a pill answered, and again on every `--waitFor` of a ✅ question, so a note written after
|
|
191
|
+
the answer still reaches you. Plain mode: stdout is still the answer alone, and the notes go
|
|
192
|
+
to stderr. `--json`: stdout is one object
|
|
193
|
+
`{status, answer, how, who, notes:[{ts,user,text,permalink}], cursor, permalink}`, with the same
|
|
194
|
+
exit codes. Pass `cursor` back as `--after` on your next `--waitFor --timeout 0` and you
|
|
195
|
+
never get the same note twice. Only the question's audience counts; the asker, bots and
|
|
196
|
+
bystanders are never notes.
|
|
197
|
+
|
|
198
|
+
**Answering keeps the context.** The ✅ rewrite keeps the question's body (its background)
|
|
199
|
+
and the chosen option; only the options not chosen, the ❓ line and the instructions go.
|
|
200
|
+
The head is unchanged (`:white_check_mark:` prefix, question, stamp, quoted answer), so
|
|
201
|
+
anything that keys on the prefix or re-reads the answer works on old and new ✅ bodies alike.
|
|
202
|
+
|
|
203
|
+
**Voiding a question (無効化).** When a question has expired or stopped meaning anything
|
|
204
|
+
(the head it was pinned to moved, the decision was made elsewhere), retire it:
|
|
205
|
+
`slack ask --void='<permalink>' --reason '…' [--superseded-by '<new permalink>']`
|
|
206
|
+
(repeatable `--void=`; alias `slack ask void <link…>`; same `--code` gate; own questions
|
|
207
|
+
only, `--as-bot` for the bot's). The text becomes `:no_entry_sign:` + reason with the body
|
|
208
|
+
kept, our pills come off, and a 🚫 reaction is added. Three states, three prefixes:
|
|
209
|
+
`:question:` open, `:white_check_mark:` answered, `:no_entry_sign:` void. `--wait` /
|
|
210
|
+
`--waitFor` on a void question **exit 6** (`--json` → `status: "void"`): stop waiting.
|
|
211
|
+
Answered questions cannot be voided.
|
|
212
|
+
|
|
213
|
+
**Changing a question: `--edit`, not `slack edit`.**
|
|
214
|
+
`slack ask --edit='<permalink>' ["new question" [choices…]] [--body …]` rebuilds it with the
|
|
215
|
+
ask layout (same `--code` gate), so collect still reads it. Wording can change any time;
|
|
216
|
+
the **options** only while nobody has answered. After that, re-ask it:
|
|
217
|
+
`slack ask --void='<permalink>' --reask [--reason …] ["new question" [choices…]]` posts the
|
|
218
|
+
question again in the same place (old text/choices/body unless you give new ones) and voids
|
|
219
|
+
the old one as replaced by it — one gate for both. Plain `slack edit` refuses an edit that
|
|
220
|
+
would break an ask/poll (text no longer readable, or an answered/void question made open
|
|
221
|
+
again); edits that keep it readable — e.g. a script writing the ✅ form — pass as usual.
|
|
222
|
+
|
|
223
|
+
**What did I ask, and what became of it.** `slack ask --ls` lists your asks from the local
|
|
224
|
+
sent-log with their LIVE state (`--state open|answered|void|all`, default open; `--channel`;
|
|
225
|
+
`--json`). `--ls --stale 24h` = open and older than 24h, and prints the one `--void=` command
|
|
226
|
+
that would retire them all (behind the usual gate). Only asks sent from this machine.
|
|
227
|
+
|
|
180
228
|
**Collecting an answer you did not block on.** Without `--wait`, stdout is a runnable
|
|
181
229
|
`slack ask --waitFor='<permalink>'`. Run it any time — it re-reads the question from Slack
|
|
182
230
|
and recovers everything it needs by parsing the message, so nothing is stored locally and
|
|
@@ -275,6 +323,22 @@ Reason flags stack independently of progress and of each other: ❗ `exclamation
|
|
|
275
323
|
`slack thread`/`slack read` before replying to avoid duplicates; consolidate multiple
|
|
276
324
|
points into one message.
|
|
277
325
|
|
|
326
|
+
### todos — Slack's To-dos tab (read-only)
|
|
327
|
+
|
|
328
|
+
Not `slack todo`: that tracks tasks as reactions. `slack todos` reads Slack's own
|
|
329
|
+
**personal** To-dos tab (the successor of "Later"), the list in the sidebar.
|
|
330
|
+
|
|
331
|
+
```bash
|
|
332
|
+
slack todos # open to-dos, soonest due first (OVERDUE marked)
|
|
333
|
+
slack todos --filter completed # also: saved (everything saved), archived
|
|
334
|
+
slack todos --json -n 20 # one object per item: due, done, permalink, text
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
There is no public API: it uses the desktop client's internal `saved.list`, so
|
|
338
|
+
it needs the **xoxc session** (`slack auth login`) and shows only your own
|
|
339
|
+
to-dos. Bots can't see them. Slack can change this endpoint without notice.
|
|
340
|
+
Adding and completing to-dos is not supported yet.
|
|
341
|
+
|
|
278
342
|
## Output formatting
|
|
279
343
|
|
|
280
344
|
- DM channels render as `@DisplayName`; public channels as `#channel-name`.
|