Rename Telegram bot commands from hyphens to underscores (#1126)
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>
This commit is contained in:
@@ -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.
|
||||
|
||||
+8
-8
@@ -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
|
||||
|
||||
+14
-85
@@ -82,7 +82,7 @@ function createMockApi(pluginConfigOverride: Record<string, any> = {}) {
|
||||
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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user