Skip to content

Commit 11cc5b3

Browse files
committed
feat: version system v2.2.0, fix Dockerfile, periodic update checks
- Fix Dockerfile: remove unnecessary Node.js and old CLI install - Bump deno.json version 1.0.0 -> 2.2.0 - Add BOT_VERSION (read from deno.json) throughout codebase - Show version + update status in /status command - Show version in startup embed title - Add periodic update checks every 12 hours - Update docs to reflect Dockerfile changes - CHANGELOG v2.2.0 with all changes documented
1 parent c0794fe commit 11cc5b3

File tree

9 files changed

+106
-18
lines changed

9 files changed

+106
-18
lines changed

CHANGELOG.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [2.2.0] - 2025-07-18
9+
10+
### Added
11+
- **Version in /status**: Shows bot version (e.g. `v2.2.0`) and update status in the `/status` embed
12+
- **Periodic Update Checks**: Automatically checks for updates every 12 hours and notifies in Discord
13+
- **Semver in Startup Embed**: Startup message now shows version number
14+
- **BOT_VERSION Export**: `deno.json` version read at startup and available throughout codebase
15+
16+
### Changed
17+
- **Dockerfile Optimized**: Removed unnecessary Node.js and `@anthropic-ai/claude-code` CLI install — bot uses SDK directly via Deno imports, reducing image size
18+
19+
### Fixed
20+
- `deno.json` version bumped from `1.0.0` to `2.2.0` (was not updated for v2.1.0)
21+
- CHANGELOG legacy reference to deprecated CLI corrected to `@anthropic-ai/claude-agent-sdk`
22+
823
## [2.1.0] - 2025-07-17
924

1025
### Added
@@ -169,9 +184,10 @@ This is the first stable release of Claude Code Discord Bot - a Discord bot that
169184
### Technical Details
170185
- Built with Deno 2.x and TypeScript
171186
- Uses Discord.js 14.14.1
172-
- Claude API via @anthropic-ai/claude-code (deprecated; see v2.0.0 for migration)
187+
- Claude API via @anthropic-ai/claude-agent-sdk
173188

174189
---
175190

191+
[2.2.0]: https://github.com/zebbern/claude-code-discord/releases/tag/v2.2.0
176192
[2.0.0]: https://github.com/zebbern/claude-code-discord/releases/tag/v2.0.0
177193
[1.0.0]: https://github.com/zebbern/claude-code-discord/releases/tag/v1.0.0

Dockerfile

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,12 @@ WORKDIR /app
99
# Set environment variable to indicate Docker container
1010
ENV DOCKER_CONTAINER=true
1111

12-
# Install git and Node.js (required for Claude CLI and branch tracking)
12+
# Install git (required for branch tracking and version checks)
1313
USER root
1414
RUN apt-get update && \
15-
apt-get install -y git curl && \
16-
curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
17-
apt-get install -y nodejs && \
15+
apt-get install -y git && \
1816
rm -rf /var/lib/apt/lists/*
1917

20-
# Install Claude CLI globally
21-
RUN npm install -g @anthropic-ai/claude-code
22-
2318
# Create non-root user for security
2419
RUN groupadd -r claude && useradd -r -g claude claude
2520

core/git-shell-handlers.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type { CommandHandlers, InteractionContext } from "../discord/index.ts";
99
import { formatShellOutput, formatGitOutput, formatError, createFormattedEmbed, cleanupPaginationStates } from "../discord/index.ts";
1010
import type { AllHandlers } from "./handler-registry.ts";
1111
import type { ProcessCrashHandler, ProcessHealthMonitor } from "../process/index.ts";
12+
import { BOT_VERSION, getLastCheckResult } from "../util/version-check.ts";
1213

1314
// ================================
1415
// Types
@@ -549,12 +550,18 @@ export function createUtilityCommandHandlers(
549550
const gitStatusInfo = await gitHandlers.getStatus();
550551
const runningCount = shellHandlers.onShellList(ctx).size;
551552
const worktreeStatus = gitHandlers.onWorktreeBots(ctx);
553+
const lastCheck = getLastCheckResult();
554+
const updateStatus = lastCheck
555+
? (lastCheck.behind ? `⚠️ Update available (${lastCheck.remoteCommit})` : "✅ Up to date")
556+
: "⏳ Checking...";
552557

553558
await ctx.editReply({
554559
embeds: [{
555560
color: 0x00ffff,
556561
title: 'Status',
557562
fields: [
563+
{ name: 'Version', value: `v${BOT_VERSION}`, inline: true },
564+
{ name: 'Updates', value: updateStatus, inline: true },
558565
{ name: 'Claude Code', value: sessionStatus, inline: true },
559566
{ name: 'Git Branch', value: gitStatusInfo.branch, inline: true },
560567
{ name: 'Shell Processes', value: `${runningCount} running`, inline: true },

deno.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "1.0.0",
2+
"version": "2.2.0",
33
"compilerOptions": {
44
"lib": ["deno.window"],
55
"strict": true

discord/bot.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { sanitizeChannelName } from "./utils.ts";
1919
import { handlePaginationInteraction } from "./pagination.ts";
2020
import { checkCommandPermission } from "../core/rbac.ts";
2121
import { SETTINGS_ACTIONS, SETTINGS_VALUES } from "../settings/unified-settings.ts";
22+
import { BOT_VERSION } from "../util/version-check.ts";
2223
import type {
2324
BotConfig,
2425
CommandHandlers,
@@ -513,7 +514,7 @@ export async function createDiscordBot(
513514
await myChannel.send(convertMessageContent({
514515
embeds: [{
515516
color: 0x00ff00,
516-
title: '🚀 Startup Complete',
517+
title: `🚀 v${BOT_VERSION}Startup Complete`,
517518
description: `Claude Code bot for branch ${branchName} has started`,
518519
fields: [
519520
{ name: 'Category', value: actualCategoryName, inline: true },

docs/docker.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,7 @@ This checks for new images every 5 minutes and restarts the bot automatically.
8282
8383
The Dockerfile builds on `denoland/deno:latest` and adds:
8484

85-
- **Node.js 20** (required for Claude CLI)
86-
- **`@anthropic-ai/claude-code`** CLI (installed globally via npm)
85+
- **Git** (required for branch tracking and version checks)
8786
- **Deno cached dependencies** from `deno.json`
8887

8988
## Resource Limits

docs/installation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,5 +146,5 @@ Environment variables override `.env` file settings. CLI flags override environm
146146
### Docker (all platforms)
147147

148148
- Docker Desktop required on Windows/macOS, Docker Engine on Linux
149-
- The image bundles Deno, Node.js, and Claude CLI so no local installs needed
149+
- The image bundles Deno and Git so no local installs needed
150150
- See [Docker Guide](docker.md) for volumes, GHCR, and Watchtower

index.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import { systemCommands } from "./system/index.ts";
3333
import { helpCommand } from "./help/index.ts";
3434
import { agentCommand } from "./agent/index.ts";
3535
import { cleanupPaginationStates } from "./discord/index.ts";
36-
import { runVersionCheck } from "./util/version-check.ts";
36+
import { runVersionCheck, startPeriodicUpdateCheck, BOT_VERSION } from "./util/version-check.ts";
3737

3838
// Core modules - now handle most of the heavy lifting
3939
import {
@@ -248,6 +248,34 @@ export async function createClaudeCodeBot(config: BotConfig) {
248248
}
249249
}
250250
}).catch(() => { /* version check is best-effort */ });
251+
252+
// Start periodic update checks (every 12 hours)
253+
startPeriodicUpdateCheck(async (result) => {
254+
try {
255+
const channel = bot.getChannel();
256+
if (channel) {
257+
const { EmbedBuilder } = await import("npm:discord.js@14.14.1");
258+
const embed = new EmbedBuilder()
259+
.setColor(0xFFA500)
260+
.setTitle("🔄 Update Available")
261+
.setDescription(`A newer version is available. You are running **v${BOT_VERSION}** (\`${result.localCommit}\`).`)
262+
.addFields(
263+
{ name: "Latest Commit", value: `\`${result.remoteCommit}\``, inline: true },
264+
{
265+
name: "How to Update",
266+
value: Deno.env.get("DOCKER_CONTAINER")
267+
? "```\ndocker compose pull && docker compose up -d\n```"
268+
: "```\ngit pull origin main && deno task start\n```",
269+
inline: false
270+
}
271+
)
272+
.setTimestamp();
273+
await channel.send({ embeds: [embed] });
274+
}
275+
} catch {
276+
// Periodic notification is best-effort
277+
}
278+
});
251279

252280
// Setup signal handlers for graceful shutdown
253281
setupSignalHandlers({

util/version-check.ts

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
/**
22
* Version checker - compares local commit hash against GitHub's latest.
33
* Notifies at startup if the bot is behind.
4+
* Also provides periodic update checks and semver display.
45
*
56
* @module util/version-check
67
*/
78

9+
// Read version from deno.json at startup
10+
const denoConfig = JSON.parse(Deno.readTextFileSync("deno.json"));
11+
12+
/** Current bot version from deno.json */
13+
export const BOT_VERSION: string = denoConfig.version ?? "unknown";
14+
815
const REPO_OWNER = "zebbern";
916
const REPO_NAME = "claude-code-discord";
1017

11-
interface VersionCheckResult {
18+
export interface VersionCheckResult {
1219
upToDate: boolean;
1320
localCommit: string;
1421
remoteCommit: string;
@@ -109,10 +116,10 @@ export async function runVersionCheck(): Promise<{
109116
embed: {
110117
color: 0xFFA500, // Orange
111118
title: "Update Available",
112-
description: "A newer version of claude-code-discord is available on GitHub.",
119+
description: `A newer version of claude-code-discord is available on GitHub. You are running **v${BOT_VERSION}**.`,
113120
fields: [
114-
{ name: "Your Version", value: `\`${result.localCommit}\``, inline: true },
115-
{ name: "Latest Version", value: `\`${result.remoteCommit}\``, inline: true },
121+
{ name: "Your Commit", value: `\`${result.localCommit}\``, inline: true },
122+
{ name: "Latest Commit", value: `\`${result.remoteCommit}\``, inline: true },
116123
{
117124
name: "How to Update",
118125
value: Deno.env.get("DOCKER_CONTAINER")
@@ -124,3 +131,38 @@ export async function runVersionCheck(): Promise<{
124131
},
125132
};
126133
}
134+
135+
/** Cached update check result for use in /status and periodic checks */
136+
let lastCheckResult: VersionCheckResult | null = null;
137+
138+
/** Get cached update status (non-blocking, returns last known state) */
139+
export function getLastCheckResult(): VersionCheckResult | null {
140+
return lastCheckResult;
141+
}
142+
143+
/**
144+
* Start periodic update checks.
145+
* Runs checkForUpdates every `intervalMs` (default: 12 hours).
146+
* Calls `onUpdateAvailable` when an update is detected.
147+
*/
148+
export function startPeriodicUpdateCheck(
149+
onUpdateAvailable: (result: VersionCheckResult) => void,
150+
intervalMs = 12 * 60 * 60 * 1000
151+
): number {
152+
const check = async () => {
153+
try {
154+
const result = await checkForUpdates();
155+
lastCheckResult = result;
156+
if (result.behind) {
157+
onUpdateAvailable(result);
158+
}
159+
} catch {
160+
// Silently ignore periodic check failures
161+
}
162+
};
163+
164+
// Run initial check to populate cache
165+
check();
166+
167+
return setInterval(check, intervalMs) as unknown as number;
168+
}

0 commit comments

Comments
 (0)