standup-mr 0.6.0 → 0.6.1

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/CHANGELOG.md CHANGED
@@ -4,6 +4,18 @@ All notable changes to standup-mr are recorded here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
5
5
  [semantic versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.6.1] - 2026-09-02
8
+
9
+ ### Fixed
10
+
11
+ - A note posted to Google Chat or Slack arrived with its formatting showing:
12
+ `**bold**` as literal asterisks, `## Dün` as a literal heading marker.
13
+ Neither renders standard Markdown — both use a single asterisk for bold and
14
+ have no headings — while the note is Markdown throughout. Bold is now
15
+ converted and headings become bold lines for those two. Discord speaks
16
+ Markdown natively and is sent untouched, and fenced blocks pass through
17
+ verbatim so a code sample keeps its asterisks.
18
+
7
19
  ## [0.6.0] - 2026-09-02
8
20
 
9
21
  ### Added
package/README.md CHANGED
@@ -135,7 +135,12 @@ it belongs with the tokens, not in a transcript. The payload shape is inferred
135
135
  from the URL host; `kind` is only needed when a proxy hides it.
136
136
 
137
137
  Three shapes are implemented: `slack` and `google-chat` both post `{"text"}`,
138
- `discord` posts `{"content"}`. Anything else that accepts a Slack-shaped body —
138
+ `discord` posts `{"content"}`.
139
+
140
+ Slack and Google Chat do not render standard Markdown, so the note is rewritten
141
+ on the way out: `**bold**` becomes `*bold*` and a `##` heading becomes a bold
142
+ line. Inline code, fenced blocks and their contents are left alone. Discord
143
+ speaks Markdown natively and is sent untouched. Anything else that accepts a Slack-shaped body —
139
144
  Mattermost, Rocket.Chat, an n8n or Zapier endpoint — works today by passing
140
145
  `kind: "slack"`, or `--slack URL` on the CLI.
141
146
 
@@ -194,6 +194,26 @@ var PAYLOAD_FIELD = {
194
194
  };
195
195
  var WEBHOOK_KINDS = Object.keys(PAYLOAD_FIELD);
196
196
 
197
+ // src/render/chat.ts
198
+ var MARKDOWN_NATIVE = ["discord"];
199
+ var FENCE = /^```/;
200
+ function convertLine(line) {
201
+ const heading = line.match(/^#{1,6}\s+(.*)$/);
202
+ if (heading) return `*${heading[1]}*`;
203
+ return line.replace(/\*\*(?=\S)([\s\S]*?\S)\*\*/g, "*$1*");
204
+ }
205
+ function toChatText(markdown, kind) {
206
+ if (MARKDOWN_NATIVE.includes(kind)) return markdown;
207
+ let fenced = false;
208
+ return markdown.split("\n").map((line) => {
209
+ if (FENCE.test(line)) {
210
+ fenced = !fenced;
211
+ return line;
212
+ }
213
+ return fenced ? line : convertLine(line);
214
+ }).join("\n");
215
+ }
216
+
197
217
  // src/notify/notify.ts
198
218
  async function postWebhook(url, text, kind = "slack", fetchImpl = fetch) {
199
219
  const field = PAYLOAD_FIELD[kind];
@@ -205,7 +225,7 @@ async function postWebhook(url, text, kind = "slack", fetchImpl = fetch) {
205
225
  const response = await fetchImpl(url, {
206
226
  method: "POST",
207
227
  headers: { "Content-Type": "application/json" },
208
- body: JSON.stringify({ [field]: text })
228
+ body: JSON.stringify({ [field]: toChatText(text, kind) })
209
229
  });
210
230
  if (!response.ok) {
211
231
  throw new Error(`Webhook rejected the message: HTTP ${response.status}.`);
@@ -1204,6 +1224,7 @@ export {
1204
1224
  ghHosts,
1205
1225
  ghToken,
1206
1226
  WEBHOOK_KINDS,
1227
+ toChatText,
1207
1228
  postWebhook,
1208
1229
  inferWebhookKind,
1209
1230
  buildUrl,
package/dist/cli.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  postWebhook,
9
9
  readStandupSkillBody,
10
10
  toMarkdown
11
- } from "./chunk-MB7KWLUR.js";
11
+ } from "./chunk-NJO6LFYN.js";
12
12
 
13
13
  // src/cli/cli.ts
14
14
  import { realpathSync } from "fs";
package/dist/index.d.ts CHANGED
@@ -277,6 +277,8 @@ interface SelectOptions {
277
277
  declare function chooseKind(options?: SelectOptions): ProviderKind;
278
278
  declare function connect(options?: SelectOptions): Provider;
279
279
 
280
+ declare function toChatText(markdown: string, kind: WebhookKind): string;
281
+
280
282
  declare function toMarkdown(report: StandupReport, lang?: string): string;
281
283
 
282
284
  declare function buildReport(provider: Provider, today: Date, lang?: string, lookbackDays?: number): Promise<StandupReport>;
@@ -285,4 +287,4 @@ declare function readStandupSkillBody(): string;
285
287
 
286
288
  declare function extractErrors(rawTrace: string, limit?: number): string[];
287
289
 
288
- export { type ActiveDay, type ActivityEvent, ApiError, type Blocker, type Bucket, ConfigError, DIAGNOSIS_UNAVAILABLE, type FetchLike, GITHUB_LABELS, GITLAB_LABELS, GitHubProvider, GitLabProvider, type Identity, type MergeRequest, type Provider, type ProviderKind, type ProviderLabels, RETRY_ATTEMPTS, RETRY_BACKOFF_MS, type Review, STALE_DAYS, type SelectOptions, type StandupReport, approvedBy, assertUsable, buildReport, buildUrl, chooseKind, classify, connect, countChangesRequested, degradable, extractErrors, ghHosts, ghToken, glabHosts, glabToken, inferWebhookKind, isoDay, label, latestStateByReviewer, localAt, mapEvent, markMissingPipelines, normalizeChecks, parseGlabHosts, parseLoggedInHosts, postWebhook, previousActiveDays, readStandupSkillBody, repoFromUrl, resolveHost, resolveToken, sendWithRetry, toMarkdown, undiagnosed, unreachable };
290
+ export { type ActiveDay, type ActivityEvent, ApiError, type Blocker, type Bucket, ConfigError, DIAGNOSIS_UNAVAILABLE, type FetchLike, GITHUB_LABELS, GITLAB_LABELS, GitHubProvider, GitLabProvider, type Identity, type MergeRequest, type Provider, type ProviderKind, type ProviderLabels, RETRY_ATTEMPTS, RETRY_BACKOFF_MS, type Review, STALE_DAYS, type SelectOptions, type StandupReport, approvedBy, assertUsable, buildReport, buildUrl, chooseKind, classify, connect, countChangesRequested, degradable, extractErrors, ghHosts, ghToken, glabHosts, glabToken, inferWebhookKind, isoDay, label, latestStateByReviewer, localAt, mapEvent, markMissingPipelines, normalizeChecks, parseGlabHosts, parseLoggedInHosts, postWebhook, previousActiveDays, readStandupSkillBody, repoFromUrl, resolveHost, resolveToken, sendWithRetry, toChatText, toMarkdown, undiagnosed, unreachable };
package/dist/index.js CHANGED
@@ -41,10 +41,11 @@ import {
41
41
  resolveHost,
42
42
  resolveToken,
43
43
  sendWithRetry,
44
+ toChatText,
44
45
  toMarkdown,
45
46
  undiagnosed,
46
47
  unreachable
47
- } from "./chunk-MB7KWLUR.js";
48
+ } from "./chunk-NJO6LFYN.js";
48
49
  export {
49
50
  ApiError,
50
51
  ConfigError,
@@ -87,6 +88,7 @@ export {
87
88
  resolveHost,
88
89
  resolveToken,
89
90
  sendWithRetry,
91
+ toChatText,
90
92
  toMarkdown,
91
93
  undiagnosed,
92
94
  unreachable
@@ -39,6 +39,26 @@ var PAYLOAD_FIELD = {
39
39
  };
40
40
  var WEBHOOK_KINDS = Object.keys(PAYLOAD_FIELD);
41
41
 
42
+ // src/render/chat.ts
43
+ var MARKDOWN_NATIVE = ["discord"];
44
+ var FENCE = /^```/;
45
+ function convertLine(line) {
46
+ const heading = line.match(/^#{1,6}\s+(.*)$/);
47
+ if (heading) return `*${heading[1]}*`;
48
+ return line.replace(/\*\*(?=\S)([\s\S]*?\S)\*\*/g, "*$1*");
49
+ }
50
+ function toChatText(markdown, kind) {
51
+ if (MARKDOWN_NATIVE.includes(kind)) return markdown;
52
+ let fenced = false;
53
+ return markdown.split("\n").map((line) => {
54
+ if (FENCE.test(line)) {
55
+ fenced = !fenced;
56
+ return line;
57
+ }
58
+ return fenced ? line : convertLine(line);
59
+ }).join("\n");
60
+ }
61
+
42
62
  // src/notify/notify.ts
43
63
  async function postWebhook(url, text2, kind = "slack", fetchImpl = fetch) {
44
64
  const field = PAYLOAD_FIELD[kind];
@@ -50,7 +70,7 @@ async function postWebhook(url, text2, kind = "slack", fetchImpl = fetch) {
50
70
  const response = await fetchImpl(url, {
51
71
  method: "POST",
52
72
  headers: { "Content-Type": "application/json" },
53
- body: JSON.stringify({ [field]: text2 })
73
+ body: JSON.stringify({ [field]: toChatText(text2, kind) })
54
74
  });
55
75
  if (!response.ok) {
56
76
  throw new Error(`Webhook rejected the message: HTTP ${response.status}.`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "standup-mr",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "mcpName": "io.github.Jubstaaa/standup-mr",
5
5
  "description": "Standup notes from merge request state, not commit logs.",
6
6
  "keywords": [