slack-term 1.17.0 → 1.18.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 +5 -3
- package/dist/cli.js +2 -2
- package/package.json +1 -1
- package/ts/cli.ts +7 -4
package/README.md
CHANGED
|
@@ -66,10 +66,12 @@ slack send "#general" "Hello team" --code=<code>
|
|
|
66
66
|
slack send "#general:1700000000.000100" "Replying in thread"
|
|
67
67
|
slack send "https://acme.slack.com/archives/C0123456789/p1700000000000100" "Replying in thread"
|
|
68
68
|
|
|
69
|
-
#
|
|
69
|
+
# @handle tokens are auto-converted to real <@USERID> mentions (on by default; also on `edit`).
|
|
70
70
|
# Resolves via users.list, then the channel's members so Slack Connect guests work;
|
|
71
|
-
# any handle that can't be resolved is left as plain text.
|
|
72
|
-
|
|
71
|
+
# any handle that can't be resolved is left as plain text. The confirm preview shows
|
|
72
|
+
# the converted message before sending. Use --no-mentions to keep @text literal.
|
|
73
|
+
slack send "#general" "thanks @t.matsuda19790127 and @taku"
|
|
74
|
+
slack send "#general" "ping @ops on call" --no-mentions # leave @ops as plain text
|
|
73
75
|
|
|
74
76
|
# Edit or delete a sent message (same confirm-code gate)
|
|
75
77
|
slack edit "<permalink>" "fixed wording"
|
package/dist/cli.js
CHANGED
|
@@ -147,11 +147,11 @@ Set it with: slack workspace set-cookie <workspace-name> <xoxd-value>
|
|
|
147
147
|
`).join(`
|
|
148
148
|
`)}`:J;if(typeof J!=="object")return String(J);if(Array.isArray(J))return J.map((W)=>`
|
|
149
149
|
${O} - ${Q(W,O+" ")}`).join("");return Object.entries(J).map(([W,H])=>`
|
|
150
|
-
${O} ${W}: ${Q(H,O+" ")}`).join("")};console.log("---");for(let[J,O]of Object.entries(G))console.log(`${J}: ${Q(O)}`)}return}let Z=Intl.DateTimeFormat().resolvedOptions().timeZone;for(let G of z){let Q=y(G.profile),J=String(G.name??G.id),O=String(G.id??""),W=String(Q.display_name||""),H=String(Q.real_name||""),Y=String(Q.email||""),q=String(G.tz??""),N=[...new Set([W,H].filter((c)=>c&&c!==J))].join(" / "),w=[Y,q&&q!==Z?q:""].filter(Boolean).join(" ");console.log(`@${J} ${O} ${N}${w?" "+w:""}`)}}).command("get <user>","Show user details",(E)=>E.positional("user",{type:"string",demandOption:!0,describe:"@handle or user ID"}),async(E)=>{let C=D(E),B=E.user.startsWith("@")?E.user.slice(1):E.user,$=B;if(!/^U[A-Z0-9]+$/.test(B)){let w=await N0(C),c=a(w.members).map(y).find((e)=>String(e.name??"")===B);if(!c)console.error(`User not found: @${B}`),process.exit(1);$=String(c.id)}let z=y(await N1(C,$)),Z=y(z.user),G=y(Z.profile),Q=Intl.DateTimeFormat().resolvedOptions().timeZone,J=String(Z.name??$),O=String(Z.id??$),W=String(G.display_name||""),H=String(G.real_name||""),Y=String(G.email||""),q=String(Z.tz??""),j=String(G.phone||""),N=String(G.title||"");console.log(`@${J} ${O}`);let k=[...new Set([W,H].filter((w)=>w&&w!==J))];if(k.length)console.log(`name: ${k.join(" / ")}`);if(Y)console.log(`email: ${Y}`);if(j)console.log(`phone: ${j}`);if(N)console.log(`title: ${N}`);if(q&&q!==Q)console.log(`tz: ${q}`)}).demandCommand(1,"").showHelpOnFail(!0)).command("news","Activity feed (mentions to you)",(F)=>F.option("limit",{alias:"l",type:"number",default:20}),async(F)=>{await u7(D(F),F.limit)}).command("search <query>","Full-text search",(F)=>F.positional("query",{type:"string",demandOption:!0}).option("count",{alias:"n",type:"number",default:100}).option("json",{type:"boolean",default:!1,describe:"Output raw JSON"}),async(F)=>{await E7(D(F),F.query,F.count,F.json)}).command("send <target> <message>","Send a message (confirm-hash safety gate)",(F)=>F.positional("target",{type:"string",demandOption:!0,describe:"#chan, @user, #chan:thread_ts, or permalink (a message permalink replies in its thread)"}).positional("message",{type:"string",demandOption:!0}).option("code",{type:"string",describe:"Safety hash to confirm send"}).option("channel-id",{type:"string",describe:"Raw channel ID"}).option("user-id",{type:"string",describe:"Raw user ID (opens DM)"}).option("as-bot",{type:"boolean",default:!1,describe:"Send via the bot token (xoxb / SLACK_BOT_TOKEN) so a DM notifies the recipient and can be two-way"}).option("broadcast",{type:"boolean",default:!1,describe:`Also send to channel: broadcast a threaded reply back to the channel (Slack's "Also send to #channel" checkbox). Only effective with a thread target.`}).option("mentions",{type:"boolean",default:!
|
|
150
|
+
${O} ${W}: ${Q(H,O+" ")}`).join("")};console.log("---");for(let[J,O]of Object.entries(G))console.log(`${J}: ${Q(O)}`)}return}let Z=Intl.DateTimeFormat().resolvedOptions().timeZone;for(let G of z){let Q=y(G.profile),J=String(G.name??G.id),O=String(G.id??""),W=String(Q.display_name||""),H=String(Q.real_name||""),Y=String(Q.email||""),q=String(G.tz??""),N=[...new Set([W,H].filter((c)=>c&&c!==J))].join(" / "),w=[Y,q&&q!==Z?q:""].filter(Boolean).join(" ");console.log(`@${J} ${O} ${N}${w?" "+w:""}`)}}).command("get <user>","Show user details",(E)=>E.positional("user",{type:"string",demandOption:!0,describe:"@handle or user ID"}),async(E)=>{let C=D(E),B=E.user.startsWith("@")?E.user.slice(1):E.user,$=B;if(!/^U[A-Z0-9]+$/.test(B)){let w=await N0(C),c=a(w.members).map(y).find((e)=>String(e.name??"")===B);if(!c)console.error(`User not found: @${B}`),process.exit(1);$=String(c.id)}let z=y(await N1(C,$)),Z=y(z.user),G=y(Z.profile),Q=Intl.DateTimeFormat().resolvedOptions().timeZone,J=String(Z.name??$),O=String(Z.id??$),W=String(G.display_name||""),H=String(G.real_name||""),Y=String(G.email||""),q=String(Z.tz??""),j=String(G.phone||""),N=String(G.title||"");console.log(`@${J} ${O}`);let k=[...new Set([W,H].filter((w)=>w&&w!==J))];if(k.length)console.log(`name: ${k.join(" / ")}`);if(Y)console.log(`email: ${Y}`);if(j)console.log(`phone: ${j}`);if(N)console.log(`title: ${N}`);if(q&&q!==Q)console.log(`tz: ${q}`)}).demandCommand(1,"").showHelpOnFail(!0)).command("news","Activity feed (mentions to you)",(F)=>F.option("limit",{alias:"l",type:"number",default:20}),async(F)=>{await u7(D(F),F.limit)}).command("search <query>","Full-text search",(F)=>F.positional("query",{type:"string",demandOption:!0}).option("count",{alias:"n",type:"number",default:100}).option("json",{type:"boolean",default:!1,describe:"Output raw JSON"}),async(F)=>{await E7(D(F),F.query,F.count,F.json)}).command("send <target> <message>","Send a message (confirm-hash safety gate)",(F)=>F.positional("target",{type:"string",demandOption:!0,describe:"#chan, @user, #chan:thread_ts, or permalink (a message permalink replies in its thread)"}).positional("message",{type:"string",demandOption:!0}).option("code",{type:"string",describe:"Safety hash to confirm send"}).option("channel-id",{type:"string",describe:"Raw channel ID"}).option("user-id",{type:"string",describe:"Raw user ID (opens DM)"}).option("as-bot",{type:"boolean",default:!1,describe:"Send via the bot token (xoxb / SLACK_BOT_TOKEN) so a DM notifies the recipient and can be two-way"}).option("broadcast",{type:"boolean",default:!1,describe:`Also send to channel: broadcast a threaded reply back to the channel (Slack's "Also send to #channel" checkbox). Only effective with a thread target.`}).option("mentions",{type:"boolean",default:!0,describe:"Convert @handle tokens to real <@USERID> mentions (on by default; resolves via users.list, then channel members for Slack Connect guests). Unresolved handles stay as plain text. The confirm preview shows the converted message before sending. Disable with --no-mentions for literal @text."}),async(F)=>{let E={target:F.target,message:F.message};if(F.code)E.code=F.code;if(F["channel-id"])E.channelId=F["channel-id"];if(F["user-id"])E.userId=F["user-id"];if(F.broadcast)E.broadcast=!0;if(F.mentions!==!1)E.mentions=!0,E.mentionToken=D(F);let C;if(F["as-bot"]){let B=G0();if(!B)console.error(`Error: --as-bot needs a bot token, but no xoxb- token was found.
|
|
151
151
|
Set SLACK_BOT_TOKEN=xoxb-... in ~/.config/slack-cli/.env (or your shell).`),process.exit(1);if(!E.channelId&&!E.userId&&E.target.startsWith("@"))try{E.userId=await K1(D(F),E.target)}catch($){console.error(`Error: could not resolve ${E.target} to a user for the bot DM.
|
|
152
152
|
${$ instanceof Error?$.message:String($)}
|
|
153
153
|
Tip: pass --user-id <Uxxxx> to skip the lookup.`),process.exit(1)}C=B,E.asBot=!0}else C=D(F);try{await Q7(C,E)}catch(B){console.error(B instanceof Error?B.message:String(B)),process.exit(1)}}).command("doctor","Check the bot token (xoxb) can carry a two-way DM (scopes + Messages Tab)",(F)=>F,async()=>{let F=G0();if(!F)console.error(`Error: slack doctor checks the bot token, but no xoxb- token was found.
|
|
154
|
-
Set SLACK_BOT_TOKEN=xoxb-... in ~/.config/slack-cli/.env (or your shell).`),process.exit(1);await O7(F)}).command("schedule","Manage scheduled messages",(F)=>F.command("send <target> <message>","Schedule a message for later delivery",(E)=>E.positional("target",{type:"string",demandOption:!0,describe:"#chan, @user, #chan:thread_ts, or permalink (a message permalink replies in its thread)"}).positional("message",{type:"string",demandOption:!0}).option("at",{type:"string",demandOption:!0,describe:"Delivery time (ISO datetime or Unix ts)"}).option("code",{type:"string",describe:"Safety hash to confirm"}).option("channel-id",{type:"string",describe:"Raw channel ID"}).option("user-id",{type:"string",describe:"Raw user ID (opens DM)"}),async(E)=>{let C={target:E.target,message:E.message,at:E.at};if(E.code)C.code=E.code;if(E["channel-id"])C.channelId=E["channel-id"];if(E["user-id"])C.userId=E["user-id"];await W7(D(E),C)}).command(["ls","list"],"List pending scheduled messages",(E)=>E.positional("target",{type:"string",describe:"#channel to filter by"}).option("channel-id",{type:"string",describe:"Raw channel ID"}),async(E)=>{await H7(D(E),E.target,E["channel-id"])}).command("rm <target> <id>","Delete a scheduled message",(E)=>E.positional("target",{type:"string",demandOption:!0,describe:"#channel or @user"}).positional("id",{type:"string",demandOption:!0,describe:"Scheduled message ID"}).option("code",{type:"string",describe:"Safety hash to confirm"}).option("channel-id",{type:"string",describe:"Raw channel ID"}),async(E)=>{let C={target:E.target,id:E.id};if(E.code)C.code=E.code;if(E["channel-id"])C.channelId=E["channel-id"];await V7(D(E),C)}).demandCommand(1,"").showHelpOnFail(!0),()=>{}).command("edit <target> <newText>","Edit a sent message",(F)=>F.positional("target",{type:"string",demandOption:!0,describe:"#chan:ts, @user:ts, or permalink"}).positional("newText",{type:"string",demandOption:!0}).option("code",{type:"string",describe:"Safety hash to confirm edit"}).option("channel-id",{type:"string",describe:"Raw channel ID"}).option("mentions",{type:"boolean",default:!
|
|
154
|
+
Set SLACK_BOT_TOKEN=xoxb-... in ~/.config/slack-cli/.env (or your shell).`),process.exit(1);await O7(F)}).command("schedule","Manage scheduled messages",(F)=>F.command("send <target> <message>","Schedule a message for later delivery",(E)=>E.positional("target",{type:"string",demandOption:!0,describe:"#chan, @user, #chan:thread_ts, or permalink (a message permalink replies in its thread)"}).positional("message",{type:"string",demandOption:!0}).option("at",{type:"string",demandOption:!0,describe:"Delivery time (ISO datetime or Unix ts)"}).option("code",{type:"string",describe:"Safety hash to confirm"}).option("channel-id",{type:"string",describe:"Raw channel ID"}).option("user-id",{type:"string",describe:"Raw user ID (opens DM)"}),async(E)=>{let C={target:E.target,message:E.message,at:E.at};if(E.code)C.code=E.code;if(E["channel-id"])C.channelId=E["channel-id"];if(E["user-id"])C.userId=E["user-id"];await W7(D(E),C)}).command(["ls","list"],"List pending scheduled messages",(E)=>E.positional("target",{type:"string",describe:"#channel to filter by"}).option("channel-id",{type:"string",describe:"Raw channel ID"}),async(E)=>{await H7(D(E),E.target,E["channel-id"])}).command("rm <target> <id>","Delete a scheduled message",(E)=>E.positional("target",{type:"string",demandOption:!0,describe:"#channel or @user"}).positional("id",{type:"string",demandOption:!0,describe:"Scheduled message ID"}).option("code",{type:"string",describe:"Safety hash to confirm"}).option("channel-id",{type:"string",describe:"Raw channel ID"}),async(E)=>{let C={target:E.target,id:E.id};if(E.code)C.code=E.code;if(E["channel-id"])C.channelId=E["channel-id"];await V7(D(E),C)}).demandCommand(1,"").showHelpOnFail(!0),()=>{}).command("edit <target> <newText>","Edit a sent message",(F)=>F.positional("target",{type:"string",demandOption:!0,describe:"#chan:ts, @user:ts, or permalink"}).positional("newText",{type:"string",demandOption:!0}).option("code",{type:"string",describe:"Safety hash to confirm edit"}).option("channel-id",{type:"string",describe:"Raw channel ID"}).option("mentions",{type:"boolean",default:!0,describe:"Convert @handle tokens in the new text to real <@USERID> mentions (on by default). Unresolved handles stay as plain text. Disable with --no-mentions for literal @text."}),async(F)=>{let E={target:F.target,newText:F.newText};if(F.code)E.code=F.code;if(F["channel-id"])E.channelId=F["channel-id"];if(F.mentions!==!1)E.mentions=!0;await Z7(D(F),E)}).command("delete <target>","Delete a sent message (confirm-hash safety gate)",(F)=>F.positional("target",{type:"string",demandOption:!0,describe:"#chan:ts, @user:ts, or permalink"}).option("code",{type:"string",describe:"Safety hash to confirm delete"}).option("channel-id",{type:"string",describe:"Raw channel ID"}),async(F)=>{let E={target:F.target};if(F.code)E.code=F.code;if(F["channel-id"])E.channelId=F["channel-id"];await J7(D(F),E)}).command("upload <target> <file..>","Upload one or more files to a channel or DM",(F)=>F.positional("target",{type:"string",demandOption:!0,describe:"#chan, @user, #chan:thread_ts, or permalink (a message permalink replies in its thread)"}).positional("file",{type:"string",array:!0,demandOption:!0,describe:"Path(s) to file(s)"}).option("title",{type:"string",describe:"Title (single file only)"}).option("comment",{type:"string",describe:"Initial comment (first file)"}).option("code",{type:"string",describe:"4-hex safety code to confirm upload"}).option("channel-id",{type:"string"}).option("user-id",{type:"string"}),async(F)=>{let E={target:F.target,filePaths:F.file};if(F.title)E.title=F.title;if(F.comment)E.comment=F.comment;if(F.code)E.code=F.code;if(F["channel-id"])E.channelId=F["channel-id"];if(F["user-id"])E.userId=F["user-id"];await M7(D(F),E)}).command("dump","Bulk export channel history as markdown",(F)=>F.option("days",{alias:"d",type:"number",default:7,describe:"Days of history"}).option("limit",{alias:"l",type:"number",default:200}).option("filter",{alias:"f",type:"string",describe:"Filter channel names"}),async(F)=>{await C7(D(F),F.days,F.limit,F.filter)}).command("drafts","Manage message drafts (requires xoxc desktop token)",(F)=>F.command(["$0","ls","list"],"List pending drafts",(E)=>E.option("all",{alias:"a",type:"boolean",default:!1,describe:"Include sent drafts"}),async(E)=>{await $7(D(E),u(E),E.all)}).command(["new <channel> [text..]","save <channel> [text..]"],"Create a draft",(E)=>E.positional("channel",{type:"string",demandOption:!0}).positional("text",{type:"string",array:!0,default:[]}),async(E)=>{let C=D(E),B=u(E),$=E.text.join(" ");if(!$)console.error("Usage: slack drafts new <#channel|@user> <text>"),process.exit(2);let z=await ND(C,E.channel,B),Z=await j1(C,z,$,B);console.log(`\u2713 Draft created (id: ${y(Z.draft).id??"?"})`)}).command("get <id>","Show a draft",(E)=>E.positional("id",{type:"string",demandOption:!0}),async(E)=>{await z7(D(E),u(E),E.id)}).command(["edit <id> [text..]","update <id> [text..]"],"Edit a draft",(E)=>E.positional("id",{type:"string",demandOption:!0}).positional("text",{type:"string",array:!0,default:[]}).option("code",{type:"string"}),async(E)=>{let C=D(E),B=u(E),$=E.text.join(" ");if(!$)console.error("Usage: slack drafts edit <id> <new-text>"),process.exit(2);let z=await yu(C,B),Z=a(z.drafts).map(y).find((O)=>String(O.id)===E.id);if(!Z)console.error(`Draft not found: ${E.id}`),process.exit(1);let G=jF(Z),Q=iD(G,$);if(E.code!==Q)nD(E.code,Q,["--- Current draft ----------------------------",...G.split(`
|
|
155
155
|
`).map((O)=>` ${O}`),"--- Replacing with ---------------------------",...$.split(`
|
|
156
156
|
`).map((O)=>` ${O}`),"--------------------------------\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"]);let J=await A1(C,E.id,b0(Z),$,B);console.log(`\u2713 Draft updated (id: ${y(J.draft).id??"?"})`)}).command(["delete <id>","rm <id>"],"Delete a draft",(E)=>E.positional("id",{type:"string",demandOption:!0}).option("code",{type:"string"}),async(E)=>{let C=D(E),B=u(E),$=await yu(C,B),z=a($.drafts).map(y).find((Q)=>String(Q.id)===E.id);if(!z)console.error(`Draft not found: ${E.id}`),process.exit(1);let Z=jF(z),G=iD(E.id,Z);if(E.code!==G)nD(E.code,G,["\u2500-- Deleting draft \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",` id: ${E.id}`,...Z.split(`
|
|
157
157
|
`).map((Q)=>` ${Q}`),"--------------------------------\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"]);await R1(C,E.id,B),console.log(`\u2713 Draft deleted (id: ${E.id})`)})).command("auth","Authentication and workspace management",(F)=>F.command("token","Add a workspace \u2014 paste an existing xoxp-/xoxb- token",(E)=>E.option("token",{type:"string",describe:"Token to save directly (non-interactive)"}).option("name",{type:"string",describe:"Workspace name (used with --token)"}),async(E)=>{await D1({...E.token!==void 0?{token:E.token}:{},...E.name!==void 0?{name:E.name}:{}})}).command("app","Create a new Slack app and obtain a token (guided wizard)",(E)=>E.option("bot",{type:"boolean",describe:"Create a bot token (xoxb-) instead of user (xoxp-)"}),async(E)=>{await u1({...E.bot!==void 0?{bot:E.bot}:{}})}).command("login","Interactive auth wizard (all auth methods: desktop app, token, new app)",(E)=>E.option("token",{type:"string",describe:"Token to save directly (non-interactive)"}).option("name",{type:"string",describe:"Workspace name (used with --token)"}),async(E)=>{await VF({...E.token!==void 0?{token:E.token}:{},...E.name!==void 0?{name:E.name}:{}})}).command(["ls","status"],"Show auth status",()=>{},()=>{let E=K8();if(E.length===0){console.log("No workspaces configured. Run: slack auth login");return}for(let{name:C,profile:B,current:$}of E)console.log(`${$?"* ":" "}${C} ${B.team} (${B.user}) ${B.url??""}`)}).command("use <name>","Switch active workspace",(E)=>E.positional("name",{type:"string",demandOption:!0}).option("g",{type:"boolean",default:!1,describe:"Write global lockfile (~/.slack-cli/workspace)"}),(E)=>{if(!E.g)l6(Wu(process.cwd(),".slack-cli"));A8(E.name,E.g),console.log(`Switched to workspace "${E.name}" ${E.g?"globally":"locally"}`)}).command(["logout <name>","rm <name>","remove <name>"],"Remove a workspace",(E)=>E.positional("name",{type:"string",demandOption:!0}),(E)=>{j8(E.name),console.log(`Removed workspace "${E.name}"`)}).command(["chrome","cookie"],"Attach Chrome browser xoxd cookie to a workspace (macOS, interactive)",(E)=>E.option("workspace",{type:"string",alias:"w",describe:"Workspace name to update (default: active)"}),async(E)=>{await a8({...E.workspace!==void 0?{workspace:E.workspace}:{}})}).command("firefox","Attach Firefox browser xoxd cookie to a workspace (all platforms)",(E)=>E.option("workspace",{type:"string",alias:"w",describe:"Workspace name to update (default: active)"}),async(E)=>{await e8({...E.workspace!==void 0?{workspace:E.workspace}:{}})}).command("$0",!1,()=>{},()=>{F.showHelp(),process.exit(0)})).command("tail [target]","Stream new messages in real time (like tail -f)",(F)=>F.positional("target",{type:"string",describe:"#channel or @user to follow"}).option("since",{type:"string",describe:"Backfill from N ago (e.g. 10m, 2h, 1d)"}).option("thread",{type:"string",describe:"Follow a single thread by timestamp"}).option("watch-thread",{type:"string",describe:"Watch the channel's top-level timeline AND one thread's replies together (ts or permalink)"}).option("me",{type:"boolean",default:!1,describe:"Filter to messages that mention you"}).option("interval",{type:"number",default:60000,describe:"Poll interval in ms (default 60s; use --interval=3000 for near-real-time)"}).option("timeout",{type:"string",describe:"Auto-stop after this long (e.g. 30m, 2h). Exit code 0 even if nothing arrived."}).option("exit-on-message",{type:"boolean",default:!1,describe:"Stop as soon as the first new message from someone else arrives (wait-for-reply)"}).option("rtm",{type:"boolean",default:!0,describe:"Use RTM WebSocket when available (xoxc + cookie); pass --no-rtm to force polling"}),async(F)=>{let E=D(F),C=u(F),B=new AbortController;process.on("SIGINT",()=>{B.abort(),process.exit(0)}),await G1(E,F.target,{...F.since!==void 0?{since:F.since}:{},...F.thread!==void 0?{thread:F.thread}:{},...F["watch-thread"]!==void 0?{watchThread:F["watch-thread"]}:{},me:F.me,interval:F.interval,...F.timeout!==void 0?{timeout:F.timeout}:{},...F["exit-on-message"]===!0?{exitOnMessage:!0}:{},...C!==void 0?{cookie:C}:{},...F.rtm===!1?{noRtm:!0}:{}},B.signal)}).command("login",!1,(F)=>F.option("token",{type:"string"}).option("name",{type:"string"}),async(F)=>{await VF({...F.token!==void 0?{token:F.token}:{},...F.name!==void 0?{name:F.name}:{}})}).demandCommand(1,"Specify a command. Run with --help for usage.").strict().help().alias("help","h").parseAsync()}U7().catch((D)=>{console.error(D instanceof Error?D.message:String(D)),process.exit(1)});
|
package/package.json
CHANGED
package/ts/cli.ts
CHANGED
|
@@ -1264,14 +1264,17 @@ async function main(): Promise<void> {
|
|
|
1264
1264
|
.option("user-id", { type: "string", describe: "Raw user ID (opens DM)" })
|
|
1265
1265
|
.option("as-bot", { type: "boolean", default: false, describe: "Send via the bot token (xoxb / SLACK_BOT_TOKEN) so a DM notifies the recipient and can be two-way" })
|
|
1266
1266
|
.option("broadcast", { type: "boolean", default: false, describe: "Also send to channel: broadcast a threaded reply back to the channel (Slack's \"Also send to #channel\" checkbox). Only effective with a thread target." })
|
|
1267
|
-
.option("mentions", { type: "boolean", default:
|
|
1267
|
+
.option("mentions", { type: "boolean", default: true, describe: "Convert @handle tokens to real <@USERID> mentions (on by default; resolves via users.list, then channel members for Slack Connect guests). Unresolved handles stay as plain text. The confirm preview shows the converted message before sending. Disable with --no-mentions for literal @text." }),
|
|
1268
1268
|
async (argv) => {
|
|
1269
1269
|
const args: SendArgs = { target: argv.target!, message: argv.message! };
|
|
1270
1270
|
if (argv.code) args.code = argv.code;
|
|
1271
1271
|
if (argv["channel-id"]) args.channelId = argv["channel-id"];
|
|
1272
1272
|
if (argv["user-id"]) args.userId = argv["user-id"];
|
|
1273
1273
|
if (argv.broadcast) args.broadcast = true;
|
|
1274
|
-
|
|
1274
|
+
// Mentions on by default; `--no-mentions` (yargs negation) sets it false.
|
|
1275
|
+
// A message with no `@token` short-circuits inside encodeMentions, so the
|
|
1276
|
+
// common case pays no extra API call.
|
|
1277
|
+
if (argv.mentions !== false) {
|
|
1275
1278
|
args.mentions = true;
|
|
1276
1279
|
// Resolve mentions with the user token (has users:read) even when the
|
|
1277
1280
|
// message itself is sent via the bot token.
|
|
@@ -1394,12 +1397,12 @@ async function main(): Promise<void> {
|
|
|
1394
1397
|
.positional("newText", { type: "string", demandOption: true })
|
|
1395
1398
|
.option("code", { type: "string", describe: "Safety hash to confirm edit" })
|
|
1396
1399
|
.option("channel-id", { type: "string", describe: "Raw channel ID" })
|
|
1397
|
-
.option("mentions", { type: "boolean", default:
|
|
1400
|
+
.option("mentions", { type: "boolean", default: true, describe: "Convert @handle tokens in the new text to real <@USERID> mentions (on by default). Unresolved handles stay as plain text. Disable with --no-mentions for literal @text." }),
|
|
1398
1401
|
async (argv) => {
|
|
1399
1402
|
const args: EditArgs = { target: argv.target!, newText: argv.newText! };
|
|
1400
1403
|
if (argv.code) args.code = argv.code;
|
|
1401
1404
|
if (argv["channel-id"]) args.channelId = argv["channel-id"];
|
|
1402
|
-
if (argv.mentions) args.mentions = true;
|
|
1405
|
+
if (argv.mentions !== false) args.mentions = true;
|
|
1403
1406
|
await cmdEdit(tok(argv as W), args);
|
|
1404
1407
|
},
|
|
1405
1408
|
)
|