instar 0.26.3 → 0.26.5

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 (102) hide show
  1. package/README.md +61 -7
  2. package/dashboard/index.html +55 -0
  3. package/dist/commands/init.d.ts.map +1 -1
  4. package/dist/commands/init.js +2 -1
  5. package/dist/commands/init.js.map +1 -1
  6. package/dist/commands/server.d.ts.map +1 -1
  7. package/dist/commands/server.js +188 -3
  8. package/dist/commands/server.js.map +1 -1
  9. package/dist/commands/slack-cli.d.ts.map +1 -1
  10. package/dist/commands/slack-cli.js +6 -0
  11. package/dist/commands/slack-cli.js.map +1 -1
  12. package/dist/core/CapabilityMapper.d.ts.map +1 -1
  13. package/dist/core/CapabilityMapper.js +2 -0
  14. package/dist/core/CapabilityMapper.js.map +1 -1
  15. package/dist/core/EvolutionManager.d.ts +17 -0
  16. package/dist/core/EvolutionManager.d.ts.map +1 -1
  17. package/dist/core/EvolutionManager.js +64 -0
  18. package/dist/core/EvolutionManager.js.map +1 -1
  19. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  20. package/dist/core/PostUpdateMigrator.js +37 -0
  21. package/dist/core/PostUpdateMigrator.js.map +1 -1
  22. package/dist/core/SessionManager.d.ts +31 -0
  23. package/dist/core/SessionManager.d.ts.map +1 -1
  24. package/dist/core/SessionManager.js +169 -16
  25. package/dist/core/SessionManager.js.map +1 -1
  26. package/dist/index.d.ts +1 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +1 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/messaging/imessage/IMessageAdapter.d.ts +128 -0
  31. package/dist/messaging/imessage/IMessageAdapter.d.ts.map +1 -0
  32. package/dist/messaging/imessage/IMessageAdapter.js +541 -0
  33. package/dist/messaging/imessage/IMessageAdapter.js.map +1 -0
  34. package/dist/messaging/imessage/NativeBackend.d.ts +82 -0
  35. package/dist/messaging/imessage/NativeBackend.d.ts.map +1 -0
  36. package/dist/messaging/imessage/NativeBackend.js +353 -0
  37. package/dist/messaging/imessage/NativeBackend.js.map +1 -0
  38. package/dist/messaging/imessage/OutboundAuditLog.d.ts +49 -0
  39. package/dist/messaging/imessage/OutboundAuditLog.d.ts.map +1 -0
  40. package/dist/messaging/imessage/OutboundAuditLog.js +58 -0
  41. package/dist/messaging/imessage/OutboundAuditLog.js.map +1 -0
  42. package/dist/messaging/imessage/OutboundRateLimiter.d.ts +54 -0
  43. package/dist/messaging/imessage/OutboundRateLimiter.d.ts.map +1 -0
  44. package/dist/messaging/imessage/OutboundRateLimiter.js +111 -0
  45. package/dist/messaging/imessage/OutboundRateLimiter.js.map +1 -0
  46. package/dist/messaging/imessage/index.d.ts +10 -0
  47. package/dist/messaging/imessage/index.d.ts.map +1 -0
  48. package/dist/messaging/imessage/index.js +13 -0
  49. package/dist/messaging/imessage/index.js.map +1 -0
  50. package/dist/messaging/imessage/normalize-phone.d.ts +26 -0
  51. package/dist/messaging/imessage/normalize-phone.d.ts.map +1 -0
  52. package/dist/messaging/imessage/normalize-phone.js +55 -0
  53. package/dist/messaging/imessage/normalize-phone.js.map +1 -0
  54. package/dist/messaging/imessage/types.d.ts +95 -0
  55. package/dist/messaging/imessage/types.d.ts.map +1 -0
  56. package/dist/messaging/imessage/types.js +5 -0
  57. package/dist/messaging/imessage/types.js.map +1 -0
  58. package/dist/messaging/shared/MessagingEventBus.d.ts +5 -0
  59. package/dist/messaging/shared/MessagingEventBus.d.ts.map +1 -1
  60. package/dist/messaging/shared/MessagingEventBus.js.map +1 -1
  61. package/dist/messaging/slack/SlackAdapter.d.ts.map +1 -1
  62. package/dist/messaging/slack/SlackAdapter.js +65 -1
  63. package/dist/messaging/slack/SlackAdapter.js.map +1 -1
  64. package/dist/messaging/slack/SocketModeClient.d.ts.map +1 -1
  65. package/dist/messaging/slack/SocketModeClient.js +6 -0
  66. package/dist/messaging/slack/SocketModeClient.js.map +1 -1
  67. package/dist/monitoring/PresenceProxy.d.ts +6 -0
  68. package/dist/monitoring/PresenceProxy.d.ts.map +1 -1
  69. package/dist/monitoring/PresenceProxy.js +46 -0
  70. package/dist/monitoring/PresenceProxy.js.map +1 -1
  71. package/dist/monitoring/QuotaExhaustionDetector.d.ts +15 -0
  72. package/dist/monitoring/QuotaExhaustionDetector.d.ts.map +1 -1
  73. package/dist/monitoring/QuotaExhaustionDetector.js +26 -3
  74. package/dist/monitoring/QuotaExhaustionDetector.js.map +1 -1
  75. package/dist/monitoring/SessionMonitor.d.ts.map +1 -1
  76. package/dist/monitoring/SessionMonitor.js +5 -2
  77. package/dist/monitoring/SessionMonitor.js.map +1 -1
  78. package/dist/monitoring/SessionRecovery.d.ts +16 -1
  79. package/dist/monitoring/SessionRecovery.d.ts.map +1 -1
  80. package/dist/monitoring/SessionRecovery.js +71 -8
  81. package/dist/monitoring/SessionRecovery.js.map +1 -1
  82. package/dist/scaffold/templates.d.ts +1 -1
  83. package/dist/scaffold/templates.d.ts.map +1 -1
  84. package/dist/scaffold/templates.js +32 -1
  85. package/dist/scaffold/templates.js.map +1 -1
  86. package/dist/scheduler/JobScheduler.js +1 -1
  87. package/dist/scheduler/JobScheduler.js.map +1 -1
  88. package/dist/server/AgentServer.d.ts +1 -0
  89. package/dist/server/AgentServer.d.ts.map +1 -1
  90. package/dist/server/AgentServer.js +1 -0
  91. package/dist/server/AgentServer.js.map +1 -1
  92. package/dist/server/routes.d.ts +1 -0
  93. package/dist/server/routes.d.ts.map +1 -1
  94. package/dist/server/routes.js +169 -0
  95. package/dist/server/routes.js.map +1 -1
  96. package/package.json +1 -1
  97. package/src/data/builtin-manifest.json +83 -67
  98. package/src/templates/hooks/intercept-imsg-send.js +68 -0
  99. package/src/templates/hooks/settings-template.json +11 -0
  100. package/src/templates/scripts/imessage-reply.sh +130 -0
  101. package/upgrades/0.26.4.md +17 -0
  102. package/upgrades/0.26.5.md +15 -0
@@ -0,0 +1,541 @@
1
+ /**
2
+ * IMessageAdapter — Native iMessage messaging adapter for Instar.
3
+ *
4
+ * Implements the MessagingAdapter interface using the NativeBackend
5
+ * (direct SQLite reads from chat.db + polling for new messages).
6
+ *
7
+ * Key design decisions:
8
+ * - macOS-only (requires Messages.app + Full Disk Access on node)
9
+ * - Read-only from server context (NativeBackend reads chat.db)
10
+ * - Sending happens from Claude Code sessions via imessage-reply.sh
11
+ * - authorizedContacts gates BOTH inbound AND outbound (unified allowlist)
12
+ * - sendEnabled defaults to false (read-only mode)
13
+ * - proactiveSendEnabled defaults to false (replies only)
14
+ * - Config is cached at startup — runtime edits don't expand permissions
15
+ * - SessionChannelRegistry maps senders to sessions
16
+ * - StallDetector monitors for unanswered messages
17
+ */
18
+ import path from 'node:path';
19
+ import crypto from 'node:crypto';
20
+ import { NativeBackend } from './NativeBackend.js';
21
+ import { MessageLogger } from '../shared/MessageLogger.js';
22
+ import { MessagingEventBus } from '../shared/MessagingEventBus.js';
23
+ import { SessionChannelRegistry } from '../shared/SessionChannelRegistry.js';
24
+ import { StallDetector } from '../shared/StallDetector.js';
25
+ import { OutboundRateLimiter } from './OutboundRateLimiter.js';
26
+ import { OutboundAuditLog } from './OutboundAuditLog.js';
27
+ import { normalizeIdentifier, normalizeIdentifierSet } from './normalize-phone.js';
28
+ const RECEIVED_IDS_MAX_SIZE = 1_000;
29
+ export class IMessageAdapter {
30
+ platform = 'imessage';
31
+ // Config (cached at startup — immutable at runtime)
32
+ config;
33
+ stateDir;
34
+ sendEnabled;
35
+ proactiveSendEnabled;
36
+ reactiveWindowHours;
37
+ triggerMode;
38
+ agentName;
39
+ // Components
40
+ backend;
41
+ logger;
42
+ eventBus;
43
+ registry;
44
+ stallDetector;
45
+ rateLimiter;
46
+ auditLog;
47
+ // State
48
+ messageHandler = null;
49
+ started = false;
50
+ authorizedContacts; // normalized E.164
51
+ receivedMessageIds = new Set();
52
+ lastInboundFrom = new Map(); // normalized contact → timestamp
53
+ pendingSendTokens = new Map();
54
+ // Callbacks (wired by server.ts)
55
+ onMessageLogged = null;
56
+ onStallDetected = null;
57
+ constructor(config, stateDir) {
58
+ this.config = config;
59
+ this.stateDir = stateDir;
60
+ // Resolve authorizedContacts with deprecation handling
61
+ const contacts = this._resolveAuthorizedContacts();
62
+ this.authorizedContacts = normalizeIdentifierSet(contacts);
63
+ if (this.authorizedContacts.size === 0) {
64
+ console.warn('[imessage] authorizedContacts is empty — all messages will be rejected and all sends blocked (fail-closed)');
65
+ }
66
+ // Cache config at startup — runtime edits to config.json don't take effect
67
+ this.sendEnabled = this.config.sendEnabled ?? false;
68
+ this.proactiveSendEnabled = this.config.proactiveSendEnabled ?? false;
69
+ this.reactiveWindowHours = this.config.reactiveWindowHours ?? 24;
70
+ this.triggerMode = this.config.triggerMode ?? 'mention';
71
+ this.agentName = this.config.agentName;
72
+ // Initialize backend (read-only)
73
+ this.backend = new NativeBackend({
74
+ dbPath: this.config.dbPath,
75
+ pollIntervalMs: this.config.pollIntervalMs,
76
+ includeAttachments: this.config.includeAttachments,
77
+ offsetPath: path.join(stateDir, 'imessage-poll-offset.json'),
78
+ authorizedContacts: Array.from(this.authorizedContacts),
79
+ });
80
+ // Initialize logger
81
+ this.logger = new MessageLogger({
82
+ logPath: path.join(stateDir, 'imessage-messages.jsonl'),
83
+ maxLines: 100_000,
84
+ keepLines: 75_000,
85
+ });
86
+ // Initialize event bus
87
+ this.eventBus = new MessagingEventBus('imessage');
88
+ // Initialize session-channel registry
89
+ this.registry = new SessionChannelRegistry({
90
+ registryPath: path.join(stateDir, 'imessage-sessions.json'),
91
+ });
92
+ // Initialize stall detector
93
+ this.stallDetector = new StallDetector({
94
+ stallTimeoutMinutes: this.config.stallTimeoutMinutes ?? 5,
95
+ promiseTimeoutMinutes: this.config.promiseTimeoutMinutes ?? 10,
96
+ });
97
+ // Initialize rate limiter
98
+ this.rateLimiter = new OutboundRateLimiter({
99
+ maxPerHour: this.config.maxOutboundPerHour ?? 20,
100
+ maxPerDay: this.config.maxOutboundPerDay ?? 100,
101
+ });
102
+ // Initialize audit log
103
+ this.auditLog = new OutboundAuditLog(path.join(stateDir, 'imessage-outbound.jsonl'));
104
+ // Wire backend message events
105
+ this.backend.on('message', (msg) => this._handleIncomingMessage(msg));
106
+ this.backend.on('stateChange', (state) => {
107
+ console.log(`[imessage] Connection state: ${state}`);
108
+ });
109
+ }
110
+ // ── MessagingAdapter Interface ──
111
+ async start() {
112
+ if (this.started)
113
+ return;
114
+ // Startup security warnings
115
+ this._logStartupWarnings();
116
+ await this.backend.connect();
117
+ this.started = true;
118
+ // Start stall detection
119
+ this.stallDetector.start();
120
+ console.log('[imessage] Adapter started (backend: native)');
121
+ }
122
+ async stop() {
123
+ this.started = false;
124
+ this.stallDetector.stop();
125
+ await this.backend.disconnect();
126
+ console.log('[imessage] Adapter stopped');
127
+ }
128
+ /**
129
+ * Send is NOT supported from the server process.
130
+ * iMessages must be sent from Claude Code sessions via imessage-reply.sh.
131
+ */
132
+ async send(_message) {
133
+ throw new Error('[imessage] Cannot send from server process — AppleScript Automation permission ' +
134
+ 'does not propagate through LaunchAgent. Use imessage-reply.sh from session context.');
135
+ }
136
+ onMessage(handler) {
137
+ this.messageHandler = handler;
138
+ }
139
+ async resolveUser(channelIdentifier) {
140
+ return channelIdentifier || null;
141
+ }
142
+ // ── Session Management ──
143
+ registerSession(sender, sessionName) {
144
+ this.registry.register(normalizeIdentifier(sender), sessionName, sender);
145
+ }
146
+ getSessionForSender(sender) {
147
+ return this.registry.getSessionForChannel(normalizeIdentifier(sender));
148
+ }
149
+ getSenderForSession(sessionName) {
150
+ return this.registry.getChannelForSession(sessionName);
151
+ }
152
+ // ── Stall Detection ──
153
+ trackMessageInjection(sender, sessionName, text) {
154
+ this.stallDetector.trackMessageInjection(normalizeIdentifier(sender), sessionName, text);
155
+ }
156
+ clearStallForSender(sender) {
157
+ this.stallDetector.clearStallForChannel(normalizeIdentifier(sender));
158
+ }
159
+ setIsSessionAlive(check) {
160
+ this.stallDetector.setIsSessionAlive(check);
161
+ }
162
+ setOnStall(callback) {
163
+ this.stallDetector.setOnStall(callback);
164
+ }
165
+ // ── Context & History ──
166
+ getConversationContext(sender, limit = 20) {
167
+ return this.backend.getConversationContext(sender, limit);
168
+ }
169
+ listChats(limit = 20) {
170
+ return this.backend.listChats(limit);
171
+ }
172
+ getChatHistory(chatId, limit = 50) {
173
+ return this.backend.getChatHistory(chatId, limit);
174
+ }
175
+ // ── Connection Info ──
176
+ getConnectionInfo() {
177
+ return {
178
+ state: this.backend.state,
179
+ connectedAt: this.started ? new Date().toISOString() : undefined,
180
+ lastError: undefined,
181
+ reconnectAttempts: 0,
182
+ };
183
+ }
184
+ // ── Auth (unified — gates both directions) ──
185
+ isAuthorized(sender) {
186
+ return this.authorizedContacts.has(normalizeIdentifier(sender));
187
+ }
188
+ // ── Outbound Safety ──
189
+ /** Whether sending is enabled (cached from startup config). */
190
+ isSendEnabled() {
191
+ return this.sendEnabled;
192
+ }
193
+ /** Whether proactive (agent-initiated) sends are enabled. */
194
+ isProactiveSendEnabled() {
195
+ return this.proactiveSendEnabled;
196
+ }
197
+ /**
198
+ * Check if a send to this recipient is a reactive reply (within reactive window)
199
+ * or a proactive send (no recent inbound).
200
+ */
201
+ getSendMode(recipient) {
202
+ const normalized = normalizeIdentifier(recipient);
203
+ const lastInbound = this.lastInboundFrom.get(normalized);
204
+ if (!lastInbound)
205
+ return 'proactive';
206
+ const windowMs = this.reactiveWindowHours * 3_600_000;
207
+ if (Date.now() - lastInbound > windowMs)
208
+ return 'proactive';
209
+ return 'reactive';
210
+ }
211
+ /**
212
+ * Validate a send request. Returns either an approval with a single-use token,
213
+ * or a rejection with reason.
214
+ *
215
+ * This is Layer 3 of the 5-layer defense-in-depth.
216
+ */
217
+ validateSend(recipient) {
218
+ const normalized = normalizeIdentifier(recipient);
219
+ // Check send enabled
220
+ if (!this.sendEnabled) {
221
+ this.auditLog.record({
222
+ recipient: normalized,
223
+ text: '',
224
+ allowed: false,
225
+ blockedBy: 'layer3:sendDisabled',
226
+ rateStatus: this.rateLimiter.countsFor(normalized),
227
+ });
228
+ return { allowed: false, reason: 'sendEnabled is false (read-only mode)' };
229
+ }
230
+ // Check authorized
231
+ if (!this.authorizedContacts.has(normalized)) {
232
+ this.auditLog.record({
233
+ recipient: normalized,
234
+ text: '',
235
+ allowed: false,
236
+ blockedBy: 'layer3:unauthorized',
237
+ rateStatus: this.rateLimiter.countsFor(normalized),
238
+ });
239
+ return { allowed: false, reason: 'recipient not in authorizedContacts' };
240
+ }
241
+ // Check proactive vs reactive
242
+ const sendMode = this.getSendMode(normalized);
243
+ if (sendMode === 'proactive' && !this.proactiveSendEnabled) {
244
+ this.auditLog.record({
245
+ recipient: normalized,
246
+ text: '',
247
+ allowed: false,
248
+ blockedBy: 'layer3:proactiveDisabled',
249
+ sendMode: 'proactive',
250
+ rateStatus: this.rateLimiter.countsFor(normalized),
251
+ });
252
+ return { allowed: false, reason: 'proactive sends not enabled — no recent inbound from this contact' };
253
+ }
254
+ // Check rate limits
255
+ const rateCheck = this.rateLimiter.check(normalized);
256
+ if (!rateCheck.allowed) {
257
+ this.auditLog.record({
258
+ recipient: normalized,
259
+ text: '',
260
+ allowed: false,
261
+ blockedBy: 'layer4:rateLimit',
262
+ sendMode,
263
+ rateStatus: this.rateLimiter.countsFor(normalized),
264
+ });
265
+ // Emit rate limit event for user notification
266
+ this.eventBus.emit('rate:outbound-limited', {
267
+ recipient: IMessageAdapter.maskIdentifier(normalized),
268
+ reason: rateCheck.reason || 'rate limit exceeded',
269
+ }).catch(() => { });
270
+ return { allowed: false, reason: rateCheck.reason || 'rate limit exceeded' };
271
+ }
272
+ // Issue single-use send token (TOCTOU mitigation)
273
+ const token = crypto.randomUUID();
274
+ const sendToken = {
275
+ token,
276
+ recipient: normalized,
277
+ issuedAt: Date.now(),
278
+ ttlMs: 30_000, // 30 seconds
279
+ };
280
+ this.pendingSendTokens.set(token, sendToken);
281
+ // Clean up expired tokens
282
+ this._cleanupExpiredTokens();
283
+ return { allowed: true, token, sendMode };
284
+ }
285
+ /**
286
+ * Confirm a send (called after the message is actually delivered).
287
+ * Validates the send token and records the send for rate limiting + audit.
288
+ */
289
+ confirmSend(token, recipient, text) {
290
+ const normalized = normalizeIdentifier(recipient);
291
+ const sendToken = this.pendingSendTokens.get(token);
292
+ if (!sendToken) {
293
+ this.auditLog.record({
294
+ recipient: normalized,
295
+ text,
296
+ allowed: false,
297
+ blockedBy: 'layer3:invalidToken',
298
+ rateStatus: this.rateLimiter.countsFor(normalized),
299
+ });
300
+ return { ok: false, reason: 'invalid or expired send token' };
301
+ }
302
+ // Consume the token (single-use)
303
+ this.pendingSendTokens.delete(token);
304
+ // Verify token matches the recipient (prevents validate-for-A, send-to-B)
305
+ if (sendToken.recipient !== normalized) {
306
+ this.auditLog.record({
307
+ recipient: normalized,
308
+ text,
309
+ allowed: false,
310
+ blockedBy: 'layer3:tokenMismatch',
311
+ sendToken: token,
312
+ rateStatus: this.rateLimiter.countsFor(normalized),
313
+ });
314
+ return { ok: false, reason: 'send token was issued for a different recipient' };
315
+ }
316
+ // Check TTL
317
+ if (Date.now() - sendToken.issuedAt > sendToken.ttlMs) {
318
+ this.auditLog.record({
319
+ recipient: normalized,
320
+ text,
321
+ allowed: false,
322
+ blockedBy: 'layer3:tokenExpired',
323
+ sendToken: token,
324
+ rateStatus: this.rateLimiter.countsFor(normalized),
325
+ });
326
+ return { ok: false, reason: 'send token expired (30s TTL)' };
327
+ }
328
+ // Record for rate limiting
329
+ this.rateLimiter.record(normalized);
330
+ // Audit log — allowed
331
+ const sendMode = this.getSendMode(normalized);
332
+ this.auditLog.record({
333
+ recipient: normalized,
334
+ text,
335
+ allowed: true,
336
+ sendMode,
337
+ sendToken: token,
338
+ rateStatus: this.rateLimiter.countsFor(normalized),
339
+ });
340
+ return { ok: true };
341
+ }
342
+ /** Get rate limiter status (for debugging/admin endpoints). */
343
+ getRateLimitStatus() {
344
+ return this.rateLimiter.status();
345
+ }
346
+ // ── Trigger Mode ──
347
+ /** Set the agent name for mention-based triggering. */
348
+ setAgentName(name) {
349
+ this.agentName = name;
350
+ }
351
+ /** Get the current trigger mode. */
352
+ getTriggerMode() {
353
+ return this.triggerMode;
354
+ }
355
+ /**
356
+ * Check whether an incoming message triggers the agent.
357
+ * In "mention" mode, requires @{agentName} in the message text.
358
+ * In "all" mode, every message triggers.
359
+ * Returns the stripped text (mention removed) if triggered.
360
+ */
361
+ _checkTrigger(text) {
362
+ if (this.triggerMode === 'all') {
363
+ return { triggered: true, strippedText: text };
364
+ }
365
+ // Mention mode — require @{agentName}
366
+ if (!this.agentName) {
367
+ // No agent name configured — fall back to triggering on all messages
368
+ return { triggered: true, strippedText: text };
369
+ }
370
+ const escaped = this.agentName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
371
+ const mentionPattern = new RegExp(`@${escaped}\\b`, 'i');
372
+ const match = text.match(mentionPattern);
373
+ if (!match) {
374
+ return { triggered: false, strippedText: text };
375
+ }
376
+ // Strip the mention from the message before routing
377
+ const stripped = text.replace(mentionPattern, '').replace(/\s+/g, ' ').trim();
378
+ return { triggered: true, strippedText: stripped || text };
379
+ }
380
+ // ── Logging ──
381
+ get messageLogger() {
382
+ return this.logger;
383
+ }
384
+ logOutboundMessage(recipient, text) {
385
+ this._logMessage({
386
+ messageId: `out-${Date.now()}`,
387
+ channelId: normalizeIdentifier(recipient),
388
+ text,
389
+ fromUser: false,
390
+ timestamp: new Date().toISOString(),
391
+ sessionName: null,
392
+ platform: 'imessage',
393
+ });
394
+ }
395
+ static maskIdentifier(id) {
396
+ if (id.startsWith('+') && id.length > 6) {
397
+ return id.slice(0, 4) + '***' + id.slice(-4);
398
+ }
399
+ if (id.includes('@')) {
400
+ const [local, domain] = id.split('@');
401
+ return local.slice(0, 2) + '***@' + domain;
402
+ }
403
+ return '***';
404
+ }
405
+ // ── Internal ──
406
+ /**
407
+ * Resolve the contact allowlist from config, handling the
408
+ * authorizedSenders → authorizedContacts migration.
409
+ */
410
+ _resolveAuthorizedContacts() {
411
+ const newKey = this.config.authorizedContacts;
412
+ const oldKey = this.config.authorizedSenders;
413
+ if (newKey && Array.isArray(newKey)) {
414
+ if (oldKey && Array.isArray(oldKey)) {
415
+ console.warn('[imessage] Both authorizedContacts and authorizedSenders are present. ' +
416
+ 'Using authorizedContacts only. Rename authorizedSenders to authorizedContacts to suppress this warning.');
417
+ }
418
+ return newKey;
419
+ }
420
+ if (oldKey && Array.isArray(oldKey)) {
421
+ console.warn('[imessage] authorizedSenders is deprecated — rename to authorizedContacts. ' +
422
+ 'Both gate inbound AND outbound messaging.');
423
+ return oldKey;
424
+ }
425
+ // Neither present — fail-closed
426
+ throw new Error('[imessage] authorizedContacts is required (array of phone numbers or email addresses)');
427
+ }
428
+ _logStartupWarnings() {
429
+ if (this.sendEnabled) {
430
+ console.warn('[imessage] ⚠️ iMessage send is enabled with software-level guardrails. ' +
431
+ 'Read-only mode (sendEnabled: false) provides stronger security. ' +
432
+ 'Server-mediated sending (Phase 2) is planned.');
433
+ }
434
+ if (this.proactiveSendEnabled) {
435
+ console.warn('[imessage] ⚠️ Proactive iMessage send is enabled. ' +
436
+ 'The agent can initiate messages to authorized contacts without them messaging first.');
437
+ }
438
+ }
439
+ async _handleIncomingMessage(msg) {
440
+ // Skip own outbound messages
441
+ if (msg.isFromMe)
442
+ return;
443
+ // Skip duplicate notifications
444
+ if (this.receivedMessageIds.has(msg.messageId))
445
+ return;
446
+ this._trackReceivedId(msg.messageId);
447
+ // Authorization check (fail-closed) — uses normalized comparison
448
+ const senderNormalized = normalizeIdentifier(msg.sender);
449
+ if (!this.authorizedContacts.has(senderNormalized)) {
450
+ console.log(`[imessage] Rejected message from unauthorized sender: ${IMessageAdapter.maskIdentifier(msg.sender)}`);
451
+ return;
452
+ }
453
+ // Track last inbound time for reactive window
454
+ this.lastInboundFrom.set(senderNormalized, Date.now());
455
+ // Check trigger mode — in "mention" mode, only respond if @agentName is present
456
+ const triggerResult = this._checkTrigger(msg.text);
457
+ if (!triggerResult.triggered) {
458
+ console.log(`[imessage] Message from ${IMessageAdapter.maskIdentifier(msg.sender)} logged but not triggered (mention mode, no @${this.agentName})`);
459
+ // Still log the message for awareness, just don't route it
460
+ this._logMessage({
461
+ messageId: msg.messageId,
462
+ channelId: msg.chatId,
463
+ text: msg.text,
464
+ fromUser: true,
465
+ timestamp: new Date(msg.timestamp * 1000).toISOString(),
466
+ sessionName: null,
467
+ senderName: msg.senderName,
468
+ platformUserId: msg.sender,
469
+ platform: 'imessage',
470
+ });
471
+ return;
472
+ }
473
+ // Use the stripped text (mention removed) for downstream processing
474
+ const processedText = triggerResult.strippedText;
475
+ // Log inbound message
476
+ this._logMessage({
477
+ messageId: msg.messageId,
478
+ channelId: msg.chatId,
479
+ text: msg.text,
480
+ fromUser: true,
481
+ timestamp: new Date(msg.timestamp * 1000).toISOString(),
482
+ sessionName: null,
483
+ senderName: msg.senderName,
484
+ platformUserId: msg.sender,
485
+ platform: 'imessage',
486
+ });
487
+ // Emit on event bus
488
+ await this.eventBus.emit('message:incoming', {
489
+ channelId: msg.chatId,
490
+ userId: msg.sender,
491
+ text: processedText,
492
+ timestamp: new Date(msg.timestamp * 1000).toISOString(),
493
+ raw: msg,
494
+ });
495
+ // Route to registered message handler
496
+ if (this.messageHandler) {
497
+ const message = {
498
+ id: msg.messageId,
499
+ userId: msg.sender,
500
+ content: processedText,
501
+ channel: { type: 'imessage', identifier: msg.sender },
502
+ receivedAt: new Date(msg.timestamp * 1000).toISOString(),
503
+ metadata: {
504
+ chatId: msg.chatId,
505
+ senderName: msg.senderName,
506
+ service: msg.service,
507
+ attachments: msg.attachments,
508
+ },
509
+ };
510
+ try {
511
+ await this.messageHandler(message);
512
+ }
513
+ catch (err) {
514
+ console.error(`[imessage] Message handler error: ${err.message}`);
515
+ }
516
+ }
517
+ }
518
+ _trackReceivedId(messageId) {
519
+ this.receivedMessageIds.add(messageId);
520
+ if (this.receivedMessageIds.size > RECEIVED_IDS_MAX_SIZE) {
521
+ const oldest = this.receivedMessageIds.values().next().value;
522
+ if (oldest !== undefined)
523
+ this.receivedMessageIds.delete(oldest);
524
+ }
525
+ }
526
+ _logMessage(entry) {
527
+ this.logger.append(entry);
528
+ if (this.onMessageLogged) {
529
+ this.onMessageLogged(entry);
530
+ }
531
+ }
532
+ _cleanupExpiredTokens() {
533
+ const now = Date.now();
534
+ for (const [token, sendToken] of this.pendingSendTokens) {
535
+ if (now - sendToken.issuedAt > sendToken.ttlMs) {
536
+ this.pendingSendTokens.delete(token);
537
+ }
538
+ }
539
+ }
540
+ }
541
+ //# sourceMappingURL=IMessageAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IMessageAdapter.js","sourceRoot":"","sources":["../../../src/messaging/imessage/IMessageAdapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * NativeBackend — Read-only macOS Messages database integration.
3
+ *
4
+ * Provides:
5
+ * - SQLite reads from ~/Library/Messages/chat.db (via better-sqlite3)
6
+ * - Polling for new messages (watches max ROWID)
7
+ * - Conversation context formatting for session bootstrap
8
+ *
9
+ * Does NOT send messages. Sending happens from Claude Code sessions
10
+ * via imessage-reply.sh → imsg send CLI, because AppleScript Automation
11
+ * permission doesn't propagate through LaunchAgent process trees.
12
+ *
13
+ * Requires:
14
+ * - Full Disk Access for the process reading chat.db
15
+ */
16
+ import { EventEmitter } from 'node:events';
17
+ import type { IMessageIncoming, IMessageChat, ConnectionState } from './types.js';
18
+ export interface NativeBackendOptions {
19
+ /** Path to chat.db (default: ~/Library/Messages/chat.db) */
20
+ dbPath?: string;
21
+ /** Poll interval for new messages in ms (default: 2000) */
22
+ pollIntervalMs?: number;
23
+ /** Include attachment metadata (default: true) */
24
+ includeAttachments?: boolean;
25
+ /** Path to persist poll offset (lastRowId) across restarts */
26
+ offsetPath?: string;
27
+ /** Authorized contacts (normalized E.164) — scopes SQL queries for defense-in-depth */
28
+ authorizedContacts?: string[];
29
+ }
30
+ export declare class NativeBackend extends EventEmitter {
31
+ private db;
32
+ private pollTimer;
33
+ private lastRowId;
34
+ private _state;
35
+ private readonly dbPath;
36
+ private readonly pollIntervalMs;
37
+ private readonly includeAttachments;
38
+ private readonly offsetPath;
39
+ private readonly authorizedContacts;
40
+ private stmtNewMessages;
41
+ private stmtChats;
42
+ private stmtHistory;
43
+ private stmtMaxRowId;
44
+ private stmtContextHistory;
45
+ constructor(options?: NativeBackendOptions);
46
+ get state(): ConnectionState;
47
+ /**
48
+ * Open the Messages database and start polling for new messages.
49
+ */
50
+ connect(): Promise<void>;
51
+ /**
52
+ * Stop polling and close the database.
53
+ */
54
+ disconnect(): Promise<void>;
55
+ /**
56
+ * List recent chats.
57
+ */
58
+ listChats(limit?: number): IMessageChat[];
59
+ /**
60
+ * Get message history for a chat.
61
+ */
62
+ getChatHistory(chatId: string, limit?: number): IMessageIncoming[];
63
+ /**
64
+ * Format conversation context for session bootstrap.
65
+ * Returns a formatted string of recent messages suitable for injection
66
+ * into a Claude Code session as conversation history.
67
+ */
68
+ getConversationContext(sender: string, limit?: number): string;
69
+ private _startPolling;
70
+ private _stopPolling;
71
+ _poll(): void;
72
+ private _setState;
73
+ /** Convert Apple Cocoa nanosecond timestamp to Unix epoch seconds. */
74
+ _cocoaToUnix(cocoaNanos: number): number;
75
+ /** Load persisted poll offset from disk. */
76
+ private _loadOffset;
77
+ /** Save poll offset to disk. */
78
+ private _saveOffset;
79
+ /** Convert Apple Cocoa nanosecond timestamp to ISO string. */
80
+ private _cocoaToIso;
81
+ }
82
+ //# sourceMappingURL=NativeBackend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeBackend.d.ts","sourceRoot":"","sources":["../../../src/messaging/imessage/NativeBackend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAQlF,MAAM,WAAW,oBAAoB;IACnC,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kDAAkD;IAClD,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uFAAuF;IACvF,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED,qBAAa,aAAc,SAAQ,YAAY;IAC7C,OAAO,CAAC,EAAE,CAAkD;IAC5D,OAAO,CAAC,SAAS,CAA+C;IAChE,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAU;IAC7C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAC3C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAW;IAG9C,OAAO,CAAC,eAAe,CAAmD;IAC1E,OAAO,CAAC,SAAS,CAAmD;IACpE,OAAO,CAAC,WAAW,CAAmD;IACtE,OAAO,CAAC,YAAY,CAAmD;IACvE,OAAO,CAAC,kBAAkB,CAAmD;gBAEjE,OAAO,GAAE,oBAAyB;IAS9C,IAAI,KAAK,IAAI,eAAe,CAE3B;IAED;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAyH9B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAcjC;;OAEG;IACH,SAAS,CAAC,KAAK,SAAK,GAAG,YAAY,EAAE;IA6BrC;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,gBAAgB,EAAE;IA+B9D;;;;OAIG;IACH,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,MAAM;IAoC1D,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,YAAY;IAOpB,KAAK,IAAI,IAAI;IAuDb,OAAO,CAAC,SAAS;IAQjB,sEAAsE;IACtE,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAIxC,4CAA4C;IAC5C,OAAO,CAAC,WAAW;IAWnB,gCAAgC;IAChC,OAAO,CAAC,WAAW;IAOnB,8DAA8D;IAC9D,OAAO,CAAC,WAAW;CAGpB"}