slack-term 1.50.0 → 1.51.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slack-term",
3
- "version": "1.50.0",
3
+ "version": "1.51.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/snomiao/slack-term.git"
package/ts/botIntent.ts CHANGED
@@ -11,7 +11,7 @@
11
11
  /** Write commands, as `argv._` spells them (aliases included). Read-only
12
12
  * commands are never refused — reading as the user impersonates no one. */
13
13
  const WRITES = new Set([
14
- "send", "reply", "outbox flush", "ask", "poll", "vote", "edit", "tick", "delete", "react", "upload",
14
+ "send", "reply", "outbox flush", "inbox nudge", "ask", "poll", "vote", "edit", "tick", "delete", "react", "upload",
15
15
  "schedule send", "schedule rm",
16
16
  "pinlog new", "pinlog set", "pinlog note", "pinlog pin",
17
17
  "todo set", "todo flag",
package/ts/cli.ts CHANGED
@@ -56,7 +56,7 @@ import { keepLanePrefix, tickText } from "./tick.ts";
56
56
  import { applyIdentity, inAgent, listIdentities, splitWho, userSessionRefusal } from "./identity.ts";
57
57
  import { emojiMap, firstDifference, normText, storedAsSent } from "./readback.ts";
58
58
  import { choiceHint, choiceQuestionLang } from "./choiceHint.ts";
59
- import { addOutbox, deliver, listInbox, listOutbox, markDone, overdue, recordFailure, recordSent as recordOutboxSent } from "./inbox.ts";
59
+ import { addOutbox, deliver, listInbox, listOutbox, markDone, markNudged, overdue, recordFailure, recordSent as recordOutboxSent } from "./inbox.ts";
60
60
  import {
61
61
  POLL_KEYCAPS,
62
62
  POLL_MARKER,
@@ -6616,12 +6616,35 @@ async function main(): Promise<void> {
6616
6616
  )
6617
6617
  .command(
6618
6618
  "nudge",
6619
- "Pending messages older than settings' nudge_after_min (default 30): exit 1 when there are any",
6620
- (yy) => yy.option("json", { type: "boolean", default: false }),
6621
- (argv) => {
6622
- const items = overdue(findScope());
6623
- if (argv.json) console.log(JSON.stringify(items.map((i) => ({ file: i.file, ts: i.entry.ts, channel: i.entry.channel, permalink: i.entry.permalink, waiting_min: Math.round((Date.now() - i.mtimeMs) / 60_000) }))));
6624
- else for (const i of items) console.log(`${i.entry.ts}\t${Math.round((Date.now() - i.mtimeMs) / 60_000)} min\t${i.entry.permalink}`);
6619
+ "Pending messages older than settings' nudge_after_min (default 30): exit 1 when there are any; --eyes also puts šŸ‘€ on each, once",
6620
+ (yy) => yy
6621
+ .option("json", { type: "boolean", default: false })
6622
+ .option("eyes", { type: "boolean", default: false, describe: "React šŸ‘€ on each overdue message (once per message: recorded as nudged_at)" })
6623
+ .option("as-bot", { type: "boolean", describe: "React via the bot token (default: settings' as_bot)" }),
6624
+ async (argv) => {
6625
+ const scope = findScope();
6626
+ const items = overdue(scope);
6627
+ if (argv.eyes) {
6628
+ const asBot = argv["as-bot"] ?? readSettings(scope).as_bot ?? false;
6629
+ const token = asBot ? resolveBotToken() : tok(argv as W);
6630
+ if (!token) { console.error("Error: as_bot needs a bot token (SLACK_BOT_TOKEN)"); process.exit(1); }
6631
+ const cookie = asBot ? undefined : ck(argv as W);
6632
+ for (const i of items) {
6633
+ if (i.entry.nudged_at) continue;
6634
+ try {
6635
+ await reactionAdd(token, i.entry.channel, i.entry.ts, "eyes", cookie);
6636
+ } catch (e: unknown) {
6637
+ if (!/already_reacted/.test(e instanceof Error ? e.message : String(e))) {
6638
+ console.error(`⚠ ${i.entry.channel}:${i.entry.ts}: could not add šŸ‘€: ${friendlySlackError(e)}`);
6639
+ continue;
6640
+ }
6641
+ }
6642
+ markNudged(i);
6643
+ i.entry.nudged_at = new Date().toISOString();
6644
+ }
6645
+ }
6646
+ if (argv.json) console.log(JSON.stringify(items.map((i) => ({ file: i.file, ts: i.entry.ts, channel: i.entry.channel, permalink: i.entry.permalink, waiting_min: Math.round((Date.now() - i.mtimeMs) / 60_000), ...(i.entry.nudged_at ? { nudged_at: i.entry.nudged_at } : {}) }))));
6647
+ else for (const i of items) console.log(`${i.entry.ts}\t${Math.round((Date.now() - i.mtimeMs) / 60_000)} min\t${i.entry.permalink}${i.entry.nudged_at ? "\tšŸ‘€" : ""}`);
6625
6648
  if (items.length) process.exitCode = 1;
6626
6649
  },
6627
6650
  )
package/ts/inbox.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  // outbox/<name>.yml {to, text, in_reply_to?}. `slack outbox flush` sends
9
9
  // them (behind the --code gate) and moves each to sent/ with its ts and
10
10
  // permalink; a failure stays in outbox/ with `error` and `attempts`.
11
- import { existsSync, readdirSync, readFileSync, renameSync, statSync, unlinkSync } from "node:fs";
11
+ import { existsSync, readdirSync, readFileSync, renameSync, statSync, unlinkSync, utimesSync } from "node:fs";
12
12
  import { join } from "node:path";
13
13
  import { redact } from "./redact.ts";
14
14
  import { atomicWrite, readSettings, registeredScopes, setAlias, whoSubscribes, type Alias, type Scope } from "./scope.ts";
@@ -30,6 +30,8 @@ export type InboxEntry = {
30
30
  /** The subscription that routed it here. */
31
31
  alias: string;
32
32
  received_at: string;
33
+ /** When `slack inbox nudge --eyes` put šŸ‘€ on it: never twice. */
34
+ nudged_at?: string;
33
35
  };
34
36
 
35
37
  /** What a stream hands over (its StreamMatch, plus the attachment count). */
@@ -189,3 +191,12 @@ export function overdue(scope: Scope, nowMs = Date.now()): Listed<InboxEntry>[]
189
191
  const min = readSettings(scope).nudge_after_min ?? 30;
190
192
  return listInbox(scope).filter((i) => nowMs - i.mtimeMs >= min * 60_000);
191
193
  }
194
+
195
+ /** Record that an entry was nudged (šŸ‘€ added), so a later run skips it. */
196
+ export function markNudged(item: Listed<InboxEntry>, now = new Date()): void {
197
+ atomicWrite(item.file, yaml({ ...item.entry, nudged_at: now.toISOString() }));
198
+ // The file's mtime is when it arrived (`overdue` waits from it): keep it, or
199
+ // a nudged message would drop out of `nudge` for another nudge_after_min.
200
+ const t = new Date(item.mtimeMs);
201
+ utimesSync(item.file, t, t);
202
+ }