mirror of
https://github.com/hanzoai/bot.git
synced 2026-10-30 17:24:26 +00:00
The big rebrand left a residue of HanzoBot* identifiers inside camelCase compounds (resolveHanzoBotAgentDir, HanzoBotPackageRoot, hanzoBotRoot, HanzoBotTmpDir, …) that the canonical bot-root.ts / tmp-bot-dir.ts had always exported as Bot* / bot*. The earlier \b-anchored sweep missed them because the H is mid-identifier with no word boundary. Replace HanzoBot(?=[A-Z][a-z]) → Bot (and hanzoBot equivalent) everywhere, plus HanzoBotKit → BotKit (the on-disk module is apps/shared/BotKit). Also one stray pi-tools.ts type narrowing (senderId is string|null but the target wants string|undefined) — coerce with ?? undefined. pnpm build → ✔ Build complete in 7s.
111 lines
3.1 KiB
TypeScript
111 lines
3.1 KiB
TypeScript
import fs from "node:fs/promises";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import type {
|
|
BotPluginApi,
|
|
BotPluginCommandDefinition,
|
|
PluginCommandContext,
|
|
} from "@hanzo/bot/plugin-sdk/phone-control";
|
|
import { describe, expect, it, vi } from "vitest";
|
|
import registerPhoneControl from "./index.js";
|
|
|
|
function createApi(params: {
|
|
stateDir: string;
|
|
getConfig: () => Record<string, unknown>;
|
|
writeConfig: (next: Record<string, unknown>) => Promise<void>;
|
|
registerCommand: (command: BotPluginCommandDefinition) => void;
|
|
}): BotPluginApi {
|
|
return {
|
|
id: "phone-control",
|
|
name: "phone-control",
|
|
source: "test",
|
|
config: {},
|
|
pluginConfig: {},
|
|
runtime: {
|
|
state: {
|
|
resolveStateDir: () => params.stateDir,
|
|
},
|
|
config: {
|
|
loadConfig: () => params.getConfig(),
|
|
writeConfigFile: (next: Record<string, unknown>) => params.writeConfig(next),
|
|
},
|
|
} as BotPluginApi["runtime"],
|
|
logger: { info() {}, warn() {}, error() {} },
|
|
registerTool() {},
|
|
registerHook() {},
|
|
registerHttpRoute() {},
|
|
registerChannel() {},
|
|
registerGatewayMethod() {},
|
|
registerCli() {},
|
|
registerService() {},
|
|
registerProvider() {},
|
|
registerContextEngine() {},
|
|
registerCommand: params.registerCommand,
|
|
resolvePath(input: string) {
|
|
return input;
|
|
},
|
|
on() {},
|
|
};
|
|
}
|
|
|
|
function createCommandContext(args: string): PluginCommandContext {
|
|
return {
|
|
channel: "test",
|
|
isAuthorizedSender: true,
|
|
commandBody: `/phone ${args}`,
|
|
args,
|
|
config: {},
|
|
};
|
|
}
|
|
|
|
describe("phone-control plugin", () => {
|
|
it("arms sms.send as part of the writes group", async () => {
|
|
const stateDir = await fs.mkdtemp(path.join(os.tmpdir(), "bot-phone-control-test-"));
|
|
try {
|
|
let config: Record<string, unknown> = {
|
|
gateway: {
|
|
nodes: {
|
|
allowCommands: [],
|
|
denyCommands: ["calendar.add", "contacts.add", "reminders.add", "sms.send"],
|
|
},
|
|
},
|
|
};
|
|
const writeConfigFile = vi.fn(async (next: Record<string, unknown>) => {
|
|
config = next;
|
|
});
|
|
|
|
let command: BotPluginCommandDefinition | undefined;
|
|
registerPhoneControl(
|
|
createApi({
|
|
stateDir,
|
|
getConfig: () => config,
|
|
writeConfig: writeConfigFile,
|
|
registerCommand: (nextCommand) => {
|
|
command = nextCommand;
|
|
},
|
|
}),
|
|
);
|
|
|
|
expect(command?.name).toBe("phone");
|
|
|
|
const res = await command?.handler(createCommandContext("arm writes 30s"));
|
|
const text = String(res?.text ?? "");
|
|
const nodes = (
|
|
config.gateway as { nodes?: { allowCommands?: string[]; denyCommands?: string[] } }
|
|
).nodes;
|
|
|
|
expect(writeConfigFile).toHaveBeenCalledTimes(1);
|
|
expect(nodes?.allowCommands).toEqual([
|
|
"calendar.add",
|
|
"contacts.add",
|
|
"reminders.add",
|
|
"sms.send",
|
|
]);
|
|
expect(nodes?.denyCommands).toEqual([]);
|
|
expect(text).toContain("sms.send");
|
|
} finally {
|
|
await fs.rm(stateDir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
});
|