@elizaos/plugin-imessage 2.0.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,548 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import imessagePlugin, {
4
+ IMessageService,
5
+ chatContextProvider,
6
+ sendMessage,
7
+ // Type utilities
8
+ isPhoneNumber,
9
+ isEmail,
10
+ isValidIMessageTarget,
11
+ normalizeIMessageTarget,
12
+ formatPhoneNumber,
13
+ splitMessageForIMessage,
14
+ MAX_IMESSAGE_MESSAGE_LENGTH,
15
+ // Parsing functions
16
+ parseMessagesFromAppleScript,
17
+ parseChatsFromAppleScript,
18
+ // Error classes
19
+ IMessagePluginError,
20
+ IMessageConfigurationError,
21
+ IMessageNotSupportedError,
22
+ IMessageCliError,
23
+ // Event types
24
+ IMessageEventTypes,
25
+ IMESSAGE_SERVICE_NAME,
26
+ } from "../src/index";
27
+
28
+ // ============================================================
29
+ // Plugin exports
30
+ // ============================================================
31
+
32
+ describe("iMessage plugin exports", () => {
33
+ it("exports plugin metadata", () => {
34
+ expect(imessagePlugin.name).toBe("imessage");
35
+ expect(imessagePlugin.description).toContain("iMessage");
36
+ expect(Array.isArray(imessagePlugin.actions)).toBe(true);
37
+ expect(Array.isArray(imessagePlugin.providers)).toBe(true);
38
+ expect(Array.isArray(imessagePlugin.services)).toBe(true);
39
+ });
40
+
41
+ it("exports actions, providers, and service", () => {
42
+ expect(sendMessage).toBeDefined();
43
+ expect(chatContextProvider).toBeDefined();
44
+ expect(IMessageService).toBeDefined();
45
+ });
46
+
47
+ it("exports parsing utility functions", () => {
48
+ expect(parseMessagesFromAppleScript).toBeDefined();
49
+ expect(parseChatsFromAppleScript).toBeDefined();
50
+ });
51
+
52
+ it("exports constants", () => {
53
+ expect(IMESSAGE_SERVICE_NAME).toBe("imessage");
54
+ expect(MAX_IMESSAGE_MESSAGE_LENGTH).toBe(4000);
55
+ expect(IMessageEventTypes.MESSAGE_RECEIVED).toBe(
56
+ "IMESSAGE_MESSAGE_RECEIVED",
57
+ );
58
+ expect(IMessageEventTypes.MESSAGE_SENT).toBe("IMESSAGE_MESSAGE_SENT");
59
+ expect(IMessageEventTypes.CONNECTION_READY).toBe(
60
+ "IMESSAGE_CONNECTION_READY",
61
+ );
62
+ expect(IMessageEventTypes.ERROR).toBe("IMESSAGE_ERROR");
63
+ });
64
+ });
65
+
66
+ // ============================================================
67
+ // isPhoneNumber
68
+ // ============================================================
69
+
70
+ describe("isPhoneNumber", () => {
71
+ it("accepts valid US phone numbers", () => {
72
+ expect(isPhoneNumber("+15551234567")).toBe(true);
73
+ expect(isPhoneNumber("15551234567")).toBe(true);
74
+ });
75
+
76
+ it("accepts formatted phone numbers", () => {
77
+ expect(isPhoneNumber("1-555-123-4567")).toBe(true);
78
+ expect(isPhoneNumber("(555) 123-4567")).toBe(true);
79
+ expect(isPhoneNumber("555.123.4567")).toBe(true);
80
+ });
81
+
82
+ it("accepts international phone numbers", () => {
83
+ expect(isPhoneNumber("+44 7700 900000")).toBe(true);
84
+ expect(isPhoneNumber("+61412345678")).toBe(true);
85
+ });
86
+
87
+ it("rejects emails", () => {
88
+ expect(isPhoneNumber("test@example.com")).toBe(false);
89
+ });
90
+
91
+ it("rejects too-short numbers", () => {
92
+ expect(isPhoneNumber("12345")).toBe(false);
93
+ expect(isPhoneNumber("123")).toBe(false);
94
+ });
95
+
96
+ it("rejects plain text", () => {
97
+ expect(isPhoneNumber("hello world")).toBe(false);
98
+ expect(isPhoneNumber("not a phone")).toBe(false);
99
+ });
100
+
101
+ it("rejects empty string", () => {
102
+ expect(isPhoneNumber("")).toBe(false);
103
+ });
104
+ });
105
+
106
+ // ============================================================
107
+ // isEmail
108
+ // ============================================================
109
+
110
+ describe("isEmail", () => {
111
+ it("accepts valid email addresses", () => {
112
+ expect(isEmail("test@example.com")).toBe(true);
113
+ expect(isEmail("user.name@domain.co.uk")).toBe(true);
114
+ expect(isEmail("admin@sub.domain.org")).toBe(true);
115
+ });
116
+
117
+ it("rejects phone numbers", () => {
118
+ expect(isEmail("+15551234567")).toBe(false);
119
+ });
120
+
121
+ it("rejects plain text", () => {
122
+ expect(isEmail("not an email")).toBe(false);
123
+ expect(isEmail("hello")).toBe(false);
124
+ });
125
+
126
+ it("rejects partial addresses", () => {
127
+ expect(isEmail("@domain.com")).toBe(false);
128
+ expect(isEmail("user@")).toBe(false);
129
+ });
130
+
131
+ it("rejects empty string", () => {
132
+ expect(isEmail("")).toBe(false);
133
+ });
134
+ });
135
+
136
+ // ============================================================
137
+ // isValidIMessageTarget
138
+ // ============================================================
139
+
140
+ describe("isValidIMessageTarget", () => {
141
+ it("accepts phone numbers", () => {
142
+ expect(isValidIMessageTarget("+15551234567")).toBe(true);
143
+ });
144
+
145
+ it("accepts email addresses", () => {
146
+ expect(isValidIMessageTarget("user@example.com")).toBe(true);
147
+ });
148
+
149
+ it("accepts chat_id: prefixed targets", () => {
150
+ expect(isValidIMessageTarget("chat_id:iMessage;+;chat12345")).toBe(true);
151
+ });
152
+
153
+ it("rejects invalid targets", () => {
154
+ expect(isValidIMessageTarget("hello world")).toBe(false);
155
+ expect(isValidIMessageTarget("123")).toBe(false);
156
+ });
157
+
158
+ it("handles whitespace", () => {
159
+ expect(isValidIMessageTarget(" +15551234567 ")).toBe(true);
160
+ });
161
+ });
162
+
163
+ // ============================================================
164
+ // normalizeIMessageTarget
165
+ // ============================================================
166
+
167
+ describe("normalizeIMessageTarget", () => {
168
+ it("returns null for empty string", () => {
169
+ expect(normalizeIMessageTarget("")).toBeNull();
170
+ expect(normalizeIMessageTarget(" ")).toBeNull();
171
+ });
172
+
173
+ it("preserves chat_id: prefix", () => {
174
+ expect(normalizeIMessageTarget("chat_id:12345")).toBe("chat_id:12345");
175
+ });
176
+
177
+ it("strips imessage: prefix", () => {
178
+ const result = normalizeIMessageTarget("imessage:+15551234567");
179
+ expect(result).toBe("+15551234567");
180
+ });
181
+
182
+ it("trims whitespace", () => {
183
+ expect(normalizeIMessageTarget(" +15551234567 ")).toBe("+15551234567");
184
+ });
185
+
186
+ it("returns phone/email as-is", () => {
187
+ expect(normalizeIMessageTarget("+15551234567")).toBe("+15551234567");
188
+ expect(normalizeIMessageTarget("user@example.com")).toBe(
189
+ "user@example.com",
190
+ );
191
+ });
192
+ });
193
+
194
+ // ============================================================
195
+ // formatPhoneNumber
196
+ // ============================================================
197
+
198
+ describe("formatPhoneNumber", () => {
199
+ it("removes formatting characters", () => {
200
+ expect(formatPhoneNumber("+1 (555) 123-4567")).toBe("+15551234567");
201
+ });
202
+
203
+ it("adds + prefix for international numbers > 10 digits", () => {
204
+ expect(formatPhoneNumber("15551234567")).toBe("+15551234567");
205
+ });
206
+
207
+ it("preserves existing + prefix", () => {
208
+ expect(formatPhoneNumber("+15551234567")).toBe("+15551234567");
209
+ });
210
+
211
+ it("does not add + for 10-digit numbers", () => {
212
+ expect(formatPhoneNumber("5551234567")).toBe("5551234567");
213
+ });
214
+
215
+ it("handles dots and spaces", () => {
216
+ expect(formatPhoneNumber("555.123.4567")).toBe("5551234567");
217
+ });
218
+ });
219
+
220
+ // ============================================================
221
+ // splitMessageForIMessage
222
+ // ============================================================
223
+
224
+ describe("splitMessageForIMessage", () => {
225
+ it("returns single chunk for short messages", () => {
226
+ const result = splitMessageForIMessage("Hello world");
227
+ expect(result).toEqual(["Hello world"]);
228
+ });
229
+
230
+ it("returns single chunk for exactly max-length messages", () => {
231
+ const text = "a".repeat(MAX_IMESSAGE_MESSAGE_LENGTH);
232
+ const result = splitMessageForIMessage(text);
233
+ expect(result).toHaveLength(1);
234
+ expect(result[0]).toBe(text);
235
+ });
236
+
237
+ it("splits long messages at word boundaries", () => {
238
+ const words = Array.from({ length: 500 }, (_, i) => `word${i}`).join(" ");
239
+ const result = splitMessageForIMessage(words, 100);
240
+ expect(result.length).toBeGreaterThan(1);
241
+ for (const chunk of result) {
242
+ expect(chunk.length).toBeLessThanOrEqual(100);
243
+ }
244
+ });
245
+
246
+ it("prefers newline break points", () => {
247
+ const text = "a".repeat(60) + "\n" + "b".repeat(30);
248
+ const result = splitMessageForIMessage(text, 80);
249
+ expect(result).toHaveLength(2);
250
+ expect(result[0]).toBe("a".repeat(60));
251
+ expect(result[1]).toBe("b".repeat(30));
252
+ });
253
+
254
+ it("handles text with no break points", () => {
255
+ const text = "a".repeat(200);
256
+ const result = splitMessageForIMessage(text, 100);
257
+ expect(result.length).toBeGreaterThan(1);
258
+ // All text should be preserved
259
+ expect(result.join("")).toBe(text);
260
+ });
261
+
262
+ it("returns empty array for empty string", () => {
263
+ const result = splitMessageForIMessage("");
264
+ expect(result).toEqual([""]);
265
+ });
266
+ });
267
+
268
+ // ============================================================
269
+ // parseMessagesFromAppleScript
270
+ // ============================================================
271
+
272
+ describe("parseMessagesFromAppleScript", () => {
273
+ it("parses a single message line", () => {
274
+ const input =
275
+ "msg001\tHello there\t1700000000000\t0\tchat123\t+15551234567";
276
+ const result = parseMessagesFromAppleScript(input);
277
+
278
+ expect(result).toHaveLength(1);
279
+ expect(result[0].id).toBe("msg001");
280
+ expect(result[0].text).toBe("Hello there");
281
+ expect(result[0].timestamp).toBe(1700000000000);
282
+ expect(result[0].isFromMe).toBe(false);
283
+ expect(result[0].chatId).toBe("chat123");
284
+ expect(result[0].handle).toBe("+15551234567");
285
+ expect(result[0].hasAttachments).toBe(false);
286
+ });
287
+
288
+ it("parses multiple message lines", () => {
289
+ const input = [
290
+ "msg001\tHello\t1700000000000\t0\tchat1\t+15551111111",
291
+ "msg002\tWorld\t1700000001000\t1\tchat1\t+15552222222",
292
+ "msg003\tTest\t1700000002000\ttrue\tchat2\tuser@test.com",
293
+ ].join("\n");
294
+
295
+ const result = parseMessagesFromAppleScript(input);
296
+ expect(result).toHaveLength(3);
297
+ expect(result[0].text).toBe("Hello");
298
+ expect(result[0].isFromMe).toBe(false);
299
+ expect(result[1].text).toBe("World");
300
+ expect(result[1].isFromMe).toBe(true);
301
+ expect(result[2].text).toBe("Test");
302
+ expect(result[2].isFromMe).toBe(true);
303
+ });
304
+
305
+ it("returns empty array for empty string", () => {
306
+ expect(parseMessagesFromAppleScript("")).toEqual([]);
307
+ });
308
+
309
+ it("returns empty array for whitespace-only input", () => {
310
+ expect(parseMessagesFromAppleScript(" \n \n ")).toEqual([]);
311
+ });
312
+
313
+ it("skips lines with fewer than 6 fields", () => {
314
+ const input =
315
+ "partial\tdata\n" +
316
+ "msg001\tHello\t1700000000000\t0\tchat1\t+15551234567";
317
+ const result = parseMessagesFromAppleScript(input);
318
+ expect(result).toHaveLength(1);
319
+ expect(result[0].id).toBe("msg001");
320
+ });
321
+
322
+ it("handles is_from_me variations", () => {
323
+ const lines = [
324
+ "m1\ttext\t1000\t1\tchat\tsender",
325
+ "m2\ttext\t1000\ttrue\tchat\tsender",
326
+ "m3\ttext\t1000\tTrue\tchat\tsender",
327
+ "m4\ttext\t1000\t0\tchat\tsender",
328
+ "m5\ttext\t1000\tfalse\tchat\tsender",
329
+ ].join("\n");
330
+
331
+ const result = parseMessagesFromAppleScript(lines);
332
+ expect(result[0].isFromMe).toBe(true);
333
+ expect(result[1].isFromMe).toBe(true);
334
+ expect(result[2].isFromMe).toBe(true);
335
+ expect(result[3].isFromMe).toBe(false);
336
+ expect(result[4].isFromMe).toBe(false);
337
+ });
338
+
339
+ it("handles invalid date by setting timestamp to 0", () => {
340
+ const input = "msg001\tHello\tinvalid_date\t0\tchat1\tsender";
341
+ const result = parseMessagesFromAppleScript(input);
342
+ expect(result).toHaveLength(1);
343
+ expect(result[0].timestamp).toBe(0);
344
+ });
345
+
346
+ it("handles empty fields gracefully", () => {
347
+ // Use boundary placeholders so trim() doesn't strip leading/trailing tabs
348
+ const input = ".\t\t1000\t0\t\t.";
349
+ const result = parseMessagesFromAppleScript(input);
350
+ expect(result).toHaveLength(1);
351
+ expect(result[0].id).toBe(".");
352
+ expect(result[0].text).toBe("");
353
+ expect(result[0].chatId).toBe("");
354
+ expect(result[0].handle).toBe(".");
355
+ });
356
+
357
+ it("returns empty for all-tab line (tabs trimmed as whitespace)", () => {
358
+ const input = "\t\t1000\t0\t\t";
359
+ const result = parseMessagesFromAppleScript(input);
360
+ expect(result).toHaveLength(0);
361
+ });
362
+
363
+ it("handles extra tab-separated fields (forward compat)", () => {
364
+ const input =
365
+ "msg001\tHello\t1000\t1\tchat1\tsender\textra1\textra2";
366
+ const result = parseMessagesFromAppleScript(input);
367
+ expect(result).toHaveLength(1);
368
+ expect(result[0].id).toBe("msg001");
369
+ });
370
+ });
371
+
372
+ // ============================================================
373
+ // parseChatsFromAppleScript
374
+ // ============================================================
375
+
376
+ describe("parseChatsFromAppleScript", () => {
377
+ it("parses a single chat line", () => {
378
+ const input = "chat123\tWork Group\t5\t1700000000000";
379
+ const result = parseChatsFromAppleScript(input);
380
+
381
+ expect(result).toHaveLength(1);
382
+ expect(result[0].chatId).toBe("chat123");
383
+ expect(result[0].displayName).toBe("Work Group");
384
+ expect(result[0].chatType).toBe("group");
385
+ expect(result[0].participants).toEqual([]);
386
+ });
387
+
388
+ it("parses multiple chat lines", () => {
389
+ const input = [
390
+ "chat1\tWork\t5\t1700000000000",
391
+ "chat2\tFamily\t3\t1700000001000",
392
+ "chat3\t\t1\t1700000002000",
393
+ ].join("\n");
394
+
395
+ const result = parseChatsFromAppleScript(input);
396
+ expect(result).toHaveLength(3);
397
+ expect(result[0].chatType).toBe("group");
398
+ expect(result[1].chatType).toBe("group");
399
+ expect(result[2].chatType).toBe("direct");
400
+ });
401
+
402
+ it("returns empty array for empty string", () => {
403
+ expect(parseChatsFromAppleScript("")).toEqual([]);
404
+ });
405
+
406
+ it("returns empty array for whitespace-only input", () => {
407
+ expect(parseChatsFromAppleScript(" \n \n ")).toEqual([]);
408
+ });
409
+
410
+ it("classifies direct chats (participant_count <= 1)", () => {
411
+ const input = "chat1\tJohn\t1\t1700000000000";
412
+ const result = parseChatsFromAppleScript(input);
413
+ expect(result[0].chatType).toBe("direct");
414
+ });
415
+
416
+ it("classifies group chats (participant_count > 1)", () => {
417
+ const input = "chat1\tTeam\t2\t1700000000000";
418
+ const result = parseChatsFromAppleScript(input);
419
+ expect(result[0].chatType).toBe("group");
420
+ });
421
+
422
+ it("handles empty display name", () => {
423
+ const input = "chat1\t\t1\t1700000000000";
424
+ const result = parseChatsFromAppleScript(input);
425
+ expect(result[0].displayName).toBeUndefined();
426
+ });
427
+
428
+ it("handles invalid participant count", () => {
429
+ const input = "chat1\tTest\tnotanumber\t1700000000000";
430
+ const result = parseChatsFromAppleScript(input);
431
+ expect(result).toHaveLength(1);
432
+ expect(result[0].chatType).toBe("direct");
433
+ });
434
+
435
+ it("skips lines with fewer than 4 fields", () => {
436
+ const input =
437
+ "incomplete\tdata\n" + "chat1\tTest\t3\t1700000000000";
438
+ const result = parseChatsFromAppleScript(input);
439
+ expect(result).toHaveLength(1);
440
+ expect(result[0].chatId).toBe("chat1");
441
+ });
442
+
443
+ it("handles extra tab-separated fields (forward compat)", () => {
444
+ const input = "chat1\tTest\t3\t1700000000000\textra";
445
+ const result = parseChatsFromAppleScript(input);
446
+ expect(result).toHaveLength(1);
447
+ expect(result[0].chatId).toBe("chat1");
448
+ });
449
+ });
450
+
451
+ // ============================================================
452
+ // Error classes
453
+ // ============================================================
454
+
455
+ describe("Error classes", () => {
456
+ it("IMessagePluginError has correct properties", () => {
457
+ const error = new IMessagePluginError("test error", "TEST_CODE", {
458
+ key: "value",
459
+ });
460
+ expect(error.message).toBe("test error");
461
+ expect(error.code).toBe("TEST_CODE");
462
+ expect(error.details).toEqual({ key: "value" });
463
+ expect(error.name).toBe("IMessagePluginError");
464
+ expect(error instanceof Error).toBe(true);
465
+ });
466
+
467
+ it("IMessageConfigurationError sets correct code", () => {
468
+ const error = new IMessageConfigurationError("bad config", "cli_path");
469
+ expect(error.code).toBe("CONFIGURATION_ERROR");
470
+ expect(error.details).toEqual({ setting: "cli_path" });
471
+ expect(error.name).toBe("IMessageConfigurationError");
472
+ expect(error instanceof IMessagePluginError).toBe(true);
473
+ });
474
+
475
+ it("IMessageNotSupportedError has default message", () => {
476
+ const error = new IMessageNotSupportedError();
477
+ expect(error.message).toBe("iMessage is only supported on macOS");
478
+ expect(error.code).toBe("NOT_SUPPORTED");
479
+ expect(error.name).toBe("IMessageNotSupportedError");
480
+ });
481
+
482
+ it("IMessageNotSupportedError accepts custom message", () => {
483
+ const error = new IMessageNotSupportedError("custom msg");
484
+ expect(error.message).toBe("custom msg");
485
+ });
486
+
487
+ it("IMessageCliError includes exit code", () => {
488
+ const error = new IMessageCliError("command failed", 1);
489
+ expect(error.code).toBe("CLI_ERROR");
490
+ expect(error.details).toEqual({ exitCode: 1 });
491
+ expect(error.name).toBe("IMessageCliError");
492
+ });
493
+
494
+ it("IMessageCliError handles undefined exit code", () => {
495
+ const error = new IMessageCliError("command failed");
496
+ expect(error.details).toBeUndefined();
497
+ });
498
+ });
499
+
500
+ // ============================================================
501
+ // Action validation
502
+ // ============================================================
503
+
504
+ describe("sendMessage action", () => {
505
+ it("has correct action metadata", () => {
506
+ expect(sendMessage.name).toBe("IMESSAGE_SEND_MESSAGE");
507
+ expect(sendMessage.description).toContain("iMessage");
508
+ expect(Array.isArray(sendMessage.similes)).toBe(true);
509
+ expect(sendMessage.similes?.length).toBeGreaterThan(0);
510
+ expect(Array.isArray(sendMessage.examples)).toBe(true);
511
+ expect(sendMessage.examples?.length).toBeGreaterThan(0);
512
+ });
513
+
514
+ it("validate returns false for non-imessage sources", async () => {
515
+ const mockRuntime = {} as Parameters<
516
+ NonNullable<typeof sendMessage.validate>
517
+ >[0];
518
+ const mockMessage = {
519
+ content: { source: "discord" },
520
+ } as Parameters<NonNullable<typeof sendMessage.validate>>[1];
521
+
522
+ const result = await sendMessage.validate!(mockRuntime, mockMessage);
523
+ expect(result).toBe(false);
524
+ });
525
+
526
+ it("validate returns true for imessage source", async () => {
527
+ const mockRuntime = {} as Parameters<
528
+ NonNullable<typeof sendMessage.validate>
529
+ >[0];
530
+ const mockMessage = {
531
+ content: { source: "imessage" },
532
+ } as Parameters<NonNullable<typeof sendMessage.validate>>[1];
533
+
534
+ const result = await sendMessage.validate!(mockRuntime, mockMessage);
535
+ expect(result).toBe(true);
536
+ });
537
+ });
538
+
539
+ // ============================================================
540
+ // Chat context provider
541
+ // ============================================================
542
+
543
+ describe("chatContextProvider", () => {
544
+ it("has correct provider metadata", () => {
545
+ expect(chatContextProvider.name).toBe("imessageChatContext");
546
+ expect(chatContextProvider.description).toContain("iMessage");
547
+ });
548
+ });
package/build.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { execSync } from "node:child_process";
2
+ import { rmSync } from "node:fs";
3
+ import { join } from "node:path";
4
+
5
+ const distDir = join(import.meta.dirname, "dist");
6
+
7
+ // Clean
8
+ rmSync(distDir, { recursive: true, force: true });
9
+
10
+ // Build
11
+ execSync("npx tsc -p tsconfig.json", {
12
+ cwd: import.meta.dirname,
13
+ stdio: "inherit",
14
+ });
15
+
16
+ console.log("Build complete: plugin-imessage");
package/dist/index.js ADDED
@@ -0,0 +1,46 @@
1
+ /**
2
+ * iMessage Plugin for ElizaOS
3
+ *
4
+ * Provides iMessage integration for ElizaOS agents on macOS.
5
+ * Uses AppleScript and/or CLI tools to send and receive messages.
6
+ */
7
+ import { platform } from "node:os";
8
+ import { logger } from "@elizaos/core";
9
+ import { sendMessage } from "./actions/index.js";
10
+ import { chatContextProvider } from "./providers/index.js";
11
+ import { IMessageService } from "./service.js";
12
+ // Re-export types and service
13
+ export * from "./types.js";
14
+ export { IMessageService };
15
+ export { sendMessage };
16
+ export { chatContextProvider };
17
+ // Account management exports
18
+ export { DEFAULT_ACCOUNT_ID, isIMessageMentionRequired, isIMessageUserAllowed, isMultiAccountEnabled, listEnabledIMessageAccounts, listIMessageAccountIds, normalizeAccountId, resolveDefaultIMessageAccountId, resolveIMessageAccount, resolveIMessageGroupConfig, } from "./accounts.js";
19
+ // RPC client exports
20
+ export { createIMessageRpcClient, DEFAULT_PROBE_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS, getChatInfo, getContactInfo, getMessages, IMessageRpcClient, listChats, listContacts, probeIMessageRpc, sendIMessageRpc, } from "./rpc.js";
21
+ /**
22
+ * iMessage plugin for ElizaOS agents.
23
+ */
24
+ const imessagePlugin = {
25
+ name: "imessage",
26
+ description: "iMessage plugin for ElizaOS agents (macOS only)",
27
+ services: [IMessageService],
28
+ actions: [sendMessage],
29
+ providers: [chatContextProvider],
30
+ tests: [],
31
+ init: async (config, _runtime) => {
32
+ logger.info("Initializing iMessage plugin...");
33
+ const isMacOS = platform() === "darwin";
34
+ logger.info("iMessage plugin configuration:");
35
+ logger.info(` - Platform: ${platform()}`);
36
+ logger.info(` - macOS: ${isMacOS ? "Yes" : "No"}`);
37
+ logger.info(` - CLI path: ${config.IMESSAGE_CLI_PATH || process.env.IMESSAGE_CLI_PATH || "imsg (default)"}`);
38
+ logger.info(` - DM policy: ${config.IMESSAGE_DM_POLICY || process.env.IMESSAGE_DM_POLICY || "pairing"}`);
39
+ if (!isMacOS) {
40
+ logger.warn("iMessage plugin is only supported on macOS. The plugin will be inactive on this platform.");
41
+ }
42
+ logger.info("iMessage plugin initialized");
43
+ },
44
+ };
45
+ export default imessagePlugin;
46
+ //# sourceMappingURL=index.js.map
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@elizaos/plugin-imessage",
3
+ "version": "2.0.0-alpha.3",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "bun run build.ts",
9
+ "test": "vitest run",
10
+ "lint": "biome check --write --unsafe src"
11
+ },
12
+ "dependencies": {
13
+ "@elizaos/core": "2.0.0-alpha.3",
14
+ "zod": "^4.3.6"
15
+ },
16
+ "devDependencies": {
17
+ "@types/node": "^20.0.0",
18
+ "typescript": "^5.6.0",
19
+ "vitest": "^2.0.0"
20
+ },
21
+ "milaidy": {
22
+ "platforms": [
23
+ "node"
24
+ ],
25
+ "runtime": "node",
26
+ "platformDetails": {
27
+ "node": "Node.js via main entry point"
28
+ }
29
+ },
30
+ "publishConfig": {
31
+ "access": "public"
32
+ }
33
+ }