Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ agent-slack message edit "#general" "Updated text" --workspace "myteam" --ts "17
agent-slack message delete "#general" --workspace "myteam" --ts "1770165109.628379"
```

`message edit` and ordinary `message send` calls convert bullet/numbered lists to Slack native rich text. `message send --blocks` uses the supplied blocks instead, while `message send --attach` sends its initial comment as plain text without automatic list conversion. Inside auto-converted lists, inline mentions, broadcasts, emoji shortcodes, `<#C...>` channel references, and Slack manual links such as `<https://example.com/pull/42|PR #42>` are preserved as Slack elements. CommonMark links such as `[PR #42](https://example.com/pull/42)` are not converted into labeled link elements.
`message edit` and ordinary `message send` calls normalize links and convert bullet/numbered lists to Slack native rich text. `message send --blocks` uses the supplied blocks instead, while `message send --attach` sends its initial comment as plain text without automatic list conversion. Links may be bare HTTP(S) URLs or use Markdown (`[PR #42](https://example.com/pull/42)`) or Slack (`<https://example.com/pull/42|PR #42>`) syntax. Inside auto-converted lists, links, inline mentions, broadcasts, emoji shortcodes, and `<#C...>` channel references become Slack elements.

Send options for `message send`:

Expand Down
2 changes: 1 addition & 1 deletion skills/agent-slack/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Named `later remind --in` values such as `tomorrow` or `monday` also use the exe

Use `--no-unfurl` with `message send` or `message compose` when the user wants Slack link and media previews suppressed. It cannot be combined with `message send --attach`.

Ordinary `message send` and `message edit` calls auto-convert lists. `message send --blocks` and `message edit --blocks` use supplied Block Kit blocks, while `message send --attach` sends its initial comment without automatic list conversion. Inside auto-converted lists, use Slack's `<URL|label>` syntax because CommonMark `[label](URL)` links are not converted into labeled link elements.
Ordinary `message send` and `message edit` calls normalize bare HTTP(S), `[label](URL)`, and `<URL|label>` links and auto-convert lists. `message send --blocks` and `message edit --blocks` use supplied Block Kit blocks, while `message send --attach` sends its initial comment without automatic list conversion.

Slack-native drafts (`message draft list|create|update|delete`) manage drafts that appear in the user's Slack client; `create` posts nothing. `create` and `update` accept repeatable `--attach <path>`; on `update` the files are added to the draft's existing attachments rather than replacing them. They use undocumented session endpoints and require browser-style auth (xoxc/xoxd).

Expand Down
15 changes: 11 additions & 4 deletions src/slack/format-outbound.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { markdownLinksToSlackMrkdwn } from "./markdown-inline.ts";

/**
* Prepare user-authored text for Slack's `chat.postMessage` / `chat.update`.
*
Expand All @@ -8,18 +10,23 @@
* `<!here>` / `<!channel>` / `<!everyone>`
*
* Humans (and LLMs piping text into the CLI) commonly write `@U123` and
* raw `&`/`<`/`>` — this helper normalizes that to what Slack expects,
* while leaving already-well-formed Slack tokens intact.
* `[label](https://example.com)` links as well as raw `&`/`<`/`>` — this
* helper normalizes those to what Slack expects, while leaving
* already-well-formed Slack tokens intact.
*/
export function formatOutboundSlackText(text: string): string {
if (!text) {
return "";
}

// Slack does not understand CommonMark links in message text. Normalize the
// common inline form while leaving images, escaped links, and code alone.
let out = markdownLinksToSlackMrkdwn(text);

// Protect already-formatted Slack tokens so `<`/`>` inside them aren't escaped.
const stash: string[] = [];
let out = text.replace(
/<(?:@[UWB][A-Z0-9]+(?:\|[^>]*)?|#[CG][A-Z0-9]+(?:\|[^>]*)?|!subteam\^[A-Z0-9]+(?:\|[^>]*)?|![a-zA-Z]+(?:\|[^>]*)?|(?:https?:\/\/|mailto:)[^>]+)>/g,
out = out.replace(
/<(?:@[UWB][A-Z0-9]+(?:\|[^>]*)?|#[CG][A-Z0-9]+(?:\|[^>]*)?|!subteam\^[A-Z0-9]+(?:\|[^>]*)?|![a-zA-Z]+(?:\|[^>]*)?|(?:[Hh][Tt][Tt][Pp][Ss]?:\/\/|[Mm][Aa][Ii][Ll][Tt][Oo]:)[^>]+)>/g,
(m) => {
stash.push(m);
return `\u0000${stash.length - 1}\u0000`;
Expand Down
Loading
Loading