fix(tui): validate activation slash commands

This commit is contained in:
Shakker 2026-03-27 10:31:30 +00:00
parent 14c63ca42a
commit 58cdcf74c7
No known key found for this signature in database
2 changed files with 50 additions and 5 deletions

View File

@ -7,14 +7,18 @@ type SetSessionMock = ReturnType<typeof vi.fn> & ((key: string) => Promise<void>
function createHarness(params?: {
sendChat?: ReturnType<typeof vi.fn>;
patchSession?: ReturnType<typeof vi.fn>;
resetSession?: ReturnType<typeof vi.fn>;
setSession?: SetSessionMock;
loadHistory?: LoadHistoryMock;
refreshSessionInfo?: ReturnType<typeof vi.fn>;
applySessionInfoFromPatch?: ReturnType<typeof vi.fn>;
setActivityStatus?: SetActivityStatusMock;
isConnected?: boolean;
activeChatRunId?: string | null;
}) {
const sendChat = params?.sendChat ?? vi.fn().mockResolvedValue({ runId: "r1" });
const patchSession = params?.patchSession ?? vi.fn().mockResolvedValue({});
const resetSession = params?.resetSession ?? vi.fn().mockResolvedValue({ ok: true });
const setSession = params?.setSession ?? (vi.fn().mockResolvedValue(undefined) as SetSessionMock);
const addUser = vi.fn();
@ -24,6 +28,8 @@ function createHarness(params?: {
const noteLocalBtwRunId = vi.fn();
const loadHistory =
params?.loadHistory ?? (vi.fn().mockResolvedValue(undefined) as LoadHistoryMock);
const refreshSessionInfo = params?.refreshSessionInfo ?? vi.fn().mockResolvedValue(undefined);
const applySessionInfoFromPatch = params?.applySessionInfoFromPatch ?? vi.fn();
const setActivityStatus = params?.setActivityStatus ?? (vi.fn() as SetActivityStatusMock);
const state = {
currentSessionKey: "agent:main:main",
@ -33,7 +39,7 @@ function createHarness(params?: {
};
const { handleCommand } = createCommandHandlers({
client: { sendChat, resetSession } as never,
client: { sendChat, patchSession, resetSession } as never,
chatLog: { addUser, addSystem } as never,
tui: { requestRender } as never,
opts: {},
@ -41,14 +47,14 @@ function createHarness(params?: {
deliverDefault: false,
openOverlay: vi.fn(),
closeOverlay: vi.fn(),
refreshSessionInfo: vi.fn(),
refreshSessionInfo: refreshSessionInfo as never,
loadHistory,
setSession,
refreshAgents: vi.fn(),
abortActive: vi.fn(),
setActivityStatus,
formatSessionKey: vi.fn(),
applySessionInfoFromPatch: vi.fn(),
applySessionInfoFromPatch: applySessionInfoFromPatch as never,
noteLocalRunId,
noteLocalBtwRunId,
forgetLocalRunId: vi.fn(),
@ -59,12 +65,15 @@ function createHarness(params?: {
return {
handleCommand,
sendChat,
patchSession,
resetSession,
setSession,
addUser,
addSystem,
requestRender,
loadHistory,
refreshSessionInfo,
applySessionInfoFromPatch,
setActivityStatus,
noteLocalRunId,
noteLocalBtwRunId,
@ -202,4 +211,34 @@ describe("tui command handlers", () => {
expect(addSystem).toHaveBeenCalledWith("not connected to gateway — message not sent");
expect(setActivityStatus).toHaveBeenLastCalledWith("disconnected");
});
it("rejects invalid /activation values before patching the session", async () => {
const { handleCommand, patchSession, addSystem } = createHarness();
await handleCommand("/activation sometimes");
expect(patchSession).not.toHaveBeenCalled();
expect(addSystem).toHaveBeenCalledWith("usage: /activation <mention|always>");
});
it("patches the session for valid /activation values", async () => {
const refreshSessionInfo = vi.fn().mockResolvedValue(undefined);
const applySessionInfoFromPatch = vi.fn();
const patchSession = vi.fn().mockResolvedValue({ groupActivation: "always" });
const { handleCommand, addSystem } = createHarness({
patchSession,
refreshSessionInfo,
applySessionInfoFromPatch,
});
await handleCommand("/activation always");
expect(patchSession).toHaveBeenCalledWith({
key: "agent:main:main",
groupActivation: "always",
});
expect(addSystem).toHaveBeenCalledWith("activation set to always");
expect(applySessionInfoFromPatch).toHaveBeenCalledWith({ groupActivation: "always" });
expect(refreshSessionInfo).toHaveBeenCalledTimes(1);
});
});

View File

@ -1,5 +1,6 @@
import { randomUUID } from "node:crypto";
import type { Component, SelectItem, TUI } from "@mariozechner/pi-tui";
import { normalizeGroupActivation } from "../auto-reply/group-activation.js";
import {
formatThinkingLevels,
normalizeUsageDisplay,
@ -440,12 +441,17 @@ export function createCommandHandlers(context: CommandHandlerContext) {
chatLog.addSystem("usage: /activation <mention|always>");
break;
}
const activation = normalizeGroupActivation(args);
if (!activation) {
chatLog.addSystem("usage: /activation <mention|always>");
break;
}
try {
const result = await client.patchSession({
key: state.currentSessionKey,
groupActivation: args === "always" ? "always" : "mention",
groupActivation: activation,
});
chatLog.addSystem(`activation set to ${args}`);
chatLog.addSystem(`activation set to ${activation}`);
applySessionInfoFromPatch(result);
await refreshSessionInfo();
} catch (err) {