alvin-bot 4.16.0 → 4.16.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
@@ -2,6 +2,25 @@
2
2
 
3
3
  All notable changes to Alvin Bot are documented here.
4
4
 
5
+ ## [4.16.1] — 2026-04-20
6
+
7
+ ### šŸ†• Feature: /update shows release highlights
8
+
9
+ After a successful `/update`, the bot now sends a second short message with a bullet-point summary of what actually changed in the newly installed version. Pulled from the CHANGELOG entry matching the version string in the update result.
10
+
11
+ **Implementation:**
12
+ - New module `src/services/release-highlights.ts` parses the CHANGELOG block for a given version and returns at most 5 bullet points, ≤500 chars total.
13
+ - Strategy: prefer `### ` subsection headlines (feature/fix titles); fall back to first non-empty paragraph lines.
14
+ - Telegram-friendly output: plain bullets (`• ...`), no tables, no code blocks, truncates gracefully with an ellipsis line if too long.
15
+
16
+ **Result format in chat:**
17
+ ```
18
+ āœ… Installed v4.16.1 (was v4.16.0). Restarting...
19
+ šŸ“ What's new in v4.16.1
20
+
21
+ • Feature: /update shows release highlights
22
+ ```
23
+
5
24
  ## [4.16.0] — 2026-04-20
6
25
 
7
26
  ### šŸš€ Feature: bot-owned CDP Chromium — no more hub dependency
@@ -27,6 +27,7 @@ import { BOT_VERSION } from "../version.js";
27
27
  import { getWebPort } from "../web/server.js";
28
28
  import { getUsageSummary, getAllRateLimits, formatTokens } from "../services/usage-tracker.js";
29
29
  import { runUpdate, getAutoUpdate, setAutoUpdate, startAutoUpdateLoop } from "../services/updater.js";
30
+ import { getReleaseHighlights } from "../services/release-highlights.js";
30
31
  import { getHealthStatus, isFailedOver } from "../services/heartbeat.js";
31
32
  import { t, LOCALE_NAMES, LOCALE_FLAGS } from "../i18n.js";
32
33
  // Kick off auto-update loop on module load if the persistent flag is set.
@@ -1875,6 +1876,17 @@ export function registerCommands(bot) {
1875
1876
  const result = await runUpdate();
1876
1877
  if (result.ok) {
1877
1878
  await ctx.reply(`āœ… ${result.message}`);
1879
+ // Extract the installed version from the message (e.g. "Installed v4.16.1 ...")
1880
+ // so we can look up its CHANGELOG block. Falls silently if no match.
1881
+ const versionMatch = result.message.match(/v(\d+\.\d+\.\d+)/);
1882
+ if (versionMatch) {
1883
+ const highlights = getReleaseHighlights(versionMatch[1]);
1884
+ if (highlights) {
1885
+ await ctx.reply(`šŸ“ *What's new in v${versionMatch[1]}*\n\n${highlights}`, {
1886
+ parse_mode: "Markdown",
1887
+ });
1888
+ }
1889
+ }
1878
1890
  if (result.requiresRestart) {
1879
1891
  await ctx.reply(t("bot.update.restarting", lang));
1880
1892
  setTimeout(() => process.exit(0), 500);
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Release Highlights — extract a short human-readable summary for a given
3
+ * version from CHANGELOG.md.
4
+ *
5
+ * Used by the /update command to tell users what actually changed after a
6
+ * successful upgrade. Deliberately short — Telegram-friendly (<500 chars),
7
+ * headline + up to 5 bullets, no markdown tables, no code blocks.
8
+ */
9
+ import fs from "fs";
10
+ import path from "path";
11
+ import { BOT_ROOT } from "../paths.js";
12
+ const CHANGELOG_PATH = path.resolve(BOT_ROOT, "CHANGELOG.md");
13
+ const MAX_BULLETS = 5;
14
+ const MAX_CHARS = 500;
15
+ /**
16
+ * Find the block for `## [<version>]` in CHANGELOG.md and return a
17
+ * compact summary (headline + a few bullet points). Returns null if the
18
+ * version block is not found or CHANGELOG.md is missing.
19
+ */
20
+ export function getReleaseHighlights(version) {
21
+ let content;
22
+ try {
23
+ content = fs.readFileSync(CHANGELOG_PATH, "utf8");
24
+ }
25
+ catch {
26
+ return null;
27
+ }
28
+ const versionEscaped = version.replace(/\./g, "\\.");
29
+ // Match from "## [X.Y.Z]" up to the next "## [" (or end of file)
30
+ const blockRe = new RegExp(`^##\\s*\\[${versionEscaped}\\][^\\n]*\\n([\\s\\S]*?)(?=^##\\s*\\[|\\Z)`, "m");
31
+ const match = content.match(blockRe);
32
+ if (!match)
33
+ return null;
34
+ return compactHighlights(match[1]);
35
+ }
36
+ /**
37
+ * Extract up to MAX_BULLETS short lines from a CHANGELOG block.
38
+ * Strategy:
39
+ * 1. Prefer "### " subsection headlines (feature/fix titles)
40
+ * 2. Otherwise the first few non-empty lines of the first paragraph
41
+ * Truncate to MAX_CHARS total so it fits comfortably in a Telegram message.
42
+ */
43
+ function compactHighlights(block) {
44
+ const lines = block.split("\n");
45
+ const headlines = [];
46
+ for (const line of lines) {
47
+ const m = line.match(/^###\s+(.+?)\s*$/);
48
+ if (!m)
49
+ continue;
50
+ // Strip leading emoji/punctuation like "šŸš€ Feature: ..."
51
+ const title = m[1].replace(/^[^a-zA-Z0-9]+/, "").replace(/\s+/g, " ").trim();
52
+ if (title)
53
+ headlines.push(title);
54
+ }
55
+ let bullets;
56
+ if (headlines.length > 0) {
57
+ bullets = headlines.slice(0, MAX_BULLETS);
58
+ }
59
+ else {
60
+ // Fallback: grab the first non-empty lines (skip bold marker paragraphs,
61
+ // keep narrative). Limit to MAX_BULLETS lines.
62
+ const flat = lines
63
+ .map((l) => l.trim())
64
+ .filter((l) => l.length > 0 && !l.startsWith("```") && !l.startsWith("|"));
65
+ bullets = flat.slice(0, MAX_BULLETS);
66
+ }
67
+ const rendered = bullets.map((b) => `• ${b}`).join("\n");
68
+ if (rendered.length <= MAX_CHARS)
69
+ return rendered;
70
+ // Trim to fit — add a soft ellipsis on a whole line
71
+ let out = "";
72
+ for (const b of bullets) {
73
+ const next = out ? out + "\n• " + b : "• " + b;
74
+ if (next.length > MAX_CHARS - 4)
75
+ break;
76
+ out = next;
77
+ }
78
+ return out + "\n…";
79
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alvin-bot",
3
- "version": "4.16.0",
3
+ "version": "4.16.1",
4
4
  "description": "Alvin Bot \u2014 Your personal AI agent on Telegram, WhatsApp, Discord, Signal, and Web.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",