mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-13 15:47:28 +00:00
fix(imessage): report non-mac default imsg hosts
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
"name": "@openclaw/imessage",
|
"name": "@openclaw/imessage",
|
||||||
"version": "2026.5.6",
|
"version": "2026.5.6",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "OpenClaw iMessage channel plugin",
|
"description": "OpenClaw iMessage channel plugin using imsg on a signed-in Mac",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@openclaw/plugin-sdk": "workspace:*"
|
"@openclaw/plugin-sdk": "workspace:*"
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
"detailLabel": "iMessage",
|
"detailLabel": "iMessage",
|
||||||
"docsPath": "/channels/imessage",
|
"docsPath": "/channels/imessage",
|
||||||
"docsLabel": "imessage",
|
"docsLabel": "imessage",
|
||||||
"blurb": "this is still a work in progress.",
|
"blurb": "iMessage via the imsg CLI on a signed-in Mac or SSH wrapper.",
|
||||||
"aliases": [
|
"aliases": [
|
||||||
"imsg"
|
"imsg"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import path from "node:path";
|
||||||
import type { BaseProbeResult } from "openclaw/plugin-sdk/channel-contract";
|
import type { BaseProbeResult } from "openclaw/plugin-sdk/channel-contract";
|
||||||
import { runCommandWithTimeout } from "openclaw/plugin-sdk/process-runtime";
|
import { runCommandWithTimeout } from "openclaw/plugin-sdk/process-runtime";
|
||||||
import { getRuntimeConfig } from "openclaw/plugin-sdk/runtime-config-snapshot";
|
import { getRuntimeConfig } from "openclaw/plugin-sdk/runtime-config-snapshot";
|
||||||
@@ -17,6 +18,7 @@ export type IMessageProbe = BaseProbeResult & {
|
|||||||
export type IMessageProbeOptions = {
|
export type IMessageProbeOptions = {
|
||||||
cliPath?: string;
|
cliPath?: string;
|
||||||
dbPath?: string;
|
dbPath?: string;
|
||||||
|
platform?: NodeJS.Platform;
|
||||||
runtime?: RuntimeEnv;
|
runtime?: RuntimeEnv;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -28,6 +30,21 @@ type RpcSupportResult = {
|
|||||||
|
|
||||||
const rpcSupportCache = new Map<string, RpcSupportResult>();
|
const rpcSupportCache = new Map<string, RpcSupportResult>();
|
||||||
|
|
||||||
|
function isDefaultLocalIMessageCliPath(cliPath: string): boolean {
|
||||||
|
const trimmed = cliPath.trim();
|
||||||
|
return trimmed === "imsg" || (!trimmed.includes("/") && path.basename(trimmed) === "imsg");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveIMessageNonMacHostError(
|
||||||
|
cliPath: string,
|
||||||
|
platform: NodeJS.Platform = process.platform,
|
||||||
|
): string | undefined {
|
||||||
|
if (platform === "darwin" || !isDefaultLocalIMessageCliPath(cliPath)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return "iMessage via the default imsg CLI must run on macOS. Run OpenClaw on the signed-in Messages Mac, or set channels.imessage.cliPath to an SSH wrapper that runs imsg on that Mac.";
|
||||||
|
}
|
||||||
|
|
||||||
async function probeRpcSupport(cliPath: string, timeoutMs: number): Promise<RpcSupportResult> {
|
async function probeRpcSupport(cliPath: string, timeoutMs: number): Promise<RpcSupportResult> {
|
||||||
const cached = rpcSupportCache.get(cliPath);
|
const cached = rpcSupportCache.get(cliPath);
|
||||||
if (cached) {
|
if (cached) {
|
||||||
@@ -76,6 +93,11 @@ export async function probeIMessage(
|
|||||||
const effectiveTimeout =
|
const effectiveTimeout =
|
||||||
timeoutMs ?? cfg?.channels?.imessage?.probeTimeoutMs ?? DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS;
|
timeoutMs ?? cfg?.channels?.imessage?.probeTimeoutMs ?? DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS;
|
||||||
|
|
||||||
|
const nonMacHostError = resolveIMessageNonMacHostError(cliPath, opts.platform);
|
||||||
|
if (nonMacHostError) {
|
||||||
|
return { ok: false, fatal: true, error: nonMacHostError };
|
||||||
|
}
|
||||||
|
|
||||||
const detected = await detectBinary(cliPath);
|
const detected = await detectBinary(cliPath);
|
||||||
if (!detected) {
|
if (!detected) {
|
||||||
return { ok: false, error: `imsg not found (${cliPath})` };
|
return { ok: false, error: `imsg not found (${cliPath})` };
|
||||||
|
|||||||
@@ -169,7 +169,8 @@ export function createIMessageCliPathTextInput(
|
|||||||
export const imessageCompletionNote = {
|
export const imessageCompletionNote = {
|
||||||
title: "iMessage next steps",
|
title: "iMessage next steps",
|
||||||
lines: [
|
lines: [
|
||||||
"This is still a work in progress.",
|
"Run OpenClaw on the Mac signed into Messages, or set cliPath to an SSH wrapper that runs imsg on that Mac.",
|
||||||
|
"Linux/Windows hosts cannot run the default local imsg path directly.",
|
||||||
"Ensure OpenClaw has Full Disk Access to Messages DB.",
|
"Ensure OpenClaw has Full Disk Access to Messages DB.",
|
||||||
"Grant Automation permission for Messages when prompted.",
|
"Grant Automation permission for Messages when prompted.",
|
||||||
"List chats with: imsg chats --limit 20",
|
"List chats with: imsg chats --limit 20",
|
||||||
|
|||||||
@@ -169,6 +169,24 @@ describe("probeIMessage", () => {
|
|||||||
expect(createIMessageRpcClientMock).not.toHaveBeenCalled();
|
expect(createIMessageRpcClientMock).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("fails fast for default local imsg probes on non-mac hosts", async () => {
|
||||||
|
const createIMessageRpcClientMock = vi
|
||||||
|
.spyOn(clientModule, "createIMessageRpcClient")
|
||||||
|
.mockResolvedValue({
|
||||||
|
request: vi.fn(),
|
||||||
|
stop: vi.fn(),
|
||||||
|
} as unknown as Awaited<ReturnType<typeof clientModule.createIMessageRpcClient>>);
|
||||||
|
|
||||||
|
const result = await probeIMessage(1000, { cliPath: "imsg", platform: "linux" });
|
||||||
|
|
||||||
|
expect(result.ok).toBe(false);
|
||||||
|
expect(result.fatal).toBe(true);
|
||||||
|
expect(result.error).toMatch(/macOS/i);
|
||||||
|
expect(result.error).toMatch(/SSH wrapper/i);
|
||||||
|
expect(setupRuntime.detectBinary).not.toHaveBeenCalled();
|
||||||
|
expect(createIMessageRpcClientMock).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
it("status probe uses account-scoped cliPath and dbPath", async () => {
|
it("status probe uses account-scoped cliPath and dbPath", async () => {
|
||||||
const probeSpy = vi.spyOn(channelRuntimeModule, "probeIMessageAccount").mockResolvedValue({
|
const probeSpy = vi.spyOn(channelRuntimeModule, "probeIMessageAccount").mockResolvedValue({
|
||||||
ok: true,
|
ok: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user