test: cover auto-reply command gating
This commit is contained in:
66
src/auto-reply/reply/commands.test.ts
Normal file
66
src/auto-reply/reply/commands.test.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MsgContext } from "../templating.js";
|
||||
import { buildCommandContext, handleCommands } from "./commands.js";
|
||||
import { parseInlineDirectives } from "./directive-handling.js";
|
||||
|
||||
function buildParams(commandBody: string, cfg: ClawdbotConfig) {
|
||||
const ctx = {
|
||||
Body: commandBody,
|
||||
CommandBody: commandBody,
|
||||
CommandSource: "text",
|
||||
CommandAuthorized: true,
|
||||
Provider: "whatsapp",
|
||||
Surface: "whatsapp",
|
||||
} as MsgContext;
|
||||
|
||||
const command = buildCommandContext({
|
||||
ctx,
|
||||
cfg,
|
||||
isGroup: false,
|
||||
triggerBodyNormalized: commandBody.trim().toLowerCase(),
|
||||
commandAuthorized: true,
|
||||
});
|
||||
|
||||
return {
|
||||
ctx,
|
||||
cfg,
|
||||
command,
|
||||
directives: parseInlineDirectives(commandBody),
|
||||
sessionKey: "agent:main:main",
|
||||
workspaceDir: "/tmp",
|
||||
defaultGroupActivation: () => "mention",
|
||||
resolvedVerboseLevel: "off" as const,
|
||||
resolvedReasoningLevel: "off" as const,
|
||||
resolveDefaultThinkingLevel: async () => undefined,
|
||||
provider: "whatsapp",
|
||||
model: "test-model",
|
||||
contextTokens: 0,
|
||||
isGroup: false,
|
||||
};
|
||||
}
|
||||
|
||||
describe("handleCommands gating", () => {
|
||||
it("blocks /config when disabled", async () => {
|
||||
const cfg = {
|
||||
commands: { config: false, debug: false, text: true },
|
||||
whatsapp: { allowFrom: ["*"] },
|
||||
} as ClawdbotConfig;
|
||||
const params = buildParams("/config show", cfg);
|
||||
const result = await handleCommands(params);
|
||||
expect(result.shouldContinue).toBe(false);
|
||||
expect(result.reply?.text).toContain("/config is disabled");
|
||||
});
|
||||
|
||||
it("blocks /debug when disabled", async () => {
|
||||
const cfg = {
|
||||
commands: { config: false, debug: false, text: true },
|
||||
whatsapp: { allowFrom: ["*"] },
|
||||
} as ClawdbotConfig;
|
||||
const params = buildParams("/debug show", cfg);
|
||||
const result = await handleCommands(params);
|
||||
expect(result.shouldContinue).toBe(false);
|
||||
expect(result.reply?.text).toContain("/debug is disabled");
|
||||
});
|
||||
});
|
||||
@@ -613,7 +613,10 @@ export async function handleCommands(params: {
|
||||
);
|
||||
return { shouldContinue: false };
|
||||
}
|
||||
return { shouldContinue: false, reply: { text: buildCommandsMessage(cfg) } };
|
||||
return {
|
||||
shouldContinue: false,
|
||||
reply: { text: buildCommandsMessage(cfg) },
|
||||
};
|
||||
}
|
||||
|
||||
const statusRequested =
|
||||
|
||||
@@ -336,10 +336,7 @@ function renderGatewayServiceStartHints(
|
||||
}
|
||||
case "linux": {
|
||||
const unit = resolveGatewaySystemdServiceName(profile);
|
||||
return [
|
||||
...base,
|
||||
`systemctl --user start ${unit}.service`,
|
||||
];
|
||||
return [...base, `systemctl --user start ${unit}.service`];
|
||||
}
|
||||
case "win32": {
|
||||
const task = resolveGatewayWindowsTaskName(profile);
|
||||
@@ -726,7 +723,8 @@ function printDaemonStatus(status: DaemonStatus, opts: { json: boolean }) {
|
||||
spacer();
|
||||
}
|
||||
if (service.runtime?.cachedLabel) {
|
||||
const env = (service.command?.environment ?? process.env) as NodeJS.ProcessEnv;
|
||||
const env = (service.command?.environment ??
|
||||
process.env) as NodeJS.ProcessEnv;
|
||||
const label = resolveGatewayLaunchAgentLabel(env.CLAWDBOT_PROFILE);
|
||||
defaultRuntime.error(
|
||||
errorText(
|
||||
@@ -782,7 +780,8 @@ function printDaemonStatus(status: DaemonStatus, opts: { json: boolean }) {
|
||||
);
|
||||
}
|
||||
if (process.platform === "linux") {
|
||||
const env = (service.command?.environment ?? process.env) as NodeJS.ProcessEnv;
|
||||
const env = (service.command?.environment ??
|
||||
process.env) as NodeJS.ProcessEnv;
|
||||
const unit = resolveGatewaySystemdServiceName(env.CLAWDBOT_PROFILE);
|
||||
defaultRuntime.error(
|
||||
errorText(
|
||||
|
||||
@@ -505,15 +505,15 @@ export async function runNonInteractiveOnboarding(
|
||||
runtime: daemonRuntimeRaw,
|
||||
nodePath,
|
||||
});
|
||||
const environment = buildServiceEnvironment({
|
||||
env: process.env,
|
||||
port,
|
||||
token: gatewayToken,
|
||||
launchdLabel:
|
||||
process.platform === "darwin"
|
||||
? resolveGatewayLaunchAgentLabel(process.env.CLAWDBOT_PROFILE)
|
||||
: undefined,
|
||||
});
|
||||
const environment = buildServiceEnvironment({
|
||||
env: process.env,
|
||||
port,
|
||||
token: gatewayToken,
|
||||
launchdLabel:
|
||||
process.platform === "darwin"
|
||||
? resolveGatewayLaunchAgentLabel(process.env.CLAWDBOT_PROFILE)
|
||||
: undefined,
|
||||
});
|
||||
await service.install({
|
||||
env: process.env,
|
||||
stdout: process.stdout,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
formatGatewayServiceDescription,
|
||||
GATEWAY_LAUNCH_AGENT_LABEL,
|
||||
GATEWAY_SYSTEMD_SERVICE_NAME,
|
||||
GATEWAY_WINDOWS_TASK_NAME,
|
||||
formatGatewayServiceDescription,
|
||||
resolveGatewayLaunchAgentLabel,
|
||||
resolveGatewaySystemdServiceName,
|
||||
resolveGatewayWindowsTaskName,
|
||||
@@ -149,15 +149,15 @@ describe("formatGatewayServiceDescription", () => {
|
||||
});
|
||||
|
||||
it("includes profile when set", () => {
|
||||
expect(
|
||||
formatGatewayServiceDescription({ profile: "work" }),
|
||||
).toBe("Clawdbot Gateway (profile: work)");
|
||||
expect(formatGatewayServiceDescription({ profile: "work" })).toBe(
|
||||
"Clawdbot Gateway (profile: work)",
|
||||
);
|
||||
});
|
||||
|
||||
it("includes version when set", () => {
|
||||
expect(
|
||||
formatGatewayServiceDescription({ version: "2026.1.10" }),
|
||||
).toBe("Clawdbot Gateway (v2026.1.10)");
|
||||
expect(formatGatewayServiceDescription({ version: "2026.1.10" })).toBe(
|
||||
"Clawdbot Gateway (v2026.1.10)",
|
||||
);
|
||||
});
|
||||
|
||||
it("includes profile and version when set", () => {
|
||||
|
||||
@@ -103,7 +103,9 @@ function isClawdbotGatewayTaskName(name: string): boolean {
|
||||
const normalized = name.trim().toLowerCase();
|
||||
if (!normalized) return false;
|
||||
const defaultName = resolveGatewayWindowsTaskName().toLowerCase();
|
||||
return normalized === defaultName || normalized.startsWith("clawdbot gateway");
|
||||
return (
|
||||
normalized === defaultName || normalized.startsWith("clawdbot gateway")
|
||||
);
|
||||
}
|
||||
|
||||
function tryExtractPlistLabel(contents: string): string | null {
|
||||
|
||||
@@ -5,9 +5,9 @@ import { promisify } from "node:util";
|
||||
|
||||
import { colorize, isRich, theme } from "../terminal/theme.js";
|
||||
import {
|
||||
formatGatewayServiceDescription,
|
||||
GATEWAY_LAUNCH_AGENT_LABEL,
|
||||
LEGACY_GATEWAY_LAUNCH_AGENT_LABELS,
|
||||
formatGatewayServiceDescription,
|
||||
resolveGatewayLaunchAgentLabel,
|
||||
} from "./constants.js";
|
||||
import { parseKeyValueOutput } from "./runtime-parse.js";
|
||||
@@ -190,12 +190,11 @@ export function buildLaunchAgentPlist({
|
||||
<key>WorkingDirectory</key>
|
||||
<string>${plistEscape(workingDirectory)}</string>`
|
||||
: "";
|
||||
const commentXml =
|
||||
comment && comment.trim()
|
||||
? `
|
||||
const commentXml = comment?.trim()
|
||||
? `
|
||||
<key>Comment</key>
|
||||
<string>${plistEscape(comment.trim())}</string>`
|
||||
: "";
|
||||
: "";
|
||||
const envXml = renderEnvDict(environment);
|
||||
return `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
|
||||
@@ -5,8 +5,8 @@ import { promisify } from "node:util";
|
||||
|
||||
import { colorize, isRich, theme } from "../terminal/theme.js";
|
||||
import {
|
||||
LEGACY_GATEWAY_WINDOWS_TASK_NAMES,
|
||||
formatGatewayServiceDescription,
|
||||
LEGACY_GATEWAY_WINDOWS_TASK_NAMES,
|
||||
resolveGatewayWindowsTaskName,
|
||||
} from "./constants.js";
|
||||
import { parseKeyValueOutput } from "./runtime-parse.js";
|
||||
|
||||
@@ -103,7 +103,10 @@ export function resolveGatewayService(): GatewayService {
|
||||
await uninstallSystemdService(args);
|
||||
},
|
||||
stop: async (args) => {
|
||||
await stopSystemdService({ stdout: args.stdout, profile: args.profile });
|
||||
await stopSystemdService({
|
||||
stdout: args.stdout,
|
||||
profile: args.profile,
|
||||
});
|
||||
},
|
||||
restart: async (args) => {
|
||||
await restartSystemdService({
|
||||
|
||||
@@ -6,8 +6,8 @@ import { promisify } from "node:util";
|
||||
import { runCommandWithTimeout, runExec } from "../process/exec.js";
|
||||
import { colorize, isRich, theme } from "../terminal/theme.js";
|
||||
import {
|
||||
LEGACY_GATEWAY_SYSTEMD_SERVICE_NAMES,
|
||||
formatGatewayServiceDescription,
|
||||
LEGACY_GATEWAY_SYSTEMD_SERVICE_NAMES,
|
||||
resolveGatewaySystemdServiceName,
|
||||
} from "./constants.js";
|
||||
import { parseKeyValueOutput } from "./runtime-parse.js";
|
||||
|
||||
Reference in New Issue
Block a user