Slack: accept slash command names with or without leading slash
Closes #798
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
- Memory: allow custom OpenAI-compatible embedding endpoints for memory search (remote baseUrl/apiKey/headers). (#819 — thanks @mukhtharcm)
|
||||
|
||||
### Fixes
|
||||
- Slack: accept slash commands with or without leading `/` for custom command configs. (#798 — thanks @thewilloftheshadow)
|
||||
- Onboarding/Configure: refuse to proceed with invalid configs; run `clawdbot doctor` first to avoid wiping custom fields. (#764 — thanks @mukhtharcm)
|
||||
- Anthropic: merge consecutive user turns (preserve newest metadata) before validation to avoid “Incorrect role information” errors. (#804 — thanks @ThomsenDrake)
|
||||
- Discord/Slack: centralize reply-thread planning so auto-thread replies stay in the created thread without parent reply refs.
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { isSlackRoomAllowedByPolicy, resolveSlackThreadTs } from "./monitor.js";
|
||||
import {
|
||||
buildSlackSlashCommandMatcher,
|
||||
isSlackRoomAllowedByPolicy,
|
||||
resolveSlackThreadTs,
|
||||
} from "./monitor.js";
|
||||
|
||||
describe("slack groupPolicy gating", () => {
|
||||
it("allows when policy is open", () => {
|
||||
@@ -152,3 +156,19 @@ describe("resolveSlackThreadTs", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildSlackSlashCommandMatcher", () => {
|
||||
it("matches with or without a leading slash", () => {
|
||||
const matcher = buildSlackSlashCommandMatcher("clawd");
|
||||
|
||||
expect(matcher.test("clawd")).toBe(true);
|
||||
expect(matcher.test("/clawd")).toBe(true);
|
||||
});
|
||||
|
||||
it("does not match similar names", () => {
|
||||
const matcher = buildSlackSlashCommandMatcher("clawd");
|
||||
|
||||
expect(matcher.test("/clawd-bot")).toBe(false);
|
||||
expect(matcher.test("clawd-bot")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -173,6 +173,15 @@ function normalizeSlackSlug(raw?: string) {
|
||||
return cleaned.replace(/-{2,}/g, "-").replace(/^[-.]+|[-.]+$/g, "");
|
||||
}
|
||||
|
||||
function normalizeSlackSlashCommandName(raw: string) {
|
||||
return raw.replace(/^\/+/, "");
|
||||
}
|
||||
|
||||
export function buildSlackSlashCommandMatcher(name: string) {
|
||||
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
return new RegExp(`^/?${escaped}$`);
|
||||
}
|
||||
|
||||
function normalizeAllowList(list?: Array<string | number>) {
|
||||
return (list ?? []).map((entry) => String(entry).trim()).filter(Boolean);
|
||||
}
|
||||
@@ -227,9 +236,13 @@ function resolveSlackUserAllowed(params: {
|
||||
function resolveSlackSlashCommandConfig(
|
||||
raw?: SlackSlashCommandConfig,
|
||||
): Required<SlackSlashCommandConfig> {
|
||||
const normalizedName = normalizeSlackSlashCommandName(
|
||||
raw?.name?.trim() || "clawd",
|
||||
);
|
||||
const name = normalizedName || "clawd";
|
||||
return {
|
||||
enabled: raw?.enabled === true,
|
||||
name: raw?.name?.trim() || "clawd",
|
||||
name,
|
||||
sessionPrefix: raw?.sessionPrefix?.trim() || "slack:slash",
|
||||
ephemeral: raw?.ephemeral !== false,
|
||||
};
|
||||
@@ -1980,7 +1993,7 @@ export async function monitorSlackProvider(opts: MonitorSlackOpts = {}) {
|
||||
}
|
||||
} else if (slashCommand.enabled) {
|
||||
app.command(
|
||||
slashCommand.name,
|
||||
buildSlackSlashCommandMatcher(slashCommand.name),
|
||||
async ({ command, ack, respond }: SlackCommandMiddlewareArgs) => {
|
||||
await handleSlashCommand({
|
||||
command,
|
||||
|
||||
Reference in New Issue
Block a user