@elizaos/plugin-imessage 2.0.0-beta.1 → 2.0.3-beta.2

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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +13 -18
  3. package/auto-enable.ts +1 -1
  4. package/package.json +21 -4
  5. package/dist/accounts.d.ts +0 -135
  6. package/dist/accounts.d.ts.map +0 -1
  7. package/dist/accounts.js +0 -209
  8. package/dist/accounts.js.map +0 -1
  9. package/dist/api/bluebubbles-routes.d.ts +0 -10
  10. package/dist/api/bluebubbles-routes.d.ts.map +0 -1
  11. package/dist/api/bluebubbles-routes.js +0 -132
  12. package/dist/api/bluebubbles-routes.js.map +0 -1
  13. package/dist/api/imessage-routes.d.ts +0 -80
  14. package/dist/api/imessage-routes.d.ts.map +0 -1
  15. package/dist/api/imessage-routes.js +0 -230
  16. package/dist/api/imessage-routes.js.map +0 -1
  17. package/dist/chatdb-reader.d.ts +0 -240
  18. package/dist/chatdb-reader.d.ts.map +0 -1
  19. package/dist/chatdb-reader.js +0 -647
  20. package/dist/chatdb-reader.js.map +0 -1
  21. package/dist/config.d.ts +0 -60
  22. package/dist/config.d.ts.map +0 -1
  23. package/dist/config.js +0 -8
  24. package/dist/config.js.map +0 -1
  25. package/dist/connector-account-provider.d.ts +0 -18
  26. package/dist/connector-account-provider.d.ts.map +0 -1
  27. package/dist/connector-account-provider.js +0 -83
  28. package/dist/connector-account-provider.js.map +0 -1
  29. package/dist/contacts-reader.d.ts +0 -147
  30. package/dist/contacts-reader.d.ts.map +0 -1
  31. package/dist/contacts-reader.js +0 -481
  32. package/dist/contacts-reader.js.map +0 -1
  33. package/dist/index.d.ts +0 -23
  34. package/dist/index.d.ts.map +0 -1
  35. package/dist/index.js +0 -78
  36. package/dist/index.js.map +0 -1
  37. package/dist/providers/index.d.ts +0 -4
  38. package/dist/providers/index.d.ts.map +0 -1
  39. package/dist/providers/index.js +0 -5
  40. package/dist/providers/index.js.map +0 -1
  41. package/dist/rpc.d.ts +0 -206
  42. package/dist/rpc.d.ts.map +0 -1
  43. package/dist/rpc.js +0 -393
  44. package/dist/rpc.js.map +0 -1
  45. package/dist/service.d.ts +0 -266
  46. package/dist/service.d.ts.map +0 -1
  47. package/dist/service.js +0 -1694
  48. package/dist/service.js.map +0 -1
  49. package/dist/setup-routes.d.ts +0 -38
  50. package/dist/setup-routes.d.ts.map +0 -1
  51. package/dist/setup-routes.js +0 -322
  52. package/dist/setup-routes.js.map +0 -1
  53. package/dist/types.d.ts +0 -192
  54. package/dist/types.d.ts.map +0 -1
  55. package/dist/types.js +0 -138
  56. package/dist/types.js.map +0 -1
package/dist/service.d.ts DELETED
@@ -1,266 +0,0 @@
1
- /**
2
- * iMessage service implementation for elizaOS.
3
- */
4
- import { type IAgentRuntime, Service } from "@elizaos/core";
5
- import { type ChatDbMessage } from "./chatdb-reader.js";
6
- import { type ContactPatch, type ContactsMap, type FullContact, type NewContactInput } from "./contacts-reader.js";
7
- import { type IIMessageService, type IMessageChat, type IMessageListMessagesOptions, type IMessageMessage, type IMessageSendOptions, type IMessageSendResult, type IMessageServiceStatus, type IMessageSettings } from "./types.js";
8
- /**
9
- * iMessage service for Eliza agents.
10
- * Note: This only works on macOS.
11
- */
12
- export declare class IMessageService extends Service implements IIMessageService {
13
- static serviceType: string;
14
- capabilityDescription: string;
15
- private settings;
16
- private connected;
17
- private pollInterval;
18
- /**
19
- * Highest `message.ROWID` we've already dispatched to the agent. The
20
- * polling loop asks chat.db for rows strictly greater than this value,
21
- * then advances the cursor to the largest row it actually processed.
22
- * Initialized to 0 on start; bumped on every successful dispatch so
23
- * we skip backlog on a fresh launch without ever double-delivering.
24
- */
25
- private lastRowId;
26
- /**
27
- * Reentrancy gate for the polling loop. Dispatch calls
28
- * `messageService.handleMessage` which invokes the LLM and typically
29
- * takes several seconds per message. With a 2-second poll interval
30
- * that means multiple ticks can land on top of each other, each
31
- * seeing the same stale cursor and re-dispatching the same rows.
32
- * This flag ensures at most one poll is in flight at a time; ticks
33
- * that arrive while a poll is active are dropped (the next scheduled
34
- * tick will pick up where the current one left off).
35
- */
36
- private pollInFlight;
37
- /**
38
- * Room keys we've already emitted a WORLD_JOINED event for in this
39
- * service lifetime. Not persisted — on restart every room is
40
- * re-greeted, which is correct: a fresh Eliza process doesn't know
41
- * what previous processes already synced, and the bootstrap plugin's
42
- * WORLD_JOINED handler is idempotent (handleServerSync tolerates
43
- * already-known rooms via upsert semantics).
44
- */
45
- private seenWorlds;
46
- /**
47
- * Entity keys we've already emitted an ENTITY_JOINED event for.
48
- * Same lifetime + rationale as seenWorlds.
49
- */
50
- private seenEntities;
51
- /**
52
- * Live chat.db handle, bound to the lifetime of this service. Non-null
53
- * means inbound polling is active. Null means either (a) not running
54
- * under Bun, or (b) chat.db couldn't be opened — in both cases the
55
- * service remains send-only and logs a one-time warning on start.
56
- */
57
- private chatDb;
58
- private chatDbPath;
59
- /**
60
- * Cached handle → display name map from the user's Apple Contacts.
61
- * Populated lazily on first inbound message via AppleScript against
62
- * Contacts.app, NOT at service start. Loading at boot would trigger
63
- * the macOS Contacts TCC dialog at app launch, even though the user
64
- * may never receive an inbound iMessage. We defer the AppleScript
65
- * call (and its TCC prompt) until the first message that actually
66
- * needs handle→name resolution. Empty map means either the user
67
- * hasn't authorized Contacts access yet, the address book is empty,
68
- * or no inbound message has triggered the lazy load yet.
69
- */
70
- private contacts;
71
- /** Whether the lazy contact load has been attempted this session. */
72
- private contactsLoadAttempted;
73
- /**
74
- * Start the iMessage service.
75
- */
76
- static start(runtime: IAgentRuntime): Promise<IMessageService>;
77
- static registerSendHandlers(runtime: IAgentRuntime, service: IMessageService): void;
78
- /**
79
- * Stop the iMessage service.
80
- */
81
- stop(): Promise<void>;
82
- /**
83
- * Check if the service is connected.
84
- */
85
- isConnected(): boolean;
86
- getStatus(): IMessageServiceStatus;
87
- /**
88
- * Check if running on macOS.
89
- */
90
- isMacOS(): boolean;
91
- /**
92
- * Send a message via iMessage.
93
- */
94
- sendMessage(to: string, text: string, options?: IMessageSendOptions): Promise<IMessageSendResult>;
95
- /**
96
- * Get recent messages by reading chat.db. Returns the most recent
97
- * `limit` messages (any sender, any chat) in chronological order.
98
- *
99
- * Returns an empty array if the chat.db reader is unavailable (plugin
100
- * running under plain Node without bun:sqlite, or Full Disk Access not
101
- * granted, etc.).
102
- */
103
- getRecentMessages(limit?: number): Promise<IMessageMessage[]>;
104
- /**
105
- * Return the newest messages in chronological order, optionally scoped
106
- * to a single chat identifier. Returns an empty array if chat.db is not
107
- * available and the connector is currently running in send-only mode.
108
- */
109
- getMessages(options?: IMessageListMessagesOptions): Promise<IMessageMessage[]>;
110
- /**
111
- * List every chat the Messages.app database knows about, joined with
112
- * participant handles. Returns an empty list if the chat.db reader is
113
- * unavailable (Node runtime, missing FDA, etc.).
114
- *
115
- * Previously this method used an AppleScript stub against
116
- * Messages.app's `chats` collection. That verb works but is slow and
117
- * returns a coarser view (no participant handles, no style field), so
118
- * the chat.db path is strictly better when it's available.
119
- */
120
- getChats(): Promise<IMessageChat[]>;
121
- /**
122
- * Get current settings.
123
- */
124
- getSettings(): IMessageSettings | null;
125
- /**
126
- * Get the cached Apple Contacts map loaded at service start.
127
- *
128
- * Keys are normalized handles (phones in digits-only + optional leading `+`,
129
- * emails lowercased). Values carry the contact's display name.
130
- *
131
- * Exposed for providers that want to inject contact lookups into agent
132
- * state so the LLM can resolve a person's name ("text Shaw") to a handle
133
- * it can pass to `sendMessage`.
134
- *
135
- * Returns an empty map if Contacts access was denied, failed to load,
136
- * or the service hasn't finished starting.
137
- */
138
- getContacts(): ContactsMap;
139
- /**
140
- * Lazy-load the Apple Contacts map on first call. Subsequent calls
141
- * are no-ops. We split this out from `start()` so the macOS Contacts
142
- * TCC dialog only fires when the runtime actually needs handle→name
143
- * resolution — typically the first inbound message — instead of at
144
- * app launch. Failure is non-fatal; the cached map stays empty and
145
- * the service falls back to raw handles.
146
- */
147
- private ensureContactsLoaded;
148
- /**
149
- * List every contact in the user's address book as a full record with
150
- * id, name, and all phones/emails. Delegates to contacts-reader's
151
- * `listAllContacts` which goes through Contacts.app's AppleScript
152
- * dump. Returns `[]` on failure (permission denied, etc.).
153
- */
154
- listAllContacts(): Promise<FullContact[]>;
155
- /**
156
- * Create a new contact in Contacts.app. Requires Contacts WRITE
157
- * permission (macOS prompts on first call). Returns the new person's
158
- * id on success, or null on failure.
159
- *
160
- * After a successful create we refresh the cached handle→name map so
161
- * inbound messages from the new contact resolve to their name on the
162
- * very next poll, without requiring a service restart.
163
- */
164
- addContact(input: NewContactInput): Promise<string | null>;
165
- /**
166
- * Patch an existing contact (name fields, add/remove phones, add/remove
167
- * emails). Returns true on success, false on failure. Refreshes the
168
- * cached map on success so name resolution reflects the change.
169
- */
170
- updateContact(personId: string, patch: ContactPatch): Promise<boolean>;
171
- /**
172
- * Delete a contact by Contacts.app id. Returns true on success,
173
- * false on failure. Refreshes the cached map on success.
174
- */
175
- deleteContact(personId: string): Promise<boolean>;
176
- private loadSettings;
177
- private validateSettings;
178
- private sendSingleMessage;
179
- private sendViaCli;
180
- private sendViaAppleScript;
181
- private runAppleScript;
182
- private startPolling;
183
- /**
184
- * Poll chat.db for rows newer than the cursor and route each inbound
185
- * message through the agent's message pipeline.
186
- *
187
- * Flow per message:
188
- * 1. Read new rows from chat.db via the bun:sqlite reader.
189
- * 2. Skip outbound (is_from_me=1), already-seen, and policy-denied rows.
190
- * 3. Build a Memory object in the shape the bootstrap plugin expects.
191
- * 4. Ensure the entity + room + world exist via ensureConnection.
192
- * 5. Call runtime.messageService.handleMessage with a callback that
193
- * sends the agent's reply back through sendViaAppleScript.
194
- * 6. Also emit the plugin-namespaced IMESSAGE_MESSAGE_RECEIVED event
195
- * and the core EventType.MESSAGE_RECEIVED event for any listeners.
196
- *
197
- * Advances this.lastRowId unconditionally to the max rowId we saw in
198
- * this batch — even for skipped rows — so the cursor keeps moving
199
- * forward and we never get stuck re-reading the same row on every poll.
200
- */
201
- private pollForNewMessages;
202
- private pollForNewMessagesInner;
203
- /**
204
- * Turn a single chat.db row into a `Memory`, wire up a reply callback,
205
- * and hand the whole thing to `runtime.messageService.handleMessage`.
206
- *
207
- * Mirrors the shape used by @elizaos/plugin-telegram so the bootstrap
208
- * plugin's message pipeline picks up inbound iMessages the same way it
209
- * picks up Telegram messages — same entity/room/world creation, same
210
- * `source: "imessage"` tag on content, same HandlerCallback signature
211
- * for the reply path.
212
- */
213
- private dispatchInboundMessage;
214
- /**
215
- * Handle non-conversational chat.db rows — reactions, group events,
216
- * anything that isn't a normal text turn. These shouldn't flow through
217
- * `messageService.handleMessage` (which would try to generate a reply)
218
- * but they're still useful to surface as plugin-namespaced events so
219
- * listeners can react, log, or update state.
220
- *
221
- * Emits two events:
222
- * - A plugin-namespaced event on the existing `IMessageEventTypes`
223
- * enum (e.g. `IMESSAGE_REACTION_RECEIVED`).
224
- * - The generic `EventType.REACTION_RECEIVED` from core when the
225
- * row is a reaction, so core-level handlers see it.
226
- */
227
- private emitAuxiliaryEvent;
228
- private isAllowed;
229
- /**
230
- * Register a recurring heartbeat task with Eliza's task system and
231
- * kick off one if it isn't already queued.
232
- *
233
- * The heartbeat runs once a minute (configurable via
234
- * `IMESSAGE_HEARTBEAT_INTERVAL_MS`) and does a lightweight health
235
- * probe: (a) chat.db reader is still open and responsive,
236
- * (b) Contacts map still populated, (c) polling cursor is advancing
237
- * when expected. On failure it logs + emits
238
- * `IMESSAGE_HEARTBEAT_UNHEALTHY`; on success it emits
239
- * `IMESSAGE_HEARTBEAT_OK`. Observers (Eliza's heartbeat UI, ops
240
- * dashboards, trajectory logger) subscribe to these events.
241
- *
242
- * The task is tagged `["queue", "repeat", "imessage"]` so Eliza's
243
- * built-in TaskService picks it up via its standard polling loop.
244
- * Without `updateInterval` being set in metadata, the task fires
245
- * once and then deletes; with it, the task service re-schedules.
246
- */
247
- private registerHeartbeat;
248
- }
249
- /**
250
- * Convert a `ChatDbMessage` (the shape the bun:sqlite reader returns)
251
- * into the public `IMessageMessage` shape exposed by this plugin's API.
252
- * Exported so the test suite can exercise it in isolation without
253
- * spinning up a full runtime + service instance.
254
- */
255
- export declare function chatDbMessageToPublicShape(row: ChatDbMessage): IMessageMessage;
256
- /**
257
- * Parse tab-delimited AppleScript messages output.
258
- * Expected format per line: "id\ttext\tdate_sent\tis_from_me\tchat_identifier\tsender"
259
- */
260
- export declare function parseMessagesFromAppleScript(result: string): IMessageMessage[];
261
- /**
262
- * Parse tab-delimited AppleScript chats output.
263
- * Expected format per line: "chat_identifier\tdisplay_name\tparticipant_count\tlast_message_date"
264
- */
265
- export declare function parseChatsFromAppleScript(result: string): IMessageChat[];
266
- //# sourceMappingURL=service.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}