style: apply biome formatting
This commit is contained in:
@@ -438,11 +438,11 @@ export async function agentCommand(
|
||||
? whatsappTarget
|
||||
: deliveryProvider === "discord"
|
||||
? discordTarget
|
||||
: deliveryProvider === "signal"
|
||||
? signalTarget
|
||||
: deliveryProvider === "imessage"
|
||||
? imessageTarget
|
||||
: undefined;
|
||||
: deliveryProvider === "signal"
|
||||
? signalTarget
|
||||
: deliveryProvider === "imessage"
|
||||
? imessageTarget
|
||||
: undefined;
|
||||
const message = `Delivery failed (${deliveryProvider}${deliveryTarget ? ` to ${deliveryTarget}` : ""}): ${String(err)}`;
|
||||
runtime.error?.(message);
|
||||
if (!runtime.error) runtime.log(message);
|
||||
|
||||
@@ -102,7 +102,13 @@ export type HookMappingConfig = {
|
||||
messageTemplate?: string;
|
||||
textTemplate?: string;
|
||||
deliver?: boolean;
|
||||
channel?: "last" | "whatsapp" | "telegram" | "discord" | "signal" | "imessage";
|
||||
channel?:
|
||||
| "last"
|
||||
| "whatsapp"
|
||||
| "telegram"
|
||||
| "discord"
|
||||
| "signal"
|
||||
| "imessage";
|
||||
to?: string;
|
||||
thinking?: string;
|
||||
timeoutSeconds?: number;
|
||||
@@ -940,11 +946,7 @@ const ClawdisSchema = z.object({
|
||||
cliPath: z.string().optional(),
|
||||
dbPath: z.string().optional(),
|
||||
service: z
|
||||
.union([
|
||||
z.literal("imessage"),
|
||||
z.literal("sms"),
|
||||
z.literal("auto"),
|
||||
])
|
||||
.union([z.literal("imessage"), z.literal("sms"), z.literal("auto")])
|
||||
.optional(),
|
||||
region: z.string().optional(),
|
||||
allowFrom: z.array(z.union([z.string(), z.number()])).optional(),
|
||||
|
||||
@@ -53,7 +53,9 @@ function normalizeReactionEmoji(raw: string) {
|
||||
throw new Error("emoji required");
|
||||
}
|
||||
const customMatch = trimmed.match(/^<a?:([^:>]+):(\d+)>$/);
|
||||
const identifier = customMatch ? `${customMatch[1]}:${customMatch[2]}` : trimmed;
|
||||
const identifier = customMatch
|
||||
? `${customMatch[1]}:${customMatch[2]}`
|
||||
: trimmed;
|
||||
return encodeURIComponent(identifier);
|
||||
}
|
||||
|
||||
|
||||
@@ -3664,7 +3664,9 @@ describe("gateway server", () => {
|
||||
ws,
|
||||
(o) => {
|
||||
if (o.type !== "event" || o.event !== "chat") return false;
|
||||
const payload = o.payload as { state?: unknown; runId?: unknown } | undefined;
|
||||
const payload = o.payload as
|
||||
| { state?: unknown; runId?: unknown }
|
||||
| undefined;
|
||||
return payload?.state === "final" && payload.runId === "run-auto-1";
|
||||
},
|
||||
8000,
|
||||
|
||||
@@ -74,12 +74,12 @@ import {
|
||||
sendMessageDiscord,
|
||||
} from "../discord/index.js";
|
||||
import { type DiscordProbe, probeDiscord } from "../discord/probe.js";
|
||||
import { isVerbose } from "../globals.js";
|
||||
import {
|
||||
monitorIMessageProvider,
|
||||
sendMessageIMessage,
|
||||
} from "../imessage/index.js";
|
||||
import { probeIMessage, type IMessageProbe } from "../imessage/probe.js";
|
||||
import { isVerbose } from "../globals.js";
|
||||
import { type IMessageProbe, probeIMessage } from "../imessage/probe.js";
|
||||
import {
|
||||
clearAgentRunContext,
|
||||
getAgentRunContext,
|
||||
@@ -1394,14 +1394,13 @@ export async function startGatewayServer(
|
||||
? channelRaw
|
||||
: channelRaw === "imsg"
|
||||
? "imessage"
|
||||
: channelRaw === undefined
|
||||
? "last"
|
||||
: null;
|
||||
: channelRaw === undefined
|
||||
? "last"
|
||||
: null;
|
||||
if (channel === null) {
|
||||
return {
|
||||
ok: false,
|
||||
error:
|
||||
"channel must be last|whatsapp|telegram|discord|signal|imessage",
|
||||
error: "channel must be last|whatsapp|telegram|discord|signal|imessage",
|
||||
};
|
||||
}
|
||||
const toRaw = payload.to;
|
||||
@@ -4331,7 +4330,8 @@ export async function startGatewayServer(
|
||||
|
||||
const imessageCfg = cfg.imessage;
|
||||
const imessageEnabled = imessageCfg?.enabled !== false;
|
||||
const imessageConfigured = Boolean(imessageCfg) && imessageEnabled;
|
||||
const imessageConfigured =
|
||||
Boolean(imessageCfg) && imessageEnabled;
|
||||
let imessageProbe: IMessageProbe | undefined;
|
||||
let imessageLastProbeAt: number | null = null;
|
||||
if (probe && imessageConfigured) {
|
||||
@@ -6788,9 +6788,7 @@ export async function startGatewayServer(
|
||||
await Promise.allSettled(
|
||||
[whatsappTask, telegramTask, signalTask, imessageTask].filter(
|
||||
Boolean,
|
||||
) as Array<
|
||||
Promise<unknown>
|
||||
>,
|
||||
) as Array<Promise<unknown>>,
|
||||
);
|
||||
await new Promise<void>((resolve) => wss.close(() => resolve()));
|
||||
await new Promise<void>((resolve, reject) =>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { spawn, type ChildProcessWithoutNullStreams } from "node:child_process";
|
||||
import { type ChildProcessWithoutNullStreams, spawn } from "node:child_process";
|
||||
import { createInterface, type Interface } from "node:readline";
|
||||
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
@@ -51,7 +51,9 @@ export class IMessageRpcClient {
|
||||
|
||||
constructor(opts: IMessageRpcClientOptions = {}) {
|
||||
this.cliPath = opts.cliPath?.trim() || "imsg";
|
||||
this.dbPath = opts.dbPath?.trim() ? resolveUserPath(opts.dbPath) : undefined;
|
||||
this.dbPath = opts.dbPath?.trim()
|
||||
? resolveUserPath(opts.dbPath)
|
||||
: undefined;
|
||||
this.runtime = opts.runtime;
|
||||
this.onNotification = opts.onNotification;
|
||||
this.closed = new Promise((resolve) => {
|
||||
@@ -166,7 +168,7 @@ export class IMessageRpcClient {
|
||||
let parsed: IMessageRpcResponse<unknown>;
|
||||
try {
|
||||
parsed = JSON.parse(line) as IMessageRpcResponse<unknown>;
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
this.runtime?.error?.(`imsg rpc: failed to parse ${line}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,9 @@ const replyMock = vi.fn();
|
||||
const updateLastRouteMock = vi.fn();
|
||||
|
||||
let config: Record<string, unknown> = {};
|
||||
let notificationHandler: ((msg: { method: string; params?: unknown }) => void) | undefined;
|
||||
let notificationHandler:
|
||||
| ((msg: { method: string; params?: unknown }) => void)
|
||||
| undefined;
|
||||
let closeResolve: (() => void) | undefined;
|
||||
|
||||
vi.mock("../config/config.js", () => ({
|
||||
@@ -30,24 +32,27 @@ vi.mock("../config/sessions.js", () => ({
|
||||
}));
|
||||
|
||||
vi.mock("./client.js", () => ({
|
||||
createIMessageRpcClient: vi.fn(async (opts: { onNotification?: typeof notificationHandler }) => {
|
||||
notificationHandler = opts.onNotification;
|
||||
return {
|
||||
request: (...args: unknown[]) => requestMock(...args),
|
||||
waitForClose: () =>
|
||||
new Promise<void>((resolve) => {
|
||||
closeResolve = resolve;
|
||||
}),
|
||||
stop: (...args: unknown[]) => stopMock(...args),
|
||||
};
|
||||
}),
|
||||
createIMessageRpcClient: vi.fn(
|
||||
async (opts: { onNotification?: typeof notificationHandler }) => {
|
||||
notificationHandler = opts.onNotification;
|
||||
return {
|
||||
request: (...args: unknown[]) => requestMock(...args),
|
||||
waitForClose: () =>
|
||||
new Promise<void>((resolve) => {
|
||||
closeResolve = resolve;
|
||||
}),
|
||||
stop: (...args: unknown[]) => stopMock(...args),
|
||||
};
|
||||
},
|
||||
),
|
||||
}));
|
||||
|
||||
const flush = () => new Promise((resolve) => setTimeout(resolve, 0));
|
||||
|
||||
async function waitForSubscribe() {
|
||||
for (let i = 0; i < 5; i += 1) {
|
||||
if (requestMock.mock.calls.some((call) => call[0] === "watch.subscribe")) return;
|
||||
if (requestMock.mock.calls.some((call) => call[0] === "watch.subscribe"))
|
||||
return;
|
||||
await flush();
|
||||
}
|
||||
}
|
||||
@@ -62,7 +67,8 @@ beforeEach(() => {
|
||||
},
|
||||
};
|
||||
requestMock.mockReset().mockImplementation((method: string) => {
|
||||
if (method === "watch.subscribe") return Promise.resolve({ subscription: 1 });
|
||||
if (method === "watch.subscribe")
|
||||
return Promise.resolve({ subscription: 1 });
|
||||
return Promise.resolve({});
|
||||
});
|
||||
stopMock.mockReset().mockResolvedValue(undefined);
|
||||
|
||||
@@ -176,15 +176,18 @@ export async function monitorIMessageProvider(
|
||||
return;
|
||||
}
|
||||
|
||||
const attachments = includeAttachments ? message.attachments ?? [] : [];
|
||||
const attachments = includeAttachments ? (message.attachments ?? []) : [];
|
||||
const firstAttachment = attachments?.find(
|
||||
(entry) => entry?.original_path && !entry?.missing,
|
||||
);
|
||||
const mediaPath = firstAttachment?.original_path ?? undefined;
|
||||
const mediaType = firstAttachment?.mime_type ?? undefined;
|
||||
const kind = mediaKindFromMime(mediaType ?? undefined);
|
||||
const placeholder =
|
||||
kind ? `<media:${kind}>` : attachments?.length ? "<media:attachment>" : "";
|
||||
const placeholder = kind
|
||||
? `<media:${kind}>`
|
||||
: attachments?.length
|
||||
? "<media:attachment>"
|
||||
: "";
|
||||
const bodyText = messageText || placeholder;
|
||||
if (!bodyText) return;
|
||||
|
||||
@@ -279,7 +282,9 @@ export async function monitorIMessageProvider(
|
||||
const abort = opts.abortSignal;
|
||||
const onAbort = () => {
|
||||
if (subscriptionId) {
|
||||
void client.request("watch.unsubscribe", { subscription: subscriptionId });
|
||||
void client.request("watch.unsubscribe", {
|
||||
subscription: subscriptionId,
|
||||
});
|
||||
}
|
||||
void client.stop();
|
||||
};
|
||||
|
||||
@@ -7,9 +7,7 @@ export type IMessageProbe = {
|
||||
error?: string | null;
|
||||
};
|
||||
|
||||
export async function probeIMessage(
|
||||
timeoutMs = 2000,
|
||||
): Promise<IMessageProbe> {
|
||||
export async function probeIMessage(timeoutMs = 2000): Promise<IMessageProbe> {
|
||||
const cfg = loadConfig();
|
||||
const cliPath = cfg.imessage?.cliPath?.trim() || "imsg";
|
||||
const dbPath = cfg.imessage?.dbPath?.trim();
|
||||
|
||||
@@ -5,8 +5,8 @@ import { loadWebMedia } from "../web/media.js";
|
||||
import { createIMessageRpcClient, type IMessageRpcClient } from "./client.js";
|
||||
import {
|
||||
formatIMessageChatTarget,
|
||||
parseIMessageTarget,
|
||||
type IMessageService,
|
||||
parseIMessageTarget,
|
||||
} from "./targets.js";
|
||||
|
||||
export type IMessageSendOpts = {
|
||||
@@ -38,9 +38,7 @@ function resolveDbPath(explicit?: string): string | undefined {
|
||||
function resolveService(explicit?: IMessageService): IMessageService {
|
||||
const cfg = loadConfig();
|
||||
return (
|
||||
explicit ||
|
||||
(cfg.imessage?.service as IMessageService | undefined) ||
|
||||
"auto"
|
||||
explicit || (cfg.imessage?.service as IMessageService | undefined) || "auto"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -85,7 +83,8 @@ export async function sendMessageIMessage(
|
||||
filePath = resolved.path;
|
||||
if (!message.trim()) {
|
||||
const kind = mediaKindFromMime(resolved.contentType ?? undefined);
|
||||
if (kind) message = kind === "image" ? "<media:image>" : `<media:${kind}>`;
|
||||
if (kind)
|
||||
message = kind === "image" ? "<media:image>" : `<media:${kind}>`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +109,8 @@ export async function sendMessageIMessage(
|
||||
params.to = target.to;
|
||||
}
|
||||
|
||||
const client = opts.client ?? (await createIMessageRpcClient({ cliPath, dbPath }));
|
||||
const client =
|
||||
opts.client ?? (await createIMessageRpcClient({ cliPath, dbPath }));
|
||||
const shouldClose = !opts.client;
|
||||
try {
|
||||
const result = await client.request<{ ok?: boolean }>("send", params, {
|
||||
|
||||
@@ -27,9 +27,7 @@ describe("imessage targets", () => {
|
||||
expect(normalizeIMessageHandle("Name@Example.com")).toBe(
|
||||
"name@example.com",
|
||||
);
|
||||
expect(normalizeIMessageHandle(" +1 (555) 222-3333 ")).toBe(
|
||||
"+15552223333",
|
||||
);
|
||||
expect(normalizeIMessageHandle(" +1 (555) 222-3333 ")).toBe("+15552223333");
|
||||
});
|
||||
|
||||
it("checks allowFrom against chat_id", () => {
|
||||
|
||||
@@ -35,9 +35,12 @@ export function normalizeIMessageHandle(raw: string): string {
|
||||
const trimmed = raw.trim();
|
||||
if (!trimmed) return "";
|
||||
const lowered = trimmed.toLowerCase();
|
||||
if (lowered.startsWith("imessage:")) return normalizeIMessageHandle(trimmed.slice(9));
|
||||
if (lowered.startsWith("sms:")) return normalizeIMessageHandle(trimmed.slice(4));
|
||||
if (lowered.startsWith("auto:")) return normalizeIMessageHandle(trimmed.slice(5));
|
||||
if (lowered.startsWith("imessage:"))
|
||||
return normalizeIMessageHandle(trimmed.slice(9));
|
||||
if (lowered.startsWith("sms:"))
|
||||
return normalizeIMessageHandle(trimmed.slice(4));
|
||||
if (lowered.startsWith("auto:"))
|
||||
return normalizeIMessageHandle(trimmed.slice(5));
|
||||
if (trimmed.includes("@")) return trimmed.toLowerCase();
|
||||
const normalized = normalizeE164(trimmed);
|
||||
if (normalized) return normalized;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
import {
|
||||
clearAgentRunContext,
|
||||
emitAgentEvent,
|
||||
getAgentRunContext,
|
||||
onAgentEvent,
|
||||
registerAgentRunContext,
|
||||
getAgentRunContext,
|
||||
clearAgentRunContext,
|
||||
resetAgentRunContextForTest,
|
||||
} from "./agent-events.js";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user