From ab2dbb7dc7259608ba3f695b656aed05c3e3b330 Mon Sep 17 00:00:00 2001 From: Alex Newman Date: Mon, 16 Feb 2026 00:33:55 -0500 Subject: [PATCH] Rename Telegram bot commands from hyphens to underscores (#1126) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Telegram Bot API only allows a-z, 0-9, and underscores in command names. Rename /claude-mem-feed → /claude_mem_feed and /claude-mem-status → /claude_mem_status. Fixes #1108 Co-authored-by: Manantra <113709296+Manantra@users.noreply.github.com> --- docs/public/openclaw-integration.mdx | 14 ++-- openclaw/SKILL.md | 16 ++--- openclaw/src/index.test.ts | 99 ++++------------------------ openclaw/src/index.ts | 8 +-- 4 files changed, 33 insertions(+), 104 deletions(-) diff --git a/docs/public/openclaw-integration.mdx b/docs/public/openclaw-integration.mdx index e52083a7..67fbb142 100644 --- a/docs/public/openclaw-integration.mdx +++ b/docs/public/openclaw-integration.mdx @@ -235,7 +235,7 @@ After starting the gateway, check that the feed is connected: [claude-mem] Connected to SSE stream ``` -2. **Use the status command** — Run `/claude-mem-feed` in any OpenClaw chat to see: +2. **Use the status command** — Run `/claude_mem_feed` in any OpenClaw chat to see: ``` Claude-Mem Observation Feed Enabled: yes @@ -340,22 +340,22 @@ The claude-mem worker service must be running on the same machine as the OpenCla ## Commands -### /claude-mem-feed +### /claude_mem_feed Show or toggle the observation feed status. ``` -/claude-mem-feed # Show current status -/claude-mem-feed on # Request enable -/claude-mem-feed off # Request disable +/claude_mem_feed # Show current status +/claude_mem_feed on # Request enable +/claude_mem_feed off # Request disable ``` -### /claude-mem-status +### /claude_mem_status Check worker health and session status. ``` -/claude-mem-status +/claude_mem_status ``` Returns worker status, port, active session count, and observation feed connection state. diff --git a/openclaw/SKILL.md b/openclaw/SKILL.md index 47cea087..f0895096 100644 --- a/openclaw/SKILL.md +++ b/openclaw/SKILL.md @@ -152,7 +152,7 @@ Restart your OpenClaw gateway so it picks up the new plugin configuration. After [claude-mem] OpenClaw plugin loaded — v1.0.0 (worker: 127.0.0.1:37777) ``` -If you see this, the plugin is loaded. You can also verify by running `/claude-mem-status` in any OpenClaw chat: +If you see this, the plugin is loaded. You can also verify by running `/claude_mem_status` in any OpenClaw chat: ``` Claude-Mem Worker Status @@ -324,7 +324,7 @@ Restart the gateway. Check the logs for these three lines in order: [claude-mem] Connected to SSE stream ``` -Then run `/claude-mem-feed` in any OpenClaw chat: +Then run `/claude_mem_feed` in any OpenClaw chat: ``` Claude-Mem Observation Feed @@ -340,12 +340,12 @@ If `Connection` shows `connected`, you're done. Have an agent do some work and w The plugin registers two commands: -### /claude-mem-status +### /claude_mem_status Reports worker health and current session state. ``` -/claude-mem-status +/claude_mem_status ``` Output: @@ -357,14 +357,14 @@ Active sessions: 2 Observation feed: connected ``` -### /claude-mem-feed +### /claude_mem_feed Shows observation feed status. Accepts optional `on`/`off` argument. ``` -/claude-mem-feed — show status -/claude-mem-feed on — request enable (update config to persist) -/claude-mem-feed off — request disable (update config to persist) +/claude_mem_feed — show status +/claude_mem_feed on — request enable (update config to persist) +/claude_mem_feed off — request disable (update config to persist) ``` ## How It All Works diff --git a/openclaw/src/index.test.ts b/openclaw/src/index.test.ts index 021444b8..9995fc1c 100644 --- a/openclaw/src/index.test.ts +++ b/openclaw/src/index.test.ts @@ -82,7 +82,7 @@ function createMockApi(pluginConfigOverride: Record = {}) { getService: () => registeredService, getCommand: (name?: string) => { if (name) return registeredCommands.get(name); - return registeredCommands.get("claude-mem-feed"); + return registeredCommands.get("claude_mem_feed"); }, getEventHandlers: (event: string) => eventHandlers.get(event) || [], fireEvent: async (event: string, data: any, ctx: any = {}) => { @@ -101,8 +101,8 @@ describe("claudeMemPlugin", () => { assert.ok(getService(), "service should be registered"); assert.equal(getService().id, "claude-mem-observation-feed"); - assert.ok(getCommand("claude-mem-feed"), "feed command should be registered"); - assert.ok(getCommand("claude-mem-status"), "status command should be registered"); + assert.ok(getCommand("claude_mem_feed"), "feed command should be registered"); + assert.ok(getCommand("claude_mem_status"), "status command should be registered"); assert.ok(getEventHandlers("session_start").length > 0, "session_start handler registered"); assert.ok(getEventHandlers("after_compaction").length > 0, "after_compaction handler registered"); assert.ok(getEventHandlers("before_agent_start").length > 0, "before_agent_start handler registered"); @@ -167,7 +167,7 @@ describe("claudeMemPlugin", () => { const { api, getCommand } = createMockApi({}); claudeMemPlugin(api); - const result = await getCommand().handler({ args: "", channel: "telegram", isAuthorizedSender: true, commandBody: "/claude-mem-feed", config: {} }); + const result = await getCommand().handler({ args: "", channel: "telegram", isAuthorizedSender: true, commandBody: "/claude_mem_feed", config: {} }); assert.ok(result.text.includes("not configured")); }); @@ -177,7 +177,7 @@ describe("claudeMemPlugin", () => { }); claudeMemPlugin(api); - const result = await getCommand().handler({ args: "", channel: "telegram", isAuthorizedSender: true, commandBody: "/claude-mem-feed", config: {} }); + const result = await getCommand().handler({ args: "", channel: "telegram", isAuthorizedSender: true, commandBody: "/claude_mem_feed", config: {} }); assert.ok(result.text.includes("Enabled: yes")); assert.ok(result.text.includes("Channel: telegram")); assert.ok(result.text.includes("Target: 123")); @@ -190,7 +190,7 @@ describe("claudeMemPlugin", () => { }); claudeMemPlugin(api); - const result = await getCommand().handler({ args: "on", channel: "telegram", isAuthorizedSender: true, commandBody: "/claude-mem-feed on", config: {} }); + const result = await getCommand().handler({ args: "on", channel: "telegram", isAuthorizedSender: true, commandBody: "/claude_mem_feed on", config: {} }); assert.ok(result.text.includes("enable requested")); assert.ok(logs.some((l) => l.includes("enable requested"))); }); @@ -201,7 +201,7 @@ describe("claudeMemPlugin", () => { }); claudeMemPlugin(api); - const result = await getCommand().handler({ args: "off", channel: "telegram", isAuthorizedSender: true, commandBody: "/claude-mem-feed off", config: {} }); + const result = await getCommand().handler({ args: "off", channel: "telegram", isAuthorizedSender: true, commandBody: "/claude_mem_feed off", config: {} }); assert.ok(result.text.includes("disable requested")); assert.ok(logs.some((l) => l.includes("disable requested"))); }); @@ -212,7 +212,7 @@ describe("claudeMemPlugin", () => { }); claudeMemPlugin(api); - const result = await getCommand().handler({ args: "", channel: "slack", isAuthorizedSender: true, commandBody: "/claude-mem-feed", config: {} }); + const result = await getCommand().handler({ args: "", channel: "slack", isAuthorizedSender: true, commandBody: "/claude_mem_feed", config: {} }); assert.ok(result.text.includes("Connection: disconnected")); }); }); @@ -485,27 +485,27 @@ describe("Observation I/O event handlers", () => { assert.equal(initRequest!.body.project, "my-project"); }); - it("claude-mem-status command reports worker health", async () => { + it("claude_mem_status command reports worker health", async () => { const { api, getCommand } = createMockApi({ workerPort }); claudeMemPlugin(api); - const statusCmd = getCommand("claude-mem-status"); + const statusCmd = getCommand("claude_mem_status"); assert.ok(statusCmd, "status command should exist"); - const result = await statusCmd.handler({ args: "", channel: "telegram", isAuthorizedSender: true, commandBody: "/claude-mem-status", config: {} }); + const result = await statusCmd.handler({ args: "", channel: "telegram", isAuthorizedSender: true, commandBody: "/claude_mem_status", config: {} }); assert.ok(result.text.includes("Status: ok")); assert.ok(result.text.includes(`Port: ${workerPort}`)); }); - it("claude-mem-status reports unreachable when worker is down", async () => { + it("claude_mem_status reports unreachable when worker is down", async () => { workerServer.close(); await new Promise((resolve) => setTimeout(resolve, 100)); const { api, getCommand } = createMockApi({ workerPort: 59999 }); claudeMemPlugin(api); - const statusCmd = getCommand("claude-mem-status"); - const result = await statusCmd.handler({ args: "", channel: "telegram", isAuthorizedSender: true, commandBody: "/claude-mem-status", config: {} }); + const statusCmd = getCommand("claude_mem_status"); + const result = await statusCmd.handler({ args: "", channel: "telegram", isAuthorizedSender: true, commandBody: "/claude_mem_status", config: {} }); assert.ok(result.text.includes("unreachable")); }); @@ -841,77 +841,6 @@ describe("SSE stream integration", () => { await getService().stop({}); }); - it("includes Claude Code project identifier in source label", async () => { - const { api, sentMessages, getService } = createMockApi({ - workerPort: serverPort, - observationFeed: { enabled: true, channel: "telegram", to: "12345" }, - }); - claudeMemPlugin(api); - - await getService().start({}); - await new Promise((resolve) => setTimeout(resolve, 200)); - - const observation = { - type: "new_observation", - observation: { - id: 11, - title: "Project Label", - subtitle: "Check source label", - project: "workspace-alpha", - }, - timestamp: Date.now(), - }; - - for (const res of serverResponses) { - res.write(`data: ${JSON.stringify(observation)}\n\n`); - } - - await new Promise((resolve) => setTimeout(resolve, 200)); - - assert.equal(sentMessages.length, 1); - assert.ok(sentMessages[0].text.includes("Claude Code Session (workspace-alpha)")); - - await getService().stop({}); - }); - - it("uses custom Claude Code label prefix while preserving project identifier", async () => { - const { api, sentMessages, getService } = createMockApi({ - workerPort: serverPort, - observationFeed: { - enabled: true, - channel: "telegram", - to: "12345", - emojis: { claudeCodeLabel: "Coding Session" }, - }, - }); - claudeMemPlugin(api); - - await getService().start({}); - await new Promise((resolve) => setTimeout(resolve, 200)); - - const observation = { - type: "new_observation", - observation: { - id: 12, - title: "Custom Label", - subtitle: "Custom prefix", - project: "workspace-beta", - }, - timestamp: Date.now(), - }; - - for (const res of serverResponses) { - res.write(`data: ${JSON.stringify(observation)}\n\n`); - } - - await new Promise((resolve) => setTimeout(resolve, 200)); - - assert.equal(sentMessages.length, 1); - assert.ok(sentMessages[0].text.includes("Coding Session (workspace-beta)")); - - await getService().stop({}); - }); - it("filters out non-observation events", async () => { const { api, sentMessages, getService } = createMockApi({ workerPort: serverPort, diff --git a/openclaw/src/index.ts b/openclaw/src/index.ts index a5f4f93b..97ba4503 100644 --- a/openclaw/src/index.ts +++ b/openclaw/src/index.ts @@ -806,10 +806,10 @@ export default function claudeMemPlugin(api: OpenClawPluginApi): void { } // ------------------------------------------------------------------ - // Command: /claude-mem-feed — status & toggle + // Command: /claude_mem_feed — status & toggle // ------------------------------------------------------------------ api.registerCommand({ - name: "claude-mem-feed", + name: "claude_mem_feed", description: "Show or toggle Claude-Mem observation feed status", acceptsArgs: true, handler: async (ctx) => { @@ -977,10 +977,10 @@ export default function claudeMemPlugin(api: OpenClawPluginApi): void { }); // ------------------------------------------------------------------ - // Command: /claude-mem-status — worker health check + // Command: /claude_mem_status — worker health check // ------------------------------------------------------------------ api.registerCommand({ - name: "claude-mem-status", + name: "claude_mem_status", description: "Check Claude-Mem worker health and session status", handler: async () => { const healthText = await workerGetText(workerPort, "/api/health", api.logger);